xref: /titanic_53/usr/src/lib/libdladm/common/propfuncs.c (revision da14cebe459d3275048785f25bd869cb09b5307f)
1*da14cebeSEric Cheng /*
2*da14cebeSEric Cheng  * CDDL HEADER START
3*da14cebeSEric Cheng  *
4*da14cebeSEric Cheng  * The contents of this file are subject to the terms of the
5*da14cebeSEric Cheng  * Common Development and Distribution License (the "License").
6*da14cebeSEric Cheng  * You may not use this file except in compliance with the License.
7*da14cebeSEric Cheng  *
8*da14cebeSEric Cheng  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*da14cebeSEric Cheng  * or http://www.opensolaris.org/os/licensing.
10*da14cebeSEric Cheng  * See the License for the specific language governing permissions
11*da14cebeSEric Cheng  * and limitations under the License.
12*da14cebeSEric Cheng  *
13*da14cebeSEric Cheng  * When distributing Covered Code, include this CDDL HEADER in each
14*da14cebeSEric Cheng  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*da14cebeSEric Cheng  * If applicable, add the following below this CDDL HEADER, with the
16*da14cebeSEric Cheng  * fields enclosed by brackets "[]" replaced with your own identifying
17*da14cebeSEric Cheng  * information: Portions Copyright [yyyy] [name of copyright owner]
18*da14cebeSEric Cheng  *
19*da14cebeSEric Cheng  * CDDL HEADER END
20*da14cebeSEric Cheng  */
21*da14cebeSEric Cheng /*
22*da14cebeSEric Cheng  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*da14cebeSEric Cheng  * Use is subject to license terms.
24*da14cebeSEric Cheng  */
25*da14cebeSEric Cheng 
26*da14cebeSEric Cheng #include <stdlib.h>
27*da14cebeSEric Cheng #include <strings.h>
28*da14cebeSEric Cheng #include <errno.h>
29*da14cebeSEric Cheng #include <ctype.h>
30*da14cebeSEric Cheng #include <sys/types.h>
31*da14cebeSEric Cheng #include <sys/stat.h>
32*da14cebeSEric Cheng #include <sys/dld.h>
33*da14cebeSEric Cheng #include <fcntl.h>
34*da14cebeSEric Cheng #include <unistd.h>
35*da14cebeSEric Cheng #include <libdladm_impl.h>
36*da14cebeSEric Cheng #include <libdlflow_impl.h>
37*da14cebeSEric Cheng 
38*da14cebeSEric Cheng /*
39*da14cebeSEric Cheng  * XXX duplicate defines
40*da14cebeSEric Cheng  */
41*da14cebeSEric Cheng #define	DLADM_PROP_VAL_MAX	32
42*da14cebeSEric Cheng #define	DLADM_MAX_PROPS		32
43*da14cebeSEric Cheng 
44*da14cebeSEric Cheng static void
45*da14cebeSEric Cheng free_props(prop_db_info_t *lip)
46*da14cebeSEric Cheng {
47*da14cebeSEric Cheng 	prop_db_info_t	*lip_next;
48*da14cebeSEric Cheng 	prop_val_t	*lvp, *lvp_next;
49*da14cebeSEric Cheng 
50*da14cebeSEric Cheng 	for (; lip != NULL; lip = lip_next) {
51*da14cebeSEric Cheng 		lip_next = lip->li_nextprop;
52*da14cebeSEric Cheng 		for (lvp = lip->li_val; lvp != NULL; lvp = lvp_next) {
53*da14cebeSEric Cheng 			lvp_next = lvp->lv_nextval;
54*da14cebeSEric Cheng 			free(lvp);
55*da14cebeSEric Cheng 		}
56*da14cebeSEric Cheng 		free(lip);
57*da14cebeSEric Cheng 	}
58*da14cebeSEric Cheng }
59*da14cebeSEric Cheng 
60*da14cebeSEric Cheng /*
61*da14cebeSEric Cheng  * Generate an entry in the property database.
62*da14cebeSEric Cheng  * Each entry has this format:
63*da14cebeSEric Cheng  * <name>	<prop0>=<val0>,...,<valn>;...;<propn>=<val0>,...,<valn>;
64*da14cebeSEric Cheng  */
65*da14cebeSEric Cheng static void
66*da14cebeSEric Cheng generate_prop_line(const char *name, char *buf,
67*da14cebeSEric Cheng     prop_db_info_t *listp, dladm_status_t *statusp)
68*da14cebeSEric Cheng {
69*da14cebeSEric Cheng 	char		tmpbuf[MAXLINELEN];
70*da14cebeSEric Cheng 	char		*ptr, *lim = tmpbuf + MAXLINELEN;
71*da14cebeSEric Cheng 	prop_db_info_t	*lip = listp;
72*da14cebeSEric Cheng 	prop_val_t	*lvp = NULL;
73*da14cebeSEric Cheng 
74*da14cebeSEric Cheng 	/*
75*da14cebeSEric Cheng 	 * Delete line if there are no properties left.
76*da14cebeSEric Cheng 	 */
77*da14cebeSEric Cheng 	if (lip == NULL ||
78*da14cebeSEric Cheng 	    (lip->li_val == NULL && lip->li_nextprop == NULL)) {
79*da14cebeSEric Cheng 		buf[0] = '\0';
80*da14cebeSEric Cheng 		return;
81*da14cebeSEric Cheng 	}
82*da14cebeSEric Cheng 	ptr = tmpbuf;
83*da14cebeSEric Cheng 	ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t", name);
84*da14cebeSEric Cheng 	for (; lip != NULL; lip = lip->li_nextprop) {
85*da14cebeSEric Cheng 		/*
86*da14cebeSEric Cheng 		 * Skip properties without values.
87*da14cebeSEric Cheng 		 */
88*da14cebeSEric Cheng 		if (lip->li_val == NULL)
89*da14cebeSEric Cheng 			continue;
90*da14cebeSEric Cheng 
91*da14cebeSEric Cheng 		ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s=", lip->li_name);
92*da14cebeSEric Cheng 		for (lvp = lip->li_val; lvp != NULL; lvp = lvp->lv_nextval) {
93*da14cebeSEric Cheng 			ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s%c",
94*da14cebeSEric Cheng 			    lvp->lv_name,
95*da14cebeSEric Cheng 			    ((lvp->lv_nextval == NULL) ? ';' : ','));
96*da14cebeSEric Cheng 		}
97*da14cebeSEric Cheng 	}
98*da14cebeSEric Cheng 	if (ptr > lim) {
99*da14cebeSEric Cheng 		*statusp = DLADM_STATUS_TOOSMALL;
100*da14cebeSEric Cheng 		return;
101*da14cebeSEric Cheng 	}
102*da14cebeSEric Cheng 	(void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf);
103*da14cebeSEric Cheng }
104*da14cebeSEric Cheng 
105*da14cebeSEric Cheng /*
106*da14cebeSEric Cheng  * This function is used to update or create an entry in the persistent db.
107*da14cebeSEric Cheng  * process_prop_db() will first scan the db for an entry matching the
108*da14cebeSEric Cheng  * specified name. If a match is found, this function is invoked with the
109*da14cebeSEric Cheng  * entry's contents (buf) and its linked-list representation (listp). lsp
110*da14cebeSEric Cheng  * holds the name and values of the property to be added or updated; this
111*da14cebeSEric Cheng  * information will be merged with listp. Subsequently, an updated entry
112*da14cebeSEric Cheng  * will be written to buf, which will in turn be written to disk by
113*da14cebeSEric Cheng  * process_prop_db(). If no entry matches the specified name, listp
114*da14cebeSEric Cheng  * will be NULL; a new entry will be generated in this case and it will
115*da14cebeSEric Cheng  * contain only the property information in lsp.
116*da14cebeSEric Cheng  */
117*da14cebeSEric Cheng boolean_t
118*da14cebeSEric Cheng process_prop_set(prop_db_state_t *lsp, char *buf,
119*da14cebeSEric Cheng     prop_db_info_t *listp, dladm_status_t *statusp)
120*da14cebeSEric Cheng {
121*da14cebeSEric Cheng 	dladm_status_t	status;
122*da14cebeSEric Cheng 	prop_db_info_t	*lastp = NULL, *lip = listp, *nlip = NULL;
123*da14cebeSEric Cheng 	prop_val_t	**lvpp;
124*da14cebeSEric Cheng 	int		i;
125*da14cebeSEric Cheng 
126*da14cebeSEric Cheng 	if (lsp->ls_propname == NULL) {
127*da14cebeSEric Cheng 		buf[0] = '\0';
128*da14cebeSEric Cheng 		return (B_FALSE);
129*da14cebeSEric Cheng 	}
130*da14cebeSEric Cheng 
131*da14cebeSEric Cheng 	/*
132*da14cebeSEric Cheng 	 * Find the prop we want to change.
133*da14cebeSEric Cheng 	 */
134*da14cebeSEric Cheng 	for (; lip != NULL; lip = lip->li_nextprop) {
135*da14cebeSEric Cheng 		if (strcmp(lip->li_name, lsp->ls_propname) == 0)
136*da14cebeSEric Cheng 			break;
137*da14cebeSEric Cheng 
138*da14cebeSEric Cheng 		lastp = lip;
139*da14cebeSEric Cheng 	}
140*da14cebeSEric Cheng 
141*da14cebeSEric Cheng 	if (lip == NULL) {
142*da14cebeSEric Cheng 		/*
143*da14cebeSEric Cheng 		 * If the prop is not found, append it to the list.
144*da14cebeSEric Cheng 		 */
145*da14cebeSEric Cheng 		if ((nlip = malloc(sizeof (prop_db_info_t))) == NULL) {
146*da14cebeSEric Cheng 			status = DLADM_STATUS_NOMEM;
147*da14cebeSEric Cheng 			goto fail;
148*da14cebeSEric Cheng 		}
149*da14cebeSEric Cheng 		/*
150*da14cebeSEric Cheng 		 * nlip will need to be freed later if there is no list to
151*da14cebeSEric Cheng 		 * append to.
152*da14cebeSEric Cheng 		 */
153*da14cebeSEric Cheng 		if (lastp != NULL)
154*da14cebeSEric Cheng 			lastp->li_nextprop = nlip;
155*da14cebeSEric Cheng 		nlip->li_name = lsp->ls_propname;
156*da14cebeSEric Cheng 		nlip->li_nextprop = NULL;
157*da14cebeSEric Cheng 		nlip->li_val = NULL;
158*da14cebeSEric Cheng 		lvpp = &nlip->li_val;
159*da14cebeSEric Cheng 	} else {
160*da14cebeSEric Cheng 		prop_val_t	*lvp, *lvp_next;
161*da14cebeSEric Cheng 
162*da14cebeSEric Cheng 		/*
163*da14cebeSEric Cheng 		 * If the prop is found, delete the existing values from it.
164*da14cebeSEric Cheng 		 */
165*da14cebeSEric Cheng 		for (lvp = lip->li_val; lvp != NULL; lvp = lvp_next) {
166*da14cebeSEric Cheng 			lvp_next = lvp->lv_nextval;
167*da14cebeSEric Cheng 			free(lvp);
168*da14cebeSEric Cheng 		}
169*da14cebeSEric Cheng 		lip->li_val = NULL;
170*da14cebeSEric Cheng 		lvpp = &lip->li_val;
171*da14cebeSEric Cheng 	}
172*da14cebeSEric Cheng 
173*da14cebeSEric Cheng 	/*
174*da14cebeSEric Cheng 	 * Fill our prop with the specified values.
175*da14cebeSEric Cheng 	 */
176*da14cebeSEric Cheng 	for (i = 0; i < *lsp->ls_valcntp; i++) {
177*da14cebeSEric Cheng 		if ((*lvpp = malloc(sizeof (prop_val_t))) == NULL) {
178*da14cebeSEric Cheng 			status = DLADM_STATUS_NOMEM;
179*da14cebeSEric Cheng 			goto fail;
180*da14cebeSEric Cheng 		}
181*da14cebeSEric Cheng 		(*lvpp)->lv_name = lsp->ls_propval[i];
182*da14cebeSEric Cheng 		(*lvpp)->lv_nextval = NULL;
183*da14cebeSEric Cheng 		lvpp = &(*lvpp)->lv_nextval;
184*da14cebeSEric Cheng 	}
185*da14cebeSEric Cheng 
186*da14cebeSEric Cheng 	if (listp != NULL) {
187*da14cebeSEric Cheng 		generate_prop_line(lsp->ls_name, buf, listp, statusp);
188*da14cebeSEric Cheng 	} else {
189*da14cebeSEric Cheng 		generate_prop_line(lsp->ls_name, buf, nlip, statusp);
190*da14cebeSEric Cheng 		free_props(nlip);
191*da14cebeSEric Cheng 	}
192*da14cebeSEric Cheng 	return (B_FALSE);
193*da14cebeSEric Cheng 
194*da14cebeSEric Cheng fail:
195*da14cebeSEric Cheng 	*statusp = status;
196*da14cebeSEric Cheng 	if (listp == NULL)
197*da14cebeSEric Cheng 		free_props(nlip);
198*da14cebeSEric Cheng 
199*da14cebeSEric Cheng 	return (B_FALSE);
200*da14cebeSEric Cheng }
201*da14cebeSEric Cheng 
202*da14cebeSEric Cheng /*
203*da14cebeSEric Cheng  * This function is used for retrieving the values for a specific property.
204*da14cebeSEric Cheng  * It gets called if an entry matching the specified name exists in the db.
205*da14cebeSEric Cheng  * The entry is converted into a linked-list listp. This list is then scanned
206*da14cebeSEric Cheng  * for the specified property name; if a matching property exists, its
207*da14cebeSEric Cheng  * associated values are copied to the array lsp->ls_propval.
208*da14cebeSEric Cheng  */
209*da14cebeSEric Cheng /* ARGSUSED */
210*da14cebeSEric Cheng boolean_t
211*da14cebeSEric Cheng process_prop_get(prop_db_state_t *lsp, char *buf,
212*da14cebeSEric Cheng     prop_db_info_t *listp, dladm_status_t *statusp)
213*da14cebeSEric Cheng {
214*da14cebeSEric Cheng 	prop_db_info_t	*lip = listp;
215*da14cebeSEric Cheng 	prop_val_t	*lvp;
216*da14cebeSEric Cheng 	uint_t		valcnt = 0;
217*da14cebeSEric Cheng 
218*da14cebeSEric Cheng 	/*
219*da14cebeSEric Cheng 	 * Find the prop we want to get.
220*da14cebeSEric Cheng 	 */
221*da14cebeSEric Cheng 	for (; lip != NULL; lip = lip->li_nextprop) {
222*da14cebeSEric Cheng 		if (strcmp(lip->li_name, lsp->ls_propname) == 0)
223*da14cebeSEric Cheng 			break;
224*da14cebeSEric Cheng 	}
225*da14cebeSEric Cheng 	if (lip == NULL) {
226*da14cebeSEric Cheng 		*statusp = DLADM_STATUS_NOTFOUND;
227*da14cebeSEric Cheng 		return (B_FALSE);
228*da14cebeSEric Cheng 	}
229*da14cebeSEric Cheng 
230*da14cebeSEric Cheng 	for (lvp = lip->li_val; lvp != NULL; lvp = lvp->lv_nextval) {
231*da14cebeSEric Cheng 		(void) strncpy(lsp->ls_propval[valcnt], lvp->lv_name,
232*da14cebeSEric Cheng 		    DLADM_PROP_VAL_MAX);
233*da14cebeSEric Cheng 
234*da14cebeSEric Cheng 		if (++valcnt >= *lsp->ls_valcntp && lvp->lv_nextval != NULL) {
235*da14cebeSEric Cheng 			*statusp = DLADM_STATUS_TOOSMALL;
236*da14cebeSEric Cheng 			return (B_FALSE);
237*da14cebeSEric Cheng 		}
238*da14cebeSEric Cheng 	}
239*da14cebeSEric Cheng 	/*
240*da14cebeSEric Cheng 	 * This function is meant to be called at most once for each call
241*da14cebeSEric Cheng 	 * to process_prop_db(). For this reason, it's ok to overwrite
242*da14cebeSEric Cheng 	 * the caller's valcnt array size with the actual number of values
243*da14cebeSEric Cheng 	 * returned.
244*da14cebeSEric Cheng 	 */
245*da14cebeSEric Cheng 	*lsp->ls_valcntp = valcnt;
246*da14cebeSEric Cheng 	return (B_FALSE);
247*da14cebeSEric Cheng }
248*da14cebeSEric Cheng 
249*da14cebeSEric Cheng /*
250*da14cebeSEric Cheng  * This is used for initializing properties.
251*da14cebeSEric Cheng  * Unlike the other routines, this gets called for every entry in the
252*da14cebeSEric Cheng  * database. lsp->ls_name is not user-specified but instead is set to
253*da14cebeSEric Cheng  * the current name being processed.
254*da14cebeSEric Cheng  */
255*da14cebeSEric Cheng /* ARGSUSED */
256*da14cebeSEric Cheng boolean_t
257*da14cebeSEric Cheng process_prop_init(prop_db_state_t *lsp, char *buf,
258*da14cebeSEric Cheng     prop_db_info_t *listp, dladm_status_t *statusp)
259*da14cebeSEric Cheng {
260*da14cebeSEric Cheng 	dladm_status_t	status = DLADM_STATUS_OK;
261*da14cebeSEric Cheng 	prop_db_info_t	*lip = listp;
262*da14cebeSEric Cheng 	prop_val_t	*lvp;
263*da14cebeSEric Cheng 	uint_t		valcnt, i;
264*da14cebeSEric Cheng 	char		**propval;
265*da14cebeSEric Cheng 
266*da14cebeSEric Cheng 	for (; lip != NULL; lip = lip->li_nextprop) {
267*da14cebeSEric Cheng 		/*
268*da14cebeSEric Cheng 		 * Construct the propval array and fill it with
269*da14cebeSEric Cheng 		 * values from listp.
270*da14cebeSEric Cheng 		 */
271*da14cebeSEric Cheng 		for (lvp = lip->li_val, valcnt = 0;
272*da14cebeSEric Cheng 		    lvp != NULL; lvp = lvp->lv_nextval, valcnt++) {
273*da14cebeSEric Cheng 		}
274*da14cebeSEric Cheng 
275*da14cebeSEric Cheng 		propval = malloc(sizeof (char *) * valcnt);
276*da14cebeSEric Cheng 		if (propval == NULL) {
277*da14cebeSEric Cheng 			*statusp = DLADM_STATUS_NOMEM;
278*da14cebeSEric Cheng 			break;
279*da14cebeSEric Cheng 		}
280*da14cebeSEric Cheng 		lvp = lip->li_val;
281*da14cebeSEric Cheng 		for (i = 0; i < valcnt; i++, lvp = lvp->lv_nextval)
282*da14cebeSEric Cheng 			propval[i] = (char *)lvp->lv_name;
283*da14cebeSEric Cheng 
284*da14cebeSEric Cheng 		status = (*lsp->ls_initop)(lsp->ls_name, lip->li_name,
285*da14cebeSEric Cheng 		    propval, valcnt, DLADM_OPT_ACTIVE, NULL);
286*da14cebeSEric Cheng 
287*da14cebeSEric Cheng 		/*
288*da14cebeSEric Cheng 		 * We continue with initializing other properties even
289*da14cebeSEric Cheng 		 * after encountering an error. This error will be
290*da14cebeSEric Cheng 		 * propagated to the caller via 'statusp'.
291*da14cebeSEric Cheng 		 */
292*da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
293*da14cebeSEric Cheng 			*statusp = status;
294*da14cebeSEric Cheng 
295*da14cebeSEric Cheng 		free(propval);
296*da14cebeSEric Cheng 	}
297*da14cebeSEric Cheng 	return (B_TRUE);
298*da14cebeSEric Cheng }
299*da14cebeSEric Cheng 
300*da14cebeSEric Cheng static int
301*da14cebeSEric Cheng parse_props(char *buf, prop_db_info_t **lipp)
302*da14cebeSEric Cheng {
303*da14cebeSEric Cheng 	int			i, len;
304*da14cebeSEric Cheng 	char			*curr;
305*da14cebeSEric Cheng 	prop_db_info_t		*lip = NULL;
306*da14cebeSEric Cheng 	prop_db_info_t		**tailp = lipp;
307*da14cebeSEric Cheng 	prop_val_t		*lvp = NULL;
308*da14cebeSEric Cheng 	prop_val_t		**vtailp = NULL;
309*da14cebeSEric Cheng 
310*da14cebeSEric Cheng 	curr = buf;
311*da14cebeSEric Cheng 	len = strlen(buf);
312*da14cebeSEric Cheng 	for (i = 0; i < len; i++) {
313*da14cebeSEric Cheng 		char		c = buf[i];
314*da14cebeSEric Cheng 		boolean_t	match = (c == '=' || c == ',' || c == ';');
315*da14cebeSEric Cheng 
316*da14cebeSEric Cheng 		/*
317*da14cebeSEric Cheng 		 * Move to the next character if there is no match and
318*da14cebeSEric Cheng 		 * if we have not reached the last character.
319*da14cebeSEric Cheng 		 */
320*da14cebeSEric Cheng 		if (!match && i != len - 1)
321*da14cebeSEric Cheng 			continue;
322*da14cebeSEric Cheng 
323*da14cebeSEric Cheng 		if (match) {
324*da14cebeSEric Cheng 			/*
325*da14cebeSEric Cheng 			 * Nul-terminate the string pointed to by 'curr'.
326*da14cebeSEric Cheng 			 */
327*da14cebeSEric Cheng 			buf[i] = '\0';
328*da14cebeSEric Cheng 			if (*curr == '\0')
329*da14cebeSEric Cheng 				goto fail;
330*da14cebeSEric Cheng 		}
331*da14cebeSEric Cheng 
332*da14cebeSEric Cheng 		if (lip != NULL) {
333*da14cebeSEric Cheng 			/*
334*da14cebeSEric Cheng 			 * We get here after we have processed the "<prop>="
335*da14cebeSEric Cheng 			 * pattern. The pattern we are now interested in is
336*da14cebeSEric Cheng 			 * "<val0>,<val1>,...,<valn>;". For each value we
337*da14cebeSEric Cheng 			 * find, a prop_val_t will be allocated and
338*da14cebeSEric Cheng 			 * added to the current 'lip'.
339*da14cebeSEric Cheng 			 */
340*da14cebeSEric Cheng 			if (c == '=')
341*da14cebeSEric Cheng 				goto fail;
342*da14cebeSEric Cheng 
343*da14cebeSEric Cheng 			lvp = malloc(sizeof (*lvp));
344*da14cebeSEric Cheng 			if (lvp == NULL)
345*da14cebeSEric Cheng 				goto fail;
346*da14cebeSEric Cheng 
347*da14cebeSEric Cheng 			lvp->lv_name = curr;
348*da14cebeSEric Cheng 			lvp->lv_nextval = NULL;
349*da14cebeSEric Cheng 			*vtailp = lvp;
350*da14cebeSEric Cheng 			vtailp = &lvp->lv_nextval;
351*da14cebeSEric Cheng 
352*da14cebeSEric Cheng 			if (c == ';') {
353*da14cebeSEric Cheng 				tailp = &lip->li_nextprop;
354*da14cebeSEric Cheng 				vtailp = NULL;
355*da14cebeSEric Cheng 				lip = NULL;
356*da14cebeSEric Cheng 			}
357*da14cebeSEric Cheng 		} else {
358*da14cebeSEric Cheng 			/*
359*da14cebeSEric Cheng 			 * lip == NULL indicates that 'curr' must be refering
360*da14cebeSEric Cheng 			 * to a property name. We allocate a new prop_db_info_t
361*da14cebeSEric Cheng 			 * append it to the list given by the caller.
362*da14cebeSEric Cheng 			 */
363*da14cebeSEric Cheng 			if (c != '=')
364*da14cebeSEric Cheng 				goto fail;
365*da14cebeSEric Cheng 
366*da14cebeSEric Cheng 			lip = malloc(sizeof (*lip));
367*da14cebeSEric Cheng 			if (lip == NULL)
368*da14cebeSEric Cheng 				goto fail;
369*da14cebeSEric Cheng 
370*da14cebeSEric Cheng 			lip->li_name = curr;
371*da14cebeSEric Cheng 			lip->li_val = NULL;
372*da14cebeSEric Cheng 			lip->li_nextprop = NULL;
373*da14cebeSEric Cheng 			*tailp = lip;
374*da14cebeSEric Cheng 			vtailp = &lip->li_val;
375*da14cebeSEric Cheng 		}
376*da14cebeSEric Cheng 		curr = buf + i + 1;
377*da14cebeSEric Cheng 	}
378*da14cebeSEric Cheng 	/*
379*da14cebeSEric Cheng 	 * The list must be non-empty and the last character must be ';'.
380*da14cebeSEric Cheng 	 */
381*da14cebeSEric Cheng 	if (*lipp == NULL || lip != NULL)
382*da14cebeSEric Cheng 		goto fail;
383*da14cebeSEric Cheng 
384*da14cebeSEric Cheng 	return (0);
385*da14cebeSEric Cheng 
386*da14cebeSEric Cheng fail:
387*da14cebeSEric Cheng 	free_props(*lipp);
388*da14cebeSEric Cheng 	*lipp = NULL;
389*da14cebeSEric Cheng 	return (-1);
390*da14cebeSEric Cheng }
391*da14cebeSEric Cheng 
392*da14cebeSEric Cheng static boolean_t
393*da14cebeSEric Cheng process_prop_line(prop_db_state_t *lsp, char *buf,
394*da14cebeSEric Cheng     dladm_status_t *statusp)
395*da14cebeSEric Cheng {
396*da14cebeSEric Cheng 	prop_db_info_t		*lip = NULL;
397*da14cebeSEric Cheng 	int			i, len, llen;
398*da14cebeSEric Cheng 	char			*str, *lasts;
399*da14cebeSEric Cheng 	boolean_t		cont, noname = B_FALSE;
400*da14cebeSEric Cheng 
401*da14cebeSEric Cheng 	/*
402*da14cebeSEric Cheng 	 * Skip leading spaces, blank lines, and comments.
403*da14cebeSEric Cheng 	 */
404*da14cebeSEric Cheng 	len = strlen(buf);
405*da14cebeSEric Cheng 	for (i = 0; i < len; i++) {
406*da14cebeSEric Cheng 		if (!isspace(buf[i]))
407*da14cebeSEric Cheng 			break;
408*da14cebeSEric Cheng 	}
409*da14cebeSEric Cheng 	if (i == len || buf[i] == '#')
410*da14cebeSEric Cheng 		return (B_TRUE);
411*da14cebeSEric Cheng 
412*da14cebeSEric Cheng 	str = buf + i;
413*da14cebeSEric Cheng 	if (lsp->ls_name != NULL) {
414*da14cebeSEric Cheng 		/*
415*da14cebeSEric Cheng 		 * Skip names we're not interested in.
416*da14cebeSEric Cheng 		 * Note that strncmp() and isspace() are used here
417*da14cebeSEric Cheng 		 * instead of strtok() and strcmp() because we don't
418*da14cebeSEric Cheng 		 * want to modify buf in case it does not contain the
419*da14cebeSEric Cheng 		 * specified name.
420*da14cebeSEric Cheng 		 */
421*da14cebeSEric Cheng 		llen = strlen(lsp->ls_name);
422*da14cebeSEric Cheng 		if (strncmp(str, lsp->ls_name, llen) != 0 ||
423*da14cebeSEric Cheng 		    !isspace(str[llen]))
424*da14cebeSEric Cheng 			return (B_TRUE);
425*da14cebeSEric Cheng 	} else {
426*da14cebeSEric Cheng 		/*
427*da14cebeSEric Cheng 		 * If a name is not specified, find the name
428*da14cebeSEric Cheng 		 * and assign it to lsp->ls_name.
429*da14cebeSEric Cheng 		 */
430*da14cebeSEric Cheng 		if (strtok_r(str, " \n\t", &lasts) == NULL)
431*da14cebeSEric Cheng 			goto fail;
432*da14cebeSEric Cheng 
433*da14cebeSEric Cheng 		llen = strlen(str);
434*da14cebeSEric Cheng 		lsp->ls_name = str;
435*da14cebeSEric Cheng 		noname = B_TRUE;
436*da14cebeSEric Cheng 	}
437*da14cebeSEric Cheng 	str += llen + 1;
438*da14cebeSEric Cheng 	if (str >= buf + len)
439*da14cebeSEric Cheng 		goto fail;
440*da14cebeSEric Cheng 
441*da14cebeSEric Cheng 	/*
442*da14cebeSEric Cheng 	 * Now find the list of properties.
443*da14cebeSEric Cheng 	 */
444*da14cebeSEric Cheng 	if ((str = strtok_r(str, " \n\t", &lasts)) == NULL)
445*da14cebeSEric Cheng 		goto fail;
446*da14cebeSEric Cheng 
447*da14cebeSEric Cheng 	if (parse_props(str, &lip) < 0)
448*da14cebeSEric Cheng 		goto fail;
449*da14cebeSEric Cheng 
450*da14cebeSEric Cheng 	cont = (*lsp->ls_op)(lsp, buf, lip, statusp);
451*da14cebeSEric Cheng 	free_props(lip);
452*da14cebeSEric Cheng 	if (noname)
453*da14cebeSEric Cheng 		lsp->ls_name = NULL;
454*da14cebeSEric Cheng 	return (cont);
455*da14cebeSEric Cheng 
456*da14cebeSEric Cheng fail:
457*da14cebeSEric Cheng 	free_props(lip);
458*da14cebeSEric Cheng 	if (noname)
459*da14cebeSEric Cheng 		lsp->ls_name = NULL;
460*da14cebeSEric Cheng 
461*da14cebeSEric Cheng 	/*
462*da14cebeSEric Cheng 	 * Delete corrupted line.
463*da14cebeSEric Cheng 	 */
464*da14cebeSEric Cheng 	buf[0] = '\0';
465*da14cebeSEric Cheng 	return (B_TRUE);
466*da14cebeSEric Cheng }
467*da14cebeSEric Cheng 
468*da14cebeSEric Cheng dladm_status_t
469*da14cebeSEric Cheng process_prop_db(void *arg, FILE *fp, FILE *nfp)
470*da14cebeSEric Cheng {
471*da14cebeSEric Cheng 	prop_db_state_t	*lsp = arg;
472*da14cebeSEric Cheng 	dladm_status_t		status = DLADM_STATUS_OK;
473*da14cebeSEric Cheng 	char			buf[MAXLINELEN];
474*da14cebeSEric Cheng 	boolean_t		cont = B_TRUE;
475*da14cebeSEric Cheng 
476*da14cebeSEric Cheng 	/*
477*da14cebeSEric Cheng 	 * This loop processes each line of the configuration file.
478*da14cebeSEric Cheng 	 * buf can potentially be modified by process_prop_line().
479*da14cebeSEric Cheng 	 * If this is a write operation and buf is not truncated, buf will
480*da14cebeSEric Cheng 	 * be written to disk. process_prop_line() will no longer be
481*da14cebeSEric Cheng 	 * called after it returns B_FALSE; at which point the remainder
482*da14cebeSEric Cheng 	 * of the file will continue to be read and, if necessary, written
483*da14cebeSEric Cheng 	 * to disk as well.
484*da14cebeSEric Cheng 	 */
485*da14cebeSEric Cheng 	while (fgets(buf, MAXLINELEN, fp) != NULL) {
486*da14cebeSEric Cheng 		if (cont)
487*da14cebeSEric Cheng 			cont = process_prop_line(lsp, buf, &status);
488*da14cebeSEric Cheng 
489*da14cebeSEric Cheng 		if (nfp != NULL && buf[0] != '\0' && fputs(buf, nfp) == EOF) {
490*da14cebeSEric Cheng 			status = dladm_errno2status(errno);
491*da14cebeSEric Cheng 			break;
492*da14cebeSEric Cheng 		}
493*da14cebeSEric Cheng 	}
494*da14cebeSEric Cheng 
495*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK || !cont)
496*da14cebeSEric Cheng 		return (status);
497*da14cebeSEric Cheng 
498*da14cebeSEric Cheng 	if (lsp->ls_op == process_prop_set) {
499*da14cebeSEric Cheng 		/*
500*da14cebeSEric Cheng 		 * If the specified name is not found above, we add the
501*da14cebeSEric Cheng 		 * name and its properties to the configuration file.
502*da14cebeSEric Cheng 		 */
503*da14cebeSEric Cheng 		(void) (*lsp->ls_op)(lsp, buf, NULL, &status);
504*da14cebeSEric Cheng 		if (status == DLADM_STATUS_OK && fputs(buf, nfp) == EOF)
505*da14cebeSEric Cheng 			status = dladm_errno2status(errno);
506*da14cebeSEric Cheng 	}
507*da14cebeSEric Cheng 
508*da14cebeSEric Cheng 	if (lsp->ls_op == process_prop_get)
509*da14cebeSEric Cheng 		status = DLADM_STATUS_NOTFOUND;
510*da14cebeSEric Cheng 
511*da14cebeSEric Cheng 	return (status);
512*da14cebeSEric Cheng }
513*da14cebeSEric Cheng 
514*da14cebeSEric Cheng dladm_status_t
515*da14cebeSEric Cheng i_dladm_get_prop_temp(const char *name, prop_type_t type,
516*da14cebeSEric Cheng     const char *prop_name, char **prop_val, uint_t *val_cntp,
517*da14cebeSEric Cheng     prop_table_t *prop_tbl)
518*da14cebeSEric Cheng {
519*da14cebeSEric Cheng 	int 		i;
520*da14cebeSEric Cheng 	dladm_status_t	status;
521*da14cebeSEric Cheng 	uint_t		cnt;
522*da14cebeSEric Cheng 	fprop_desc_t	*pdp;
523*da14cebeSEric Cheng 
524*da14cebeSEric Cheng 	if (name == NULL || prop_name == NULL || prop_val == NULL ||
525*da14cebeSEric Cheng 	    val_cntp == NULL || *val_cntp == 0)
526*da14cebeSEric Cheng 		return (DLADM_STATUS_BADARG);
527*da14cebeSEric Cheng 
528*da14cebeSEric Cheng 	for (i = 0; i < prop_tbl->pt_size; i++)
529*da14cebeSEric Cheng 		if (strcasecmp(prop_name, prop_tbl->pt_table[i].pd_name) == 0)
530*da14cebeSEric Cheng 			break;
531*da14cebeSEric Cheng 
532*da14cebeSEric Cheng 	if (i == prop_tbl->pt_size)
533*da14cebeSEric Cheng 		return (DLADM_STATUS_NOTFOUND);
534*da14cebeSEric Cheng 
535*da14cebeSEric Cheng 	pdp = &prop_tbl->pt_table[i];
536*da14cebeSEric Cheng 	status = DLADM_STATUS_OK;
537*da14cebeSEric Cheng 
538*da14cebeSEric Cheng 	switch (type) {
539*da14cebeSEric Cheng 	case DLADM_PROP_VAL_CURRENT:
540*da14cebeSEric Cheng 		status = pdp->pd_get(name, prop_val, val_cntp);
541*da14cebeSEric Cheng 		break;
542*da14cebeSEric Cheng 	case DLADM_PROP_VAL_DEFAULT:
543*da14cebeSEric Cheng 		if (pdp->pd_defval.vd_name == NULL) {
544*da14cebeSEric Cheng 			status = DLADM_STATUS_NOTSUP;
545*da14cebeSEric Cheng 			break;
546*da14cebeSEric Cheng 		}
547*da14cebeSEric Cheng 		(void) strcpy(*prop_val, pdp->pd_defval.vd_name);
548*da14cebeSEric Cheng 		*val_cntp = 1;
549*da14cebeSEric Cheng 		break;
550*da14cebeSEric Cheng 
551*da14cebeSEric Cheng 	case DLADM_PROP_VAL_MODIFIABLE:
552*da14cebeSEric Cheng 		if (pdp->pd_getmod != NULL) {
553*da14cebeSEric Cheng 			status = pdp->pd_getmod(name, prop_val, val_cntp);
554*da14cebeSEric Cheng 			break;
555*da14cebeSEric Cheng 		}
556*da14cebeSEric Cheng 		cnt = pdp->pd_nmodval;
557*da14cebeSEric Cheng 		if (cnt == 0) {
558*da14cebeSEric Cheng 			status = DLADM_STATUS_NOTSUP;
559*da14cebeSEric Cheng 		} else if (cnt > *val_cntp) {
560*da14cebeSEric Cheng 			status = DLADM_STATUS_TOOSMALL;
561*da14cebeSEric Cheng 		} else {
562*da14cebeSEric Cheng 			for (i = 0; i < cnt; i++) {
563*da14cebeSEric Cheng 				(void) strcpy(prop_val[i],
564*da14cebeSEric Cheng 				    pdp->pd_modval[i].vd_name);
565*da14cebeSEric Cheng 			}
566*da14cebeSEric Cheng 			*val_cntp = cnt;
567*da14cebeSEric Cheng 		}
568*da14cebeSEric Cheng 		break;
569*da14cebeSEric Cheng 	default:
570*da14cebeSEric Cheng 		status = DLADM_STATUS_BADARG;
571*da14cebeSEric Cheng 		break;
572*da14cebeSEric Cheng 	}
573*da14cebeSEric Cheng 
574*da14cebeSEric Cheng 	return (status);
575*da14cebeSEric Cheng }
576*da14cebeSEric Cheng 
577*da14cebeSEric Cheng static dladm_status_t
578*da14cebeSEric Cheng i_dladm_set_one_prop_temp(const char *name, fprop_desc_t *pdp, char **prop_val,
579*da14cebeSEric Cheng     uint_t val_cnt, uint_t flags)
580*da14cebeSEric Cheng {
581*da14cebeSEric Cheng 	dladm_status_t	status;
582*da14cebeSEric Cheng 	val_desc_t	*vdp = NULL;
583*da14cebeSEric Cheng 	uint_t		cnt;
584*da14cebeSEric Cheng 
585*da14cebeSEric Cheng 	if (pdp->pd_temponly && (flags & DLADM_OPT_PERSIST) != 0)
586*da14cebeSEric Cheng 		return (DLADM_STATUS_TEMPONLY);
587*da14cebeSEric Cheng 
588*da14cebeSEric Cheng 	if (pdp->pd_set == NULL)
589*da14cebeSEric Cheng 		return (DLADM_STATUS_PROPRDONLY);
590*da14cebeSEric Cheng 
591*da14cebeSEric Cheng 	if (prop_val != NULL) {
592*da14cebeSEric Cheng 		if (pdp->pd_check != NULL)
593*da14cebeSEric Cheng 			status = pdp->pd_check(pdp, prop_val, val_cnt, &vdp);
594*da14cebeSEric Cheng 		else
595*da14cebeSEric Cheng 			status = DLADM_STATUS_BADARG;
596*da14cebeSEric Cheng 
597*da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
598*da14cebeSEric Cheng 			return (status);
599*da14cebeSEric Cheng 
600*da14cebeSEric Cheng 		cnt = val_cnt;
601*da14cebeSEric Cheng 	} else {
602*da14cebeSEric Cheng 		if (pdp->pd_defval.vd_name == NULL)
603*da14cebeSEric Cheng 			return (DLADM_STATUS_NOTSUP);
604*da14cebeSEric Cheng 
605*da14cebeSEric Cheng 		if ((vdp = malloc(sizeof (val_desc_t))) == NULL)
606*da14cebeSEric Cheng 			return (DLADM_STATUS_NOMEM);
607*da14cebeSEric Cheng 
608*da14cebeSEric Cheng 		(void) memcpy(vdp, &pdp->pd_defval, sizeof (val_desc_t));
609*da14cebeSEric Cheng 		cnt = 1;
610*da14cebeSEric Cheng 	}
611*da14cebeSEric Cheng 
612*da14cebeSEric Cheng 	status = pdp->pd_set(name, vdp, cnt);
613*da14cebeSEric Cheng 
614*da14cebeSEric Cheng 	free(vdp);
615*da14cebeSEric Cheng 	return (status);
616*da14cebeSEric Cheng }
617*da14cebeSEric Cheng 
618*da14cebeSEric Cheng dladm_status_t
619*da14cebeSEric Cheng i_dladm_set_prop_temp(const char *name, const char *prop_name, char **prop_val,
620*da14cebeSEric Cheng     uint_t val_cnt, uint_t flags, char **errprop, prop_table_t *prop_tbl)
621*da14cebeSEric Cheng {
622*da14cebeSEric Cheng 	int 		i;
623*da14cebeSEric Cheng 	dladm_status_t	status = DLADM_STATUS_OK;
624*da14cebeSEric Cheng 	boolean_t	found = B_FALSE;
625*da14cebeSEric Cheng 
626*da14cebeSEric Cheng 	for (i = 0; i < prop_tbl->pt_size; i++) {
627*da14cebeSEric Cheng 		fprop_desc_t	*pdp = &prop_tbl->pt_table[i];
628*da14cebeSEric Cheng 		dladm_status_t	s;
629*da14cebeSEric Cheng 
630*da14cebeSEric Cheng 		if (prop_name != NULL &&
631*da14cebeSEric Cheng 		    (strcasecmp(prop_name, pdp->pd_name) != 0))
632*da14cebeSEric Cheng 			continue;
633*da14cebeSEric Cheng 
634*da14cebeSEric Cheng 		found = B_TRUE;
635*da14cebeSEric Cheng 		s = i_dladm_set_one_prop_temp(name, pdp, prop_val, val_cnt,
636*da14cebeSEric Cheng 		    flags);
637*da14cebeSEric Cheng 
638*da14cebeSEric Cheng 		if (prop_name != NULL) {
639*da14cebeSEric Cheng 			status = s;
640*da14cebeSEric Cheng 			break;
641*da14cebeSEric Cheng 		} else {
642*da14cebeSEric Cheng 			if (s != DLADM_STATUS_OK &&
643*da14cebeSEric Cheng 			    s != DLADM_STATUS_NOTSUP) {
644*da14cebeSEric Cheng 				if (errprop != NULL)
645*da14cebeSEric Cheng 					*errprop = pdp->pd_name;
646*da14cebeSEric Cheng 				status = s;
647*da14cebeSEric Cheng 				break;
648*da14cebeSEric Cheng 			}
649*da14cebeSEric Cheng 		}
650*da14cebeSEric Cheng 	}
651*da14cebeSEric Cheng 
652*da14cebeSEric Cheng 	if (!found)
653*da14cebeSEric Cheng 		status = DLADM_STATUS_NOTFOUND;
654*da14cebeSEric Cheng 
655*da14cebeSEric Cheng 	return (status);
656*da14cebeSEric Cheng }
657*da14cebeSEric Cheng 
658*da14cebeSEric Cheng boolean_t
659*da14cebeSEric Cheng i_dladm_is_prop_temponly(const char *prop_name, char **errprop,
660*da14cebeSEric Cheng     prop_table_t *prop_tbl)
661*da14cebeSEric Cheng {
662*da14cebeSEric Cheng 	int 		i;
663*da14cebeSEric Cheng 
664*da14cebeSEric Cheng 	if (prop_name == NULL)
665*da14cebeSEric Cheng 		return (B_FALSE);
666*da14cebeSEric Cheng 
667*da14cebeSEric Cheng 	for (i = 0; i < prop_tbl->pt_size; i++) {
668*da14cebeSEric Cheng 		fprop_desc_t	*pdp = &prop_tbl->pt_table[i];
669*da14cebeSEric Cheng 
670*da14cebeSEric Cheng 		if (strcasecmp(prop_name, pdp->pd_name) != 0)
671*da14cebeSEric Cheng 			continue;
672*da14cebeSEric Cheng 
673*da14cebeSEric Cheng 		if (errprop != NULL)
674*da14cebeSEric Cheng 			*errprop = pdp->pd_name;
675*da14cebeSEric Cheng 
676*da14cebeSEric Cheng 		if (pdp->pd_temponly)
677*da14cebeSEric Cheng 			return (B_TRUE);
678*da14cebeSEric Cheng 	}
679*da14cebeSEric Cheng 
680*da14cebeSEric Cheng 	return (B_FALSE);
681*da14cebeSEric Cheng }
682*da14cebeSEric Cheng void
683*da14cebeSEric Cheng dladm_free_props(dladm_arg_list_t *list)
684*da14cebeSEric Cheng {
685*da14cebeSEric Cheng 	dladm_free_args(list);
686*da14cebeSEric Cheng }
687*da14cebeSEric Cheng 
688*da14cebeSEric Cheng dladm_status_t
689*da14cebeSEric Cheng dladm_parse_props(char *str, dladm_arg_list_t **listp, boolean_t novalues)
690*da14cebeSEric Cheng {
691*da14cebeSEric Cheng 	if (dladm_parse_args(str, listp, novalues) != DLADM_STATUS_OK)
692*da14cebeSEric Cheng 		goto fail;
693*da14cebeSEric Cheng 
694*da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
695*da14cebeSEric Cheng 
696*da14cebeSEric Cheng fail:
697*da14cebeSEric Cheng 	dladm_free_args(*listp);
698*da14cebeSEric Cheng 	return (DLADM_STATUS_PROP_PARSE_ERR);
699*da14cebeSEric Cheng }
700