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