xref: /onnv-gate/usr/src/lib/libdladm/common/propfuncs.c (revision 8453:15fa4bb77d8c)
18275SEric Cheng /*
28275SEric Cheng  * CDDL HEADER START
38275SEric Cheng  *
48275SEric Cheng  * The contents of this file are subject to the terms of the
58275SEric Cheng  * Common Development and Distribution License (the "License").
68275SEric Cheng  * You may not use this file except in compliance with the License.
78275SEric Cheng  *
88275SEric Cheng  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98275SEric Cheng  * or http://www.opensolaris.org/os/licensing.
108275SEric Cheng  * See the License for the specific language governing permissions
118275SEric Cheng  * and limitations under the License.
128275SEric Cheng  *
138275SEric Cheng  * When distributing Covered Code, include this CDDL HEADER in each
148275SEric Cheng  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158275SEric Cheng  * If applicable, add the following below this CDDL HEADER, with the
168275SEric Cheng  * fields enclosed by brackets "[]" replaced with your own identifying
178275SEric Cheng  * information: Portions Copyright [yyyy] [name of copyright owner]
188275SEric Cheng  *
198275SEric Cheng  * CDDL HEADER END
208275SEric Cheng  */
218275SEric Cheng /*
228275SEric Cheng  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
238275SEric Cheng  * Use is subject to license terms.
248275SEric Cheng  */
258275SEric Cheng 
268275SEric Cheng #include <stdlib.h>
278275SEric Cheng #include <strings.h>
288275SEric Cheng #include <errno.h>
298275SEric Cheng #include <ctype.h>
308275SEric Cheng #include <sys/types.h>
318275SEric Cheng #include <sys/stat.h>
328275SEric Cheng #include <sys/dld.h>
338275SEric Cheng #include <fcntl.h>
348275SEric Cheng #include <unistd.h>
358275SEric Cheng #include <libdladm_impl.h>
368275SEric Cheng #include <libdlflow_impl.h>
378275SEric Cheng 
388275SEric Cheng /*
398275SEric Cheng  * XXX duplicate defines
408275SEric Cheng  */
418275SEric Cheng #define	DLADM_PROP_VAL_MAX	32
428275SEric Cheng #define	DLADM_MAX_PROPS		32
438275SEric Cheng 
448275SEric Cheng static void
free_props(prop_db_info_t * lip)458275SEric Cheng free_props(prop_db_info_t *lip)
468275SEric Cheng {
478275SEric Cheng 	prop_db_info_t	*lip_next;
488275SEric Cheng 	prop_val_t	*lvp, *lvp_next;
498275SEric Cheng 
508275SEric Cheng 	for (; lip != NULL; lip = lip_next) {
518275SEric Cheng 		lip_next = lip->li_nextprop;
528275SEric Cheng 		for (lvp = lip->li_val; lvp != NULL; lvp = lvp_next) {
538275SEric Cheng 			lvp_next = lvp->lv_nextval;
548275SEric Cheng 			free(lvp);
558275SEric Cheng 		}
568275SEric Cheng 		free(lip);
578275SEric Cheng 	}
588275SEric Cheng }
598275SEric Cheng 
608275SEric Cheng /*
618275SEric Cheng  * Generate an entry in the property database.
628275SEric Cheng  * Each entry has this format:
638275SEric Cheng  * <name>	<prop0>=<val0>,...,<valn>;...;<propn>=<val0>,...,<valn>;
648275SEric Cheng  */
658275SEric Cheng static void
generate_prop_line(const char * name,char * buf,prop_db_info_t * listp,dladm_status_t * statusp)668275SEric Cheng generate_prop_line(const char *name, char *buf,
678275SEric Cheng     prop_db_info_t *listp, dladm_status_t *statusp)
688275SEric Cheng {
698275SEric Cheng 	char		tmpbuf[MAXLINELEN];
708275SEric Cheng 	char		*ptr, *lim = tmpbuf + MAXLINELEN;
718275SEric Cheng 	prop_db_info_t	*lip = listp;
728275SEric Cheng 	prop_val_t	*lvp = NULL;
738275SEric Cheng 
748275SEric Cheng 	/*
758275SEric Cheng 	 * Delete line if there are no properties left.
768275SEric Cheng 	 */
778275SEric Cheng 	if (lip == NULL ||
788275SEric Cheng 	    (lip->li_val == NULL && lip->li_nextprop == NULL)) {
798275SEric Cheng 		buf[0] = '\0';
808275SEric Cheng 		return;
818275SEric Cheng 	}
828275SEric Cheng 	ptr = tmpbuf;
838275SEric Cheng 	ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t", name);
848275SEric Cheng 	for (; lip != NULL; lip = lip->li_nextprop) {
858275SEric Cheng 		/*
868275SEric Cheng 		 * Skip properties without values.
878275SEric Cheng 		 */
888275SEric Cheng 		if (lip->li_val == NULL)
898275SEric Cheng 			continue;
908275SEric Cheng 
918275SEric Cheng 		ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s=", lip->li_name);
928275SEric Cheng 		for (lvp = lip->li_val; lvp != NULL; lvp = lvp->lv_nextval) {
938275SEric Cheng 			ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s%c",
948275SEric Cheng 			    lvp->lv_name,
958275SEric Cheng 			    ((lvp->lv_nextval == NULL) ? ';' : ','));
968275SEric Cheng 		}
978275SEric Cheng 	}
988275SEric Cheng 	if (ptr > lim) {
998275SEric Cheng 		*statusp = DLADM_STATUS_TOOSMALL;
1008275SEric Cheng 		return;
1018275SEric Cheng 	}
1028275SEric Cheng 	(void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf);
1038275SEric Cheng }
1048275SEric Cheng 
1058275SEric Cheng /*
1068275SEric Cheng  * This function is used to update or create an entry in the persistent db.
1078275SEric Cheng  * process_prop_db() will first scan the db for an entry matching the
1088275SEric Cheng  * specified name. If a match is found, this function is invoked with the
1098275SEric Cheng  * entry's contents (buf) and its linked-list representation (listp). lsp
1108275SEric Cheng  * holds the name and values of the property to be added or updated; this
1118275SEric Cheng  * information will be merged with listp. Subsequently, an updated entry
1128275SEric Cheng  * will be written to buf, which will in turn be written to disk by
1138275SEric Cheng  * process_prop_db(). If no entry matches the specified name, listp
1148275SEric Cheng  * will be NULL; a new entry will be generated in this case and it will
1158275SEric Cheng  * contain only the property information in lsp.
1168275SEric Cheng  */
117*8453SAnurag.Maskey@Sun.COM /* ARGSUSED */
1188275SEric 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*8453SAnurag.Maskey@Sun.COM process_prop_set(dladm_handle_t handle, prop_db_state_t *lsp, char *buf,
1208275SEric Cheng     prop_db_info_t *listp, dladm_status_t *statusp)
1218275SEric Cheng {
1228275SEric Cheng 	dladm_status_t	status;
1238275SEric Cheng 	prop_db_info_t	*lastp = NULL, *lip = listp, *nlip = NULL;
1248275SEric Cheng 	prop_val_t	**lvpp;
1258275SEric Cheng 	int		i;
1268275SEric Cheng 
1278275SEric Cheng 	if (lsp->ls_propname == NULL) {
1288275SEric Cheng 		buf[0] = '\0';
1298275SEric Cheng 		return (B_FALSE);
1308275SEric Cheng 	}
1318275SEric Cheng 
1328275SEric Cheng 	/*
1338275SEric Cheng 	 * Find the prop we want to change.
1348275SEric Cheng 	 */
1358275SEric Cheng 	for (; lip != NULL; lip = lip->li_nextprop) {
1368275SEric Cheng 		if (strcmp(lip->li_name, lsp->ls_propname) == 0)
1378275SEric Cheng 			break;
1388275SEric Cheng 
1398275SEric Cheng 		lastp = lip;
1408275SEric Cheng 	}
1418275SEric Cheng 
1428275SEric Cheng 	if (lip == NULL) {
1438275SEric Cheng 		/*
1448275SEric Cheng 		 * If the prop is not found, append it to the list.
1458275SEric Cheng 		 */
1468275SEric Cheng 		if ((nlip = malloc(sizeof (prop_db_info_t))) == NULL) {
1478275SEric Cheng 			status = DLADM_STATUS_NOMEM;
1488275SEric Cheng 			goto fail;
1498275SEric Cheng 		}
1508275SEric Cheng 		/*
1518275SEric Cheng 		 * nlip will need to be freed later if there is no list to
1528275SEric Cheng 		 * append to.
1538275SEric Cheng 		 */
1548275SEric Cheng 		if (lastp != NULL)
1558275SEric Cheng 			lastp->li_nextprop = nlip;
1568275SEric Cheng 		nlip->li_name = lsp->ls_propname;
1578275SEric Cheng 		nlip->li_nextprop = NULL;
1588275SEric Cheng 		nlip->li_val = NULL;
1598275SEric Cheng 		lvpp = &nlip->li_val;
1608275SEric Cheng 	} else {
1618275SEric Cheng 		prop_val_t	*lvp, *lvp_next;
1628275SEric Cheng 
1638275SEric Cheng 		/*
1648275SEric Cheng 		 * If the prop is found, delete the existing values from it.
1658275SEric Cheng 		 */
1668275SEric Cheng 		for (lvp = lip->li_val; lvp != NULL; lvp = lvp_next) {
1678275SEric Cheng 			lvp_next = lvp->lv_nextval;
1688275SEric Cheng 			free(lvp);
1698275SEric Cheng 		}
1708275SEric Cheng 		lip->li_val = NULL;
1718275SEric Cheng 		lvpp = &lip->li_val;
1728275SEric Cheng 	}
1738275SEric Cheng 
1748275SEric Cheng 	/*
1758275SEric Cheng 	 * Fill our prop with the specified values.
1768275SEric Cheng 	 */
1778275SEric Cheng 	for (i = 0; i < *lsp->ls_valcntp; i++) {
1788275SEric Cheng 		if ((*lvpp = malloc(sizeof (prop_val_t))) == NULL) {
1798275SEric Cheng 			status = DLADM_STATUS_NOMEM;
1808275SEric Cheng 			goto fail;
1818275SEric Cheng 		}
1828275SEric Cheng 		(*lvpp)->lv_name = lsp->ls_propval[i];
1838275SEric Cheng 		(*lvpp)->lv_nextval = NULL;
1848275SEric Cheng 		lvpp = &(*lvpp)->lv_nextval;
1858275SEric Cheng 	}
1868275SEric Cheng 
1878275SEric Cheng 	if (listp != NULL) {
1888275SEric Cheng 		generate_prop_line(lsp->ls_name, buf, listp, statusp);
1898275SEric Cheng 	} else {
1908275SEric Cheng 		generate_prop_line(lsp->ls_name, buf, nlip, statusp);
1918275SEric Cheng 		free_props(nlip);
1928275SEric Cheng 	}
1938275SEric Cheng 	return (B_FALSE);
1948275SEric Cheng 
1958275SEric Cheng fail:
1968275SEric Cheng 	*statusp = status;
1978275SEric Cheng 	if (listp == NULL)
1988275SEric Cheng 		free_props(nlip);
1998275SEric Cheng 
2008275SEric Cheng 	return (B_FALSE);
2018275SEric Cheng }
2028275SEric Cheng 
2038275SEric Cheng /*
2048275SEric Cheng  * This function is used for retrieving the values for a specific property.
2058275SEric Cheng  * It gets called if an entry matching the specified name exists in the db.
2068275SEric Cheng  * The entry is converted into a linked-list listp. This list is then scanned
2078275SEric Cheng  * for the specified property name; if a matching property exists, its
2088275SEric Cheng  * associated values are copied to the array lsp->ls_propval.
2098275SEric Cheng  */
2108275SEric Cheng /* ARGSUSED */
2118275SEric 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*8453SAnurag.Maskey@Sun.COM process_prop_get(dladm_handle_t handle, prop_db_state_t *lsp, char *buf,
2138275SEric Cheng     prop_db_info_t *listp, dladm_status_t *statusp)
2148275SEric Cheng {
2158275SEric Cheng 	prop_db_info_t	*lip = listp;
2168275SEric Cheng 	prop_val_t	*lvp;
2178275SEric Cheng 	uint_t		valcnt = 0;
2188275SEric Cheng 
2198275SEric Cheng 	/*
2208275SEric Cheng 	 * Find the prop we want to get.
2218275SEric Cheng 	 */
2228275SEric Cheng 	for (; lip != NULL; lip = lip->li_nextprop) {
2238275SEric Cheng 		if (strcmp(lip->li_name, lsp->ls_propname) == 0)
2248275SEric Cheng 			break;
2258275SEric Cheng 	}
2268275SEric Cheng 	if (lip == NULL) {
2278275SEric Cheng 		*statusp = DLADM_STATUS_NOTFOUND;
2288275SEric Cheng 		return (B_FALSE);
2298275SEric Cheng 	}
2308275SEric Cheng 
2318275SEric Cheng 	for (lvp = lip->li_val; lvp != NULL; lvp = lvp->lv_nextval) {
2328275SEric Cheng 		(void) strncpy(lsp->ls_propval[valcnt], lvp->lv_name,
2338275SEric Cheng 		    DLADM_PROP_VAL_MAX);
2348275SEric Cheng 
2358275SEric Cheng 		if (++valcnt >= *lsp->ls_valcntp && lvp->lv_nextval != NULL) {
2368275SEric Cheng 			*statusp = DLADM_STATUS_TOOSMALL;
2378275SEric Cheng 			return (B_FALSE);
2388275SEric Cheng 		}
2398275SEric Cheng 	}
2408275SEric Cheng 	/*
2418275SEric Cheng 	 * This function is meant to be called at most once for each call
2428275SEric Cheng 	 * to process_prop_db(). For this reason, it's ok to overwrite
2438275SEric Cheng 	 * the caller's valcnt array size with the actual number of values
2448275SEric Cheng 	 * returned.
2458275SEric Cheng 	 */
2468275SEric Cheng 	*lsp->ls_valcntp = valcnt;
2478275SEric Cheng 	return (B_FALSE);
2488275SEric Cheng }
2498275SEric Cheng 
2508275SEric Cheng /*
2518275SEric Cheng  * This is used for initializing properties.
2528275SEric Cheng  * Unlike the other routines, this gets called for every entry in the
2538275SEric Cheng  * database. lsp->ls_name is not user-specified but instead is set to
2548275SEric Cheng  * the current name being processed.
2558275SEric Cheng  */
2568275SEric Cheng /* ARGSUSED */
2578275SEric 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*8453SAnurag.Maskey@Sun.COM process_prop_init(dladm_handle_t handle, prop_db_state_t *lsp, char *buf,
2598275SEric Cheng     prop_db_info_t *listp, dladm_status_t *statusp)
2608275SEric Cheng {
2618275SEric Cheng 	dladm_status_t	status = DLADM_STATUS_OK;
2628275SEric Cheng 	prop_db_info_t	*lip = listp;
2638275SEric Cheng 	prop_val_t	*lvp;
2648275SEric Cheng 	uint_t		valcnt, i;
2658275SEric Cheng 	char		**propval;
2668275SEric Cheng 
2678275SEric Cheng 	for (; lip != NULL; lip = lip->li_nextprop) {
2688275SEric Cheng 		/*
2698275SEric Cheng 		 * Construct the propval array and fill it with
2708275SEric Cheng 		 * values from listp.
2718275SEric Cheng 		 */
2728275SEric Cheng 		for (lvp = lip->li_val, valcnt = 0;
2738275SEric Cheng 		    lvp != NULL; lvp = lvp->lv_nextval, valcnt++) {
2748275SEric Cheng 		}
2758275SEric Cheng 
2768275SEric Cheng 		propval = malloc(sizeof (char *) * valcnt);
2778275SEric Cheng 		if (propval == NULL) {
2788275SEric Cheng 			*statusp = DLADM_STATUS_NOMEM;
2798275SEric Cheng 			break;
2808275SEric Cheng 		}
2818275SEric Cheng 		lvp = lip->li_val;
2828275SEric Cheng 		for (i = 0; i < valcnt; i++, lvp = lvp->lv_nextval)
2838275SEric Cheng 			propval[i] = (char *)lvp->lv_name;
2848275SEric Cheng 
285*8453SAnurag.Maskey@Sun.COM 		status = (*lsp->ls_initop)(handle, lsp->ls_name, lip->li_name,
2868275SEric Cheng 		    propval, valcnt, DLADM_OPT_ACTIVE, NULL);
2878275SEric Cheng 
2888275SEric Cheng 		/*
2898275SEric Cheng 		 * We continue with initializing other properties even
2908275SEric Cheng 		 * after encountering an error. This error will be
2918275SEric Cheng 		 * propagated to the caller via 'statusp'.
2928275SEric Cheng 		 */
2938275SEric Cheng 		if (status != DLADM_STATUS_OK)
2948275SEric Cheng 			*statusp = status;
2958275SEric Cheng 
2968275SEric Cheng 		free(propval);
2978275SEric Cheng 	}
2988275SEric Cheng 	return (B_TRUE);
2998275SEric Cheng }
3008275SEric Cheng 
3018275SEric Cheng static int
parse_props(char * buf,prop_db_info_t ** lipp)3028275SEric Cheng parse_props(char *buf, prop_db_info_t **lipp)
3038275SEric Cheng {
3048275SEric Cheng 	int			i, len;
3058275SEric Cheng 	char			*curr;
3068275SEric Cheng 	prop_db_info_t		*lip = NULL;
3078275SEric Cheng 	prop_db_info_t		**tailp = lipp;
3088275SEric Cheng 	prop_val_t		*lvp = NULL;
3098275SEric Cheng 	prop_val_t		**vtailp = NULL;
3108275SEric Cheng 
3118275SEric Cheng 	curr = buf;
3128275SEric Cheng 	len = strlen(buf);
3138275SEric Cheng 	for (i = 0; i < len; i++) {
3148275SEric Cheng 		char		c = buf[i];
3158275SEric Cheng 		boolean_t	match = (c == '=' || c == ',' || c == ';');
3168275SEric Cheng 
3178275SEric Cheng 		/*
3188275SEric Cheng 		 * Move to the next character if there is no match and
3198275SEric Cheng 		 * if we have not reached the last character.
3208275SEric Cheng 		 */
3218275SEric Cheng 		if (!match && i != len - 1)
3228275SEric Cheng 			continue;
3238275SEric Cheng 
3248275SEric Cheng 		if (match) {
3258275SEric Cheng 			/*
3268275SEric Cheng 			 * Nul-terminate the string pointed to by 'curr'.
3278275SEric Cheng 			 */
3288275SEric Cheng 			buf[i] = '\0';
3298275SEric Cheng 			if (*curr == '\0')
3308275SEric Cheng 				goto fail;
3318275SEric Cheng 		}
3328275SEric Cheng 
3338275SEric Cheng 		if (lip != NULL) {
3348275SEric Cheng 			/*
3358275SEric Cheng 			 * We get here after we have processed the "<prop>="
3368275SEric Cheng 			 * pattern. The pattern we are now interested in is
3378275SEric Cheng 			 * "<val0>,<val1>,...,<valn>;". For each value we
3388275SEric Cheng 			 * find, a prop_val_t will be allocated and
3398275SEric Cheng 			 * added to the current 'lip'.
3408275SEric Cheng 			 */
3418275SEric Cheng 			if (c == '=')
3428275SEric Cheng 				goto fail;
3438275SEric Cheng 
3448275SEric Cheng 			lvp = malloc(sizeof (*lvp));
3458275SEric Cheng 			if (lvp == NULL)
3468275SEric Cheng 				goto fail;
3478275SEric Cheng 
3488275SEric Cheng 			lvp->lv_name = curr;
3498275SEric Cheng 			lvp->lv_nextval = NULL;
3508275SEric Cheng 			*vtailp = lvp;
3518275SEric Cheng 			vtailp = &lvp->lv_nextval;
3528275SEric Cheng 
3538275SEric Cheng 			if (c == ';') {
3548275SEric Cheng 				tailp = &lip->li_nextprop;
3558275SEric Cheng 				vtailp = NULL;
3568275SEric Cheng 				lip = NULL;
3578275SEric Cheng 			}
3588275SEric Cheng 		} else {
3598275SEric Cheng 			/*
3608275SEric Cheng 			 * lip == NULL indicates that 'curr' must be refering
3618275SEric Cheng 			 * to a property name. We allocate a new prop_db_info_t
3628275SEric Cheng 			 * append it to the list given by the caller.
3638275SEric Cheng 			 */
3648275SEric Cheng 			if (c != '=')
3658275SEric Cheng 				goto fail;
3668275SEric Cheng 
3678275SEric Cheng 			lip = malloc(sizeof (*lip));
3688275SEric Cheng 			if (lip == NULL)
3698275SEric Cheng 				goto fail;
3708275SEric Cheng 
3718275SEric Cheng 			lip->li_name = curr;
3728275SEric Cheng 			lip->li_val = NULL;
3738275SEric Cheng 			lip->li_nextprop = NULL;
3748275SEric Cheng 			*tailp = lip;
3758275SEric Cheng 			vtailp = &lip->li_val;
3768275SEric Cheng 		}
3778275SEric Cheng 		curr = buf + i + 1;
3788275SEric Cheng 	}
3798275SEric Cheng 	/*
3808275SEric Cheng 	 * The list must be non-empty and the last character must be ';'.
3818275SEric Cheng 	 */
3828275SEric Cheng 	if (*lipp == NULL || lip != NULL)
3838275SEric Cheng 		goto fail;
3848275SEric Cheng 
3858275SEric Cheng 	return (0);
3868275SEric Cheng 
3878275SEric Cheng fail:
3888275SEric Cheng 	free_props(*lipp);
3898275SEric Cheng 	*lipp = NULL;
3908275SEric Cheng 	return (-1);
3918275SEric Cheng }
3928275SEric Cheng 
3938275SEric Cheng static boolean_t
process_prop_line(dladm_handle_t handle,prop_db_state_t * lsp,char * buf,dladm_status_t * statusp)394*8453SAnurag.Maskey@Sun.COM process_prop_line(dladm_handle_t handle, prop_db_state_t *lsp, char *buf,
3958275SEric Cheng     dladm_status_t *statusp)
3968275SEric Cheng {
3978275SEric Cheng 	prop_db_info_t		*lip = NULL;
3988275SEric Cheng 	int			i, len, llen;
3998275SEric Cheng 	char			*str, *lasts;
4008275SEric Cheng 	boolean_t		cont, noname = B_FALSE;
4018275SEric Cheng 
4028275SEric Cheng 	/*
4038275SEric Cheng 	 * Skip leading spaces, blank lines, and comments.
4048275SEric Cheng 	 */
4058275SEric Cheng 	len = strlen(buf);
4068275SEric Cheng 	for (i = 0; i < len; i++) {
4078275SEric Cheng 		if (!isspace(buf[i]))
4088275SEric Cheng 			break;
4098275SEric Cheng 	}
4108275SEric Cheng 	if (i == len || buf[i] == '#')
4118275SEric Cheng 		return (B_TRUE);
4128275SEric Cheng 
4138275SEric Cheng 	str = buf + i;
4148275SEric Cheng 	if (lsp->ls_name != NULL) {
4158275SEric Cheng 		/*
4168275SEric Cheng 		 * Skip names we're not interested in.
4178275SEric Cheng 		 * Note that strncmp() and isspace() are used here
4188275SEric Cheng 		 * instead of strtok() and strcmp() because we don't
4198275SEric Cheng 		 * want to modify buf in case it does not contain the
4208275SEric Cheng 		 * specified name.
4218275SEric Cheng 		 */
4228275SEric Cheng 		llen = strlen(lsp->ls_name);
4238275SEric Cheng 		if (strncmp(str, lsp->ls_name, llen) != 0 ||
4248275SEric Cheng 		    !isspace(str[llen]))
4258275SEric Cheng 			return (B_TRUE);
4268275SEric Cheng 	} else {
4278275SEric Cheng 		/*
4288275SEric Cheng 		 * If a name is not specified, find the name
4298275SEric Cheng 		 * and assign it to lsp->ls_name.
4308275SEric Cheng 		 */
4318275SEric Cheng 		if (strtok_r(str, " \n\t", &lasts) == NULL)
4328275SEric Cheng 			goto fail;
4338275SEric Cheng 
4348275SEric Cheng 		llen = strlen(str);
4358275SEric Cheng 		lsp->ls_name = str;
4368275SEric Cheng 		noname = B_TRUE;
4378275SEric Cheng 	}
4388275SEric Cheng 	str += llen + 1;
4398275SEric Cheng 	if (str >= buf + len)
4408275SEric Cheng 		goto fail;
4418275SEric Cheng 
4428275SEric Cheng 	/*
4438275SEric Cheng 	 * Now find the list of properties.
4448275SEric Cheng 	 */
4458275SEric Cheng 	if ((str = strtok_r(str, " \n\t", &lasts)) == NULL)
4468275SEric Cheng 		goto fail;
4478275SEric Cheng 
4488275SEric Cheng 	if (parse_props(str, &lip) < 0)
4498275SEric Cheng 		goto fail;
4508275SEric Cheng 
451*8453SAnurag.Maskey@Sun.COM 	cont = (*lsp->ls_op)(handle, lsp, buf, lip, statusp);
4528275SEric Cheng 	free_props(lip);
4538275SEric Cheng 	if (noname)
4548275SEric Cheng 		lsp->ls_name = NULL;
4558275SEric Cheng 	return (cont);
4568275SEric Cheng 
4578275SEric Cheng fail:
4588275SEric Cheng 	free_props(lip);
4598275SEric Cheng 	if (noname)
4608275SEric Cheng 		lsp->ls_name = NULL;
4618275SEric Cheng 
4628275SEric Cheng 	/*
4638275SEric Cheng 	 * Delete corrupted line.
4648275SEric Cheng 	 */
4658275SEric Cheng 	buf[0] = '\0';
4668275SEric Cheng 	return (B_TRUE);
4678275SEric Cheng }
4688275SEric Cheng 
4698275SEric Cheng dladm_status_t
process_prop_db(dladm_handle_t handle,void * arg,FILE * fp,FILE * nfp)470*8453SAnurag.Maskey@Sun.COM process_prop_db(dladm_handle_t handle, void *arg, FILE *fp, FILE *nfp)
4718275SEric Cheng {
4728275SEric Cheng 	prop_db_state_t	*lsp = arg;
4738275SEric Cheng 	dladm_status_t		status = DLADM_STATUS_OK;
4748275SEric Cheng 	char			buf[MAXLINELEN];
4758275SEric Cheng 	boolean_t		cont = B_TRUE;
4768275SEric Cheng 
4778275SEric Cheng 	/*
4788275SEric Cheng 	 * This loop processes each line of the configuration file.
4798275SEric Cheng 	 * buf can potentially be modified by process_prop_line().
4808275SEric Cheng 	 * If this is a write operation and buf is not truncated, buf will
4818275SEric Cheng 	 * be written to disk. process_prop_line() will no longer be
4828275SEric Cheng 	 * called after it returns B_FALSE; at which point the remainder
4838275SEric Cheng 	 * of the file will continue to be read and, if necessary, written
4848275SEric Cheng 	 * to disk as well.
4858275SEric Cheng 	 */
4868275SEric Cheng 	while (fgets(buf, MAXLINELEN, fp) != NULL) {
4878275SEric Cheng 		if (cont)
488*8453SAnurag.Maskey@Sun.COM 			cont = process_prop_line(handle, lsp, buf, &status);
4898275SEric Cheng 
4908275SEric Cheng 		if (nfp != NULL && buf[0] != '\0' && fputs(buf, nfp) == EOF) {
4918275SEric Cheng 			status = dladm_errno2status(errno);
4928275SEric Cheng 			break;
4938275SEric Cheng 		}
4948275SEric Cheng 	}
4958275SEric Cheng 
4968275SEric Cheng 	if (status != DLADM_STATUS_OK || !cont)
4978275SEric Cheng 		return (status);
4988275SEric Cheng 
4998275SEric Cheng 	if (lsp->ls_op == process_prop_set) {
5008275SEric Cheng 		/*
5018275SEric Cheng 		 * If the specified name is not found above, we add the
5028275SEric Cheng 		 * name and its properties to the configuration file.
5038275SEric Cheng 		 */
504*8453SAnurag.Maskey@Sun.COM 		(void) (*lsp->ls_op)(handle, lsp, buf, NULL, &status);
5058275SEric Cheng 		if (status == DLADM_STATUS_OK && fputs(buf, nfp) == EOF)
5068275SEric Cheng 			status = dladm_errno2status(errno);
5078275SEric Cheng 	}
5088275SEric Cheng 
5098275SEric Cheng 	if (lsp->ls_op == process_prop_get)
5108275SEric Cheng 		status = DLADM_STATUS_NOTFOUND;
5118275SEric Cheng 
5128275SEric Cheng 	return (status);
5138275SEric Cheng }
5148275SEric Cheng 
5158275SEric 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*8453SAnurag.Maskey@Sun.COM i_dladm_get_prop_temp(dladm_handle_t handle, const char *name, prop_type_t type,
5178275SEric Cheng     const char *prop_name, char **prop_val, uint_t *val_cntp,
5188275SEric Cheng     prop_table_t *prop_tbl)
5198275SEric Cheng {
5208275SEric Cheng 	int 		i;
5218275SEric Cheng 	dladm_status_t	status;
5228275SEric Cheng 	uint_t		cnt;
5238275SEric Cheng 	fprop_desc_t	*pdp;
5248275SEric Cheng 
5258275SEric Cheng 	if (name == NULL || prop_name == NULL || prop_val == NULL ||
5268275SEric Cheng 	    val_cntp == NULL || *val_cntp == 0)
5278275SEric Cheng 		return (DLADM_STATUS_BADARG);
5288275SEric Cheng 
5298275SEric Cheng 	for (i = 0; i < prop_tbl->pt_size; i++)
5308275SEric Cheng 		if (strcasecmp(prop_name, prop_tbl->pt_table[i].pd_name) == 0)
5318275SEric Cheng 			break;
5328275SEric Cheng 
5338275SEric Cheng 	if (i == prop_tbl->pt_size)
5348275SEric Cheng 		return (DLADM_STATUS_NOTFOUND);
5358275SEric Cheng 
5368275SEric Cheng 	pdp = &prop_tbl->pt_table[i];
5378275SEric Cheng 	status = DLADM_STATUS_OK;
5388275SEric Cheng 
5398275SEric Cheng 	switch (type) {
5408275SEric Cheng 	case DLADM_PROP_VAL_CURRENT:
541*8453SAnurag.Maskey@Sun.COM 		status = pdp->pd_get(handle, name, prop_val, val_cntp);
5428275SEric Cheng 		break;
5438275SEric Cheng 	case DLADM_PROP_VAL_DEFAULT:
5448275SEric Cheng 		if (pdp->pd_defval.vd_name == NULL) {
5458275SEric Cheng 			status = DLADM_STATUS_NOTSUP;
5468275SEric Cheng 			break;
5478275SEric Cheng 		}
5488275SEric Cheng 		(void) strcpy(*prop_val, pdp->pd_defval.vd_name);
5498275SEric Cheng 		*val_cntp = 1;
5508275SEric Cheng 		break;
5518275SEric Cheng 
5528275SEric Cheng 	case DLADM_PROP_VAL_MODIFIABLE:
5538275SEric Cheng 		if (pdp->pd_getmod != NULL) {
554*8453SAnurag.Maskey@Sun.COM 			status = pdp->pd_getmod(handle, name, prop_val,
555*8453SAnurag.Maskey@Sun.COM 			    val_cntp);
5568275SEric Cheng 			break;
5578275SEric Cheng 		}
5588275SEric Cheng 		cnt = pdp->pd_nmodval;
5598275SEric Cheng 		if (cnt == 0) {
5608275SEric Cheng 			status = DLADM_STATUS_NOTSUP;
5618275SEric Cheng 		} else if (cnt > *val_cntp) {
5628275SEric Cheng 			status = DLADM_STATUS_TOOSMALL;
5638275SEric Cheng 		} else {
5648275SEric Cheng 			for (i = 0; i < cnt; i++) {
5658275SEric Cheng 				(void) strcpy(prop_val[i],
5668275SEric Cheng 				    pdp->pd_modval[i].vd_name);
5678275SEric Cheng 			}
5688275SEric Cheng 			*val_cntp = cnt;
5698275SEric Cheng 		}
5708275SEric Cheng 		break;
5718275SEric Cheng 	default:
5728275SEric Cheng 		status = DLADM_STATUS_BADARG;
5738275SEric Cheng 		break;
5748275SEric Cheng 	}
5758275SEric Cheng 
5768275SEric Cheng 	return (status);
5778275SEric Cheng }
5788275SEric Cheng 
5798275SEric 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*8453SAnurag.Maskey@Sun.COM i_dladm_set_one_prop_temp(dladm_handle_t handle, const char *name,
581*8453SAnurag.Maskey@Sun.COM     fprop_desc_t *pdp, char **prop_val, uint_t val_cnt, uint_t flags)
5828275SEric Cheng {
5838275SEric Cheng 	dladm_status_t	status;
5848275SEric Cheng 	val_desc_t	*vdp = NULL;
5858275SEric Cheng 	uint_t		cnt;
5868275SEric Cheng 
5878275SEric Cheng 	if (pdp->pd_temponly && (flags & DLADM_OPT_PERSIST) != 0)
5888275SEric Cheng 		return (DLADM_STATUS_TEMPONLY);
5898275SEric Cheng 
5908275SEric Cheng 	if (pdp->pd_set == NULL)
5918275SEric Cheng 		return (DLADM_STATUS_PROPRDONLY);
5928275SEric Cheng 
5938275SEric Cheng 	if (prop_val != NULL) {
5948275SEric Cheng 		if (pdp->pd_check != NULL)
5958275SEric Cheng 			status = pdp->pd_check(pdp, prop_val, val_cnt, &vdp);
5968275SEric Cheng 		else
5978275SEric Cheng 			status = DLADM_STATUS_BADARG;
5988275SEric Cheng 
5998275SEric Cheng 		if (status != DLADM_STATUS_OK)
6008275SEric Cheng 			return (status);
6018275SEric Cheng 
6028275SEric Cheng 		cnt = val_cnt;
6038275SEric Cheng 	} else {
6048275SEric Cheng 		if (pdp->pd_defval.vd_name == NULL)
6058275SEric Cheng 			return (DLADM_STATUS_NOTSUP);
6068275SEric Cheng 
6078275SEric Cheng 		if ((vdp = malloc(sizeof (val_desc_t))) == NULL)
6088275SEric Cheng 			return (DLADM_STATUS_NOMEM);
6098275SEric Cheng 
6108275SEric Cheng 		(void) memcpy(vdp, &pdp->pd_defval, sizeof (val_desc_t));
6118275SEric Cheng 		cnt = 1;
6128275SEric Cheng 	}
6138275SEric Cheng 
614*8453SAnurag.Maskey@Sun.COM 	status = pdp->pd_set(handle, name, vdp, cnt);
6158275SEric Cheng 
6168275SEric Cheng 	free(vdp);
6178275SEric Cheng 	return (status);
6188275SEric Cheng }
6198275SEric Cheng 
6208275SEric 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*8453SAnurag.Maskey@Sun.COM i_dladm_set_prop_temp(dladm_handle_t handle, const char *name,
622*8453SAnurag.Maskey@Sun.COM     const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags,
623*8453SAnurag.Maskey@Sun.COM     char **errprop, prop_table_t *prop_tbl)
6248275SEric Cheng {
6258275SEric Cheng 	int 		i;
6268275SEric Cheng 	dladm_status_t	status = DLADM_STATUS_OK;
6278275SEric Cheng 	boolean_t	found = B_FALSE;
6288275SEric Cheng 
6298275SEric Cheng 	for (i = 0; i < prop_tbl->pt_size; i++) {
6308275SEric Cheng 		fprop_desc_t	*pdp = &prop_tbl->pt_table[i];
6318275SEric Cheng 		dladm_status_t	s;
6328275SEric Cheng 
6338275SEric Cheng 		if (prop_name != NULL &&
6348275SEric Cheng 		    (strcasecmp(prop_name, pdp->pd_name) != 0))
6358275SEric Cheng 			continue;
6368275SEric Cheng 
6378275SEric Cheng 		found = B_TRUE;
638*8453SAnurag.Maskey@Sun.COM 		s = i_dladm_set_one_prop_temp(handle, name, pdp, prop_val,
639*8453SAnurag.Maskey@Sun.COM 		    val_cnt, flags);
6408275SEric Cheng 
6418275SEric Cheng 		if (prop_name != NULL) {
6428275SEric Cheng 			status = s;
6438275SEric Cheng 			break;
6448275SEric Cheng 		} else {
6458275SEric Cheng 			if (s != DLADM_STATUS_OK &&
6468275SEric Cheng 			    s != DLADM_STATUS_NOTSUP) {
6478275SEric Cheng 				if (errprop != NULL)
6488275SEric Cheng 					*errprop = pdp->pd_name;
6498275SEric Cheng 				status = s;
6508275SEric Cheng 				break;
6518275SEric Cheng 			}
6528275SEric Cheng 		}
6538275SEric Cheng 	}
6548275SEric Cheng 
6558275SEric Cheng 	if (!found)
6568275SEric Cheng 		status = DLADM_STATUS_NOTFOUND;
6578275SEric Cheng 
6588275SEric Cheng 	return (status);
6598275SEric Cheng }
6608275SEric Cheng 
6618275SEric Cheng boolean_t
i_dladm_is_prop_temponly(const char * prop_name,char ** errprop,prop_table_t * prop_tbl)6628275SEric Cheng i_dladm_is_prop_temponly(const char *prop_name, char **errprop,
6638275SEric Cheng     prop_table_t *prop_tbl)
6648275SEric Cheng {
6658275SEric Cheng 	int 		i;
6668275SEric Cheng 
6678275SEric Cheng 	if (prop_name == NULL)
6688275SEric Cheng 		return (B_FALSE);
6698275SEric Cheng 
6708275SEric Cheng 	for (i = 0; i < prop_tbl->pt_size; i++) {
6718275SEric Cheng 		fprop_desc_t	*pdp = &prop_tbl->pt_table[i];
6728275SEric Cheng 
6738275SEric Cheng 		if (strcasecmp(prop_name, pdp->pd_name) != 0)
6748275SEric Cheng 			continue;
6758275SEric Cheng 
6768275SEric Cheng 		if (errprop != NULL)
6778275SEric Cheng 			*errprop = pdp->pd_name;
6788275SEric Cheng 
6798275SEric Cheng 		if (pdp->pd_temponly)
6808275SEric Cheng 			return (B_TRUE);
6818275SEric Cheng 	}
6828275SEric Cheng 
6838275SEric Cheng 	return (B_FALSE);
6848275SEric Cheng }
6858275SEric Cheng void
dladm_free_props(dladm_arg_list_t * list)6868275SEric Cheng dladm_free_props(dladm_arg_list_t *list)
6878275SEric Cheng {
6888275SEric Cheng 	dladm_free_args(list);
6898275SEric Cheng }
6908275SEric Cheng 
6918275SEric Cheng dladm_status_t
dladm_parse_props(char * str,dladm_arg_list_t ** listp,boolean_t novalues)6928275SEric Cheng dladm_parse_props(char *str, dladm_arg_list_t **listp, boolean_t novalues)
6938275SEric Cheng {
6948275SEric Cheng 	if (dladm_parse_args(str, listp, novalues) != DLADM_STATUS_OK)
6958275SEric Cheng 		goto fail;
6968275SEric Cheng 
6978275SEric Cheng 	return (DLADM_STATUS_OK);
6988275SEric Cheng 
6998275SEric Cheng fail:
7008275SEric Cheng 	dladm_free_args(*listp);
7018275SEric Cheng 	return (DLADM_STATUS_PROP_PARSE_ERR);
7028275SEric Cheng }
703