9128 cw(1onbld) should be able to run multiple shadows
[unleashed.git] / usr / src / common / fsreparse / fs_reparse.c
blob787706af35e30b6a0f0602d5699bae8156a777a6
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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>
30 #ifdef _KERNEL
31 #include <sys/sunddi.h>
32 #include <fs/fs_reparse.h>
33 #else
34 #include <string.h>
35 #include <limits.h>
36 #include <sys/fs_reparse.h>
38 #define strfree(str) free((str))
39 #endif
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 };
51 * reparse_init()
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.
59 nvlist_t *
60 reparse_init(void)
62 nvlist_t *nvl;
65 * Service type is unique, only one entry
66 * of each service type is allowed
68 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0))
69 return (NULL);
71 return (nvl);
75 * reparse_free()
77 * Function to free memory of a nvlist allocated previously
78 * by reparse_init().
80 void
81 reparse_free(nvlist_t *nvl)
83 nvlist_free(nvl);
87 * reparse_parse()
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.
96 int
97 reparse_parse(const char *string, nvlist_t *nvl)
99 int err;
101 if (string == NULL || nvl == NULL)
102 return (EINVAL);
104 if ((err = reparse_validate(string)) != 0)
105 return (err);
107 if ((err = reparse_create_nvlist(string, nvl)) != 0)
108 return (err);
110 return (0);
113 static char *
114 reparse_skipspace(char *cp)
116 while ((*cp) && (*cp == ' ' || *cp == '\t'))
117 cp++;
118 return (cp);
121 static boolean_t
122 reparse_validate_svctype(char *svc_str)
124 int nx, ix, len;
126 if (svc_str == NULL)
127 return (B_FALSE);
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])
133 return (B_FALSE);
136 return (B_TRUE);
139 static boolean_t
140 reparse_validate_svc_token(char *svc_token)
142 char save_c, *cp;
144 if (svc_token == NULL)
145 return (B_FALSE);
146 if ((cp = strchr(svc_token, ':')) == NULL)
147 return (B_FALSE);
149 save_c = *cp;
150 *cp = '\0';
153 * make sure service type and service data are non-empty string.
155 if (strlen(svc_token) == 0 || strlen(cp + 1) == 0) {
156 *cp = save_c;
157 return (B_FALSE);
160 *cp = save_c;
161 return (B_TRUE);
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
186 * into a nvlist.
188 static int
189 reparse_validate_create_nvlist(const char *string, nvlist_t *nvl)
191 int err, tcnt;
192 char *reparse_data, save_c, save_e, *save_e_ptr, *cp, *s_str, *e_str;
194 if (string == NULL)
195 return (EINVAL);
197 if (strlen(string) >= MAXREPARSELEN)
198 return (ENAMETOOLONG);
200 if ((reparse_data = strdup(string)) == NULL)
201 return (ENOMEM);
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);
207 return (EINVAL);
210 /* locate FS_REPARSE_TAG_END_CHAR */
211 if ((cp = strrchr(reparse_data, FS_REPARSE_TAG_END_CHAR)) == NULL) {
212 strfree(reparse_data);
213 return (EINVAL);
215 save_e = *cp;
216 save_e_ptr = cp;
217 *cp = '\0';
219 e_str = cp;
220 cp++; /* should point to NULL, or spaces */
222 cp = reparse_skipspace(cp);
223 if (*cp) {
224 *save_e_ptr = save_e;
225 strfree(reparse_data);
226 return (EINVAL);
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);
235 tcnt = 0;
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);
242 return (EINVAL);
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);
252 return (EINVAL);
255 tcnt++;
256 save_c = *cp;
257 *cp = '\0';
259 /* check for valid characters in service type */
260 if (reparse_validate_svctype(s_str) == B_FALSE) {
261 *cp = save_c;
262 *save_e_ptr = save_e;
263 strfree(reparse_data);
264 return (EINVAL);
267 if (strlen(s_str) == 0) {
268 *cp = save_c;
269 *save_e_ptr = save_e;
270 strfree(reparse_data);
271 return (EINVAL);
274 if (reparse_validate_svc_token(s_str) == B_FALSE) {
275 *cp = save_c;
276 *save_e_ptr = save_e;
277 strfree(reparse_data);
278 return (EINVAL);
281 /* create a nvpair entry */
282 if (nvl != NULL &&
283 (err = reparse_add_nvpair(s_str, nvl)) != 0) {
284 *cp = save_c;
285 *save_e_ptr = save_e;
286 strfree(reparse_data);
287 return (err);
290 *cp = save_c;
292 /* skip over FS_TOKEN_END_STR */
293 cp += strlen(FS_TOKEN_END_STR);
294 cp = reparse_skipspace(cp);
295 s_str = cp;
297 *save_e_ptr = save_e;
298 strfree(reparse_data);
300 return (tcnt ? 0 : EINVAL);
303 static int
304 reparse_add_nvpair(char *token, nvlist_t *nvl)
306 int err;
307 char save_c, *cp;
309 if ((cp = strchr(token, ':')) == NULL)
310 return (EINVAL);
312 save_c = *cp;
313 *cp = '\0';
314 err = nvlist_add_string(nvl, token, cp + 1);
315 *cp = save_c;
317 return (err);
320 static int
321 reparse_create_nvlist(const char *string, nvlist_t *nvl)
323 if (nvl == NULL)
324 return (EINVAL);
326 return (reparse_validate_create_nvlist(string, nvl));