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