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