1*d62bc4baSyz147064 /* 2*d62bc4baSyz147064 * CDDL HEADER START 3*d62bc4baSyz147064 * 4*d62bc4baSyz147064 * The contents of this file are subject to the terms of the 5*d62bc4baSyz147064 * Common Development and Distribution License (the "License"). 6*d62bc4baSyz147064 * You may not use this file except in compliance with the License. 7*d62bc4baSyz147064 * 8*d62bc4baSyz147064 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*d62bc4baSyz147064 * or http://www.opensolaris.org/os/licensing. 10*d62bc4baSyz147064 * See the License for the specific language governing permissions 11*d62bc4baSyz147064 * and limitations under the License. 12*d62bc4baSyz147064 * 13*d62bc4baSyz147064 * When distributing Covered Code, include this CDDL HEADER in each 14*d62bc4baSyz147064 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*d62bc4baSyz147064 * If applicable, add the following below this CDDL HEADER, with the 16*d62bc4baSyz147064 * fields enclosed by brackets "[]" replaced with your own identifying 17*d62bc4baSyz147064 * information: Portions Copyright [yyyy] [name of copyright owner] 18*d62bc4baSyz147064 * 19*d62bc4baSyz147064 * CDDL HEADER END 20*d62bc4baSyz147064 */ 21*d62bc4baSyz147064 22*d62bc4baSyz147064 /* 23*d62bc4baSyz147064 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24*d62bc4baSyz147064 * Use is subject to license terms. 25*d62bc4baSyz147064 */ 26*d62bc4baSyz147064 27*d62bc4baSyz147064 #pragma ident "%Z%%M% %I% %E% SMI" 28*d62bc4baSyz147064 29*d62bc4baSyz147064 #include <assert.h> 30*d62bc4baSyz147064 #include <ctype.h> 31*d62bc4baSyz147064 #include <errno.h> 32*d62bc4baSyz147064 #include <fcntl.h> 33*d62bc4baSyz147064 #include <stdio.h> 34*d62bc4baSyz147064 #include <stdlib.h> 35*d62bc4baSyz147064 #include <strings.h> 36*d62bc4baSyz147064 #include <syslog.h> 37*d62bc4baSyz147064 #include <sys/stat.h> 38*d62bc4baSyz147064 #include <pthread.h> 39*d62bc4baSyz147064 #include <unistd.h> 40*d62bc4baSyz147064 #include "dlmgmt_impl.h" 41*d62bc4baSyz147064 42*d62bc4baSyz147064 typedef enum dlmgmt_db_op { 43*d62bc4baSyz147064 DLMGMT_DB_OP_WRITE, 44*d62bc4baSyz147064 DLMGMT_DB_OP_DELETE, 45*d62bc4baSyz147064 DLMGMT_DB_OP_READ 46*d62bc4baSyz147064 } dlmgmt_db_op_t; 47*d62bc4baSyz147064 48*d62bc4baSyz147064 typedef struct dlmgmt_db_req_s { 49*d62bc4baSyz147064 struct dlmgmt_db_req_s *ls_next; 50*d62bc4baSyz147064 dlmgmt_db_op_t ls_op; 51*d62bc4baSyz147064 datalink_id_t ls_linkid; 52*d62bc4baSyz147064 uint32_t ls_flags; /* Either DLMGMT_ACTIVE or */ 53*d62bc4baSyz147064 /* DLMGMT_PERSIST, not both. */ 54*d62bc4baSyz147064 } dlmgmt_db_req_t; 55*d62bc4baSyz147064 56*d62bc4baSyz147064 /* 57*d62bc4baSyz147064 * List of pending db updates (e.g., because of a read-only filesystem). 58*d62bc4baSyz147064 */ 59*d62bc4baSyz147064 static dlmgmt_db_req_t *dlmgmt_db_req_head = NULL; 60*d62bc4baSyz147064 static dlmgmt_db_req_t *dlmgmt_db_req_tail = NULL; 61*d62bc4baSyz147064 62*d62bc4baSyz147064 static int dlmgmt_db_update(dlmgmt_db_op_t, datalink_id_t, 63*d62bc4baSyz147064 uint32_t); 64*d62bc4baSyz147064 static int dlmgmt_process_db_req(dlmgmt_db_req_t *); 65*d62bc4baSyz147064 static int dlmgmt_process_db_onereq(dlmgmt_db_req_t *, boolean_t); 66*d62bc4baSyz147064 static void *dlmgmt_db_update_thread(void *); 67*d62bc4baSyz147064 static boolean_t process_link_line(char *, dlmgmt_link_t **); 68*d62bc4baSyz147064 static int process_db_write(dlmgmt_db_req_t *, FILE *, FILE *); 69*d62bc4baSyz147064 static int process_db_read(dlmgmt_db_req_t *, FILE *, FILE *); 70*d62bc4baSyz147064 static void generate_link_line(dlmgmt_link_t *, boolean_t, char *); 71*d62bc4baSyz147064 72*d62bc4baSyz147064 #define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0) 73*d62bc4baSyz147064 #define MAXLINELEN 1024 74*d62bc4baSyz147064 75*d62bc4baSyz147064 /* 76*d62bc4baSyz147064 * Translator functions to go from dladm_datatype_t to character strings. 77*d62bc4baSyz147064 * Each function takes a pointer to a buffer, the size of the buffer, 78*d62bc4baSyz147064 * the name of the attribute, and the value to be written. The functions 79*d62bc4baSyz147064 * return the number of bytes written to the buffer. If the buffer is not big 80*d62bc4baSyz147064 * enough to hold the string representing the value, then nothing is written 81*d62bc4baSyz147064 * and 0 is returned. 82*d62bc4baSyz147064 */ 83*d62bc4baSyz147064 typedef size_t write_func_t(char *, size_t, char *, void *); 84*d62bc4baSyz147064 85*d62bc4baSyz147064 /* 86*d62bc4baSyz147064 * Translator functions to read from a NULL terminated string buffer into 87*d62bc4baSyz147064 * something of the given DLADM_TYPE_*. The functions each return the number 88*d62bc4baSyz147064 * of bytes read from the string buffer. If there is an error reading data 89*d62bc4baSyz147064 * from the buffer, then 0 is returned. It is the caller's responsibility 90*d62bc4baSyz147064 * to free the data allocated by these functions. 91*d62bc4baSyz147064 */ 92*d62bc4baSyz147064 typedef size_t read_func_t(char *, void **); 93*d62bc4baSyz147064 94*d62bc4baSyz147064 typedef struct translator_s { 95*d62bc4baSyz147064 const char *type_name; 96*d62bc4baSyz147064 write_func_t *write_func; 97*d62bc4baSyz147064 read_func_t *read_func; 98*d62bc4baSyz147064 } translator_t; 99*d62bc4baSyz147064 100*d62bc4baSyz147064 /* 101*d62bc4baSyz147064 * Translator functions, defined later but declared here so that 102*d62bc4baSyz147064 * the translator table can be defined. 103*d62bc4baSyz147064 */ 104*d62bc4baSyz147064 static write_func_t write_str, write_boolean, write_uint64; 105*d62bc4baSyz147064 static read_func_t read_str, read_boolean, read_int64; 106*d62bc4baSyz147064 107*d62bc4baSyz147064 /* 108*d62bc4baSyz147064 * Translator table, indexed by dladm_datatype_t. 109*d62bc4baSyz147064 */ 110*d62bc4baSyz147064 static translator_t translators[] = { 111*d62bc4baSyz147064 { "string", write_str, read_str }, 112*d62bc4baSyz147064 { "boolean", write_boolean, read_boolean }, 113*d62bc4baSyz147064 { "int", write_uint64, read_int64 } 114*d62bc4baSyz147064 }; 115*d62bc4baSyz147064 116*d62bc4baSyz147064 static size_t ntranslators = sizeof (translators) / sizeof (translator_t); 117*d62bc4baSyz147064 118*d62bc4baSyz147064 #define LINK_PROPERTY_DELIMINATOR ";" 119*d62bc4baSyz147064 #define LINK_PROPERTY_TYPE_VALUE_SEP "," 120*d62bc4baSyz147064 #define BASE_PROPERTY_LENGTH(t, n) (strlen(translators[(t)].type_name) +\ 121*d62bc4baSyz147064 strlen(LINK_PROPERTY_TYPE_VALUE_SEP) +\ 122*d62bc4baSyz147064 strlen(LINK_PROPERTY_DELIMINATOR) +\ 123*d62bc4baSyz147064 strlen((n))) 124*d62bc4baSyz147064 #define GENERATE_PROPERTY_STRING(buf, length, conv, name, type, val) \ 125*d62bc4baSyz147064 (snprintf((buf), (length), "%s=%s%s" conv "%s", (name), \ 126*d62bc4baSyz147064 translators[(type)].type_name, \ 127*d62bc4baSyz147064 LINK_PROPERTY_TYPE_VALUE_SEP, (val), LINK_PROPERTY_DELIMINATOR)) 128*d62bc4baSyz147064 129*d62bc4baSyz147064 #define DLMGMT_DB_OWNER 15 130*d62bc4baSyz147064 #define DLMGMT_DB_GROUP 3 131*d62bc4baSyz147064 132*d62bc4baSyz147064 /* 133*d62bc4baSyz147064 * Name of the cache file to keep the active <link name, linkid> mapping 134*d62bc4baSyz147064 */ 135*d62bc4baSyz147064 static char cachefile[MAXPATHLEN]; 136*d62bc4baSyz147064 137*d62bc4baSyz147064 #define DLMGMT_TEMP_DB_DIR "/etc/svc/volatile" 138*d62bc4baSyz147064 #define DLMGMT_PERSISTENT_DB_PATH "/etc/dladm/datalink.conf" 139*d62bc4baSyz147064 #define DLMGMT_MAKE_FILE_DB_PATH(buffer, persistent) \ 140*d62bc4baSyz147064 (void) snprintf((buffer), MAXPATHLEN, "%s", \ 141*d62bc4baSyz147064 (persistent) ? DLMGMT_PERSISTENT_DB_PATH : cachefile); 142*d62bc4baSyz147064 143*d62bc4baSyz147064 static size_t 144*d62bc4baSyz147064 write_str(char *buffer, size_t buffer_length, char *name, void *value) 145*d62bc4baSyz147064 { 146*d62bc4baSyz147064 char *ptr = value; 147*d62bc4baSyz147064 size_t data_length = strnlen(ptr, buffer_length); 148*d62bc4baSyz147064 149*d62bc4baSyz147064 /* 150*d62bc4baSyz147064 * Strings are assumed to be NULL terminated. In order to fit in 151*d62bc4baSyz147064 * the buffer, the string's length must be less then buffer_length. 152*d62bc4baSyz147064 * If the value is empty, there's no point in writing it, in fact, 153*d62bc4baSyz147064 * we shouldn't even see that case. 154*d62bc4baSyz147064 */ 155*d62bc4baSyz147064 if (data_length + BASE_PROPERTY_LENGTH(DLADM_TYPE_STR, name) == 156*d62bc4baSyz147064 buffer_length || data_length == 0) 157*d62bc4baSyz147064 return (0); 158*d62bc4baSyz147064 159*d62bc4baSyz147064 /* 160*d62bc4baSyz147064 * Since we know the string will fit in the buffer, snprintf will 161*d62bc4baSyz147064 * always return less than buffer_length, so we can just return 162*d62bc4baSyz147064 * whatever snprintf returns. 163*d62bc4baSyz147064 */ 164*d62bc4baSyz147064 return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%s", 165*d62bc4baSyz147064 name, DLADM_TYPE_STR, ptr)); 166*d62bc4baSyz147064 } 167*d62bc4baSyz147064 168*d62bc4baSyz147064 static size_t 169*d62bc4baSyz147064 write_boolean(char *buffer, size_t buffer_length, char *name, void *value) 170*d62bc4baSyz147064 { 171*d62bc4baSyz147064 boolean_t *ptr = value; 172*d62bc4baSyz147064 173*d62bc4baSyz147064 /* 174*d62bc4baSyz147064 * Booleans are either zero or one, so we only need room for two 175*d62bc4baSyz147064 * characters in the buffer. 176*d62bc4baSyz147064 */ 177*d62bc4baSyz147064 if (buffer_length <= 1 + BASE_PROPERTY_LENGTH(DLADM_TYPE_BOOLEAN, name)) 178*d62bc4baSyz147064 return (0); 179*d62bc4baSyz147064 180*d62bc4baSyz147064 return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%d", 181*d62bc4baSyz147064 name, DLADM_TYPE_BOOLEAN, *ptr)); 182*d62bc4baSyz147064 } 183*d62bc4baSyz147064 184*d62bc4baSyz147064 static size_t 185*d62bc4baSyz147064 write_uint64(char *buffer, size_t buffer_length, char *name, void *value) 186*d62bc4baSyz147064 { 187*d62bc4baSyz147064 uint64_t *ptr = value; 188*d62bc4baSyz147064 189*d62bc4baSyz147064 /* 190*d62bc4baSyz147064 * Limit checking for uint64_t is a little trickier. 191*d62bc4baSyz147064 */ 192*d62bc4baSyz147064 if (snprintf(NULL, 0, "%lld", *ptr) + 193*d62bc4baSyz147064 BASE_PROPERTY_LENGTH(DLADM_TYPE_UINT64, name) >= buffer_length) 194*d62bc4baSyz147064 return (0); 195*d62bc4baSyz147064 196*d62bc4baSyz147064 return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%lld", 197*d62bc4baSyz147064 name, DLADM_TYPE_UINT64, *ptr)); 198*d62bc4baSyz147064 } 199*d62bc4baSyz147064 200*d62bc4baSyz147064 static size_t 201*d62bc4baSyz147064 read_str(char *buffer, void **value) 202*d62bc4baSyz147064 { 203*d62bc4baSyz147064 char *ptr = calloc(MAXLINKATTRLEN, sizeof (char)); 204*d62bc4baSyz147064 ssize_t len; 205*d62bc4baSyz147064 206*d62bc4baSyz147064 if (ptr == NULL || (len = snprintf(ptr, MAXLINKATTRLEN, "%s", buffer)) 207*d62bc4baSyz147064 >= MAXLINKATTRLEN) { 208*d62bc4baSyz147064 free(ptr); 209*d62bc4baSyz147064 return (0); 210*d62bc4baSyz147064 } 211*d62bc4baSyz147064 212*d62bc4baSyz147064 *(char **)value = ptr; 213*d62bc4baSyz147064 214*d62bc4baSyz147064 /* Account for NULL terminator */ 215*d62bc4baSyz147064 return (len + 1); 216*d62bc4baSyz147064 } 217*d62bc4baSyz147064 218*d62bc4baSyz147064 static size_t 219*d62bc4baSyz147064 read_boolean(char *buffer, void **value) 220*d62bc4baSyz147064 { 221*d62bc4baSyz147064 boolean_t *ptr = calloc(1, sizeof (boolean_t)); 222*d62bc4baSyz147064 223*d62bc4baSyz147064 if (ptr == NULL) 224*d62bc4baSyz147064 return (0); 225*d62bc4baSyz147064 226*d62bc4baSyz147064 *ptr = atoi(buffer); 227*d62bc4baSyz147064 *(boolean_t **)value = ptr; 228*d62bc4baSyz147064 229*d62bc4baSyz147064 return (sizeof (boolean_t)); 230*d62bc4baSyz147064 } 231*d62bc4baSyz147064 232*d62bc4baSyz147064 static size_t 233*d62bc4baSyz147064 read_int64(char *buffer, void **value) 234*d62bc4baSyz147064 { 235*d62bc4baSyz147064 int64_t *ptr = calloc(1, sizeof (int64_t)); 236*d62bc4baSyz147064 237*d62bc4baSyz147064 if (ptr == NULL) 238*d62bc4baSyz147064 return (0); 239*d62bc4baSyz147064 240*d62bc4baSyz147064 *ptr = (int64_t)atoll(buffer); 241*d62bc4baSyz147064 *(int64_t **)value = ptr; 242*d62bc4baSyz147064 243*d62bc4baSyz147064 return (sizeof (int64_t)); 244*d62bc4baSyz147064 } 245*d62bc4baSyz147064 246*d62bc4baSyz147064 static int 247*d62bc4baSyz147064 dlmgmt_db_update(dlmgmt_db_op_t op, datalink_id_t linkid, uint32_t flags) 248*d62bc4baSyz147064 { 249*d62bc4baSyz147064 dlmgmt_db_req_t *req; 250*d62bc4baSyz147064 int err; 251*d62bc4baSyz147064 252*d62bc4baSyz147064 /* 253*d62bc4baSyz147064 * It is either a persistent request or an active request, not both. 254*d62bc4baSyz147064 */ 255*d62bc4baSyz147064 assert((flags == DLMGMT_PERSIST) || (flags == DLMGMT_ACTIVE)); 256*d62bc4baSyz147064 257*d62bc4baSyz147064 if ((req = malloc(sizeof (dlmgmt_db_req_t))) == NULL) 258*d62bc4baSyz147064 return (ENOMEM); 259*d62bc4baSyz147064 260*d62bc4baSyz147064 req->ls_next = NULL; 261*d62bc4baSyz147064 req->ls_op = op; 262*d62bc4baSyz147064 req->ls_linkid = linkid; 263*d62bc4baSyz147064 req->ls_flags = flags; 264*d62bc4baSyz147064 265*d62bc4baSyz147064 /* 266*d62bc4baSyz147064 * If the return error is EINPROGRESS, this request is handled 267*d62bc4baSyz147064 * asynchronously; return success. 268*d62bc4baSyz147064 */ 269*d62bc4baSyz147064 err = dlmgmt_process_db_req(req); 270*d62bc4baSyz147064 if (err != EINPROGRESS) 271*d62bc4baSyz147064 free(req); 272*d62bc4baSyz147064 else 273*d62bc4baSyz147064 err = 0; 274*d62bc4baSyz147064 return (err); 275*d62bc4baSyz147064 } 276*d62bc4baSyz147064 277*d62bc4baSyz147064 #define DLMGMT_DB_OP_STR(op) \ 278*d62bc4baSyz147064 (((op) == DLMGMT_DB_OP_READ) ? "read" : \ 279*d62bc4baSyz147064 (((op) == DLMGMT_DB_OP_WRITE) ? "write" : "delete")) 280*d62bc4baSyz147064 281*d62bc4baSyz147064 #define DLMGMT_DB_CONF_STR(flag) \ 282*d62bc4baSyz147064 (((flag) == DLMGMT_ACTIVE) ? "active" : \ 283*d62bc4baSyz147064 (((flag) == DLMGMT_PERSIST) ? "persistent" : "")) 284*d62bc4baSyz147064 285*d62bc4baSyz147064 static int 286*d62bc4baSyz147064 dlmgmt_process_db_req(dlmgmt_db_req_t *req) 287*d62bc4baSyz147064 { 288*d62bc4baSyz147064 pthread_t tid; 289*d62bc4baSyz147064 boolean_t writeop; 290*d62bc4baSyz147064 int err; 291*d62bc4baSyz147064 292*d62bc4baSyz147064 /* 293*d62bc4baSyz147064 * If there are already pending "write" requests, queue this request in 294*d62bc4baSyz147064 * the pending list. Note that this function is called while the 295*d62bc4baSyz147064 * dlmgmt_rw_lock is held, so it is safe to access the global variables. 296*d62bc4baSyz147064 */ 297*d62bc4baSyz147064 writeop = (req->ls_op != DLMGMT_DB_OP_READ); 298*d62bc4baSyz147064 if (writeop && (req->ls_flags == DLMGMT_PERSIST) && 299*d62bc4baSyz147064 (dlmgmt_db_req_head != NULL)) { 300*d62bc4baSyz147064 dlmgmt_db_req_tail->ls_next = req; 301*d62bc4baSyz147064 dlmgmt_db_req_tail = req; 302*d62bc4baSyz147064 return (EINPROGRESS); 303*d62bc4baSyz147064 } 304*d62bc4baSyz147064 305*d62bc4baSyz147064 err = dlmgmt_process_db_onereq(req, writeop); 306*d62bc4baSyz147064 if (err != EINPROGRESS && err != 0 && 307*d62bc4baSyz147064 (req->ls_flags != DLMGMT_ACTIVE || errno != ENOENT)) { 308*d62bc4baSyz147064 309*d62bc4baSyz147064 /* 310*d62bc4baSyz147064 * Log the error unless the request processing: 311*d62bc4baSyz147064 * - is successful; 312*d62bc4baSyz147064 * - is still in progress; 313*d62bc4baSyz147064 * - has failed with ENOENT because the active configuration 314*d62bc4baSyz147064 * file is not created yet; 315*d62bc4baSyz147064 */ 316*d62bc4baSyz147064 dlmgmt_log(LOG_WARNING, "dlmgmt_process_db_onereq() %s " 317*d62bc4baSyz147064 "operation on %s configuration failed: %s", 318*d62bc4baSyz147064 DLMGMT_DB_OP_STR(req->ls_op), 319*d62bc4baSyz147064 DLMGMT_DB_CONF_STR(req->ls_flags), strerror(err)); 320*d62bc4baSyz147064 } 321*d62bc4baSyz147064 322*d62bc4baSyz147064 if (err == EINPROGRESS) { 323*d62bc4baSyz147064 assert(req->ls_flags == DLMGMT_PERSIST); 324*d62bc4baSyz147064 assert(writeop && dlmgmt_db_req_head == NULL); 325*d62bc4baSyz147064 dlmgmt_db_req_tail = dlmgmt_db_req_head = req; 326*d62bc4baSyz147064 err = pthread_create(&tid, NULL, dlmgmt_db_update_thread, NULL); 327*d62bc4baSyz147064 if (err == 0) 328*d62bc4baSyz147064 return (EINPROGRESS); 329*d62bc4baSyz147064 } 330*d62bc4baSyz147064 return (err); 331*d62bc4baSyz147064 } 332*d62bc4baSyz147064 333*d62bc4baSyz147064 static int 334*d62bc4baSyz147064 dlmgmt_process_db_onereq(dlmgmt_db_req_t *req, boolean_t writeop) 335*d62bc4baSyz147064 { 336*d62bc4baSyz147064 int err = 0; 337*d62bc4baSyz147064 FILE *fp, *nfp = NULL; 338*d62bc4baSyz147064 char file[MAXPATHLEN]; 339*d62bc4baSyz147064 char newfile[MAXPATHLEN]; 340*d62bc4baSyz147064 int nfd; 341*d62bc4baSyz147064 342*d62bc4baSyz147064 DLMGMT_MAKE_FILE_DB_PATH(file, (req->ls_flags == DLMGMT_PERSIST)); 343*d62bc4baSyz147064 if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) { 344*d62bc4baSyz147064 if (writeop && errno == EROFS) { 345*d62bc4baSyz147064 /* 346*d62bc4baSyz147064 * This can happen at boot when the file system is 347*d62bc4baSyz147064 * read-only. So add this request to the pending 348*d62bc4baSyz147064 * request list and start a retry thread. 349*d62bc4baSyz147064 */ 350*d62bc4baSyz147064 return (EINPROGRESS); 351*d62bc4baSyz147064 } else if (req->ls_flags == DLMGMT_ACTIVE && errno == ENOENT) { 352*d62bc4baSyz147064 /* 353*d62bc4baSyz147064 * It is fine if the file keeping active configuration 354*d62bc4baSyz147064 * does not exist. This happens during a new reboot. 355*d62bc4baSyz147064 */ 356*d62bc4baSyz147064 if (!writeop) 357*d62bc4baSyz147064 return (ENOENT); 358*d62bc4baSyz147064 /* 359*d62bc4baSyz147064 * If this is an update request for the active 360*d62bc4baSyz147064 * configuration, create the file. 361*d62bc4baSyz147064 */ 362*d62bc4baSyz147064 if ((fp = fopen(file, "w")) == NULL) 363*d62bc4baSyz147064 return (errno == EROFS ? EINPROGRESS : errno); 364*d62bc4baSyz147064 } else { 365*d62bc4baSyz147064 return (errno); 366*d62bc4baSyz147064 } 367*d62bc4baSyz147064 } 368*d62bc4baSyz147064 369*d62bc4baSyz147064 if (writeop) { 370*d62bc4baSyz147064 (void) snprintf(newfile, MAXPATHLEN, "%s.new", file); 371*d62bc4baSyz147064 if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC, 372*d62bc4baSyz147064 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) { 373*d62bc4baSyz147064 (void) fclose(fp); 374*d62bc4baSyz147064 return (errno); 375*d62bc4baSyz147064 } 376*d62bc4baSyz147064 377*d62bc4baSyz147064 if ((nfp = fdopen(nfd, "w")) == NULL) { 378*d62bc4baSyz147064 (void) close(nfd); 379*d62bc4baSyz147064 (void) fclose(fp); 380*d62bc4baSyz147064 (void) unlink(newfile); 381*d62bc4baSyz147064 return (errno); 382*d62bc4baSyz147064 } 383*d62bc4baSyz147064 } 384*d62bc4baSyz147064 if (writeop) 385*d62bc4baSyz147064 err = process_db_write(req, fp, nfp); 386*d62bc4baSyz147064 else 387*d62bc4baSyz147064 err = process_db_read(req, fp, nfp); 388*d62bc4baSyz147064 if (!writeop || err != 0) 389*d62bc4baSyz147064 goto done; 390*d62bc4baSyz147064 391*d62bc4baSyz147064 /* 392*d62bc4baSyz147064 * Configuration files need to be owned by the 'dladm' user. 393*d62bc4baSyz147064 * If we are invoked by root, the file ownership needs to be fixed. 394*d62bc4baSyz147064 */ 395*d62bc4baSyz147064 if (getuid() == 0 || geteuid() == 0) { 396*d62bc4baSyz147064 if (fchown(nfd, DLMGMT_DB_OWNER, DLMGMT_DB_GROUP) < 0) { 397*d62bc4baSyz147064 err = errno; 398*d62bc4baSyz147064 goto done; 399*d62bc4baSyz147064 } 400*d62bc4baSyz147064 } 401*d62bc4baSyz147064 402*d62bc4baSyz147064 if (fflush(nfp) == EOF) { 403*d62bc4baSyz147064 err = errno; 404*d62bc4baSyz147064 goto done; 405*d62bc4baSyz147064 } 406*d62bc4baSyz147064 (void) fclose(fp); 407*d62bc4baSyz147064 (void) fclose(nfp); 408*d62bc4baSyz147064 409*d62bc4baSyz147064 if (rename(newfile, file) < 0) { 410*d62bc4baSyz147064 (void) unlink(newfile); 411*d62bc4baSyz147064 return (errno); 412*d62bc4baSyz147064 } 413*d62bc4baSyz147064 414*d62bc4baSyz147064 return (0); 415*d62bc4baSyz147064 416*d62bc4baSyz147064 done: 417*d62bc4baSyz147064 if (nfp != NULL) { 418*d62bc4baSyz147064 (void) fclose(nfp); 419*d62bc4baSyz147064 if (err != 0) 420*d62bc4baSyz147064 (void) unlink(newfile); 421*d62bc4baSyz147064 } 422*d62bc4baSyz147064 (void) fclose(fp); 423*d62bc4baSyz147064 return (err); 424*d62bc4baSyz147064 } 425*d62bc4baSyz147064 426*d62bc4baSyz147064 /*ARGSUSED*/ 427*d62bc4baSyz147064 static void * 428*d62bc4baSyz147064 dlmgmt_db_update_thread(void *arg) 429*d62bc4baSyz147064 { 430*d62bc4baSyz147064 dlmgmt_db_req_t *req; 431*d62bc4baSyz147064 int err = 0; 432*d62bc4baSyz147064 433*d62bc4baSyz147064 dlmgmt_table_lock(B_TRUE); 434*d62bc4baSyz147064 435*d62bc4baSyz147064 assert(dlmgmt_db_req_head != NULL); 436*d62bc4baSyz147064 while ((req = dlmgmt_db_req_head) != NULL) { 437*d62bc4baSyz147064 assert(req->ls_flags == DLMGMT_PERSIST); 438*d62bc4baSyz147064 err = dlmgmt_process_db_onereq(req, B_TRUE); 439*d62bc4baSyz147064 if (err == EINPROGRESS) { 440*d62bc4baSyz147064 /* 441*d62bc4baSyz147064 * The filesystem is still read only. Go to sleep and 442*d62bc4baSyz147064 * try again. 443*d62bc4baSyz147064 */ 444*d62bc4baSyz147064 dlmgmt_table_unlock(); 445*d62bc4baSyz147064 (void) sleep(5); 446*d62bc4baSyz147064 dlmgmt_table_lock(B_TRUE); 447*d62bc4baSyz147064 continue; 448*d62bc4baSyz147064 } 449*d62bc4baSyz147064 450*d62bc4baSyz147064 /* 451*d62bc4baSyz147064 * The filesystem is no longer read only. Continue processing 452*d62bc4baSyz147064 * and remove the request from the pending list. 453*d62bc4baSyz147064 */ 454*d62bc4baSyz147064 dlmgmt_db_req_head = req->ls_next; 455*d62bc4baSyz147064 if (dlmgmt_db_req_tail == req) { 456*d62bc4baSyz147064 assert(dlmgmt_db_req_head == NULL); 457*d62bc4baSyz147064 dlmgmt_db_req_tail = NULL; 458*d62bc4baSyz147064 } 459*d62bc4baSyz147064 free(req); 460*d62bc4baSyz147064 } 461*d62bc4baSyz147064 462*d62bc4baSyz147064 dlmgmt_table_unlock(); 463*d62bc4baSyz147064 return (NULL); 464*d62bc4baSyz147064 } 465*d62bc4baSyz147064 466*d62bc4baSyz147064 static int 467*d62bc4baSyz147064 parse_linkprops(char *buf, dlmgmt_link_t *linkp) 468*d62bc4baSyz147064 { 469*d62bc4baSyz147064 boolean_t found_type = B_FALSE; 470*d62bc4baSyz147064 dladm_datatype_t type = DLADM_TYPE_STR; 471*d62bc4baSyz147064 int i, len; 472*d62bc4baSyz147064 int err = 0; 473*d62bc4baSyz147064 char *curr; 474*d62bc4baSyz147064 char attr_name[MAXLINKATTRLEN]; 475*d62bc4baSyz147064 size_t attr_buf_len = 0; 476*d62bc4baSyz147064 void *attr_buf = NULL; 477*d62bc4baSyz147064 478*d62bc4baSyz147064 curr = buf; 479*d62bc4baSyz147064 len = strlen(buf); 480*d62bc4baSyz147064 attr_name[0] = '\0'; 481*d62bc4baSyz147064 for (i = 0; i < len && err == 0; i++) { 482*d62bc4baSyz147064 char c = buf[i]; 483*d62bc4baSyz147064 boolean_t match = (c == '=' || 484*d62bc4baSyz147064 (c == ',' && !found_type) || c == ';'); 485*d62bc4baSyz147064 486*d62bc4baSyz147064 /* 487*d62bc4baSyz147064 * Move to the next character if there is no match and 488*d62bc4baSyz147064 * if we have not reached the last character. 489*d62bc4baSyz147064 */ 490*d62bc4baSyz147064 if (!match && i != len - 1) 491*d62bc4baSyz147064 continue; 492*d62bc4baSyz147064 493*d62bc4baSyz147064 if (match) { 494*d62bc4baSyz147064 /* 495*d62bc4baSyz147064 * NUL-terminate the string pointed to by 'curr'. 496*d62bc4baSyz147064 */ 497*d62bc4baSyz147064 buf[i] = '\0'; 498*d62bc4baSyz147064 if (*curr == '\0') 499*d62bc4baSyz147064 goto parse_fail; 500*d62bc4baSyz147064 } 501*d62bc4baSyz147064 502*d62bc4baSyz147064 if (attr_name[0] != '\0' && found_type) { 503*d62bc4baSyz147064 /* 504*d62bc4baSyz147064 * We get here after we have processed the "<prop>=" 505*d62bc4baSyz147064 * pattern. The pattern we are now interested in is 506*d62bc4baSyz147064 * "<val>;". 507*d62bc4baSyz147064 */ 508*d62bc4baSyz147064 if (c == '=') 509*d62bc4baSyz147064 goto parse_fail; 510*d62bc4baSyz147064 511*d62bc4baSyz147064 if (strcmp(attr_name, "name") == 0) { 512*d62bc4baSyz147064 (void) read_str(curr, &attr_buf); 513*d62bc4baSyz147064 (void) snprintf(linkp->ll_link, 514*d62bc4baSyz147064 MAXLINKNAMELEN, "%s", attr_buf); 515*d62bc4baSyz147064 } else if (strcmp(attr_name, "class") == 0) { 516*d62bc4baSyz147064 (void) read_int64(curr, &attr_buf); 517*d62bc4baSyz147064 linkp->ll_class = 518*d62bc4baSyz147064 (datalink_class_t)*(int64_t *)attr_buf; 519*d62bc4baSyz147064 } else if (strcmp(attr_name, "media") == 0) { 520*d62bc4baSyz147064 (void) read_int64(curr, &attr_buf); 521*d62bc4baSyz147064 linkp->ll_media = 522*d62bc4baSyz147064 (uint32_t)*(int64_t *)attr_buf; 523*d62bc4baSyz147064 } else { 524*d62bc4baSyz147064 attr_buf_len = translators[type].read_func(curr, 525*d62bc4baSyz147064 &attr_buf); 526*d62bc4baSyz147064 err = linkattr_set(&(linkp->ll_head), attr_name, 527*d62bc4baSyz147064 attr_buf, attr_buf_len, type); 528*d62bc4baSyz147064 } 529*d62bc4baSyz147064 530*d62bc4baSyz147064 free(attr_buf); 531*d62bc4baSyz147064 attr_name[0] = '\0'; 532*d62bc4baSyz147064 found_type = B_FALSE; 533*d62bc4baSyz147064 } else if (attr_name[0] != '\0') { 534*d62bc4baSyz147064 /* 535*d62bc4baSyz147064 * Non-zero length attr_name and found_type of false 536*d62bc4baSyz147064 * indicates that we have not found the type for this 537*d62bc4baSyz147064 * attribute. The pattern now is "<type>,<val>;", we 538*d62bc4baSyz147064 * want the <type> part of the pattern. 539*d62bc4baSyz147064 */ 540*d62bc4baSyz147064 for (type = 0; type < ntranslators; type++) { 541*d62bc4baSyz147064 if (strcmp(curr, 542*d62bc4baSyz147064 translators[type].type_name) == 0) { 543*d62bc4baSyz147064 found_type = B_TRUE; 544*d62bc4baSyz147064 break; 545*d62bc4baSyz147064 } 546*d62bc4baSyz147064 } 547*d62bc4baSyz147064 548*d62bc4baSyz147064 if (!found_type) 549*d62bc4baSyz147064 goto parse_fail; 550*d62bc4baSyz147064 } else { 551*d62bc4baSyz147064 /* 552*d62bc4baSyz147064 * A zero length attr_name indicates we are looking 553*d62bc4baSyz147064 * at the beginning of a link attribute. 554*d62bc4baSyz147064 */ 555*d62bc4baSyz147064 if (c != '=') 556*d62bc4baSyz147064 goto parse_fail; 557*d62bc4baSyz147064 558*d62bc4baSyz147064 (void) snprintf(attr_name, MAXLINKATTRLEN, "%s", curr); 559*d62bc4baSyz147064 } 560*d62bc4baSyz147064 curr = buf + i + 1; 561*d62bc4baSyz147064 } 562*d62bc4baSyz147064 563*d62bc4baSyz147064 return (err); 564*d62bc4baSyz147064 565*d62bc4baSyz147064 parse_fail: 566*d62bc4baSyz147064 return (-1); 567*d62bc4baSyz147064 } 568*d62bc4baSyz147064 569*d62bc4baSyz147064 static boolean_t 570*d62bc4baSyz147064 process_link_line(char *buf, dlmgmt_link_t **linkpp) 571*d62bc4baSyz147064 { 572*d62bc4baSyz147064 dlmgmt_link_t *linkp; 573*d62bc4baSyz147064 int i, len, llen; 574*d62bc4baSyz147064 char *str, *lasts; 575*d62bc4baSyz147064 char tmpbuf[MAXLINELEN]; 576*d62bc4baSyz147064 577*d62bc4baSyz147064 /* 578*d62bc4baSyz147064 * Use a copy of buf for parsing so that we can do whatever we want. 579*d62bc4baSyz147064 */ 580*d62bc4baSyz147064 (void) strlcpy(tmpbuf, buf, MAXLINELEN); 581*d62bc4baSyz147064 582*d62bc4baSyz147064 /* 583*d62bc4baSyz147064 * Skip leading spaces, blank lines, and comments. 584*d62bc4baSyz147064 */ 585*d62bc4baSyz147064 len = strlen(tmpbuf); 586*d62bc4baSyz147064 for (i = 0; i < len; i++) { 587*d62bc4baSyz147064 if (!isspace(tmpbuf[i])) 588*d62bc4baSyz147064 break; 589*d62bc4baSyz147064 } 590*d62bc4baSyz147064 if (i == len || tmpbuf[i] == '#') { 591*d62bc4baSyz147064 *linkpp = NULL; 592*d62bc4baSyz147064 return (B_TRUE); 593*d62bc4baSyz147064 } 594*d62bc4baSyz147064 595*d62bc4baSyz147064 linkp = calloc(1, sizeof (dlmgmt_link_t)); 596*d62bc4baSyz147064 if (linkp == NULL) 597*d62bc4baSyz147064 goto fail; 598*d62bc4baSyz147064 599*d62bc4baSyz147064 str = tmpbuf + i; 600*d62bc4baSyz147064 /* 601*d62bc4baSyz147064 * Find the link id and assign it to the link structure. 602*d62bc4baSyz147064 */ 603*d62bc4baSyz147064 if (strtok_r(str, " \n\t", &lasts) == NULL) 604*d62bc4baSyz147064 goto fail; 605*d62bc4baSyz147064 606*d62bc4baSyz147064 llen = strlen(str); 607*d62bc4baSyz147064 linkp->ll_linkid = atoi(str); 608*d62bc4baSyz147064 609*d62bc4baSyz147064 str += llen + 1; 610*d62bc4baSyz147064 if (str >= tmpbuf + len) 611*d62bc4baSyz147064 goto fail; 612*d62bc4baSyz147064 613*d62bc4baSyz147064 /* 614*d62bc4baSyz147064 * Now find the list of link properties. 615*d62bc4baSyz147064 */ 616*d62bc4baSyz147064 if ((str = strtok_r(str, " \n\t", &lasts)) == NULL) 617*d62bc4baSyz147064 goto fail; 618*d62bc4baSyz147064 619*d62bc4baSyz147064 if (parse_linkprops(str, linkp) < 0) 620*d62bc4baSyz147064 goto fail; 621*d62bc4baSyz147064 622*d62bc4baSyz147064 *linkpp = linkp; 623*d62bc4baSyz147064 return (B_TRUE); 624*d62bc4baSyz147064 625*d62bc4baSyz147064 fail: 626*d62bc4baSyz147064 link_destroy(linkp); 627*d62bc4baSyz147064 628*d62bc4baSyz147064 /* 629*d62bc4baSyz147064 * Delete corrupted line. 630*d62bc4baSyz147064 */ 631*d62bc4baSyz147064 buf[0] = '\0'; 632*d62bc4baSyz147064 return (B_FALSE); 633*d62bc4baSyz147064 } 634*d62bc4baSyz147064 635*d62bc4baSyz147064 static int 636*d62bc4baSyz147064 process_db_write(dlmgmt_db_req_t *req, FILE *fp, FILE *nfp) 637*d62bc4baSyz147064 { 638*d62bc4baSyz147064 boolean_t done = B_FALSE; 639*d62bc4baSyz147064 int err = 0; 640*d62bc4baSyz147064 dlmgmt_link_t *linkp, *link_in_file, link; 641*d62bc4baSyz147064 char buf[MAXLINELEN]; 642*d62bc4baSyz147064 643*d62bc4baSyz147064 if (req->ls_op == DLMGMT_DB_OP_WRITE) { 644*d62bc4baSyz147064 /* 645*d62bc4baSyz147064 * find the link in the avl tree with the given linkid. 646*d62bc4baSyz147064 */ 647*d62bc4baSyz147064 link.ll_linkid = req->ls_linkid; 648*d62bc4baSyz147064 linkp = avl_find(&dlmgmt_id_avl, &link, NULL); 649*d62bc4baSyz147064 if (linkp == NULL || (linkp->ll_flags & req->ls_flags) == 0) { 650*d62bc4baSyz147064 /* 651*d62bc4baSyz147064 * This link has already been changed. This could 652*d62bc4baSyz147064 * happen if the request is pending because of 653*d62bc4baSyz147064 * read-only file-system. If so, we are done. 654*d62bc4baSyz147064 */ 655*d62bc4baSyz147064 return (0); 656*d62bc4baSyz147064 } 657*d62bc4baSyz147064 } 658*d62bc4baSyz147064 659*d62bc4baSyz147064 while (err == 0 && fgets(buf, sizeof (buf), fp) != NULL && 660*d62bc4baSyz147064 process_link_line(buf, &link_in_file)) { 661*d62bc4baSyz147064 if (link_in_file == NULL || done) { 662*d62bc4baSyz147064 /* 663*d62bc4baSyz147064 * this is a comment line, write it out. 664*d62bc4baSyz147064 */ 665*d62bc4baSyz147064 if (fputs(buf, nfp) == EOF) 666*d62bc4baSyz147064 err = errno; 667*d62bc4baSyz147064 continue; 668*d62bc4baSyz147064 } 669*d62bc4baSyz147064 670*d62bc4baSyz147064 switch (req->ls_op) { 671*d62bc4baSyz147064 case DLMGMT_DB_OP_WRITE: 672*d62bc4baSyz147064 /* 673*d62bc4baSyz147064 * For write operations, if the linkid of the link 674*d62bc4baSyz147064 * read from the file does not match the id of what 675*d62bc4baSyz147064 * req->ll_linkid points to, write out the buffer. 676*d62bc4baSyz147064 * Otherwise, generate a new line. If we get to the 677*d62bc4baSyz147064 * end and have not seen what req->ll_linkid points 678*d62bc4baSyz147064 * to, write it out then. 679*d62bc4baSyz147064 */ 680*d62bc4baSyz147064 if (linkp == NULL || 681*d62bc4baSyz147064 linkp->ll_linkid != link_in_file->ll_linkid) { 682*d62bc4baSyz147064 if (fputs(buf, nfp) == EOF) 683*d62bc4baSyz147064 err = errno; 684*d62bc4baSyz147064 } else { 685*d62bc4baSyz147064 generate_link_line(linkp, 686*d62bc4baSyz147064 req->ls_flags == DLMGMT_PERSIST, buf); 687*d62bc4baSyz147064 if (fputs(buf, nfp) == EOF) 688*d62bc4baSyz147064 err = errno; 689*d62bc4baSyz147064 done = B_TRUE; 690*d62bc4baSyz147064 } 691*d62bc4baSyz147064 break; 692*d62bc4baSyz147064 case DLMGMT_DB_OP_DELETE: 693*d62bc4baSyz147064 /* 694*d62bc4baSyz147064 * Delete is simple. If buf does not represent the 695*d62bc4baSyz147064 * link we're deleting, write it out. 696*d62bc4baSyz147064 */ 697*d62bc4baSyz147064 if (req->ls_linkid != link_in_file->ll_linkid) { 698*d62bc4baSyz147064 if (fputs(buf, nfp) == EOF) 699*d62bc4baSyz147064 err = errno; 700*d62bc4baSyz147064 } else { 701*d62bc4baSyz147064 done = B_TRUE; 702*d62bc4baSyz147064 } 703*d62bc4baSyz147064 break; 704*d62bc4baSyz147064 case DLMGMT_DB_OP_READ: 705*d62bc4baSyz147064 default: 706*d62bc4baSyz147064 err = EINVAL; 707*d62bc4baSyz147064 break; 708*d62bc4baSyz147064 } 709*d62bc4baSyz147064 link_destroy(link_in_file); 710*d62bc4baSyz147064 } 711*d62bc4baSyz147064 712*d62bc4baSyz147064 /* 713*d62bc4baSyz147064 * If we get to the end of the file and have not seen what 714*d62bc4baSyz147064 * req->ll_linkid points to, write it out then. 715*d62bc4baSyz147064 */ 716*d62bc4baSyz147064 if (req->ls_op == DLMGMT_DB_OP_WRITE && !done) { 717*d62bc4baSyz147064 generate_link_line(linkp, req->ls_flags == DLMGMT_PERSIST, buf); 718*d62bc4baSyz147064 done = B_TRUE; 719*d62bc4baSyz147064 if (fputs(buf, nfp) == EOF) 720*d62bc4baSyz147064 err = errno; 721*d62bc4baSyz147064 } 722*d62bc4baSyz147064 723*d62bc4baSyz147064 if (!done) 724*d62bc4baSyz147064 err = ENOENT; 725*d62bc4baSyz147064 726*d62bc4baSyz147064 return (err); 727*d62bc4baSyz147064 } 728*d62bc4baSyz147064 729*d62bc4baSyz147064 /* ARGSUSED1 */ 730*d62bc4baSyz147064 static int 731*d62bc4baSyz147064 process_db_read(dlmgmt_db_req_t *req, FILE *fp, FILE *nfp) 732*d62bc4baSyz147064 { 733*d62bc4baSyz147064 avl_index_t name_where, id_where; 734*d62bc4baSyz147064 dlmgmt_link_t *link_in_file; 735*d62bc4baSyz147064 dlmgmt_link_t *linkp1, *linkp2; 736*d62bc4baSyz147064 char buf[MAXLINELEN]; 737*d62bc4baSyz147064 int err = 0; 738*d62bc4baSyz147064 739*d62bc4baSyz147064 /* 740*d62bc4baSyz147064 * This loop processes each line of the configuration file. 741*d62bc4baSyz147064 */ 742*d62bc4baSyz147064 while (fgets(buf, MAXLINELEN, fp) != NULL) { 743*d62bc4baSyz147064 if (!process_link_line(buf, &link_in_file)) { 744*d62bc4baSyz147064 err = EINVAL; 745*d62bc4baSyz147064 break; 746*d62bc4baSyz147064 } 747*d62bc4baSyz147064 748*d62bc4baSyz147064 /* 749*d62bc4baSyz147064 * Skip the comment line. 750*d62bc4baSyz147064 */ 751*d62bc4baSyz147064 if (link_in_file == NULL) 752*d62bc4baSyz147064 continue; 753*d62bc4baSyz147064 754*d62bc4baSyz147064 linkp1 = avl_find(&dlmgmt_name_avl, link_in_file, &name_where); 755*d62bc4baSyz147064 linkp2 = avl_find(&dlmgmt_id_avl, link_in_file, &id_where); 756*d62bc4baSyz147064 if ((linkp1 != NULL) || (linkp2 != NULL)) { 757*d62bc4baSyz147064 /* 758*d62bc4baSyz147064 * If any of the following conditions are met, this is 759*d62bc4baSyz147064 * a duplicate entry: 760*d62bc4baSyz147064 * 761*d62bc4baSyz147064 * 1. link2 (with the given name) and link2 (with the 762*d62bc4baSyz147064 * given id) are not the same link; 763*d62bc4baSyz147064 * 2. This is a persistent req and find the link with 764*d62bc4baSyz147064 * the given name and id. Note that persistent db 765*d62bc4baSyz147064 * is read before the active one. 766*d62bc4baSyz147064 * 3. Found the link with the given name and id but 767*d62bc4baSyz147064 * the link is already active. 768*d62bc4baSyz147064 */ 769*d62bc4baSyz147064 if ((linkp1 != linkp2) || 770*d62bc4baSyz147064 (req->ls_flags == DLMGMT_PERSIST) || 771*d62bc4baSyz147064 ((linkp1->ll_flags & DLMGMT_ACTIVE) != 0)) { 772*d62bc4baSyz147064 dlmgmt_log(LOG_WARNING, "Duplicate link " 773*d62bc4baSyz147064 "entries in repository: link name %s " 774*d62bc4baSyz147064 "link id %i", link_in_file->ll_link, 775*d62bc4baSyz147064 link_in_file->ll_linkid); 776*d62bc4baSyz147064 } else { 777*d62bc4baSyz147064 linkp1->ll_flags |= DLMGMT_ACTIVE; 778*d62bc4baSyz147064 } 779*d62bc4baSyz147064 link_destroy(link_in_file); 780*d62bc4baSyz147064 } else { 781*d62bc4baSyz147064 avl_insert(&dlmgmt_name_avl, link_in_file, name_where); 782*d62bc4baSyz147064 avl_insert(&dlmgmt_id_avl, link_in_file, id_where); 783*d62bc4baSyz147064 dlmgmt_advance(link_in_file); 784*d62bc4baSyz147064 link_in_file->ll_flags |= req->ls_flags; 785*d62bc4baSyz147064 } 786*d62bc4baSyz147064 } 787*d62bc4baSyz147064 788*d62bc4baSyz147064 return (err); 789*d62bc4baSyz147064 } 790*d62bc4baSyz147064 791*d62bc4baSyz147064 /* 792*d62bc4baSyz147064 * Generate an entry in the link database. 793*d62bc4baSyz147064 * Each entry has this format: 794*d62bc4baSyz147064 * <link id> <prop0>=<type>,<val>;...;<propn>=<type>,<val>; 795*d62bc4baSyz147064 */ 796*d62bc4baSyz147064 static void 797*d62bc4baSyz147064 generate_link_line(dlmgmt_link_t *linkp, boolean_t persist, char *buf) 798*d62bc4baSyz147064 { 799*d62bc4baSyz147064 char tmpbuf[MAXLINELEN]; 800*d62bc4baSyz147064 char *ptr; 801*d62bc4baSyz147064 char *lim = tmpbuf + MAXLINELEN; 802*d62bc4baSyz147064 char *name_to_write = NULL; 803*d62bc4baSyz147064 datalink_id_t id_to_write; 804*d62bc4baSyz147064 dlmgmt_linkattr_t *cur_p = NULL; 805*d62bc4baSyz147064 uint64_t u64; 806*d62bc4baSyz147064 807*d62bc4baSyz147064 ptr = tmpbuf; 808*d62bc4baSyz147064 id_to_write = linkp->ll_linkid; 809*d62bc4baSyz147064 ptr += snprintf(ptr, BUFLEN(lim, ptr), "%d\t", id_to_write); 810*d62bc4baSyz147064 name_to_write = linkp->ll_link; 811*d62bc4baSyz147064 ptr += write_str(ptr, BUFLEN(lim, ptr), "name", name_to_write); 812*d62bc4baSyz147064 u64 = linkp->ll_class; 813*d62bc4baSyz147064 ptr += write_uint64(ptr, BUFLEN(lim, ptr), "class", &u64); 814*d62bc4baSyz147064 u64 = linkp->ll_media; 815*d62bc4baSyz147064 ptr += write_uint64(ptr, BUFLEN(lim, ptr), "media", &u64); 816*d62bc4baSyz147064 817*d62bc4baSyz147064 /* 818*d62bc4baSyz147064 * The daemon does not keep any active link attribute. If this request 819*d62bc4baSyz147064 * is for active configuration, we are done. 820*d62bc4baSyz147064 */ 821*d62bc4baSyz147064 if (!persist) 822*d62bc4baSyz147064 goto done; 823*d62bc4baSyz147064 824*d62bc4baSyz147064 for (cur_p = linkp->ll_head; cur_p != NULL; cur_p = cur_p->lp_next) { 825*d62bc4baSyz147064 ptr += translators[cur_p->lp_type].write_func(ptr, 826*d62bc4baSyz147064 BUFLEN(lim, ptr), cur_p->lp_name, cur_p->lp_val); 827*d62bc4baSyz147064 } 828*d62bc4baSyz147064 done: 829*d62bc4baSyz147064 if (ptr > lim) 830*d62bc4baSyz147064 return; 831*d62bc4baSyz147064 (void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf); 832*d62bc4baSyz147064 } 833*d62bc4baSyz147064 834*d62bc4baSyz147064 int 835*d62bc4baSyz147064 dlmgmt_delete_db_entry(datalink_id_t linkid, uint32_t flags) 836*d62bc4baSyz147064 { 837*d62bc4baSyz147064 return (dlmgmt_db_update(DLMGMT_DB_OP_DELETE, linkid, flags)); 838*d62bc4baSyz147064 } 839*d62bc4baSyz147064 840*d62bc4baSyz147064 int 841*d62bc4baSyz147064 dlmgmt_write_db_entry(datalink_id_t linkid, uint32_t flags) 842*d62bc4baSyz147064 { 843*d62bc4baSyz147064 int err; 844*d62bc4baSyz147064 845*d62bc4baSyz147064 if (flags & DLMGMT_PERSIST) { 846*d62bc4baSyz147064 if ((err = dlmgmt_db_update(DLMGMT_DB_OP_WRITE, 847*d62bc4baSyz147064 linkid, DLMGMT_PERSIST)) != 0) { 848*d62bc4baSyz147064 return (err); 849*d62bc4baSyz147064 } 850*d62bc4baSyz147064 } 851*d62bc4baSyz147064 852*d62bc4baSyz147064 if (flags & DLMGMT_ACTIVE) { 853*d62bc4baSyz147064 if (((err = dlmgmt_db_update(DLMGMT_DB_OP_WRITE, 854*d62bc4baSyz147064 linkid, DLMGMT_ACTIVE)) != 0) && 855*d62bc4baSyz147064 (flags & DLMGMT_PERSIST)) { 856*d62bc4baSyz147064 (void) dlmgmt_db_update(DLMGMT_DB_OP_DELETE, 857*d62bc4baSyz147064 linkid, DLMGMT_PERSIST); 858*d62bc4baSyz147064 return (err); 859*d62bc4baSyz147064 } 860*d62bc4baSyz147064 } 861*d62bc4baSyz147064 862*d62bc4baSyz147064 return (0); 863*d62bc4baSyz147064 } 864*d62bc4baSyz147064 865*d62bc4baSyz147064 /* 866*d62bc4baSyz147064 * Initialize the datalink <link name, linkid> mapping and the link's 867*d62bc4baSyz147064 * attributes list based on the configuration file /etc/dladm/datalink.conf 868*d62bc4baSyz147064 * and the active configuration cache file 869*d62bc4baSyz147064 * /etc/svc/volatile/datalink-management:default.cache. 870*d62bc4baSyz147064 * 871*d62bc4baSyz147064 * This function is called when the datalink-management service is started 872*d62bc4baSyz147064 * during reboot, and when the dlmgmtd daemon is restarted. 873*d62bc4baSyz147064 */ 874*d62bc4baSyz147064 int 875*d62bc4baSyz147064 dlmgmt_db_init() 876*d62bc4baSyz147064 { 877*d62bc4baSyz147064 char filename[MAXPATHLEN]; 878*d62bc4baSyz147064 dlmgmt_db_req_t req; 879*d62bc4baSyz147064 int err; 880*d62bc4baSyz147064 dlmgmt_link_t *linkp; 881*d62bc4baSyz147064 char *fmri, *c; 882*d62bc4baSyz147064 883*d62bc4baSyz147064 /* 884*d62bc4baSyz147064 * First derive the name of the cache file from the FMRI name. This 885*d62bc4baSyz147064 * cache name is used to keep active datalink configuration. 886*d62bc4baSyz147064 */ 887*d62bc4baSyz147064 if (debug) { 888*d62bc4baSyz147064 (void) snprintf(cachefile, MAXPATHLEN, "%s/%s%s", 889*d62bc4baSyz147064 DLMGMT_TEMP_DB_DIR, progname, ".debug.cache"); 890*d62bc4baSyz147064 } else { 891*d62bc4baSyz147064 if ((fmri = getenv("SMF_FMRI")) == NULL) { 892*d62bc4baSyz147064 dlmgmt_log(LOG_WARNING, "dlmgmtd is an smf(5) managed " 893*d62bc4baSyz147064 "service and should not be run from the command " 894*d62bc4baSyz147064 "line."); 895*d62bc4baSyz147064 return (EINVAL); 896*d62bc4baSyz147064 } 897*d62bc4baSyz147064 898*d62bc4baSyz147064 /* 899*d62bc4baSyz147064 * The FMRI name is in the form of 900*d62bc4baSyz147064 * svc:/service/service:instance. We need to remove the 901*d62bc4baSyz147064 * prefix "svc:/" and replace '/' with '-'. The cache file 902*d62bc4baSyz147064 * name is in the form of "service:instance.cache". 903*d62bc4baSyz147064 */ 904*d62bc4baSyz147064 if ((c = strchr(fmri, '/')) != NULL) 905*d62bc4baSyz147064 c++; 906*d62bc4baSyz147064 else 907*d62bc4baSyz147064 c = fmri; 908*d62bc4baSyz147064 (void) snprintf(filename, MAXPATHLEN, "%s.cache", c); 909*d62bc4baSyz147064 for (c = filename; *c != '\0'; c++) { 910*d62bc4baSyz147064 if (*c == '/') 911*d62bc4baSyz147064 *c = '-'; 912*d62bc4baSyz147064 } 913*d62bc4baSyz147064 914*d62bc4baSyz147064 (void) snprintf(cachefile, MAXPATHLEN, "%s/%s", 915*d62bc4baSyz147064 DLMGMT_TEMP_DB_DIR, filename); 916*d62bc4baSyz147064 } 917*d62bc4baSyz147064 918*d62bc4baSyz147064 dlmgmt_table_lock(B_TRUE); 919*d62bc4baSyz147064 920*d62bc4baSyz147064 req.ls_next = NULL; 921*d62bc4baSyz147064 req.ls_op = DLMGMT_DB_OP_READ; 922*d62bc4baSyz147064 req.ls_linkid = DATALINK_INVALID_LINKID; 923*d62bc4baSyz147064 req.ls_flags = DLMGMT_PERSIST; 924*d62bc4baSyz147064 925*d62bc4baSyz147064 if ((err = dlmgmt_process_db_req(&req)) != 0) 926*d62bc4baSyz147064 goto done; 927*d62bc4baSyz147064 928*d62bc4baSyz147064 req.ls_flags = DLMGMT_ACTIVE; 929*d62bc4baSyz147064 err = dlmgmt_process_db_req(&req); 930*d62bc4baSyz147064 if (err == ENOENT) { 931*d62bc4baSyz147064 /* 932*d62bc4baSyz147064 * The temporary datalink.conf does not exist. This is 933*d62bc4baSyz147064 * the first boot. Mark all the physical links active. 934*d62bc4baSyz147064 */ 935*d62bc4baSyz147064 for (linkp = avl_first(&dlmgmt_id_avl); linkp != NULL; 936*d62bc4baSyz147064 linkp = AVL_NEXT(&dlmgmt_id_avl, linkp)) { 937*d62bc4baSyz147064 if (linkp->ll_class == DATALINK_CLASS_PHYS) { 938*d62bc4baSyz147064 linkp->ll_flags |= DLMGMT_ACTIVE; 939*d62bc4baSyz147064 (void) dlmgmt_write_db_entry( 940*d62bc4baSyz147064 linkp->ll_linkid, DLMGMT_ACTIVE); 941*d62bc4baSyz147064 } 942*d62bc4baSyz147064 } 943*d62bc4baSyz147064 err = 0; 944*d62bc4baSyz147064 } 945*d62bc4baSyz147064 946*d62bc4baSyz147064 done: 947*d62bc4baSyz147064 dlmgmt_table_unlock(); 948*d62bc4baSyz147064 return (err); 949*d62bc4baSyz147064 } 950