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