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