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 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 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 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 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 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 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 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 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 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 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 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 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 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 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