dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / common / fsreparse / fs_reparse.c
blob015dfe6f3bb1cd9df59f2a0a4b7b9b73dae06c01
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 #else
33 #include <string.h>
34 #include <limits.h>
36 #define strfree(str) free((str))
37 #endif
39 /* this needs to be after the above includes */
40 #include <sys/fs_reparse.h>
42 static char *reparse_skipspace(char *cp);
43 static int reparse_create_nvlist(const char *string, nvlist_t *nvl);
44 static int reparse_add_nvpair(char *token, nvlist_t *nvl);
45 static boolean_t reparse_validate_svctype(char *svc_str);
46 static int reparse_validate_create_nvlist(const char *string, nvlist_t *nvl);
48 /* array of characters not allowed in service type string */
49 static char svctype_invalid_chars[] = { '{', '}', 0 };
52 * reparse_init()
54 * Function to allocate a new name-value pair list.
55 * Caller needs to call reparse_free() to free memory
56 * used by the list when done.
58 * Return pointer to new list else return NULL.
60 nvlist_t *
61 reparse_init(void)
63 nvlist_t *nvl;
66 * Service type is unique, only one entry
67 * of each service type is allowed
69 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0))
70 return (NULL);
72 return (nvl);
76 * reparse_free()
78 * Function to free memory of a nvlist allocated previously
79 * by reparse_init().
81 void
82 reparse_free(nvlist_t *nvl)
84 nvlist_free(nvl);
88 * reparse_parse()
90 * Parse the specified string and populate the nvlist with the svc_types
91 * and data from the 'string'. The string could be read from the reparse
92 * point symlink body. This routine will allocate memory that must be
93 * freed by reparse_free().
95 * If ok return 0 and the nvlist is populated, otherwise return error code.
97 int
98 reparse_parse(const char *string, nvlist_t *nvl)
100 int err;
102 if (string == NULL || nvl == NULL)
103 return (EINVAL);
105 if ((err = reparse_validate(string)) != 0)
106 return (err);
108 if ((err = reparse_create_nvlist(string, nvl)) != 0)
109 return (err);
111 return (0);
114 static char *
115 reparse_skipspace(char *cp)
117 while ((*cp) && (*cp == ' ' || *cp == '\t'))
118 cp++;
119 return (cp);
122 static boolean_t
123 reparse_validate_svctype(char *svc_str)
125 int nx, ix, len;
127 if (svc_str == NULL)
128 return (B_FALSE);
130 len = strlen(svc_str);
131 for (ix = 0; ix < len; ix++) {
132 for (nx = 0; nx < sizeof (svctype_invalid_chars); nx++) {
133 if (svc_str[ix] == svctype_invalid_chars[nx])
134 return (B_FALSE);
137 return (B_TRUE);
140 static boolean_t
141 reparse_validate_svc_token(char *svc_token)
143 char save_c, *cp;
145 if (svc_token == NULL)
146 return (B_FALSE);
147 if ((cp = strchr(svc_token, ':')) == NULL)
148 return (B_FALSE);
150 save_c = *cp;
151 *cp = '\0';
154 * make sure service type and service data are non-empty string.
156 if (strlen(svc_token) == 0 || strlen(cp + 1) == 0) {
157 *cp = save_c;
158 return (B_FALSE);
161 *cp = save_c;
162 return (B_TRUE);
166 * Format of reparse data:
167 * @{REPARSE@{servicetype:data} [@{servicetype:data}] ...}
168 * REPARSE_TAG_STR@{REPARSE_TOKEN} [@{REPARSE_TOKEN}] ... REPARSE_TAG_END
170 * Validating reparse data:
171 * . check for valid length of reparse data
172 * . check for valid reparse data format
173 * Return 0 if OK else return error code.
176 reparse_validate(const char *string)
178 return (reparse_validate_create_nvlist(string, NULL));
182 * reparse_validate_create_nvlist
184 * dual-purpose function:
185 * . Validate a reparse data string.
186 * . Validate a reparse data string and parse the data
187 * into a nvlist.
189 static int
190 reparse_validate_create_nvlist(const char *string, nvlist_t *nvl)
192 int err, tcnt;
193 char *reparse_data, save_c, save_e, *save_e_ptr, *cp, *s_str, *e_str;
195 if (string == NULL)
196 return (EINVAL);
198 if (strlen(string) >= MAXREPARSELEN)
199 return (ENAMETOOLONG);
201 if ((reparse_data = strdup(string)) == NULL)
202 return (ENOMEM);
204 /* check FS_REPARSE_TAG_STR */
205 if (strncmp(reparse_data, FS_REPARSE_TAG_STR,
206 strlen(FS_REPARSE_TAG_STR))) {
207 strfree(reparse_data);
208 return (EINVAL);
211 /* locate FS_REPARSE_TAG_END_CHAR */
212 if ((cp = strrchr(reparse_data, FS_REPARSE_TAG_END_CHAR)) == NULL) {
213 strfree(reparse_data);
214 return (EINVAL);
216 save_e = *cp;
217 save_e_ptr = cp;
218 *cp = '\0';
220 e_str = cp;
221 cp++; /* should point to NULL, or spaces */
223 cp = reparse_skipspace(cp);
224 if (*cp) {
225 *save_e_ptr = save_e;
226 strfree(reparse_data);
227 return (EINVAL);
230 /* skip FS_REPARSE_TAG_STR */
231 s_str = reparse_data + strlen(FS_REPARSE_TAG_STR);
233 /* skip spaces after FS_REPARSE_TAG_STR */
234 s_str = reparse_skipspace(s_str);
236 tcnt = 0;
237 while (s_str < e_str) {
238 /* check FS_TOKEN_START_STR */
239 if (strncmp(s_str, FS_TOKEN_START_STR,
240 strlen(FS_TOKEN_START_STR))) {
241 *save_e_ptr = save_e;
242 strfree(reparse_data);
243 return (EINVAL);
246 /* skip over FS_TOKEN_START_STR */
247 s_str += strlen(FS_TOKEN_START_STR);
249 /* locate FS_TOKEN_END_STR */
250 if ((cp = strstr(s_str, FS_TOKEN_END_STR)) == NULL) {
251 *save_e_ptr = save_e;
252 strfree(reparse_data);
253 return (EINVAL);
256 tcnt++;
257 save_c = *cp;
258 *cp = '\0';
260 /* check for valid characters in service type */
261 if (reparse_validate_svctype(s_str) == B_FALSE) {
262 *cp = save_c;
263 *save_e_ptr = save_e;
264 strfree(reparse_data);
265 return (EINVAL);
268 if (strlen(s_str) == 0) {
269 *cp = save_c;
270 *save_e_ptr = save_e;
271 strfree(reparse_data);
272 return (EINVAL);
275 if (reparse_validate_svc_token(s_str) == B_FALSE) {
276 *cp = save_c;
277 *save_e_ptr = save_e;
278 strfree(reparse_data);
279 return (EINVAL);
282 /* create a nvpair entry */
283 if (nvl != NULL &&
284 (err = reparse_add_nvpair(s_str, nvl)) != 0) {
285 *cp = save_c;
286 *save_e_ptr = save_e;
287 strfree(reparse_data);
288 return (err);
291 *cp = save_c;
293 /* skip over FS_TOKEN_END_STR */
294 cp += strlen(FS_TOKEN_END_STR);
295 cp = reparse_skipspace(cp);
296 s_str = cp;
298 *save_e_ptr = save_e;
299 strfree(reparse_data);
301 return (tcnt ? 0 : EINVAL);
304 static int
305 reparse_add_nvpair(char *token, nvlist_t *nvl)
307 int err;
308 char save_c, *cp;
310 if ((cp = strchr(token, ':')) == NULL)
311 return (EINVAL);
313 save_c = *cp;
314 *cp = '\0';
315 err = nvlist_add_string(nvl, token, cp + 1);
316 *cp = save_c;
318 return (err);
321 static int
322 reparse_create_nvlist(const char *string, nvlist_t *nvl)
324 if (nvl == NULL)
325 return (EINVAL);
327 return (reparse_validate_create_nvlist(string, nvl));