4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
27 #include <sys/param.h>
28 #include <sys/errno.h>
31 #include <sys/sunddi.h>
32 #include <fs/fs_reparse.h>
36 #include <sys/fs_reparse.h>
38 #define strfree(str) free((str))
41 static char *reparse_skipspace(char *cp
);
42 static int reparse_create_nvlist(const char *string
, nvlist_t
*nvl
);
43 static int reparse_add_nvpair(char *token
, nvlist_t
*nvl
);
44 static boolean_t
reparse_validate_svctype(char *svc_str
);
45 static int reparse_validate_create_nvlist(const char *string
, nvlist_t
*nvl
);
47 /* array of characters not allowed in service type string */
48 static char svctype_invalid_chars
[] = { '{', '}', 0 };
53 * Function to allocate a new name-value pair list.
54 * Caller needs to call reparse_free() to free memory
55 * used by the list when done.
57 * Return pointer to new list else return NULL.
65 * Service type is unique, only one entry
66 * of each service type is allowed
68 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0))
77 * Function to free memory of a nvlist allocated previously
81 reparse_free(nvlist_t
*nvl
)
89 * Parse the specified string and populate the nvlist with the svc_types
90 * and data from the 'string'. The string could be read from the reparse
91 * point symlink body. This routine will allocate memory that must be
92 * freed by reparse_free().
94 * If ok return 0 and the nvlist is populated, otherwise return error code.
97 reparse_parse(const char *string
, nvlist_t
*nvl
)
101 if (string
== NULL
|| nvl
== NULL
)
104 if ((err
= reparse_validate(string
)) != 0)
107 if ((err
= reparse_create_nvlist(string
, nvl
)) != 0)
114 reparse_skipspace(char *cp
)
116 while ((*cp
) && (*cp
== ' ' || *cp
== '\t'))
122 reparse_validate_svctype(char *svc_str
)
129 len
= strlen(svc_str
);
130 for (ix
= 0; ix
< len
; ix
++) {
131 for (nx
= 0; nx
< sizeof (svctype_invalid_chars
); nx
++) {
132 if (svc_str
[ix
] == svctype_invalid_chars
[nx
])
140 reparse_validate_svc_token(char *svc_token
)
144 if (svc_token
== NULL
)
146 if ((cp
= strchr(svc_token
, ':')) == NULL
)
153 * make sure service type and service data are non-empty string.
155 if (strlen(svc_token
) == 0 || strlen(cp
+ 1) == 0) {
165 * Format of reparse data:
166 * @{REPARSE@{servicetype:data} [@{servicetype:data}] ...}
167 * REPARSE_TAG_STR@{REPARSE_TOKEN} [@{REPARSE_TOKEN}] ... REPARSE_TAG_END
169 * Validating reparse data:
170 * . check for valid length of reparse data
171 * . check for valid reparse data format
172 * Return 0 if OK else return error code.
175 reparse_validate(const char *string
)
177 return (reparse_validate_create_nvlist(string
, NULL
));
181 * reparse_validate_create_nvlist
183 * dual-purpose function:
184 * . Validate a reparse data string.
185 * . Validate a reparse data string and parse the data
189 reparse_validate_create_nvlist(const char *string
, nvlist_t
*nvl
)
192 char *reparse_data
, save_c
, save_e
, *save_e_ptr
, *cp
, *s_str
, *e_str
;
197 if (strlen(string
) >= MAXREPARSELEN
)
198 return (ENAMETOOLONG
);
200 if ((reparse_data
= strdup(string
)) == NULL
)
203 /* check FS_REPARSE_TAG_STR */
204 if (strncmp(reparse_data
, FS_REPARSE_TAG_STR
,
205 strlen(FS_REPARSE_TAG_STR
))) {
206 strfree(reparse_data
);
210 /* locate FS_REPARSE_TAG_END_CHAR */
211 if ((cp
= strrchr(reparse_data
, FS_REPARSE_TAG_END_CHAR
)) == NULL
) {
212 strfree(reparse_data
);
220 cp
++; /* should point to NULL, or spaces */
222 cp
= reparse_skipspace(cp
);
224 *save_e_ptr
= save_e
;
225 strfree(reparse_data
);
229 /* skip FS_REPARSE_TAG_STR */
230 s_str
= reparse_data
+ strlen(FS_REPARSE_TAG_STR
);
232 /* skip spaces after FS_REPARSE_TAG_STR */
233 s_str
= reparse_skipspace(s_str
);
236 while (s_str
< e_str
) {
237 /* check FS_TOKEN_START_STR */
238 if (strncmp(s_str
, FS_TOKEN_START_STR
,
239 strlen(FS_TOKEN_START_STR
))) {
240 *save_e_ptr
= save_e
;
241 strfree(reparse_data
);
245 /* skip over FS_TOKEN_START_STR */
246 s_str
+= strlen(FS_TOKEN_START_STR
);
248 /* locate FS_TOKEN_END_STR */
249 if ((cp
= strstr(s_str
, FS_TOKEN_END_STR
)) == NULL
) {
250 *save_e_ptr
= save_e
;
251 strfree(reparse_data
);
259 /* check for valid characters in service type */
260 if (reparse_validate_svctype(s_str
) == B_FALSE
) {
262 *save_e_ptr
= save_e
;
263 strfree(reparse_data
);
267 if (strlen(s_str
) == 0) {
269 *save_e_ptr
= save_e
;
270 strfree(reparse_data
);
274 if (reparse_validate_svc_token(s_str
) == B_FALSE
) {
276 *save_e_ptr
= save_e
;
277 strfree(reparse_data
);
281 /* create a nvpair entry */
283 (err
= reparse_add_nvpair(s_str
, nvl
)) != 0) {
285 *save_e_ptr
= save_e
;
286 strfree(reparse_data
);
292 /* skip over FS_TOKEN_END_STR */
293 cp
+= strlen(FS_TOKEN_END_STR
);
294 cp
= reparse_skipspace(cp
);
297 *save_e_ptr
= save_e
;
298 strfree(reparse_data
);
300 return (tcnt
? 0 : EINVAL
);
304 reparse_add_nvpair(char *token
, nvlist_t
*nvl
)
309 if ((cp
= strchr(token
, ':')) == NULL
)
314 err
= nvlist_add_string(nvl
, token
, cp
+ 1);
321 reparse_create_nvlist(const char *string
, nvlist_t
*nvl
)
326 return (reparse_validate_create_nvlist(string
, nvl
));