xref: /onnv-gate/usr/src/common/fsreparse/fs_reparse.c (revision 10793:34709091de6d)
1*10793Sdai.ngo@sun.com /*
2*10793Sdai.ngo@sun.com  * CDDL HEADER START
3*10793Sdai.ngo@sun.com  *
4*10793Sdai.ngo@sun.com  * The contents of this file are subject to the terms of the
5*10793Sdai.ngo@sun.com  * Common Development and Distribution License (the "License").
6*10793Sdai.ngo@sun.com  * You may not use this file except in compliance with the License.
7*10793Sdai.ngo@sun.com  *
8*10793Sdai.ngo@sun.com  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*10793Sdai.ngo@sun.com  * or http://www.opensolaris.org/os/licensing.
10*10793Sdai.ngo@sun.com  * See the License for the specific language governing permissions
11*10793Sdai.ngo@sun.com  * and limitations under the License.
12*10793Sdai.ngo@sun.com  *
13*10793Sdai.ngo@sun.com  * When distributing Covered Code, include this CDDL HEADER in each
14*10793Sdai.ngo@sun.com  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*10793Sdai.ngo@sun.com  * If applicable, add the following below this CDDL HEADER, with the
16*10793Sdai.ngo@sun.com  * fields enclosed by brackets "[]" replaced with your own identifying
17*10793Sdai.ngo@sun.com  * information: Portions Copyright [yyyy] [name of copyright owner]
18*10793Sdai.ngo@sun.com  *
19*10793Sdai.ngo@sun.com  * CDDL HEADER END
20*10793Sdai.ngo@sun.com  */
21*10793Sdai.ngo@sun.com /*
22*10793Sdai.ngo@sun.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23*10793Sdai.ngo@sun.com  * Use is subject to license terms.
24*10793Sdai.ngo@sun.com  */
25*10793Sdai.ngo@sun.com 
26*10793Sdai.ngo@sun.com #include <sys/types.h>
27*10793Sdai.ngo@sun.com #include <sys/param.h>
28*10793Sdai.ngo@sun.com #include <sys/errno.h>
29*10793Sdai.ngo@sun.com 
30*10793Sdai.ngo@sun.com #ifdef _KERNEL
31*10793Sdai.ngo@sun.com #include <sys/sunddi.h>
32*10793Sdai.ngo@sun.com #include <fs/fs_reparse.h>
33*10793Sdai.ngo@sun.com #else
34*10793Sdai.ngo@sun.com #include <string.h>
35*10793Sdai.ngo@sun.com #include <limits.h>
36*10793Sdai.ngo@sun.com #include <sys/fs_reparse.h>
37*10793Sdai.ngo@sun.com 
38*10793Sdai.ngo@sun.com #define	strfree(str)		free((str))
39*10793Sdai.ngo@sun.com #endif
40*10793Sdai.ngo@sun.com 
41*10793Sdai.ngo@sun.com static char *reparse_skipspace(char *cp);
42*10793Sdai.ngo@sun.com static int reparse_create_nvlist(const char *string, nvlist_t *nvl);
43*10793Sdai.ngo@sun.com static int reparse_add_nvpair(char *token, nvlist_t *nvl);
44*10793Sdai.ngo@sun.com static boolean_t reparse_validate_svctype(char *svc_str);
45*10793Sdai.ngo@sun.com static int reparse_validate_create_nvlist(const char *string, nvlist_t *nvl);
46*10793Sdai.ngo@sun.com 
47*10793Sdai.ngo@sun.com /* array of characters not allowed in service type string */
48*10793Sdai.ngo@sun.com static char svctype_invalid_chars[] = { '{', '}', 0 };
49*10793Sdai.ngo@sun.com 
50*10793Sdai.ngo@sun.com /*
51*10793Sdai.ngo@sun.com  * reparse_init()
52*10793Sdai.ngo@sun.com  *
53*10793Sdai.ngo@sun.com  * Function to allocate a new name-value pair list.
54*10793Sdai.ngo@sun.com  * Caller needs to call reparse_free() to free memory
55*10793Sdai.ngo@sun.com  * used by the list when done.
56*10793Sdai.ngo@sun.com  *
57*10793Sdai.ngo@sun.com  * Return pointer to new list else return NULL.
58*10793Sdai.ngo@sun.com  */
59*10793Sdai.ngo@sun.com nvlist_t *
reparse_init(void)60*10793Sdai.ngo@sun.com reparse_init(void)
61*10793Sdai.ngo@sun.com {
62*10793Sdai.ngo@sun.com 	nvlist_t *nvl;
63*10793Sdai.ngo@sun.com 
64*10793Sdai.ngo@sun.com 	/*
65*10793Sdai.ngo@sun.com 	 * Service type is unique, only one entry
66*10793Sdai.ngo@sun.com 	 * of each service type is allowed
67*10793Sdai.ngo@sun.com 	 */
68*10793Sdai.ngo@sun.com 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0))
69*10793Sdai.ngo@sun.com 		return (NULL);
70*10793Sdai.ngo@sun.com 
71*10793Sdai.ngo@sun.com 	return (nvl);
72*10793Sdai.ngo@sun.com }
73*10793Sdai.ngo@sun.com 
74*10793Sdai.ngo@sun.com /*
75*10793Sdai.ngo@sun.com  * reparse_free()
76*10793Sdai.ngo@sun.com  *
77*10793Sdai.ngo@sun.com  * Function to free memory of a nvlist allocated previously
78*10793Sdai.ngo@sun.com  * by reparse_init().
79*10793Sdai.ngo@sun.com  */
80*10793Sdai.ngo@sun.com void
reparse_free(nvlist_t * nvl)81*10793Sdai.ngo@sun.com reparse_free(nvlist_t *nvl)
82*10793Sdai.ngo@sun.com {
83*10793Sdai.ngo@sun.com 	if (nvl)
84*10793Sdai.ngo@sun.com 		nvlist_free(nvl);
85*10793Sdai.ngo@sun.com }
86*10793Sdai.ngo@sun.com 
87*10793Sdai.ngo@sun.com /*
88*10793Sdai.ngo@sun.com  * reparse_parse()
89*10793Sdai.ngo@sun.com  *
90*10793Sdai.ngo@sun.com  * Parse the specified string and populate the nvlist with the svc_types
91*10793Sdai.ngo@sun.com  * and data from the 'string'.  The string could be read from the reparse
92*10793Sdai.ngo@sun.com  * point symlink body. This routine will allocate memory that must be
93*10793Sdai.ngo@sun.com  * freed by reparse_free().
94*10793Sdai.ngo@sun.com  *
95*10793Sdai.ngo@sun.com  * If ok return 0 and the nvlist is populated, otherwise return error code.
96*10793Sdai.ngo@sun.com  */
97*10793Sdai.ngo@sun.com int
reparse_parse(const char * string,nvlist_t * nvl)98*10793Sdai.ngo@sun.com reparse_parse(const char *string, nvlist_t *nvl)
99*10793Sdai.ngo@sun.com {
100*10793Sdai.ngo@sun.com 	int err;
101*10793Sdai.ngo@sun.com 
102*10793Sdai.ngo@sun.com 	if (string == NULL || nvl == NULL)
103*10793Sdai.ngo@sun.com 		return (EINVAL);
104*10793Sdai.ngo@sun.com 
105*10793Sdai.ngo@sun.com 	if ((err = reparse_validate(string)) != 0)
106*10793Sdai.ngo@sun.com 		return (err);
107*10793Sdai.ngo@sun.com 
108*10793Sdai.ngo@sun.com 	if ((err = reparse_create_nvlist(string, nvl)) != 0)
109*10793Sdai.ngo@sun.com 		return (err);
110*10793Sdai.ngo@sun.com 
111*10793Sdai.ngo@sun.com 	return (0);
112*10793Sdai.ngo@sun.com }
113*10793Sdai.ngo@sun.com 
114*10793Sdai.ngo@sun.com static char *
reparse_skipspace(char * cp)115*10793Sdai.ngo@sun.com reparse_skipspace(char *cp)
116*10793Sdai.ngo@sun.com {
117*10793Sdai.ngo@sun.com 	while ((*cp) && (*cp == ' ' || *cp == '\t'))
118*10793Sdai.ngo@sun.com 		cp++;
119*10793Sdai.ngo@sun.com 	return (cp);
120*10793Sdai.ngo@sun.com }
121*10793Sdai.ngo@sun.com 
122*10793Sdai.ngo@sun.com static boolean_t
reparse_validate_svctype(char * svc_str)123*10793Sdai.ngo@sun.com reparse_validate_svctype(char *svc_str)
124*10793Sdai.ngo@sun.com {
125*10793Sdai.ngo@sun.com 	int nx, ix, len;
126*10793Sdai.ngo@sun.com 
127*10793Sdai.ngo@sun.com 	if (svc_str == NULL)
128*10793Sdai.ngo@sun.com 		return (B_FALSE);
129*10793Sdai.ngo@sun.com 
130*10793Sdai.ngo@sun.com 	len = strlen(svc_str);
131*10793Sdai.ngo@sun.com 	for (ix = 0; ix < len; ix++) {
132*10793Sdai.ngo@sun.com 		for (nx = 0; nx < sizeof (svctype_invalid_chars); nx++) {
133*10793Sdai.ngo@sun.com 			if (svc_str[ix] == svctype_invalid_chars[nx])
134*10793Sdai.ngo@sun.com 				return (B_FALSE);
135*10793Sdai.ngo@sun.com 		}
136*10793Sdai.ngo@sun.com 	}
137*10793Sdai.ngo@sun.com 	return (B_TRUE);
138*10793Sdai.ngo@sun.com }
139*10793Sdai.ngo@sun.com 
140*10793Sdai.ngo@sun.com static boolean_t
reparse_validate_svc_token(char * svc_token)141*10793Sdai.ngo@sun.com reparse_validate_svc_token(char *svc_token)
142*10793Sdai.ngo@sun.com {
143*10793Sdai.ngo@sun.com 	char save_c, *cp;
144*10793Sdai.ngo@sun.com 
145*10793Sdai.ngo@sun.com 	if (svc_token == NULL)
146*10793Sdai.ngo@sun.com 		return (B_FALSE);
147*10793Sdai.ngo@sun.com 	if ((cp = strchr(svc_token, ':')) == NULL)
148*10793Sdai.ngo@sun.com 		return (B_FALSE);
149*10793Sdai.ngo@sun.com 
150*10793Sdai.ngo@sun.com 	save_c = *cp;
151*10793Sdai.ngo@sun.com 	*cp = '\0';
152*10793Sdai.ngo@sun.com 
153*10793Sdai.ngo@sun.com 	/*
154*10793Sdai.ngo@sun.com 	 * make sure service type and service data are non-empty string.
155*10793Sdai.ngo@sun.com 	 */
156*10793Sdai.ngo@sun.com 	if (strlen(svc_token) == 0 || strlen(cp + 1) == 0) {
157*10793Sdai.ngo@sun.com 		*cp = save_c;
158*10793Sdai.ngo@sun.com 		return (B_FALSE);
159*10793Sdai.ngo@sun.com 	}
160*10793Sdai.ngo@sun.com 
161*10793Sdai.ngo@sun.com 	*cp = save_c;
162*10793Sdai.ngo@sun.com 	return (B_TRUE);
163*10793Sdai.ngo@sun.com }
164*10793Sdai.ngo@sun.com 
165*10793Sdai.ngo@sun.com /*
166*10793Sdai.ngo@sun.com  * Format of reparse data:
167*10793Sdai.ngo@sun.com  * @{REPARSE@{servicetype:data} [@{servicetype:data}] ...}
168*10793Sdai.ngo@sun.com  * REPARSE_TAG_STR@{REPARSE_TOKEN} [@{REPARSE_TOKEN}] ... REPARSE_TAG_END
169*10793Sdai.ngo@sun.com  *
170*10793Sdai.ngo@sun.com  * Validating reparse data:
171*10793Sdai.ngo@sun.com  *	. check for valid length of reparse data
172*10793Sdai.ngo@sun.com  *	. check for valid reparse data format
173*10793Sdai.ngo@sun.com  * Return 0 if OK else return error code.
174*10793Sdai.ngo@sun.com  */
175*10793Sdai.ngo@sun.com int
reparse_validate(const char * string)176*10793Sdai.ngo@sun.com reparse_validate(const char *string)
177*10793Sdai.ngo@sun.com {
178*10793Sdai.ngo@sun.com 	return (reparse_validate_create_nvlist(string, NULL));
179*10793Sdai.ngo@sun.com }
180*10793Sdai.ngo@sun.com 
181*10793Sdai.ngo@sun.com /*
182*10793Sdai.ngo@sun.com  * reparse_validate_create_nvlist
183*10793Sdai.ngo@sun.com  *
184*10793Sdai.ngo@sun.com  * dual-purpose function:
185*10793Sdai.ngo@sun.com  *     . Validate a reparse data string.
186*10793Sdai.ngo@sun.com  *     . Validate a reparse data string and parse the data
187*10793Sdai.ngo@sun.com  *	 into a nvlist.
188*10793Sdai.ngo@sun.com  */
189*10793Sdai.ngo@sun.com static int
reparse_validate_create_nvlist(const char * string,nvlist_t * nvl)190*10793Sdai.ngo@sun.com reparse_validate_create_nvlist(const char *string, nvlist_t *nvl)
191*10793Sdai.ngo@sun.com {
192*10793Sdai.ngo@sun.com 	int err, tcnt;
193*10793Sdai.ngo@sun.com 	char *reparse_data, save_c, save_e, *save_e_ptr, *cp, *s_str, *e_str;
194*10793Sdai.ngo@sun.com 
195*10793Sdai.ngo@sun.com 	if (string == NULL)
196*10793Sdai.ngo@sun.com 		return (EINVAL);
197*10793Sdai.ngo@sun.com 
198*10793Sdai.ngo@sun.com 	if (strlen(string) >= MAXREPARSELEN)
199*10793Sdai.ngo@sun.com 		return (ENAMETOOLONG);
200*10793Sdai.ngo@sun.com 
201*10793Sdai.ngo@sun.com 	if ((reparse_data = strdup(string)) == NULL)
202*10793Sdai.ngo@sun.com 		return (ENOMEM);
203*10793Sdai.ngo@sun.com 
204*10793Sdai.ngo@sun.com 	/* check FS_REPARSE_TAG_STR */
205*10793Sdai.ngo@sun.com 	if (strncmp(reparse_data, FS_REPARSE_TAG_STR,
206*10793Sdai.ngo@sun.com 	    strlen(FS_REPARSE_TAG_STR))) {
207*10793Sdai.ngo@sun.com 		strfree(reparse_data);
208*10793Sdai.ngo@sun.com 		return (EINVAL);
209*10793Sdai.ngo@sun.com 	}
210*10793Sdai.ngo@sun.com 
211*10793Sdai.ngo@sun.com 	/* locate FS_REPARSE_TAG_END_CHAR */
212*10793Sdai.ngo@sun.com 	if ((cp = strrchr(reparse_data, FS_REPARSE_TAG_END_CHAR)) == NULL) {
213*10793Sdai.ngo@sun.com 		strfree(reparse_data);
214*10793Sdai.ngo@sun.com 		return (EINVAL);
215*10793Sdai.ngo@sun.com 	}
216*10793Sdai.ngo@sun.com 	save_e = *cp;
217*10793Sdai.ngo@sun.com 	save_e_ptr = cp;
218*10793Sdai.ngo@sun.com 	*cp = '\0';
219*10793Sdai.ngo@sun.com 
220*10793Sdai.ngo@sun.com 	e_str = cp;
221*10793Sdai.ngo@sun.com 	cp++;		/* should point to NULL, or spaces */
222*10793Sdai.ngo@sun.com 
223*10793Sdai.ngo@sun.com 	cp = reparse_skipspace(cp);
224*10793Sdai.ngo@sun.com 	if (*cp) {
225*10793Sdai.ngo@sun.com 		*save_e_ptr = save_e;
226*10793Sdai.ngo@sun.com 		strfree(reparse_data);
227*10793Sdai.ngo@sun.com 		return (EINVAL);
228*10793Sdai.ngo@sun.com 	}
229*10793Sdai.ngo@sun.com 
230*10793Sdai.ngo@sun.com 	/* skip FS_REPARSE_TAG_STR */
231*10793Sdai.ngo@sun.com 	s_str = reparse_data + strlen(FS_REPARSE_TAG_STR);
232*10793Sdai.ngo@sun.com 
233*10793Sdai.ngo@sun.com 	/* skip spaces after FS_REPARSE_TAG_STR */
234*10793Sdai.ngo@sun.com 	s_str = reparse_skipspace(s_str);
235*10793Sdai.ngo@sun.com 
236*10793Sdai.ngo@sun.com 	tcnt = 0;
237*10793Sdai.ngo@sun.com 	while (s_str < e_str) {
238*10793Sdai.ngo@sun.com 		/* check FS_TOKEN_START_STR */
239*10793Sdai.ngo@sun.com 		if (strncmp(s_str, FS_TOKEN_START_STR,
240*10793Sdai.ngo@sun.com 		    strlen(FS_TOKEN_START_STR))) {
241*10793Sdai.ngo@sun.com 			*save_e_ptr = save_e;
242*10793Sdai.ngo@sun.com 			strfree(reparse_data);
243*10793Sdai.ngo@sun.com 			return (EINVAL);
244*10793Sdai.ngo@sun.com 		}
245*10793Sdai.ngo@sun.com 
246*10793Sdai.ngo@sun.com 		/* skip over FS_TOKEN_START_STR */
247*10793Sdai.ngo@sun.com 		s_str += strlen(FS_TOKEN_START_STR);
248*10793Sdai.ngo@sun.com 
249*10793Sdai.ngo@sun.com 		/* locate FS_TOKEN_END_STR */
250*10793Sdai.ngo@sun.com 		if ((cp = strstr(s_str, FS_TOKEN_END_STR)) == NULL) {
251*10793Sdai.ngo@sun.com 			*save_e_ptr = save_e;
252*10793Sdai.ngo@sun.com 			strfree(reparse_data);
253*10793Sdai.ngo@sun.com 			return (EINVAL);
254*10793Sdai.ngo@sun.com 		}
255*10793Sdai.ngo@sun.com 
256*10793Sdai.ngo@sun.com 		tcnt++;
257*10793Sdai.ngo@sun.com 		save_c = *cp;
258*10793Sdai.ngo@sun.com 		*cp = '\0';
259*10793Sdai.ngo@sun.com 
260*10793Sdai.ngo@sun.com 		/* check for valid characters in service type */
261*10793Sdai.ngo@sun.com 		if (reparse_validate_svctype(s_str) == B_FALSE) {
262*10793Sdai.ngo@sun.com 			*cp = save_c;
263*10793Sdai.ngo@sun.com 			*save_e_ptr = save_e;
264*10793Sdai.ngo@sun.com 			strfree(reparse_data);
265*10793Sdai.ngo@sun.com 			return (EINVAL);
266*10793Sdai.ngo@sun.com 		}
267*10793Sdai.ngo@sun.com 
268*10793Sdai.ngo@sun.com 		if (strlen(s_str) == 0) {
269*10793Sdai.ngo@sun.com 			*cp = save_c;
270*10793Sdai.ngo@sun.com 			*save_e_ptr = save_e;
271*10793Sdai.ngo@sun.com 			strfree(reparse_data);
272*10793Sdai.ngo@sun.com 			return (EINVAL);
273*10793Sdai.ngo@sun.com 		}
274*10793Sdai.ngo@sun.com 
275*10793Sdai.ngo@sun.com 		if (reparse_validate_svc_token(s_str) == B_FALSE) {
276*10793Sdai.ngo@sun.com 			*cp = save_c;
277*10793Sdai.ngo@sun.com 			*save_e_ptr = save_e;
278*10793Sdai.ngo@sun.com 			strfree(reparse_data);
279*10793Sdai.ngo@sun.com 			return (EINVAL);
280*10793Sdai.ngo@sun.com 		}
281*10793Sdai.ngo@sun.com 
282*10793Sdai.ngo@sun.com 		/* create a nvpair entry */
283*10793Sdai.ngo@sun.com 		if (nvl != NULL &&
284*10793Sdai.ngo@sun.com 		    (err = reparse_add_nvpair(s_str, nvl)) != 0) {
285*10793Sdai.ngo@sun.com 			*cp = save_c;
286*10793Sdai.ngo@sun.com 			*save_e_ptr = save_e;
287*10793Sdai.ngo@sun.com 			strfree(reparse_data);
288*10793Sdai.ngo@sun.com 			return (err);
289*10793Sdai.ngo@sun.com 		}
290*10793Sdai.ngo@sun.com 
291*10793Sdai.ngo@sun.com 		*cp = save_c;
292*10793Sdai.ngo@sun.com 
293*10793Sdai.ngo@sun.com 		/* skip over FS_TOKEN_END_STR */
294*10793Sdai.ngo@sun.com 		cp += strlen(FS_TOKEN_END_STR);
295*10793Sdai.ngo@sun.com 		cp = reparse_skipspace(cp);
296*10793Sdai.ngo@sun.com 		s_str = cp;
297*10793Sdai.ngo@sun.com 	}
298*10793Sdai.ngo@sun.com 	*save_e_ptr = save_e;
299*10793Sdai.ngo@sun.com 	strfree(reparse_data);
300*10793Sdai.ngo@sun.com 
301*10793Sdai.ngo@sun.com 	return (tcnt ? 0 : EINVAL);
302*10793Sdai.ngo@sun.com }
303*10793Sdai.ngo@sun.com 
304*10793Sdai.ngo@sun.com static int
reparse_add_nvpair(char * token,nvlist_t * nvl)305*10793Sdai.ngo@sun.com reparse_add_nvpair(char *token, nvlist_t *nvl)
306*10793Sdai.ngo@sun.com {
307*10793Sdai.ngo@sun.com 	int err;
308*10793Sdai.ngo@sun.com 	char save_c, *cp;
309*10793Sdai.ngo@sun.com 
310*10793Sdai.ngo@sun.com 	if ((cp = strchr(token, ':')) == NULL)
311*10793Sdai.ngo@sun.com 		return (EINVAL);
312*10793Sdai.ngo@sun.com 
313*10793Sdai.ngo@sun.com 	save_c = *cp;
314*10793Sdai.ngo@sun.com 	*cp = '\0';
315*10793Sdai.ngo@sun.com 	err = nvlist_add_string(nvl, token, cp + 1);
316*10793Sdai.ngo@sun.com 	*cp = save_c;
317*10793Sdai.ngo@sun.com 
318*10793Sdai.ngo@sun.com 	return (err);
319*10793Sdai.ngo@sun.com }
320*10793Sdai.ngo@sun.com 
321*10793Sdai.ngo@sun.com static int
reparse_create_nvlist(const char * string,nvlist_t * nvl)322*10793Sdai.ngo@sun.com reparse_create_nvlist(const char *string, nvlist_t *nvl)
323*10793Sdai.ngo@sun.com {
324*10793Sdai.ngo@sun.com 	if (nvl == NULL)
325*10793Sdai.ngo@sun.com 		return (EINVAL);
326*10793Sdai.ngo@sun.com 
327*10793Sdai.ngo@sun.com 	return (reparse_validate_create_nvlist(string, nvl));
328*10793Sdai.ngo@sun.com }
329