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