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