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