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 /* 2332715170SCathy Zhou * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24d62bc4baSyz147064 */ 25d62bc4baSyz147064 26d62bc4baSyz147064 #include <assert.h> 27d62bc4baSyz147064 #include <ctype.h> 28d62bc4baSyz147064 #include <errno.h> 29d62bc4baSyz147064 #include <fcntl.h> 30d62bc4baSyz147064 #include <stdio.h> 31d62bc4baSyz147064 #include <stdlib.h> 322b24ab6bSSebastien Roy #include <string.h> 33d62bc4baSyz147064 #include <strings.h> 34d62bc4baSyz147064 #include <syslog.h> 352b24ab6bSSebastien Roy #include <zone.h> 362b24ab6bSSebastien Roy #include <sys/types.h> 37d62bc4baSyz147064 #include <sys/stat.h> 382b24ab6bSSebastien Roy #include <stropts.h> 392b24ab6bSSebastien Roy #include <sys/conf.h> 40d62bc4baSyz147064 #include <pthread.h> 41d62bc4baSyz147064 #include <unistd.h> 422b24ab6bSSebastien Roy #include <wait.h> 432b24ab6bSSebastien Roy #include <libcontract.h> 445b310668SDarren Reed #include <libcontract_priv.h> 452b24ab6bSSebastien Roy #include <sys/contract/process.h> 46d62bc4baSyz147064 #include "dlmgmt_impl.h" 47d62bc4baSyz147064 48d62bc4baSyz147064 typedef enum dlmgmt_db_op { 49d62bc4baSyz147064 DLMGMT_DB_OP_WRITE, 50d62bc4baSyz147064 DLMGMT_DB_OP_DELETE, 51d62bc4baSyz147064 DLMGMT_DB_OP_READ 52d62bc4baSyz147064 } dlmgmt_db_op_t; 53d62bc4baSyz147064 54d62bc4baSyz147064 typedef struct dlmgmt_db_req_s { 55d62bc4baSyz147064 struct dlmgmt_db_req_s *ls_next; 56d62bc4baSyz147064 dlmgmt_db_op_t ls_op; 572b24ab6bSSebastien Roy char ls_link[MAXLINKNAMELEN]; 58d62bc4baSyz147064 datalink_id_t ls_linkid; 592b24ab6bSSebastien Roy zoneid_t ls_zoneid; 60d62bc4baSyz147064 uint32_t ls_flags; /* Either DLMGMT_ACTIVE or */ 61d62bc4baSyz147064 /* DLMGMT_PERSIST, not both. */ 62d62bc4baSyz147064 } dlmgmt_db_req_t; 63d62bc4baSyz147064 64d62bc4baSyz147064 /* 65d62bc4baSyz147064 * List of pending db updates (e.g., because of a read-only filesystem). 66d62bc4baSyz147064 */ 67d62bc4baSyz147064 static dlmgmt_db_req_t *dlmgmt_db_req_head = NULL; 68d62bc4baSyz147064 static dlmgmt_db_req_t *dlmgmt_db_req_tail = NULL; 69d62bc4baSyz147064 702b24ab6bSSebastien Roy /* 712b24ab6bSSebastien Roy * rewrite_needed is set to B_TRUE by process_link_line() if it encounters a 722b24ab6bSSebastien Roy * line with an old format. This will cause the file being read to be 732b24ab6bSSebastien Roy * re-written with the current format. 742b24ab6bSSebastien Roy */ 752b24ab6bSSebastien Roy static boolean_t rewrite_needed; 762b24ab6bSSebastien Roy 772b24ab6bSSebastien Roy static int dlmgmt_db_update(dlmgmt_db_op_t, const char *, 782b24ab6bSSebastien Roy dlmgmt_link_t *, uint32_t); 79d62bc4baSyz147064 static int dlmgmt_process_db_req(dlmgmt_db_req_t *); 80d62bc4baSyz147064 static int dlmgmt_process_db_onereq(dlmgmt_db_req_t *, boolean_t); 81d62bc4baSyz147064 static void *dlmgmt_db_update_thread(void *); 822b24ab6bSSebastien Roy static boolean_t process_link_line(char *, dlmgmt_link_t *); 83d62bc4baSyz147064 static int process_db_write(dlmgmt_db_req_t *, FILE *, FILE *); 842b24ab6bSSebastien Roy static int process_db_read(dlmgmt_db_req_t *, FILE *); 85d62bc4baSyz147064 static void generate_link_line(dlmgmt_link_t *, boolean_t, char *); 86d62bc4baSyz147064 87d62bc4baSyz147064 #define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0) 88d62bc4baSyz147064 #define MAXLINELEN 1024 89d62bc4baSyz147064 902b24ab6bSSebastien Roy typedef void db_walk_func_t(dlmgmt_link_t *); 912b24ab6bSSebastien Roy 92d62bc4baSyz147064 /* 93d62bc4baSyz147064 * Translator functions to go from dladm_datatype_t to character strings. 94d62bc4baSyz147064 * Each function takes a pointer to a buffer, the size of the buffer, 95d62bc4baSyz147064 * the name of the attribute, and the value to be written. The functions 96d62bc4baSyz147064 * return the number of bytes written to the buffer. If the buffer is not big 97d62bc4baSyz147064 * enough to hold the string representing the value, then nothing is written 98d62bc4baSyz147064 * and 0 is returned. 99d62bc4baSyz147064 */ 100d62bc4baSyz147064 typedef size_t write_func_t(char *, size_t, char *, void *); 101d62bc4baSyz147064 102d62bc4baSyz147064 /* 103d62bc4baSyz147064 * Translator functions to read from a NULL terminated string buffer into 104d62bc4baSyz147064 * something of the given DLADM_TYPE_*. The functions each return the number 105d62bc4baSyz147064 * of bytes read from the string buffer. If there is an error reading data 106d62bc4baSyz147064 * from the buffer, then 0 is returned. It is the caller's responsibility 107d62bc4baSyz147064 * to free the data allocated by these functions. 108d62bc4baSyz147064 */ 109d62bc4baSyz147064 typedef size_t read_func_t(char *, void **); 110d62bc4baSyz147064 111d62bc4baSyz147064 typedef struct translator_s { 112d62bc4baSyz147064 const char *type_name; 113d62bc4baSyz147064 write_func_t *write_func; 114d62bc4baSyz147064 read_func_t *read_func; 115d62bc4baSyz147064 } translator_t; 116d62bc4baSyz147064 117d62bc4baSyz147064 /* 118d62bc4baSyz147064 * Translator functions, defined later but declared here so that 119d62bc4baSyz147064 * the translator table can be defined. 120d62bc4baSyz147064 */ 121d62bc4baSyz147064 static write_func_t write_str, write_boolean, write_uint64; 122d62bc4baSyz147064 static read_func_t read_str, read_boolean, read_int64; 123d62bc4baSyz147064 124d62bc4baSyz147064 /* 125d62bc4baSyz147064 * Translator table, indexed by dladm_datatype_t. 126d62bc4baSyz147064 */ 127d62bc4baSyz147064 static translator_t translators[] = { 128d62bc4baSyz147064 { "string", write_str, read_str }, 129d62bc4baSyz147064 { "boolean", write_boolean, read_boolean }, 130d62bc4baSyz147064 { "int", write_uint64, read_int64 } 131d62bc4baSyz147064 }; 132d62bc4baSyz147064 133d62bc4baSyz147064 static size_t ntranslators = sizeof (translators) / sizeof (translator_t); 134d62bc4baSyz147064 135d62bc4baSyz147064 #define LINK_PROPERTY_DELIMINATOR ";" 136d62bc4baSyz147064 #define LINK_PROPERTY_TYPE_VALUE_SEP "," 137d62bc4baSyz147064 #define BASE_PROPERTY_LENGTH(t, n) (strlen(translators[(t)].type_name) +\ 138d62bc4baSyz147064 strlen(LINK_PROPERTY_TYPE_VALUE_SEP) +\ 139d62bc4baSyz147064 strlen(LINK_PROPERTY_DELIMINATOR) +\ 140d62bc4baSyz147064 strlen((n))) 141d62bc4baSyz147064 #define GENERATE_PROPERTY_STRING(buf, length, conv, name, type, val) \ 142d62bc4baSyz147064 (snprintf((buf), (length), "%s=%s%s" conv "%s", (name), \ 143d62bc4baSyz147064 translators[(type)].type_name, \ 144d62bc4baSyz147064 LINK_PROPERTY_TYPE_VALUE_SEP, (val), LINK_PROPERTY_DELIMINATOR)) 145d62bc4baSyz147064 146d62bc4baSyz147064 /* 147d62bc4baSyz147064 * Name of the cache file to keep the active <link name, linkid> mapping 148d62bc4baSyz147064 */ 1492b24ab6bSSebastien Roy char cachefile[MAXPATHLEN]; 150d62bc4baSyz147064 151d62bc4baSyz147064 #define DLMGMT_PERSISTENT_DB_PATH "/etc/dladm/datalink.conf" 152d62bc4baSyz147064 #define DLMGMT_MAKE_FILE_DB_PATH(buffer, persistent) \ 153d62bc4baSyz147064 (void) snprintf((buffer), MAXPATHLEN, "%s", \ 154d62bc4baSyz147064 (persistent) ? DLMGMT_PERSISTENT_DB_PATH : cachefile); 155d62bc4baSyz147064 1562b24ab6bSSebastien Roy typedef struct zopen_arg { 1572b24ab6bSSebastien Roy const char *zopen_modestr; 1582b24ab6bSSebastien Roy int *zopen_pipe; 1592b24ab6bSSebastien Roy int zopen_fd; 1602b24ab6bSSebastien Roy } zopen_arg_t; 1612b24ab6bSSebastien Roy 1622b24ab6bSSebastien Roy typedef struct zrename_arg { 1632b24ab6bSSebastien Roy const char *zrename_newname; 1642b24ab6bSSebastien Roy } zrename_arg_t; 1652b24ab6bSSebastien Roy 1662b24ab6bSSebastien Roy typedef union zfoparg { 1672b24ab6bSSebastien Roy zopen_arg_t zfop_openarg; 1682b24ab6bSSebastien Roy zrename_arg_t zfop_renamearg; 1692b24ab6bSSebastien Roy } zfoparg_t; 1702b24ab6bSSebastien Roy 1712b24ab6bSSebastien Roy typedef struct zfcbarg { 1722b24ab6bSSebastien Roy boolean_t zfarg_inglobalzone; /* is callback in global zone? */ 1732b24ab6bSSebastien Roy zoneid_t zfarg_finglobalzone; /* is file in global zone? */ 1742b24ab6bSSebastien Roy const char *zfarg_filename; 1752b24ab6bSSebastien Roy zfoparg_t *zfarg_oparg; 1762b24ab6bSSebastien Roy } zfarg_t; 1772b24ab6bSSebastien Roy #define zfarg_openarg zfarg_oparg->zfop_openarg 1782b24ab6bSSebastien Roy #define zfarg_renamearg zfarg_oparg->zfop_renamearg 1792b24ab6bSSebastien Roy 1802b24ab6bSSebastien Roy /* zone file callback */ 1812b24ab6bSSebastien Roy typedef int zfcb_t(zfarg_t *); 1822b24ab6bSSebastien Roy 1832b24ab6bSSebastien Roy /* 1842b24ab6bSSebastien Roy * Execute an operation on filename relative to zoneid's zone root. If the 1852b24ab6bSSebastien Roy * file is in the global zone, then the zfcb() callback will simply be called 1862b24ab6bSSebastien Roy * directly. If the file is in a non-global zone, then zfcb() will be called 1872b24ab6bSSebastien Roy * both from the global zone's context, and from the non-global zone's context 1882b24ab6bSSebastien Roy * (from a fork()'ed child that has entered the non-global zone). This is 1892b24ab6bSSebastien Roy * done to allow the callback to communicate with itself if needed (e.g. to 1902b24ab6bSSebastien Roy * pass back the file descriptor of an opened file). 1912b24ab6bSSebastien Roy */ 1922b24ab6bSSebastien Roy static int 1932b24ab6bSSebastien Roy dlmgmt_zfop(const char *filename, zoneid_t zoneid, zfcb_t *zfcb, 1942b24ab6bSSebastien Roy zfoparg_t *zfoparg) 1952b24ab6bSSebastien Roy { 1962b24ab6bSSebastien Roy int ctfd; 1972b24ab6bSSebastien Roy int err; 1982b24ab6bSSebastien Roy pid_t childpid; 1992b24ab6bSSebastien Roy siginfo_t info; 2002b24ab6bSSebastien Roy zfarg_t zfarg; 2010572408dSDarren Reed ctid_t ct; 2022b24ab6bSSebastien Roy 2032b24ab6bSSebastien Roy if (zoneid != GLOBAL_ZONEID) { 2042b24ab6bSSebastien Roy /* 2052b24ab6bSSebastien Roy * We need to access a file that isn't in the global zone. 2062b24ab6bSSebastien Roy * Accessing non-global zone files from the global zone is 2072b24ab6bSSebastien Roy * unsafe (due to symlink attacks), we'll need to fork a child 2082b24ab6bSSebastien Roy * that enters the zone in question and executes the callback 2092b24ab6bSSebastien Roy * that will operate on the file. 2102b24ab6bSSebastien Roy * 2112b24ab6bSSebastien Roy * Before we proceed with this zone tango, we need to create a 2122b24ab6bSSebastien Roy * new process contract for the child, as required by 2132b24ab6bSSebastien Roy * zone_enter(). 2142b24ab6bSSebastien Roy */ 2152b24ab6bSSebastien Roy errno = 0; 2162b24ab6bSSebastien Roy ctfd = open64("/system/contract/process/template", O_RDWR); 2172b24ab6bSSebastien Roy if (ctfd == -1) 2182b24ab6bSSebastien Roy return (errno); 2192b24ab6bSSebastien Roy if ((err = ct_tmpl_set_critical(ctfd, 0)) != 0 || 2202b24ab6bSSebastien Roy (err = ct_tmpl_set_informative(ctfd, 0)) != 0 || 2212b24ab6bSSebastien Roy (err = ct_pr_tmpl_set_fatal(ctfd, CT_PR_EV_HWERR)) != 0 || 2222b24ab6bSSebastien Roy (err = ct_pr_tmpl_set_param(ctfd, CT_PR_PGRPONLY)) != 0 || 2232b24ab6bSSebastien Roy (err = ct_tmpl_activate(ctfd)) != 0) { 2240572408dSDarren Reed (void) close(ctfd); 2252b24ab6bSSebastien Roy return (err); 2262b24ab6bSSebastien Roy } 2272b24ab6bSSebastien Roy childpid = fork(); 2282b24ab6bSSebastien Roy switch (childpid) { 2292b24ab6bSSebastien Roy case -1: 2300572408dSDarren Reed (void) ct_tmpl_clear(ctfd); 2310572408dSDarren Reed (void) close(ctfd); 2322b24ab6bSSebastien Roy return (err); 2332b24ab6bSSebastien Roy case 0: 2340572408dSDarren Reed (void) ct_tmpl_clear(ctfd); 2350572408dSDarren Reed (void) close(ctfd); 2362b24ab6bSSebastien Roy /* 2372b24ab6bSSebastien Roy * Elevate our privileges as zone_enter() requires all 2382b24ab6bSSebastien Roy * privileges. 2392b24ab6bSSebastien Roy */ 2402b24ab6bSSebastien Roy if ((err = dlmgmt_elevate_privileges()) != 0) 2412b24ab6bSSebastien Roy _exit(err); 2422b24ab6bSSebastien Roy if (zone_enter(zoneid) == -1) 2432b24ab6bSSebastien Roy _exit(errno); 2442b24ab6bSSebastien Roy if ((err = dlmgmt_drop_privileges()) != 0) 2452b24ab6bSSebastien Roy _exit(err); 2462b24ab6bSSebastien Roy break; 2472b24ab6bSSebastien Roy default: 2480572408dSDarren Reed if (contract_latest(&ct) == -1) 2490572408dSDarren Reed ct = -1; 2500572408dSDarren Reed (void) ct_tmpl_clear(ctfd); 2510572408dSDarren Reed (void) close(ctfd); 2520572408dSDarren Reed if (waitid(P_PID, childpid, &info, WEXITED) == -1) { 2530572408dSDarren Reed (void) contract_abandon_id(ct); 2542b24ab6bSSebastien Roy return (errno); 2550572408dSDarren Reed } 2560572408dSDarren Reed (void) contract_abandon_id(ct); 2572b24ab6bSSebastien Roy if (info.si_status != 0) 2582b24ab6bSSebastien Roy return (info.si_status); 2592b24ab6bSSebastien Roy } 2602b24ab6bSSebastien Roy } 2612b24ab6bSSebastien Roy 2622b24ab6bSSebastien Roy zfarg.zfarg_inglobalzone = (zoneid == GLOBAL_ZONEID || childpid != 0); 2632b24ab6bSSebastien Roy zfarg.zfarg_finglobalzone = (zoneid == GLOBAL_ZONEID); 2642b24ab6bSSebastien Roy zfarg.zfarg_filename = filename; 2652b24ab6bSSebastien Roy zfarg.zfarg_oparg = zfoparg; 2662b24ab6bSSebastien Roy err = zfcb(&zfarg); 2672b24ab6bSSebastien Roy if (!zfarg.zfarg_inglobalzone) 2682b24ab6bSSebastien Roy _exit(err); 2692b24ab6bSSebastien Roy return (err); 2702b24ab6bSSebastien Roy } 2712b24ab6bSSebastien Roy 2722b24ab6bSSebastien Roy static int 2732b24ab6bSSebastien Roy dlmgmt_zopen_cb(zfarg_t *zfarg) 2742b24ab6bSSebastien Roy { 2752b24ab6bSSebastien Roy struct strrecvfd recvfd; 2762b24ab6bSSebastien Roy boolean_t newfile = B_FALSE; 2772b24ab6bSSebastien Roy boolean_t inglobalzone = zfarg->zfarg_inglobalzone; 2782b24ab6bSSebastien Roy zoneid_t finglobalzone = zfarg->zfarg_finglobalzone; 2792b24ab6bSSebastien Roy const char *filename = zfarg->zfarg_filename; 2802b24ab6bSSebastien Roy const char *modestr = zfarg->zfarg_openarg.zopen_modestr; 2812b24ab6bSSebastien Roy int *p = zfarg->zfarg_openarg.zopen_pipe; 2822b24ab6bSSebastien Roy struct stat statbuf; 2832b24ab6bSSebastien Roy int oflags; 2842b24ab6bSSebastien Roy mode_t mode; 2852b24ab6bSSebastien Roy int fd = -1; 2862b24ab6bSSebastien Roy int err; 2872b24ab6bSSebastien Roy 2882b24ab6bSSebastien Roy /* We only ever open a file for reading or writing, not both. */ 2892b24ab6bSSebastien Roy oflags = (modestr[0] == 'r') ? O_RDONLY : O_WRONLY | O_CREAT | O_TRUNC; 2902b24ab6bSSebastien Roy mode = (modestr[0] == 'r') ? 0 : S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 2912b24ab6bSSebastien Roy 2922b24ab6bSSebastien Roy /* Open the file if we're in the same zone as the file. */ 2932b24ab6bSSebastien Roy if (inglobalzone == finglobalzone) { 2942b24ab6bSSebastien Roy /* 2952b24ab6bSSebastien Roy * First determine if we will be creating the file as part of 2962b24ab6bSSebastien Roy * opening it. If so, then we'll need to ensure that it has 2972b24ab6bSSebastien Roy * the proper ownership after having opened it. 2982b24ab6bSSebastien Roy */ 2992b24ab6bSSebastien Roy if (oflags & O_CREAT) { 3002b24ab6bSSebastien Roy if (stat(filename, &statbuf) == -1) { 3012b24ab6bSSebastien Roy if (errno == ENOENT) 3022b24ab6bSSebastien Roy newfile = B_TRUE; 3032b24ab6bSSebastien Roy else 3042b24ab6bSSebastien Roy return (errno); 3052b24ab6bSSebastien Roy } 3062b24ab6bSSebastien Roy } 3072b24ab6bSSebastien Roy if ((fd = open(filename, oflags, mode)) == -1) 3082b24ab6bSSebastien Roy return (errno); 3092b24ab6bSSebastien Roy if (newfile) { 3106ba597c5SAnurag S. Maskey if (chown(filename, UID_DLADM, GID_NETADM) == -1) { 3112b24ab6bSSebastien Roy err = errno; 3122b24ab6bSSebastien Roy (void) close(fd); 3132b24ab6bSSebastien Roy return (err); 3142b24ab6bSSebastien Roy } 3152b24ab6bSSebastien Roy } 3162b24ab6bSSebastien Roy } 3172b24ab6bSSebastien Roy 3182b24ab6bSSebastien Roy /* 3192b24ab6bSSebastien Roy * If we're not in the global zone, send the file-descriptor back to 3202b24ab6bSSebastien Roy * our parent in the global zone. 3212b24ab6bSSebastien Roy */ 3222b24ab6bSSebastien Roy if (!inglobalzone) { 3232b24ab6bSSebastien Roy assert(!finglobalzone); 3242b24ab6bSSebastien Roy assert(fd != -1); 3252b24ab6bSSebastien Roy return (ioctl(p[1], I_SENDFD, fd) == -1 ? errno : 0); 3262b24ab6bSSebastien Roy } 3272b24ab6bSSebastien Roy 3282b24ab6bSSebastien Roy /* 3292b24ab6bSSebastien Roy * At this point, we know we're in the global zone. If the file was 3302b24ab6bSSebastien Roy * in a non-global zone, receive the file-descriptor from our child in 3312b24ab6bSSebastien Roy * the non-global zone. 3322b24ab6bSSebastien Roy */ 3332b24ab6bSSebastien Roy if (!finglobalzone) { 3342b24ab6bSSebastien Roy if (ioctl(p[0], I_RECVFD, &recvfd) == -1) 3352b24ab6bSSebastien Roy return (errno); 3362b24ab6bSSebastien Roy fd = recvfd.fd; 3372b24ab6bSSebastien Roy } 3382b24ab6bSSebastien Roy 3392b24ab6bSSebastien Roy zfarg->zfarg_openarg.zopen_fd = fd; 3402b24ab6bSSebastien Roy return (0); 3412b24ab6bSSebastien Roy } 3422b24ab6bSSebastien Roy 3432b24ab6bSSebastien Roy static int 3442b24ab6bSSebastien Roy dlmgmt_zunlink_cb(zfarg_t *zfarg) 3452b24ab6bSSebastien Roy { 3462b24ab6bSSebastien Roy if (zfarg->zfarg_inglobalzone != zfarg->zfarg_finglobalzone) 3472b24ab6bSSebastien Roy return (0); 3482b24ab6bSSebastien Roy return (unlink(zfarg->zfarg_filename) == 0 ? 0 : errno); 3492b24ab6bSSebastien Roy } 3502b24ab6bSSebastien Roy 3512b24ab6bSSebastien Roy static int 3522b24ab6bSSebastien Roy dlmgmt_zrename_cb(zfarg_t *zfarg) 3532b24ab6bSSebastien Roy { 3542b24ab6bSSebastien Roy if (zfarg->zfarg_inglobalzone != zfarg->zfarg_finglobalzone) 3552b24ab6bSSebastien Roy return (0); 3562b24ab6bSSebastien Roy return (rename(zfarg->zfarg_filename, 3572b24ab6bSSebastien Roy zfarg->zfarg_renamearg.zrename_newname) == 0 ? 0 : errno); 3582b24ab6bSSebastien Roy } 3592b24ab6bSSebastien Roy 3602b24ab6bSSebastien Roy /* 3612b24ab6bSSebastien Roy * Same as fopen(3C), except that it opens the file relative to zoneid's zone 3622b24ab6bSSebastien Roy * root. 3632b24ab6bSSebastien Roy */ 3642b24ab6bSSebastien Roy static FILE * 3652b24ab6bSSebastien Roy dlmgmt_zfopen(const char *filename, const char *modestr, zoneid_t zoneid, 3662b24ab6bSSebastien Roy int *err) 3672b24ab6bSSebastien Roy { 3682b24ab6bSSebastien Roy int p[2]; 3692b24ab6bSSebastien Roy zfoparg_t zfoparg; 3702b24ab6bSSebastien Roy FILE *fp = NULL; 3712b24ab6bSSebastien Roy 3722b24ab6bSSebastien Roy if (zoneid != GLOBAL_ZONEID && pipe(p) == -1) { 3732b24ab6bSSebastien Roy *err = errno; 3742b24ab6bSSebastien Roy return (NULL); 3752b24ab6bSSebastien Roy } 3762b24ab6bSSebastien Roy 3772b24ab6bSSebastien Roy zfoparg.zfop_openarg.zopen_modestr = modestr; 3782b24ab6bSSebastien Roy zfoparg.zfop_openarg.zopen_pipe = p; 3792b24ab6bSSebastien Roy *err = dlmgmt_zfop(filename, zoneid, dlmgmt_zopen_cb, &zfoparg); 3802b24ab6bSSebastien Roy if (zoneid != GLOBAL_ZONEID) { 3812b24ab6bSSebastien Roy (void) close(p[0]); 3822b24ab6bSSebastien Roy (void) close(p[1]); 3832b24ab6bSSebastien Roy } 3842b24ab6bSSebastien Roy if (*err == 0) { 3852b24ab6bSSebastien Roy fp = fdopen(zfoparg.zfop_openarg.zopen_fd, modestr); 3862b24ab6bSSebastien Roy if (fp == NULL) { 3872b24ab6bSSebastien Roy *err = errno; 3882b24ab6bSSebastien Roy (void) close(zfoparg.zfop_openarg.zopen_fd); 3892b24ab6bSSebastien Roy } 3902b24ab6bSSebastien Roy } 3912b24ab6bSSebastien Roy return (fp); 3922b24ab6bSSebastien Roy } 3932b24ab6bSSebastien Roy 3942b24ab6bSSebastien Roy /* 3952b24ab6bSSebastien Roy * Same as rename(2), except that old and new are relative to zoneid's zone 3962b24ab6bSSebastien Roy * root. 3972b24ab6bSSebastien Roy */ 3982b24ab6bSSebastien Roy static int 3992b24ab6bSSebastien Roy dlmgmt_zrename(const char *old, const char *new, zoneid_t zoneid) 4002b24ab6bSSebastien Roy { 4012b24ab6bSSebastien Roy zfoparg_t zfoparg; 4022b24ab6bSSebastien Roy 4032b24ab6bSSebastien Roy zfoparg.zfop_renamearg.zrename_newname = new; 4042b24ab6bSSebastien Roy return (dlmgmt_zfop(old, zoneid, dlmgmt_zrename_cb, &zfoparg)); 4052b24ab6bSSebastien Roy } 4062b24ab6bSSebastien Roy 4072b24ab6bSSebastien Roy /* 4082b24ab6bSSebastien Roy * Same as unlink(2), except that filename is relative to zoneid's zone root. 4092b24ab6bSSebastien Roy */ 4102b24ab6bSSebastien Roy static int 4112b24ab6bSSebastien Roy dlmgmt_zunlink(const char *filename, zoneid_t zoneid) 4122b24ab6bSSebastien Roy { 4132b24ab6bSSebastien Roy return (dlmgmt_zfop(filename, zoneid, dlmgmt_zunlink_cb, NULL)); 4142b24ab6bSSebastien Roy } 4152b24ab6bSSebastien Roy 416d62bc4baSyz147064 static size_t 417d62bc4baSyz147064 write_str(char *buffer, size_t buffer_length, char *name, void *value) 418d62bc4baSyz147064 { 419d62bc4baSyz147064 char *ptr = value; 420d62bc4baSyz147064 size_t data_length = strnlen(ptr, buffer_length); 421d62bc4baSyz147064 422d62bc4baSyz147064 /* 423d62bc4baSyz147064 * Strings are assumed to be NULL terminated. In order to fit in 424d62bc4baSyz147064 * the buffer, the string's length must be less then buffer_length. 425d62bc4baSyz147064 * If the value is empty, there's no point in writing it, in fact, 426d62bc4baSyz147064 * we shouldn't even see that case. 427d62bc4baSyz147064 */ 428d62bc4baSyz147064 if (data_length + BASE_PROPERTY_LENGTH(DLADM_TYPE_STR, name) == 429d62bc4baSyz147064 buffer_length || data_length == 0) 430d62bc4baSyz147064 return (0); 431d62bc4baSyz147064 432d62bc4baSyz147064 /* 433d62bc4baSyz147064 * Since we know the string will fit in the buffer, snprintf will 434d62bc4baSyz147064 * always return less than buffer_length, so we can just return 435d62bc4baSyz147064 * whatever snprintf returns. 436d62bc4baSyz147064 */ 437d62bc4baSyz147064 return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%s", 438d62bc4baSyz147064 name, DLADM_TYPE_STR, ptr)); 439d62bc4baSyz147064 } 440d62bc4baSyz147064 441d62bc4baSyz147064 static size_t 442d62bc4baSyz147064 write_boolean(char *buffer, size_t buffer_length, char *name, void *value) 443d62bc4baSyz147064 { 444d62bc4baSyz147064 boolean_t *ptr = value; 445d62bc4baSyz147064 446d62bc4baSyz147064 /* 447d62bc4baSyz147064 * Booleans are either zero or one, so we only need room for two 448d62bc4baSyz147064 * characters in the buffer. 449d62bc4baSyz147064 */ 450d62bc4baSyz147064 if (buffer_length <= 1 + BASE_PROPERTY_LENGTH(DLADM_TYPE_BOOLEAN, name)) 451d62bc4baSyz147064 return (0); 452d62bc4baSyz147064 453d62bc4baSyz147064 return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%d", 454d62bc4baSyz147064 name, DLADM_TYPE_BOOLEAN, *ptr)); 455d62bc4baSyz147064 } 456d62bc4baSyz147064 457d62bc4baSyz147064 static size_t 458d62bc4baSyz147064 write_uint64(char *buffer, size_t buffer_length, char *name, void *value) 459d62bc4baSyz147064 { 460d62bc4baSyz147064 uint64_t *ptr = value; 461d62bc4baSyz147064 462d62bc4baSyz147064 /* 463d62bc4baSyz147064 * Limit checking for uint64_t is a little trickier. 464d62bc4baSyz147064 */ 465d62bc4baSyz147064 if (snprintf(NULL, 0, "%lld", *ptr) + 466d62bc4baSyz147064 BASE_PROPERTY_LENGTH(DLADM_TYPE_UINT64, name) >= buffer_length) 467d62bc4baSyz147064 return (0); 468d62bc4baSyz147064 469d62bc4baSyz147064 return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%lld", 470d62bc4baSyz147064 name, DLADM_TYPE_UINT64, *ptr)); 471d62bc4baSyz147064 } 472d62bc4baSyz147064 473d62bc4baSyz147064 static size_t 474d62bc4baSyz147064 read_str(char *buffer, void **value) 475d62bc4baSyz147064 { 476024b0a25Sseb char *ptr = calloc(MAXLINKATTRVALLEN, sizeof (char)); 477d62bc4baSyz147064 ssize_t len; 478d62bc4baSyz147064 479024b0a25Sseb if (ptr == NULL || (len = strlcpy(ptr, buffer, MAXLINKATTRVALLEN)) 480024b0a25Sseb >= MAXLINKATTRVALLEN) { 481d62bc4baSyz147064 free(ptr); 482d62bc4baSyz147064 return (0); 483d62bc4baSyz147064 } 484d62bc4baSyz147064 485d62bc4baSyz147064 *(char **)value = ptr; 486d62bc4baSyz147064 487d62bc4baSyz147064 /* Account for NULL terminator */ 488d62bc4baSyz147064 return (len + 1); 489d62bc4baSyz147064 } 490d62bc4baSyz147064 491d62bc4baSyz147064 static size_t 492d62bc4baSyz147064 read_boolean(char *buffer, void **value) 493d62bc4baSyz147064 { 494d62bc4baSyz147064 boolean_t *ptr = calloc(1, sizeof (boolean_t)); 495d62bc4baSyz147064 496d62bc4baSyz147064 if (ptr == NULL) 497d62bc4baSyz147064 return (0); 498d62bc4baSyz147064 499d62bc4baSyz147064 *ptr = atoi(buffer); 500d62bc4baSyz147064 *(boolean_t **)value = ptr; 501d62bc4baSyz147064 502d62bc4baSyz147064 return (sizeof (boolean_t)); 503d62bc4baSyz147064 } 504d62bc4baSyz147064 505d62bc4baSyz147064 static size_t 506d62bc4baSyz147064 read_int64(char *buffer, void **value) 507d62bc4baSyz147064 { 508d62bc4baSyz147064 int64_t *ptr = calloc(1, sizeof (int64_t)); 509d62bc4baSyz147064 510d62bc4baSyz147064 if (ptr == NULL) 511d62bc4baSyz147064 return (0); 512d62bc4baSyz147064 513d62bc4baSyz147064 *ptr = (int64_t)atoll(buffer); 514d62bc4baSyz147064 *(int64_t **)value = ptr; 515d62bc4baSyz147064 516d62bc4baSyz147064 return (sizeof (int64_t)); 517d62bc4baSyz147064 } 518d62bc4baSyz147064 5192b24ab6bSSebastien Roy static dlmgmt_db_req_t * 5202b24ab6bSSebastien Roy dlmgmt_db_req_alloc(dlmgmt_db_op_t op, const char *linkname, 5212b24ab6bSSebastien Roy datalink_id_t linkid, zoneid_t zoneid, uint32_t flags, int *err) 5222b24ab6bSSebastien Roy { 5232b24ab6bSSebastien Roy dlmgmt_db_req_t *req; 5242b24ab6bSSebastien Roy 5252b24ab6bSSebastien Roy if ((req = calloc(1, sizeof (dlmgmt_db_req_t))) == NULL) { 5262b24ab6bSSebastien Roy *err = errno; 5272b24ab6bSSebastien Roy } else { 5282b24ab6bSSebastien Roy req->ls_op = op; 5292b24ab6bSSebastien Roy if (linkname != NULL) 5302b24ab6bSSebastien Roy (void) strlcpy(req->ls_link, linkname, MAXLINKNAMELEN); 5312b24ab6bSSebastien Roy req->ls_linkid = linkid; 5322b24ab6bSSebastien Roy req->ls_zoneid = zoneid; 5332b24ab6bSSebastien Roy req->ls_flags = flags; 5342b24ab6bSSebastien Roy } 5352b24ab6bSSebastien Roy return (req); 5362b24ab6bSSebastien Roy } 5372b24ab6bSSebastien Roy 5382b24ab6bSSebastien Roy /* 5392b24ab6bSSebastien Roy * Update the db entry with name "entryname" using information from "linkp". 5402b24ab6bSSebastien Roy */ 541d62bc4baSyz147064 static int 5422b24ab6bSSebastien Roy dlmgmt_db_update(dlmgmt_db_op_t op, const char *entryname, dlmgmt_link_t *linkp, 5432b24ab6bSSebastien Roy uint32_t flags) 544d62bc4baSyz147064 { 545d62bc4baSyz147064 dlmgmt_db_req_t *req; 546d62bc4baSyz147064 int err; 547d62bc4baSyz147064 5482b24ab6bSSebastien Roy /* It is either a persistent request or an active request, not both. */ 549d62bc4baSyz147064 assert((flags == DLMGMT_PERSIST) || (flags == DLMGMT_ACTIVE)); 550d62bc4baSyz147064 5512b24ab6bSSebastien Roy if ((req = dlmgmt_db_req_alloc(op, entryname, linkp->ll_linkid, 5522b24ab6bSSebastien Roy linkp->ll_zoneid, flags, &err)) == NULL) 5532b24ab6bSSebastien Roy return (err); 554d62bc4baSyz147064 555d62bc4baSyz147064 /* 556d62bc4baSyz147064 * If the return error is EINPROGRESS, this request is handled 557d62bc4baSyz147064 * asynchronously; return success. 558d62bc4baSyz147064 */ 559d62bc4baSyz147064 err = dlmgmt_process_db_req(req); 560d62bc4baSyz147064 if (err != EINPROGRESS) 561d62bc4baSyz147064 free(req); 562d62bc4baSyz147064 else 563d62bc4baSyz147064 err = 0; 564d62bc4baSyz147064 return (err); 565d62bc4baSyz147064 } 566d62bc4baSyz147064 567d62bc4baSyz147064 #define DLMGMT_DB_OP_STR(op) \ 568d62bc4baSyz147064 (((op) == DLMGMT_DB_OP_READ) ? "read" : \ 569d62bc4baSyz147064 (((op) == DLMGMT_DB_OP_WRITE) ? "write" : "delete")) 570d62bc4baSyz147064 571d62bc4baSyz147064 #define DLMGMT_DB_CONF_STR(flag) \ 572d62bc4baSyz147064 (((flag) == DLMGMT_ACTIVE) ? "active" : \ 573d62bc4baSyz147064 (((flag) == DLMGMT_PERSIST) ? "persistent" : "")) 574d62bc4baSyz147064 575d62bc4baSyz147064 static int 576d62bc4baSyz147064 dlmgmt_process_db_req(dlmgmt_db_req_t *req) 577d62bc4baSyz147064 { 578d62bc4baSyz147064 pthread_t tid; 579d62bc4baSyz147064 boolean_t writeop; 580d62bc4baSyz147064 int err; 581d62bc4baSyz147064 582d62bc4baSyz147064 /* 583d62bc4baSyz147064 * If there are already pending "write" requests, queue this request in 584d62bc4baSyz147064 * the pending list. Note that this function is called while the 585d62bc4baSyz147064 * dlmgmt_rw_lock is held, so it is safe to access the global variables. 586d62bc4baSyz147064 */ 587d62bc4baSyz147064 writeop = (req->ls_op != DLMGMT_DB_OP_READ); 588d62bc4baSyz147064 if (writeop && (req->ls_flags == DLMGMT_PERSIST) && 589d62bc4baSyz147064 (dlmgmt_db_req_head != NULL)) { 590d62bc4baSyz147064 dlmgmt_db_req_tail->ls_next = req; 591d62bc4baSyz147064 dlmgmt_db_req_tail = req; 592d62bc4baSyz147064 return (EINPROGRESS); 593d62bc4baSyz147064 } 594d62bc4baSyz147064 595d62bc4baSyz147064 err = dlmgmt_process_db_onereq(req, writeop); 5962b24ab6bSSebastien Roy if (err != EINPROGRESS && err != 0 && err != ENOENT) { 597d62bc4baSyz147064 /* 5982b24ab6bSSebastien Roy * Log the error unless the request processing is still in 5992b24ab6bSSebastien Roy * progress or if the configuration file hasn't been created 6002b24ab6bSSebastien Roy * yet (ENOENT). 601d62bc4baSyz147064 */ 602d62bc4baSyz147064 dlmgmt_log(LOG_WARNING, "dlmgmt_process_db_onereq() %s " 603d62bc4baSyz147064 "operation on %s configuration failed: %s", 604d62bc4baSyz147064 DLMGMT_DB_OP_STR(req->ls_op), 605d62bc4baSyz147064 DLMGMT_DB_CONF_STR(req->ls_flags), strerror(err)); 606d62bc4baSyz147064 } 607d62bc4baSyz147064 608d62bc4baSyz147064 if (err == EINPROGRESS) { 609d62bc4baSyz147064 assert(req->ls_flags == DLMGMT_PERSIST); 610d62bc4baSyz147064 assert(writeop && dlmgmt_db_req_head == NULL); 611d62bc4baSyz147064 dlmgmt_db_req_tail = dlmgmt_db_req_head = req; 612d62bc4baSyz147064 err = pthread_create(&tid, NULL, dlmgmt_db_update_thread, NULL); 613d62bc4baSyz147064 if (err == 0) 614d62bc4baSyz147064 return (EINPROGRESS); 615d62bc4baSyz147064 } 616d62bc4baSyz147064 return (err); 617d62bc4baSyz147064 } 618d62bc4baSyz147064 619d62bc4baSyz147064 static int 620d62bc4baSyz147064 dlmgmt_process_db_onereq(dlmgmt_db_req_t *req, boolean_t writeop) 621d62bc4baSyz147064 { 622d62bc4baSyz147064 int err = 0; 623d62bc4baSyz147064 FILE *fp, *nfp = NULL; 624d62bc4baSyz147064 char file[MAXPATHLEN]; 625d62bc4baSyz147064 char newfile[MAXPATHLEN]; 626d62bc4baSyz147064 627d62bc4baSyz147064 DLMGMT_MAKE_FILE_DB_PATH(file, (req->ls_flags == DLMGMT_PERSIST)); 6282b24ab6bSSebastien Roy fp = dlmgmt_zfopen(file, "r", req->ls_zoneid, &err); 629d62bc4baSyz147064 /* 6302b24ab6bSSebastien Roy * Note that it is not an error if the file doesn't exist. If we're 6312b24ab6bSSebastien Roy * reading, we treat this case the same way as an empty file. If 6322b24ab6bSSebastien Roy * we're writing, the file will be created when we open the file for 6332b24ab6bSSebastien Roy * writing below. 634d62bc4baSyz147064 */ 6352b24ab6bSSebastien Roy if (fp == NULL && !writeop) 6362b24ab6bSSebastien Roy return (err); 637d62bc4baSyz147064 638d62bc4baSyz147064 if (writeop) { 639d62bc4baSyz147064 (void) snprintf(newfile, MAXPATHLEN, "%s.new", file); 6402b24ab6bSSebastien Roy nfp = dlmgmt_zfopen(newfile, "w", req->ls_zoneid, &err); 6412b24ab6bSSebastien Roy if (nfp == NULL) { 6422b24ab6bSSebastien Roy /* 6432b24ab6bSSebastien Roy * EROFS can happen at boot when the file system is 6442b24ab6bSSebastien Roy * read-only. Return EINPROGRESS so that the caller 6452b24ab6bSSebastien Roy * can add this request to the pending request list 6462b24ab6bSSebastien Roy * and start a retry thread. 6472b24ab6bSSebastien Roy */ 6482b24ab6bSSebastien Roy err = (errno == EROFS ? EINPROGRESS : errno); 649d62bc4baSyz147064 goto done; 650d62bc4baSyz147064 } 651d62bc4baSyz147064 } 6522b24ab6bSSebastien Roy if (writeop) { 6532b24ab6bSSebastien Roy if ((err = process_db_write(req, fp, nfp)) == 0) 6542b24ab6bSSebastien Roy err = dlmgmt_zrename(newfile, file, req->ls_zoneid); 6552b24ab6bSSebastien Roy } else { 6562b24ab6bSSebastien Roy err = process_db_read(req, fp); 6572b24ab6bSSebastien Roy } 658d62bc4baSyz147064 659d62bc4baSyz147064 done: 660d62bc4baSyz147064 if (nfp != NULL) { 661d62bc4baSyz147064 (void) fclose(nfp); 662d62bc4baSyz147064 if (err != 0) 6632b24ab6bSSebastien Roy (void) dlmgmt_zunlink(newfile, req->ls_zoneid); 664d62bc4baSyz147064 } 665d62bc4baSyz147064 (void) fclose(fp); 666d62bc4baSyz147064 return (err); 667d62bc4baSyz147064 } 668d62bc4baSyz147064 669d62bc4baSyz147064 /*ARGSUSED*/ 670d62bc4baSyz147064 static void * 671d62bc4baSyz147064 dlmgmt_db_update_thread(void *arg) 672d62bc4baSyz147064 { 673d62bc4baSyz147064 dlmgmt_db_req_t *req; 674d62bc4baSyz147064 675d62bc4baSyz147064 dlmgmt_table_lock(B_TRUE); 676d62bc4baSyz147064 677d62bc4baSyz147064 assert(dlmgmt_db_req_head != NULL); 678d62bc4baSyz147064 while ((req = dlmgmt_db_req_head) != NULL) { 679d62bc4baSyz147064 assert(req->ls_flags == DLMGMT_PERSIST); 6802b24ab6bSSebastien Roy if (dlmgmt_process_db_onereq(req, B_TRUE) == EINPROGRESS) { 681d62bc4baSyz147064 /* 682d62bc4baSyz147064 * The filesystem is still read only. Go to sleep and 683d62bc4baSyz147064 * try again. 684d62bc4baSyz147064 */ 685d62bc4baSyz147064 dlmgmt_table_unlock(); 686d62bc4baSyz147064 (void) sleep(5); 687d62bc4baSyz147064 dlmgmt_table_lock(B_TRUE); 688d62bc4baSyz147064 continue; 689d62bc4baSyz147064 } 690d62bc4baSyz147064 691d62bc4baSyz147064 /* 692d62bc4baSyz147064 * The filesystem is no longer read only. Continue processing 693d62bc4baSyz147064 * and remove the request from the pending list. 694d62bc4baSyz147064 */ 695d62bc4baSyz147064 dlmgmt_db_req_head = req->ls_next; 696d62bc4baSyz147064 if (dlmgmt_db_req_tail == req) { 697d62bc4baSyz147064 assert(dlmgmt_db_req_head == NULL); 698d62bc4baSyz147064 dlmgmt_db_req_tail = NULL; 699d62bc4baSyz147064 } 700d62bc4baSyz147064 free(req); 701d62bc4baSyz147064 } 702d62bc4baSyz147064 703d62bc4baSyz147064 dlmgmt_table_unlock(); 704d62bc4baSyz147064 return (NULL); 705d62bc4baSyz147064 } 706d62bc4baSyz147064 707d62bc4baSyz147064 static int 708d62bc4baSyz147064 parse_linkprops(char *buf, dlmgmt_link_t *linkp) 709d62bc4baSyz147064 { 710d62bc4baSyz147064 boolean_t found_type = B_FALSE; 711d62bc4baSyz147064 dladm_datatype_t type = DLADM_TYPE_STR; 712d62bc4baSyz147064 int i, len; 713d62bc4baSyz147064 char *curr; 714d62bc4baSyz147064 char attr_name[MAXLINKATTRLEN]; 715d62bc4baSyz147064 size_t attr_buf_len = 0; 716d62bc4baSyz147064 void *attr_buf = NULL; 717d62bc4baSyz147064 718d62bc4baSyz147064 curr = buf; 719d62bc4baSyz147064 len = strlen(buf); 720d62bc4baSyz147064 attr_name[0] = '\0'; 72132715170SCathy Zhou for (i = 0; i < len; i++) { 722d62bc4baSyz147064 char c = buf[i]; 723d62bc4baSyz147064 boolean_t match = (c == '=' || 724d62bc4baSyz147064 (c == ',' && !found_type) || c == ';'); 725d62bc4baSyz147064 726d62bc4baSyz147064 /* 727d62bc4baSyz147064 * Move to the next character if there is no match and 728d62bc4baSyz147064 * if we have not reached the last character. 729d62bc4baSyz147064 */ 730d62bc4baSyz147064 if (!match && i != len - 1) 731d62bc4baSyz147064 continue; 732d62bc4baSyz147064 733d62bc4baSyz147064 if (match) { 734d62bc4baSyz147064 /* 735d62bc4baSyz147064 * NUL-terminate the string pointed to by 'curr'. 736d62bc4baSyz147064 */ 737d62bc4baSyz147064 buf[i] = '\0'; 738d62bc4baSyz147064 if (*curr == '\0') 739d62bc4baSyz147064 goto parse_fail; 740d62bc4baSyz147064 } 741d62bc4baSyz147064 742d62bc4baSyz147064 if (attr_name[0] != '\0' && found_type) { 743d62bc4baSyz147064 /* 744d62bc4baSyz147064 * We get here after we have processed the "<prop>=" 745d62bc4baSyz147064 * pattern. The pattern we are now interested in is 746d62bc4baSyz147064 * "<val>;". 747d62bc4baSyz147064 */ 748d62bc4baSyz147064 if (c == '=') 749d62bc4baSyz147064 goto parse_fail; 750d62bc4baSyz147064 7512b24ab6bSSebastien Roy if (strcmp(attr_name, "linkid") == 0) { 75232715170SCathy Zhou if (read_int64(curr, &attr_buf) == 0) 75332715170SCathy Zhou goto parse_fail; 7542b24ab6bSSebastien Roy linkp->ll_linkid = 7552b24ab6bSSebastien Roy (datalink_class_t)*(int64_t *)attr_buf; 7562b24ab6bSSebastien Roy } else if (strcmp(attr_name, "name") == 0) { 75732715170SCathy Zhou if (read_str(curr, &attr_buf) == 0) 75832715170SCathy Zhou goto parse_fail; 759d62bc4baSyz147064 (void) snprintf(linkp->ll_link, 760d62bc4baSyz147064 MAXLINKNAMELEN, "%s", attr_buf); 761d62bc4baSyz147064 } else if (strcmp(attr_name, "class") == 0) { 76232715170SCathy Zhou if (read_int64(curr, &attr_buf) == 0) 76332715170SCathy Zhou goto parse_fail; 764d62bc4baSyz147064 linkp->ll_class = 765d62bc4baSyz147064 (datalink_class_t)*(int64_t *)attr_buf; 766d62bc4baSyz147064 } else if (strcmp(attr_name, "media") == 0) { 76732715170SCathy Zhou if (read_int64(curr, &attr_buf) == 0) 76832715170SCathy Zhou goto parse_fail; 769d62bc4baSyz147064 linkp->ll_media = 770d62bc4baSyz147064 (uint32_t)*(int64_t *)attr_buf; 771d62bc4baSyz147064 } else { 772d62bc4baSyz147064 attr_buf_len = translators[type].read_func(curr, 773d62bc4baSyz147064 &attr_buf); 77432715170SCathy Zhou if (attr_buf_len == 0) 77532715170SCathy Zhou goto parse_fail; 77632715170SCathy Zhou 77732715170SCathy Zhou if (linkattr_set(&(linkp->ll_head), attr_name, 77832715170SCathy Zhou attr_buf, attr_buf_len, type) != 0) { 77932715170SCathy Zhou free(attr_buf); 78032715170SCathy Zhou goto parse_fail; 78132715170SCathy Zhou } 782d62bc4baSyz147064 } 783d62bc4baSyz147064 784d62bc4baSyz147064 free(attr_buf); 785d62bc4baSyz147064 attr_name[0] = '\0'; 786d62bc4baSyz147064 found_type = B_FALSE; 787d62bc4baSyz147064 } else if (attr_name[0] != '\0') { 788d62bc4baSyz147064 /* 789d62bc4baSyz147064 * Non-zero length attr_name and found_type of false 790d62bc4baSyz147064 * indicates that we have not found the type for this 791d62bc4baSyz147064 * attribute. The pattern now is "<type>,<val>;", we 792d62bc4baSyz147064 * want the <type> part of the pattern. 793d62bc4baSyz147064 */ 794d62bc4baSyz147064 for (type = 0; type < ntranslators; type++) { 795d62bc4baSyz147064 if (strcmp(curr, 796d62bc4baSyz147064 translators[type].type_name) == 0) { 797d62bc4baSyz147064 found_type = B_TRUE; 798d62bc4baSyz147064 break; 799d62bc4baSyz147064 } 800d62bc4baSyz147064 } 801d62bc4baSyz147064 802d62bc4baSyz147064 if (!found_type) 803d62bc4baSyz147064 goto parse_fail; 804d62bc4baSyz147064 } else { 805d62bc4baSyz147064 /* 806d62bc4baSyz147064 * A zero length attr_name indicates we are looking 807d62bc4baSyz147064 * at the beginning of a link attribute. 808d62bc4baSyz147064 */ 809d62bc4baSyz147064 if (c != '=') 810d62bc4baSyz147064 goto parse_fail; 811d62bc4baSyz147064 812d62bc4baSyz147064 (void) snprintf(attr_name, MAXLINKATTRLEN, "%s", curr); 813d62bc4baSyz147064 } 814d62bc4baSyz147064 curr = buf + i + 1; 815d62bc4baSyz147064 } 816d62bc4baSyz147064 817*f689bed1SRishi Srivatsavai /* Correct any erroneous IPTUN datalink class constant in the file */ 818*f689bed1SRishi Srivatsavai if (linkp->ll_class == 0x60) { 819*f689bed1SRishi Srivatsavai linkp->ll_class = DATALINK_CLASS_IPTUN; 820*f689bed1SRishi Srivatsavai rewrite_needed = B_TRUE; 821*f689bed1SRishi Srivatsavai } 822*f689bed1SRishi Srivatsavai 82332715170SCathy Zhou return (0); 824d62bc4baSyz147064 825d62bc4baSyz147064 parse_fail: 82632715170SCathy Zhou /* 82732715170SCathy Zhou * Free linkp->ll_head (link attribute list) 82832715170SCathy Zhou */ 82932715170SCathy Zhou linkattr_destroy(linkp); 830d62bc4baSyz147064 return (-1); 831d62bc4baSyz147064 } 832d62bc4baSyz147064 833d62bc4baSyz147064 static boolean_t 8342b24ab6bSSebastien Roy process_link_line(char *buf, dlmgmt_link_t *linkp) 835d62bc4baSyz147064 { 836d62bc4baSyz147064 int i, len, llen; 837d62bc4baSyz147064 char *str, *lasts; 838d62bc4baSyz147064 char tmpbuf[MAXLINELEN]; 839d62bc4baSyz147064 8402b24ab6bSSebastien Roy bzero(linkp, sizeof (*linkp)); 8412b24ab6bSSebastien Roy linkp->ll_linkid = DATALINK_INVALID_LINKID; 8422b24ab6bSSebastien Roy 843d62bc4baSyz147064 /* 844d62bc4baSyz147064 * Use a copy of buf for parsing so that we can do whatever we want. 845d62bc4baSyz147064 */ 846d62bc4baSyz147064 (void) strlcpy(tmpbuf, buf, MAXLINELEN); 847d62bc4baSyz147064 848d62bc4baSyz147064 /* 849d62bc4baSyz147064 * Skip leading spaces, blank lines, and comments. 850d62bc4baSyz147064 */ 851d62bc4baSyz147064 len = strlen(tmpbuf); 852d62bc4baSyz147064 for (i = 0; i < len; i++) { 853d62bc4baSyz147064 if (!isspace(tmpbuf[i])) 854d62bc4baSyz147064 break; 855d62bc4baSyz147064 } 8562b24ab6bSSebastien Roy if (i == len || tmpbuf[i] == '#') 857d62bc4baSyz147064 return (B_TRUE); 858d62bc4baSyz147064 859d62bc4baSyz147064 str = tmpbuf + i; 860d62bc4baSyz147064 /* 8612b24ab6bSSebastien Roy * Find the link name and assign it to the link structure. 862d62bc4baSyz147064 */ 863d62bc4baSyz147064 if (strtok_r(str, " \n\t", &lasts) == NULL) 864d62bc4baSyz147064 goto fail; 865d62bc4baSyz147064 866d62bc4baSyz147064 llen = strlen(str); 8672b24ab6bSSebastien Roy /* 8682b24ab6bSSebastien Roy * Note that a previous version of the persistent datalink.conf file 8692b24ab6bSSebastien Roy * stored the linkid as the first field. In that case, the name will 8702b24ab6bSSebastien Roy * be obtained through parse_linkprops from a property with the format 8712b24ab6bSSebastien Roy * "name=<linkname>". If we encounter such a format, we set 8722b24ab6bSSebastien Roy * rewrite_needed so that dlmgmt_db_init() can rewrite the file with 8732b24ab6bSSebastien Roy * the new format after it's done reading in the data. 8742b24ab6bSSebastien Roy */ 8752b24ab6bSSebastien Roy if (isdigit(str[0])) { 876d62bc4baSyz147064 linkp->ll_linkid = atoi(str); 8772b24ab6bSSebastien Roy rewrite_needed = B_TRUE; 8782b24ab6bSSebastien Roy } else { 8792b24ab6bSSebastien Roy if (strlcpy(linkp->ll_link, str, sizeof (linkp->ll_link)) >= 8802b24ab6bSSebastien Roy sizeof (linkp->ll_link)) 8812b24ab6bSSebastien Roy goto fail; 8822b24ab6bSSebastien Roy } 883d62bc4baSyz147064 884d62bc4baSyz147064 str += llen + 1; 885d62bc4baSyz147064 if (str >= tmpbuf + len) 886d62bc4baSyz147064 goto fail; 887d62bc4baSyz147064 888d62bc4baSyz147064 /* 889d62bc4baSyz147064 * Now find the list of link properties. 890d62bc4baSyz147064 */ 891d62bc4baSyz147064 if ((str = strtok_r(str, " \n\t", &lasts)) == NULL) 892d62bc4baSyz147064 goto fail; 893d62bc4baSyz147064 894d62bc4baSyz147064 if (parse_linkprops(str, linkp) < 0) 895d62bc4baSyz147064 goto fail; 896d62bc4baSyz147064 897d62bc4baSyz147064 return (B_TRUE); 898d62bc4baSyz147064 899d62bc4baSyz147064 fail: 900d62bc4baSyz147064 /* 901d62bc4baSyz147064 * Delete corrupted line. 902d62bc4baSyz147064 */ 903d62bc4baSyz147064 buf[0] = '\0'; 904d62bc4baSyz147064 return (B_FALSE); 905d62bc4baSyz147064 } 906d62bc4baSyz147064 9072b24ab6bSSebastien Roy /* 9082b24ab6bSSebastien Roy * Find any properties in linkp that refer to "old", and rename to "new". 9092b24ab6bSSebastien Roy * Return B_TRUE if any renaming occurred. 9102b24ab6bSSebastien Roy */ 9112b24ab6bSSebastien Roy static int 9122b24ab6bSSebastien Roy dlmgmt_attr_rename(dlmgmt_link_t *linkp, const char *old, const char *new, 9132b24ab6bSSebastien Roy boolean_t *renamed) 9142b24ab6bSSebastien Roy { 9152b24ab6bSSebastien Roy dlmgmt_linkattr_t *attrp; 9162b24ab6bSSebastien Roy char *newval = NULL, *pname; 9172b24ab6bSSebastien Roy char valcp[MAXLINKATTRVALLEN]; 9182b24ab6bSSebastien Roy size_t newsize; 9192b24ab6bSSebastien Roy 9202b24ab6bSSebastien Roy *renamed = B_FALSE; 9212b24ab6bSSebastien Roy 9222b24ab6bSSebastien Roy if ((attrp = linkattr_find(linkp->ll_head, "linkover")) != NULL || 9232b24ab6bSSebastien Roy (attrp = linkattr_find(linkp->ll_head, "simnetpeer")) != NULL) { 9242b24ab6bSSebastien Roy if (strcmp(old, (char *)attrp->lp_val) == 0) { 9252b24ab6bSSebastien Roy newsize = strlen(new) + 1; 9262b24ab6bSSebastien Roy if ((newval = malloc(newsize)) == NULL) 9272b24ab6bSSebastien Roy return (errno); 9282b24ab6bSSebastien Roy (void) strcpy(newval, new); 9292b24ab6bSSebastien Roy free(attrp->lp_val); 9302b24ab6bSSebastien Roy attrp->lp_val = newval; 9312b24ab6bSSebastien Roy attrp->lp_sz = newsize; 9322b24ab6bSSebastien Roy *renamed = B_TRUE; 9332b24ab6bSSebastien Roy } 9342b24ab6bSSebastien Roy return (0); 9352b24ab6bSSebastien Roy } 9362b24ab6bSSebastien Roy 9372b24ab6bSSebastien Roy if ((attrp = linkattr_find(linkp->ll_head, "portnames")) == NULL) 9382b24ab6bSSebastien Roy return (0); 9392b24ab6bSSebastien Roy 9402b24ab6bSSebastien Roy /* <linkname>:[<linkname>:]... */ 9412b24ab6bSSebastien Roy if ((newval = calloc(MAXLINKATTRVALLEN, sizeof (char))) == NULL) 9422b24ab6bSSebastien Roy return (errno); 9432b24ab6bSSebastien Roy 9442b24ab6bSSebastien Roy bcopy(attrp->lp_val, valcp, sizeof (valcp)); 9452b24ab6bSSebastien Roy pname = strtok(valcp, ":"); 9462b24ab6bSSebastien Roy while (pname != NULL) { 9472b24ab6bSSebastien Roy if (strcmp(pname, old) == 0) { 9482b24ab6bSSebastien Roy (void) strcat(newval, new); 9492b24ab6bSSebastien Roy *renamed = B_TRUE; 9502b24ab6bSSebastien Roy } else { 9512b24ab6bSSebastien Roy (void) strcat(newval, pname); 9522b24ab6bSSebastien Roy } 9532b24ab6bSSebastien Roy (void) strcat(newval, ":"); 9542b24ab6bSSebastien Roy pname = strtok(NULL, ":"); 9552b24ab6bSSebastien Roy } 9562b24ab6bSSebastien Roy if (*renamed) { 9572b24ab6bSSebastien Roy free(attrp->lp_val); 9582b24ab6bSSebastien Roy attrp->lp_val = newval; 9592b24ab6bSSebastien Roy attrp->lp_sz = strlen(newval) + 1; 9602b24ab6bSSebastien Roy } else { 9612b24ab6bSSebastien Roy free(newval); 9622b24ab6bSSebastien Roy } 9632b24ab6bSSebastien Roy return (0); 9642b24ab6bSSebastien Roy } 9652b24ab6bSSebastien Roy 966d62bc4baSyz147064 static int 967d62bc4baSyz147064 process_db_write(dlmgmt_db_req_t *req, FILE *fp, FILE *nfp) 968d62bc4baSyz147064 { 969d62bc4baSyz147064 boolean_t done = B_FALSE; 970d62bc4baSyz147064 int err = 0; 9712b24ab6bSSebastien Roy dlmgmt_link_t link_in_file, *linkp = NULL, *dblinkp; 9722b24ab6bSSebastien Roy boolean_t persist = (req->ls_flags == DLMGMT_PERSIST); 9732b24ab6bSSebastien Roy boolean_t writeall, rename, attr_renamed; 974d62bc4baSyz147064 char buf[MAXLINELEN]; 975d62bc4baSyz147064 9762b24ab6bSSebastien Roy writeall = (req->ls_linkid == DATALINK_ALL_LINKID); 9772b24ab6bSSebastien Roy 9782b24ab6bSSebastien Roy if (req->ls_op == DLMGMT_DB_OP_WRITE && !writeall) { 979d62bc4baSyz147064 /* 980d62bc4baSyz147064 * find the link in the avl tree with the given linkid. 981d62bc4baSyz147064 */ 9822b24ab6bSSebastien Roy linkp = link_by_id(req->ls_linkid, req->ls_zoneid); 983d62bc4baSyz147064 if (linkp == NULL || (linkp->ll_flags & req->ls_flags) == 0) { 984d62bc4baSyz147064 /* 985d62bc4baSyz147064 * This link has already been changed. This could 986d62bc4baSyz147064 * happen if the request is pending because of 987d62bc4baSyz147064 * read-only file-system. If so, we are done. 988d62bc4baSyz147064 */ 989d62bc4baSyz147064 return (0); 990d62bc4baSyz147064 } 9912b24ab6bSSebastien Roy /* 9922b24ab6bSSebastien Roy * In the case of a rename, linkp's name has been updated to 9932b24ab6bSSebastien Roy * the new name, and req->ls_link is the old link name. 9942b24ab6bSSebastien Roy */ 9952b24ab6bSSebastien Roy rename = (strcmp(req->ls_link, linkp->ll_link) != 0); 996d62bc4baSyz147064 } 997d62bc4baSyz147064 9982b24ab6bSSebastien Roy /* 9992b24ab6bSSebastien Roy * fp can be NULL if the file didn't initially exist and we're 10002b24ab6bSSebastien Roy * creating it as part of this write operation. 10012b24ab6bSSebastien Roy */ 10022b24ab6bSSebastien Roy if (fp == NULL) 10032b24ab6bSSebastien Roy goto write; 10042b24ab6bSSebastien Roy 1005d62bc4baSyz147064 while (err == 0 && fgets(buf, sizeof (buf), fp) != NULL && 1006d62bc4baSyz147064 process_link_line(buf, &link_in_file)) { 100732715170SCathy Zhou /* 100832715170SCathy Zhou * Only the link name is needed. Free the memory allocated for 100932715170SCathy Zhou * the link attributes list of link_in_file. 101032715170SCathy Zhou */ 101132715170SCathy Zhou linkattr_destroy(&link_in_file); 101232715170SCathy Zhou 10132b24ab6bSSebastien Roy if (link_in_file.ll_link[0] == '\0' || done) { 1014d62bc4baSyz147064 /* 10150dc974a9SCathy Zhou * this is a comment line or we are done updating the 10162b24ab6bSSebastien Roy * line for the specified link, write the rest of 10172b24ab6bSSebastien Roy * lines out. 1018d62bc4baSyz147064 */ 1019d62bc4baSyz147064 if (fputs(buf, nfp) == EOF) 1020d62bc4baSyz147064 err = errno; 1021d62bc4baSyz147064 continue; 1022d62bc4baSyz147064 } 1023d62bc4baSyz147064 1024d62bc4baSyz147064 switch (req->ls_op) { 1025d62bc4baSyz147064 case DLMGMT_DB_OP_WRITE: 1026d62bc4baSyz147064 /* 10272b24ab6bSSebastien Roy * For write operations, we generate a new output line 10282b24ab6bSSebastien Roy * if we're either writing all links (writeall) or if 10292b24ab6bSSebastien Roy * the name of the link in the file matches the one 10302b24ab6bSSebastien Roy * we're looking for. Otherwise, we write out the 10312b24ab6bSSebastien Roy * buffer as-is. 10322b24ab6bSSebastien Roy * 10332b24ab6bSSebastien Roy * If we're doing a rename operation, ensure that any 10342b24ab6bSSebastien Roy * references to the link being renamed in link 10352b24ab6bSSebastien Roy * properties are also updated before we write 10362b24ab6bSSebastien Roy * anything. 1037d62bc4baSyz147064 */ 10382b24ab6bSSebastien Roy if (writeall) { 10392b24ab6bSSebastien Roy linkp = link_by_name(link_in_file.ll_link, 10402b24ab6bSSebastien Roy req->ls_zoneid); 1041d62bc4baSyz147064 } 10422b24ab6bSSebastien Roy if (writeall || strcmp(req->ls_link, 10432b24ab6bSSebastien Roy link_in_file.ll_link) == 0) { 10442b24ab6bSSebastien Roy generate_link_line(linkp, persist, buf); 10452b24ab6bSSebastien Roy if (!writeall && !rename) 10462b24ab6bSSebastien Roy done = B_TRUE; 10472b24ab6bSSebastien Roy } else if (rename && persist) { 10482b24ab6bSSebastien Roy dblinkp = link_by_name(link_in_file.ll_link, 10492b24ab6bSSebastien Roy req->ls_zoneid); 10502b24ab6bSSebastien Roy err = dlmgmt_attr_rename(dblinkp, req->ls_link, 10512b24ab6bSSebastien Roy linkp->ll_link, &attr_renamed); 10522b24ab6bSSebastien Roy if (err != 0) 10532b24ab6bSSebastien Roy break; 10542b24ab6bSSebastien Roy if (attr_renamed) { 10552b24ab6bSSebastien Roy generate_link_line(dblinkp, persist, 10562b24ab6bSSebastien Roy buf); 10572b24ab6bSSebastien Roy } 10582b24ab6bSSebastien Roy } 10592b24ab6bSSebastien Roy if (fputs(buf, nfp) == EOF) 10602b24ab6bSSebastien Roy err = errno; 1061d62bc4baSyz147064 break; 1062d62bc4baSyz147064 case DLMGMT_DB_OP_DELETE: 1063d62bc4baSyz147064 /* 1064d62bc4baSyz147064 * Delete is simple. If buf does not represent the 1065d62bc4baSyz147064 * link we're deleting, write it out. 1066d62bc4baSyz147064 */ 10672b24ab6bSSebastien Roy if (strcmp(req->ls_link, link_in_file.ll_link) != 0) { 1068d62bc4baSyz147064 if (fputs(buf, nfp) == EOF) 1069d62bc4baSyz147064 err = errno; 1070d62bc4baSyz147064 } else { 1071d62bc4baSyz147064 done = B_TRUE; 1072d62bc4baSyz147064 } 1073d62bc4baSyz147064 break; 1074d62bc4baSyz147064 case DLMGMT_DB_OP_READ: 1075d62bc4baSyz147064 default: 1076d62bc4baSyz147064 err = EINVAL; 1077d62bc4baSyz147064 break; 1078d62bc4baSyz147064 } 1079d62bc4baSyz147064 } 1080d62bc4baSyz147064 10812b24ab6bSSebastien Roy write: 1082d62bc4baSyz147064 /* 10832b24ab6bSSebastien Roy * If we get to the end of the file and have not seen what linkid 10842b24ab6bSSebastien Roy * points to, write it out then. 1085d62bc4baSyz147064 */ 10862b24ab6bSSebastien Roy if (req->ls_op == DLMGMT_DB_OP_WRITE && !writeall && !rename && !done) { 10872b24ab6bSSebastien Roy generate_link_line(linkp, persist, buf); 1088d62bc4baSyz147064 done = B_TRUE; 1089d62bc4baSyz147064 if (fputs(buf, nfp) == EOF) 1090d62bc4baSyz147064 err = errno; 1091d62bc4baSyz147064 } 1092d62bc4baSyz147064 1093d62bc4baSyz147064 return (err); 1094d62bc4baSyz147064 } 1095d62bc4baSyz147064 1096d62bc4baSyz147064 static int 10972b24ab6bSSebastien Roy process_db_read(dlmgmt_db_req_t *req, FILE *fp) 1098d62bc4baSyz147064 { 1099d62bc4baSyz147064 avl_index_t name_where, id_where; 11002b24ab6bSSebastien Roy dlmgmt_link_t link_in_file, *newlink, *link_in_db; 1101d62bc4baSyz147064 char buf[MAXLINELEN]; 1102d62bc4baSyz147064 int err = 0; 1103d62bc4baSyz147064 1104d62bc4baSyz147064 /* 1105d62bc4baSyz147064 * This loop processes each line of the configuration file. 1106d62bc4baSyz147064 */ 1107d62bc4baSyz147064 while (fgets(buf, MAXLINELEN, fp) != NULL) { 1108d62bc4baSyz147064 if (!process_link_line(buf, &link_in_file)) { 1109d62bc4baSyz147064 err = EINVAL; 1110d62bc4baSyz147064 break; 1111d62bc4baSyz147064 } 1112d62bc4baSyz147064 1113d62bc4baSyz147064 /* 1114d62bc4baSyz147064 * Skip the comment line. 1115d62bc4baSyz147064 */ 111632715170SCathy Zhou if (link_in_file.ll_link[0] == '\0') { 111732715170SCathy Zhou linkattr_destroy(&link_in_file); 1118d62bc4baSyz147064 continue; 111932715170SCathy Zhou } 1120d62bc4baSyz147064 11212b24ab6bSSebastien Roy if ((req->ls_flags & DLMGMT_ACTIVE) && 112232715170SCathy Zhou link_in_file.ll_linkid == DATALINK_INVALID_LINKID) { 112332715170SCathy Zhou linkattr_destroy(&link_in_file); 11242b24ab6bSSebastien Roy continue; 112532715170SCathy Zhou } 11262b24ab6bSSebastien Roy 11272b24ab6bSSebastien Roy link_in_file.ll_zoneid = req->ls_zoneid; 1128*f689bed1SRishi Srivatsavai link_in_db = link_by_name(link_in_file.ll_link, 1129*f689bed1SRishi Srivatsavai link_in_file.ll_zoneid); 11302b24ab6bSSebastien Roy if (link_in_db != NULL) { 1131d62bc4baSyz147064 /* 11322b24ab6bSSebastien Roy * If the link in the database already has the flag 11332b24ab6bSSebastien Roy * for this request set, then the entry is a 11342b24ab6bSSebastien Roy * duplicate. If it's not a duplicate, then simply 11352b24ab6bSSebastien Roy * turn on the appropriate flag on the existing link. 1136d62bc4baSyz147064 */ 11372b24ab6bSSebastien Roy if (link_in_db->ll_flags & req->ls_flags) { 11382b24ab6bSSebastien Roy dlmgmt_log(LOG_WARNING, "Duplicate links " 11392b24ab6bSSebastien Roy "in the repository: %s", 11402b24ab6bSSebastien Roy link_in_file.ll_link); 114132715170SCathy Zhou linkattr_destroy(&link_in_file); 1142d62bc4baSyz147064 } else { 11432b24ab6bSSebastien Roy if (req->ls_flags & DLMGMT_PERSIST) { 11442b24ab6bSSebastien Roy /* 11452b24ab6bSSebastien Roy * Save the newly read properties into 11462b24ab6bSSebastien Roy * the existing link. 11472b24ab6bSSebastien Roy */ 11482b24ab6bSSebastien Roy assert(link_in_db->ll_head == NULL); 11492b24ab6bSSebastien Roy link_in_db->ll_head = 11502b24ab6bSSebastien Roy link_in_file.ll_head; 115132715170SCathy Zhou } else { 115232715170SCathy Zhou linkattr_destroy(&link_in_file); 1153d62bc4baSyz147064 } 11542b24ab6bSSebastien Roy link_in_db->ll_flags |= req->ls_flags; 11552b24ab6bSSebastien Roy } 1156d62bc4baSyz147064 } else { 11572b24ab6bSSebastien Roy /* 11582b24ab6bSSebastien Roy * This is a new link. Allocate a new dlmgmt_link_t 11592b24ab6bSSebastien Roy * and add it to the trees. 11602b24ab6bSSebastien Roy */ 11612b24ab6bSSebastien Roy newlink = calloc(1, sizeof (*newlink)); 11622b24ab6bSSebastien Roy if (newlink == NULL) { 11632b24ab6bSSebastien Roy dlmgmt_log(LOG_WARNING, "Unable to allocate " 11642b24ab6bSSebastien Roy "memory to create new link %s", 11652b24ab6bSSebastien Roy link_in_file.ll_link); 116632715170SCathy Zhou linkattr_destroy(&link_in_file); 11672b24ab6bSSebastien Roy continue; 11682b24ab6bSSebastien Roy } 11692b24ab6bSSebastien Roy bcopy(&link_in_file, newlink, sizeof (*newlink)); 11702b24ab6bSSebastien Roy 11712b24ab6bSSebastien Roy if (newlink->ll_linkid == DATALINK_INVALID_LINKID) 11722b24ab6bSSebastien Roy newlink->ll_linkid = dlmgmt_nextlinkid; 11732b24ab6bSSebastien Roy if (avl_find(&dlmgmt_id_avl, newlink, &id_where) != 11742b24ab6bSSebastien Roy NULL) { 1175*f689bed1SRishi Srivatsavai dlmgmt_log(LOG_WARNING, "Link ID %d is already" 1176*f689bed1SRishi Srivatsavai " in use, destroying link %s", 1177*f689bed1SRishi Srivatsavai newlink->ll_linkid, newlink->ll_link); 11782b24ab6bSSebastien Roy link_destroy(newlink); 11792b24ab6bSSebastien Roy continue; 11802b24ab6bSSebastien Roy } 1181*f689bed1SRishi Srivatsavai 11822b24ab6bSSebastien Roy if ((req->ls_flags & DLMGMT_ACTIVE) && 11832b24ab6bSSebastien Roy link_activate(newlink) != 0) { 11842b24ab6bSSebastien Roy dlmgmt_log(LOG_WARNING, "Unable to activate %s", 11852b24ab6bSSebastien Roy newlink->ll_link); 11862b24ab6bSSebastien Roy link_destroy(newlink); 11872b24ab6bSSebastien Roy continue; 11882b24ab6bSSebastien Roy } 1189*f689bed1SRishi Srivatsavai 11902b24ab6bSSebastien Roy avl_insert(&dlmgmt_id_avl, newlink, id_where); 1191*f689bed1SRishi Srivatsavai /* 1192*f689bed1SRishi Srivatsavai * link_activate call above can insert newlink in 1193*f689bed1SRishi Srivatsavai * dlmgmt_name_avl tree when activating a link that is 1194*f689bed1SRishi Srivatsavai * assigned to a NGZ. 1195*f689bed1SRishi Srivatsavai */ 1196*f689bed1SRishi Srivatsavai if (avl_find(&dlmgmt_name_avl, newlink, 1197*f689bed1SRishi Srivatsavai &name_where) == NULL) 1198*f689bed1SRishi Srivatsavai avl_insert(&dlmgmt_name_avl, newlink, 1199*f689bed1SRishi Srivatsavai name_where); 1200*f689bed1SRishi Srivatsavai 12012b24ab6bSSebastien Roy dlmgmt_advance(newlink); 12022b24ab6bSSebastien Roy newlink->ll_flags |= req->ls_flags; 1203d62bc4baSyz147064 } 1204d62bc4baSyz147064 } 1205d62bc4baSyz147064 1206d62bc4baSyz147064 return (err); 1207d62bc4baSyz147064 } 1208d62bc4baSyz147064 1209d62bc4baSyz147064 /* 1210d62bc4baSyz147064 * Generate an entry in the link database. 1211d62bc4baSyz147064 * Each entry has this format: 12122b24ab6bSSebastien Roy * <link name> <prop0>=<type>,<val>;...;<propn>=<type>,<val>; 1213d62bc4baSyz147064 */ 1214d62bc4baSyz147064 static void 1215d62bc4baSyz147064 generate_link_line(dlmgmt_link_t *linkp, boolean_t persist, char *buf) 1216d62bc4baSyz147064 { 1217d62bc4baSyz147064 char tmpbuf[MAXLINELEN]; 12182b24ab6bSSebastien Roy char *ptr = tmpbuf; 1219d62bc4baSyz147064 char *lim = tmpbuf + MAXLINELEN; 1220d62bc4baSyz147064 dlmgmt_linkattr_t *cur_p = NULL; 1221d62bc4baSyz147064 uint64_t u64; 1222d62bc4baSyz147064 12232b24ab6bSSebastien Roy ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t", linkp->ll_link); 12242b24ab6bSSebastien Roy if (!persist) { 12252b24ab6bSSebastien Roy /* 12262b24ab6bSSebastien Roy * We store the linkid in the active database so that dlmgmtd 12272b24ab6bSSebastien Roy * can recover in the event that it is restarted. 12282b24ab6bSSebastien Roy */ 12292b24ab6bSSebastien Roy u64 = linkp->ll_linkid; 12302b24ab6bSSebastien Roy ptr += write_uint64(ptr, BUFLEN(lim, ptr), "linkid", &u64); 12312b24ab6bSSebastien Roy } 1232d62bc4baSyz147064 u64 = linkp->ll_class; 1233d62bc4baSyz147064 ptr += write_uint64(ptr, BUFLEN(lim, ptr), "class", &u64); 1234d62bc4baSyz147064 u64 = linkp->ll_media; 1235d62bc4baSyz147064 ptr += write_uint64(ptr, BUFLEN(lim, ptr), "media", &u64); 1236d62bc4baSyz147064 1237d62bc4baSyz147064 /* 12382b24ab6bSSebastien Roy * The daemon does not keep any active link attribute. Only store the 12392b24ab6bSSebastien Roy * attributes if this request is for persistent configuration, 1240d62bc4baSyz147064 */ 12412b24ab6bSSebastien Roy if (persist) { 12422b24ab6bSSebastien Roy for (cur_p = linkp->ll_head; cur_p != NULL; 12432b24ab6bSSebastien Roy cur_p = cur_p->lp_next) { 1244d62bc4baSyz147064 ptr += translators[cur_p->lp_type].write_func(ptr, 1245d62bc4baSyz147064 BUFLEN(lim, ptr), cur_p->lp_name, cur_p->lp_val); 1246d62bc4baSyz147064 } 12472b24ab6bSSebastien Roy } 12482b24ab6bSSebastien Roy 12492b24ab6bSSebastien Roy if (ptr <= lim) 1250d62bc4baSyz147064 (void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf); 1251d62bc4baSyz147064 } 1252d62bc4baSyz147064 1253d62bc4baSyz147064 int 12542b24ab6bSSebastien Roy dlmgmt_delete_db_entry(dlmgmt_link_t *linkp, uint32_t flags) 1255d62bc4baSyz147064 { 12562b24ab6bSSebastien Roy return (dlmgmt_db_update(DLMGMT_DB_OP_DELETE, linkp->ll_link, linkp, 12572b24ab6bSSebastien Roy flags)); 1258d62bc4baSyz147064 } 1259d62bc4baSyz147064 1260d62bc4baSyz147064 int 12612b24ab6bSSebastien Roy dlmgmt_write_db_entry(const char *entryname, dlmgmt_link_t *linkp, 12622b24ab6bSSebastien Roy uint32_t flags) 1263d62bc4baSyz147064 { 1264d62bc4baSyz147064 int err; 1265d62bc4baSyz147064 1266d62bc4baSyz147064 if (flags & DLMGMT_PERSIST) { 12672b24ab6bSSebastien Roy if ((err = dlmgmt_db_update(DLMGMT_DB_OP_WRITE, entryname, 12682b24ab6bSSebastien Roy linkp, DLMGMT_PERSIST)) != 0) { 1269d62bc4baSyz147064 return (err); 1270d62bc4baSyz147064 } 1271d62bc4baSyz147064 } 1272d62bc4baSyz147064 1273d62bc4baSyz147064 if (flags & DLMGMT_ACTIVE) { 12742b24ab6bSSebastien Roy if (((err = dlmgmt_db_update(DLMGMT_DB_OP_WRITE, entryname, 12752b24ab6bSSebastien Roy linkp, DLMGMT_ACTIVE)) != 0) && (flags & DLMGMT_PERSIST)) { 12762b24ab6bSSebastien Roy (void) dlmgmt_db_update(DLMGMT_DB_OP_DELETE, entryname, 12772b24ab6bSSebastien Roy linkp, DLMGMT_PERSIST); 1278d62bc4baSyz147064 return (err); 1279d62bc4baSyz147064 } 1280d62bc4baSyz147064 } 1281d62bc4baSyz147064 1282d62bc4baSyz147064 return (0); 1283d62bc4baSyz147064 } 1284d62bc4baSyz147064 1285d62bc4baSyz147064 /* 12862b24ab6bSSebastien Roy * Upgrade properties that have link IDs as values to link names. Because '.' 12872b24ab6bSSebastien Roy * is a valid linkname character, the port separater for link aggregations 1288d501bbfeSSebastien Roy * must be changed to ':'. 12892b24ab6bSSebastien Roy */ 12902b24ab6bSSebastien Roy static void 12912b24ab6bSSebastien Roy linkattr_upgrade(dlmgmt_linkattr_t *attrp) 12922b24ab6bSSebastien Roy { 12932b24ab6bSSebastien Roy datalink_id_t linkid; 12942b24ab6bSSebastien Roy char *portidstr; 12952b24ab6bSSebastien Roy char portname[MAXLINKNAMELEN + 1]; 12962b24ab6bSSebastien Roy dlmgmt_link_t *linkp; 12972b24ab6bSSebastien Roy char *new_attr_val; 12982b24ab6bSSebastien Roy size_t new_attr_sz; 12992b24ab6bSSebastien Roy boolean_t upgraded = B_FALSE; 13002b24ab6bSSebastien Roy 13012b24ab6bSSebastien Roy if (strcmp(attrp->lp_name, "linkover") == 0 || 13022b24ab6bSSebastien Roy strcmp(attrp->lp_name, "simnetpeer") == 0) { 13032b24ab6bSSebastien Roy if (attrp->lp_type == DLADM_TYPE_UINT64) { 1304d501bbfeSSebastien Roy linkid = (datalink_id_t)*(uint64_t *)attrp->lp_val; 13052b24ab6bSSebastien Roy if ((linkp = link_by_id(linkid, GLOBAL_ZONEID)) == NULL) 13062b24ab6bSSebastien Roy return; 13072b24ab6bSSebastien Roy new_attr_sz = strlen(linkp->ll_link) + 1; 13082b24ab6bSSebastien Roy if ((new_attr_val = malloc(new_attr_sz)) == NULL) 13092b24ab6bSSebastien Roy return; 13102b24ab6bSSebastien Roy (void) strcpy(new_attr_val, linkp->ll_link); 13112b24ab6bSSebastien Roy upgraded = B_TRUE; 13122b24ab6bSSebastien Roy } 13132b24ab6bSSebastien Roy } else if (strcmp(attrp->lp_name, "portnames") == 0) { 13142b24ab6bSSebastien Roy /* 13152b24ab6bSSebastien Roy * The old format for "portnames" was 13162b24ab6bSSebastien Roy * "<linkid>.[<linkid>.]...". The new format is 13172b24ab6bSSebastien Roy * "<linkname>:[<linkname>:]...". 13182b24ab6bSSebastien Roy */ 13192b24ab6bSSebastien Roy if (!isdigit(((char *)attrp->lp_val)[0])) 13202b24ab6bSSebastien Roy return; 13212b24ab6bSSebastien Roy new_attr_val = calloc(MAXLINKATTRVALLEN, sizeof (char)); 13222b24ab6bSSebastien Roy if (new_attr_val == NULL) 13232b24ab6bSSebastien Roy return; 13242b24ab6bSSebastien Roy portidstr = (char *)attrp->lp_val; 13252b24ab6bSSebastien Roy while (*portidstr != '\0') { 13262b24ab6bSSebastien Roy errno = 0; 13272b24ab6bSSebastien Roy linkid = strtol(portidstr, &portidstr, 10); 13282b24ab6bSSebastien Roy if (linkid == 0 || *portidstr != '.' || 13292b24ab6bSSebastien Roy (linkp = link_by_id(linkid, GLOBAL_ZONEID)) == 13302b24ab6bSSebastien Roy NULL) { 13312b24ab6bSSebastien Roy free(new_attr_val); 13322b24ab6bSSebastien Roy return; 13332b24ab6bSSebastien Roy } 13342b24ab6bSSebastien Roy (void) snprintf(portname, sizeof (portname), "%s:", 13352b24ab6bSSebastien Roy linkp->ll_link); 13362b24ab6bSSebastien Roy if (strlcat(new_attr_val, portname, 13372b24ab6bSSebastien Roy MAXLINKATTRVALLEN) >= MAXLINKATTRVALLEN) { 13382b24ab6bSSebastien Roy free(new_attr_val); 13392b24ab6bSSebastien Roy return; 13402b24ab6bSSebastien Roy } 13412b24ab6bSSebastien Roy /* skip the '.' delimiter */ 13422b24ab6bSSebastien Roy portidstr++; 13432b24ab6bSSebastien Roy } 13442b24ab6bSSebastien Roy new_attr_sz = strlen(new_attr_val) + 1; 13452b24ab6bSSebastien Roy upgraded = B_TRUE; 13462b24ab6bSSebastien Roy } 13472b24ab6bSSebastien Roy 13482b24ab6bSSebastien Roy if (upgraded) { 13492b24ab6bSSebastien Roy attrp->lp_type = DLADM_TYPE_STR; 13502b24ab6bSSebastien Roy attrp->lp_sz = new_attr_sz; 13512b24ab6bSSebastien Roy free(attrp->lp_val); 13522b24ab6bSSebastien Roy attrp->lp_val = new_attr_val; 13532b24ab6bSSebastien Roy } 13542b24ab6bSSebastien Roy } 13552b24ab6bSSebastien Roy 13562b24ab6bSSebastien Roy static void 13572b24ab6bSSebastien Roy dlmgmt_db_upgrade(dlmgmt_link_t *linkp) 13582b24ab6bSSebastien Roy { 13592b24ab6bSSebastien Roy dlmgmt_linkattr_t *attrp; 13602b24ab6bSSebastien Roy 13612b24ab6bSSebastien Roy for (attrp = linkp->ll_head; attrp != NULL; attrp = attrp->lp_next) 13622b24ab6bSSebastien Roy linkattr_upgrade(attrp); 13632b24ab6bSSebastien Roy } 13642b24ab6bSSebastien Roy 13652b24ab6bSSebastien Roy static void 13662b24ab6bSSebastien Roy dlmgmt_db_phys_activate(dlmgmt_link_t *linkp) 13672b24ab6bSSebastien Roy { 13682b24ab6bSSebastien Roy linkp->ll_flags |= DLMGMT_ACTIVE; 13692b24ab6bSSebastien Roy (void) dlmgmt_write_db_entry(linkp->ll_link, linkp, DLMGMT_ACTIVE); 13702b24ab6bSSebastien Roy } 13712b24ab6bSSebastien Roy 13722b24ab6bSSebastien Roy static void 13732b24ab6bSSebastien Roy dlmgmt_db_walk(zoneid_t zoneid, datalink_class_t class, db_walk_func_t *func) 13742b24ab6bSSebastien Roy { 13752b24ab6bSSebastien Roy dlmgmt_link_t *linkp; 13762b24ab6bSSebastien Roy 13772b24ab6bSSebastien Roy for (linkp = avl_first(&dlmgmt_id_avl); linkp != NULL; 13782b24ab6bSSebastien Roy linkp = AVL_NEXT(&dlmgmt_id_avl, linkp)) { 13792b24ab6bSSebastien Roy if (linkp->ll_zoneid == zoneid && (linkp->ll_class & class)) 13802b24ab6bSSebastien Roy func(linkp); 13812b24ab6bSSebastien Roy } 13822b24ab6bSSebastien Roy } 13832b24ab6bSSebastien Roy 13842b24ab6bSSebastien Roy /* 1385d62bc4baSyz147064 * Initialize the datalink <link name, linkid> mapping and the link's 1386d62bc4baSyz147064 * attributes list based on the configuration file /etc/dladm/datalink.conf 1387d62bc4baSyz147064 * and the active configuration cache file 1388b9e076dcSyz147064 * /etc/svc/volatile/dladm/datalink-management:default.cache. 1389d62bc4baSyz147064 */ 1390d62bc4baSyz147064 int 13912b24ab6bSSebastien Roy dlmgmt_db_init(zoneid_t zoneid) 1392d62bc4baSyz147064 { 13932b24ab6bSSebastien Roy dlmgmt_db_req_t *req; 1394d62bc4baSyz147064 int err; 13952b24ab6bSSebastien Roy boolean_t boot = B_FALSE; 1396d62bc4baSyz147064 13972b24ab6bSSebastien Roy if ((req = dlmgmt_db_req_alloc(DLMGMT_DB_OP_READ, NULL, 13982b24ab6bSSebastien Roy DATALINK_INVALID_LINKID, zoneid, DLMGMT_ACTIVE, &err)) == NULL) 13992b24ab6bSSebastien Roy return (err); 14002b24ab6bSSebastien Roy 14012b24ab6bSSebastien Roy if ((err = dlmgmt_process_db_req(req)) != 0) { 1402d62bc4baSyz147064 /* 14032b24ab6bSSebastien Roy * If we get back ENOENT, that means that the active 14042b24ab6bSSebastien Roy * configuration file doesn't exist yet, and is not an error. 14052b24ab6bSSebastien Roy * We'll create it down below after we've loaded the 14062b24ab6bSSebastien Roy * persistent configuration. 1407d62bc4baSyz147064 */ 14082b24ab6bSSebastien Roy if (err != ENOENT) 1409d62bc4baSyz147064 goto done; 14102b24ab6bSSebastien Roy boot = B_TRUE; 14112b24ab6bSSebastien Roy } 1412d62bc4baSyz147064 14132b24ab6bSSebastien Roy req->ls_flags = DLMGMT_PERSIST; 14142b24ab6bSSebastien Roy err = dlmgmt_process_db_req(req); 14152b24ab6bSSebastien Roy if (err != 0 && err != ENOENT) 14162b24ab6bSSebastien Roy goto done; 1417d62bc4baSyz147064 err = 0; 14182b24ab6bSSebastien Roy if (rewrite_needed) { 14192b24ab6bSSebastien Roy /* 14202b24ab6bSSebastien Roy * First update links in memory, then dump the entire db to 14212b24ab6bSSebastien Roy * disk. 14222b24ab6bSSebastien Roy */ 14232b24ab6bSSebastien Roy dlmgmt_db_walk(zoneid, DATALINK_CLASS_ALL, dlmgmt_db_upgrade); 14242b24ab6bSSebastien Roy req->ls_op = DLMGMT_DB_OP_WRITE; 14252b24ab6bSSebastien Roy req->ls_linkid = DATALINK_ALL_LINKID; 14262b24ab6bSSebastien Roy if ((err = dlmgmt_process_db_req(req)) != 0 && 14272b24ab6bSSebastien Roy err != EINPROGRESS) 14282b24ab6bSSebastien Roy goto done; 14292b24ab6bSSebastien Roy } 14302b24ab6bSSebastien Roy if (boot) { 14312b24ab6bSSebastien Roy dlmgmt_db_walk(zoneid, DATALINK_CLASS_PHYS, 14322b24ab6bSSebastien Roy dlmgmt_db_phys_activate); 1433d62bc4baSyz147064 } 1434d62bc4baSyz147064 1435d62bc4baSyz147064 done: 14362b24ab6bSSebastien Roy if (err == EINPROGRESS) 14372b24ab6bSSebastien Roy err = 0; 14382b24ab6bSSebastien Roy else 14392b24ab6bSSebastien Roy free(req); 1440d62bc4baSyz147064 return (err); 1441d62bc4baSyz147064 } 14422b24ab6bSSebastien Roy 14432b24ab6bSSebastien Roy /* 14442b24ab6bSSebastien Roy * Remove all links in the given zoneid. 14452b24ab6bSSebastien Roy */ 14462b24ab6bSSebastien Roy void 14472b24ab6bSSebastien Roy dlmgmt_db_fini(zoneid_t zoneid) 14482b24ab6bSSebastien Roy { 14492b24ab6bSSebastien Roy dlmgmt_link_t *linkp = avl_first(&dlmgmt_name_avl), *next_linkp; 14502b24ab6bSSebastien Roy 14512b24ab6bSSebastien Roy while (linkp != NULL) { 14522b24ab6bSSebastien Roy next_linkp = AVL_NEXT(&dlmgmt_name_avl, linkp); 14532b24ab6bSSebastien Roy if (linkp->ll_zoneid == zoneid) { 14542b24ab6bSSebastien Roy (void) dlmgmt_destroy_common(linkp, 14552b24ab6bSSebastien Roy DLMGMT_ACTIVE | DLMGMT_PERSIST); 14562b24ab6bSSebastien Roy } 14572b24ab6bSSebastien Roy linkp = next_linkp; 14582b24ab6bSSebastien Roy } 14592b24ab6bSSebastien Roy } 1460