1d62bc4baSyz /* 2d62bc4baSyz * CDDL HEADER START 3d62bc4baSyz * 4d62bc4baSyz * The contents of this file are subject to the terms of the 5d62bc4baSyz * Common Development and Distribution License (the "License"). 6d62bc4baSyz * You may not use this file except in compliance with the License. 7d62bc4baSyz * 8d62bc4baSyz * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9d62bc4baSyz * or http://www.opensolaris.org/os/licensing. 10d62bc4baSyz * See the License for the specific language governing permissions 11d62bc4baSyz * and limitations under the License. 12d62bc4baSyz * 13d62bc4baSyz * When distributing Covered Code, include this CDDL HEADER in each 14d62bc4baSyz * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15d62bc4baSyz * If applicable, add the following below this CDDL HEADER, with the 16d62bc4baSyz * fields enclosed by brackets "[]" replaced with your own identifying 17d62bc4baSyz * information: Portions Copyright [yyyy] [name of copyright owner] 18d62bc4baSyz * 19d62bc4baSyz * CDDL HEADER END 20d62bc4baSyz */ 21d62bc4baSyz 22d62bc4baSyz /* 23*2b24ab6bSSebastien Roy * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24d62bc4baSyz * Use is subject to license terms. 25d62bc4baSyz */ 26d62bc4baSyz 27d62bc4baSyz #include <assert.h> 28d62bc4baSyz #include <ctype.h> 29d62bc4baSyz #include <errno.h> 30d62bc4baSyz #include <fcntl.h> 31d62bc4baSyz #include <stdio.h> 32d62bc4baSyz #include <stdlib.h> 33*2b24ab6bSSebastien Roy #include <string.h> 34d62bc4baSyz #include <strings.h> 35d62bc4baSyz #include <syslog.h> 36*2b24ab6bSSebastien Roy #include <zone.h> 37*2b24ab6bSSebastien Roy #include <sys/types.h> 38d62bc4baSyz #include <sys/stat.h> 39*2b24ab6bSSebastien Roy #include <stropts.h> 40*2b24ab6bSSebastien Roy #include <sys/conf.h> 41d62bc4baSyz #include <pthread.h> 42d62bc4baSyz #include <unistd.h> 43*2b24ab6bSSebastien Roy #include <wait.h> 44*2b24ab6bSSebastien Roy #include <libcontract.h> 45*2b24ab6bSSebastien Roy #include <sys/contract/process.h> 46d62bc4baSyz #include "dlmgmt_impl.h" 47d62bc4baSyz 48d62bc4baSyz typedef enum dlmgmt_db_op { 49d62bc4baSyz DLMGMT_DB_OP_WRITE, 50d62bc4baSyz DLMGMT_DB_OP_DELETE, 51d62bc4baSyz DLMGMT_DB_OP_READ 52d62bc4baSyz } dlmgmt_db_op_t; 53d62bc4baSyz 54d62bc4baSyz typedef struct dlmgmt_db_req_s { 55d62bc4baSyz struct dlmgmt_db_req_s *ls_next; 56d62bc4baSyz dlmgmt_db_op_t ls_op; 57*2b24ab6bSSebastien Roy char ls_link[MAXLINKNAMELEN]; 58d62bc4baSyz datalink_id_t ls_linkid; 59*2b24ab6bSSebastien Roy zoneid_t ls_zoneid; 60d62bc4baSyz uint32_t ls_flags; /* Either DLMGMT_ACTIVE or */ 61d62bc4baSyz /* DLMGMT_PERSIST, not both. */ 62d62bc4baSyz } dlmgmt_db_req_t; 63d62bc4baSyz 64d62bc4baSyz /* 65d62bc4baSyz * List of pending db updates (e.g., because of a read-only filesystem). 66d62bc4baSyz */ 67d62bc4baSyz static dlmgmt_db_req_t *dlmgmt_db_req_head = NULL; 68d62bc4baSyz static dlmgmt_db_req_t *dlmgmt_db_req_tail = NULL; 69d62bc4baSyz 70*2b24ab6bSSebastien Roy /* 71*2b24ab6bSSebastien Roy * rewrite_needed is set to B_TRUE by process_link_line() if it encounters a 72*2b24ab6bSSebastien Roy * line with an old format. This will cause the file being read to be 73*2b24ab6bSSebastien Roy * re-written with the current format. 74*2b24ab6bSSebastien Roy */ 75*2b24ab6bSSebastien Roy static boolean_t rewrite_needed; 76*2b24ab6bSSebastien Roy 77*2b24ab6bSSebastien Roy static int dlmgmt_db_update(dlmgmt_db_op_t, const char *, 78*2b24ab6bSSebastien Roy dlmgmt_link_t *, uint32_t); 79d62bc4baSyz static int dlmgmt_process_db_req(dlmgmt_db_req_t *); 80d62bc4baSyz static int dlmgmt_process_db_onereq(dlmgmt_db_req_t *, boolean_t); 81d62bc4baSyz static void *dlmgmt_db_update_thread(void *); 82*2b24ab6bSSebastien Roy static boolean_t process_link_line(char *, dlmgmt_link_t *); 83d62bc4baSyz static int process_db_write(dlmgmt_db_req_t *, FILE *, FILE *); 84*2b24ab6bSSebastien Roy static int process_db_read(dlmgmt_db_req_t *, FILE *); 85d62bc4baSyz static void generate_link_line(dlmgmt_link_t *, boolean_t, char *); 86d62bc4baSyz 87d62bc4baSyz #define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0) 88d62bc4baSyz #define MAXLINELEN 1024 89d62bc4baSyz 90*2b24ab6bSSebastien Roy typedef void db_walk_func_t(dlmgmt_link_t *); 91*2b24ab6bSSebastien Roy 92d62bc4baSyz /* 93d62bc4baSyz * Translator functions to go from dladm_datatype_t to character strings. 94d62bc4baSyz * Each function takes a pointer to a buffer, the size of the buffer, 95d62bc4baSyz * the name of the attribute, and the value to be written. The functions 96d62bc4baSyz * return the number of bytes written to the buffer. If the buffer is not big 97d62bc4baSyz * enough to hold the string representing the value, then nothing is written 98d62bc4baSyz * and 0 is returned. 99d62bc4baSyz */ 100d62bc4baSyz typedef size_t write_func_t(char *, size_t, char *, void *); 101d62bc4baSyz 102d62bc4baSyz /* 103d62bc4baSyz * Translator functions to read from a NULL terminated string buffer into 104d62bc4baSyz * something of the given DLADM_TYPE_*. The functions each return the number 105d62bc4baSyz * of bytes read from the string buffer. If there is an error reading data 106d62bc4baSyz * from the buffer, then 0 is returned. It is the caller's responsibility 107d62bc4baSyz * to free the data allocated by these functions. 108d62bc4baSyz */ 109d62bc4baSyz typedef size_t read_func_t(char *, void **); 110d62bc4baSyz 111d62bc4baSyz typedef struct translator_s { 112d62bc4baSyz const char *type_name; 113d62bc4baSyz write_func_t *write_func; 114d62bc4baSyz read_func_t *read_func; 115d62bc4baSyz } translator_t; 116d62bc4baSyz 117d62bc4baSyz /* 118d62bc4baSyz * Translator functions, defined later but declared here so that 119d62bc4baSyz * the translator table can be defined. 120d62bc4baSyz */ 121d62bc4baSyz static write_func_t write_str, write_boolean, write_uint64; 122d62bc4baSyz static read_func_t read_str, read_boolean, read_int64; 123d62bc4baSyz 124d62bc4baSyz /* 125d62bc4baSyz * Translator table, indexed by dladm_datatype_t. 126d62bc4baSyz */ 127d62bc4baSyz static translator_t translators[] = { 128d62bc4baSyz { "string", write_str, read_str }, 129d62bc4baSyz { "boolean", write_boolean, read_boolean }, 130d62bc4baSyz { "int", write_uint64, read_int64 } 131d62bc4baSyz }; 132d62bc4baSyz 133d62bc4baSyz static size_t ntranslators = sizeof (translators) / sizeof (translator_t); 134d62bc4baSyz 135d62bc4baSyz #define LINK_PROPERTY_DELIMINATOR ";" 136d62bc4baSyz #define LINK_PROPERTY_TYPE_VALUE_SEP "," 137d62bc4baSyz #define BASE_PROPERTY_LENGTH(t, n) (strlen(translators[(t)].type_name) +\ 138d62bc4baSyz strlen(LINK_PROPERTY_TYPE_VALUE_SEP) +\ 139d62bc4baSyz strlen(LINK_PROPERTY_DELIMINATOR) +\ 140d62bc4baSyz strlen((n))) 141d62bc4baSyz #define GENERATE_PROPERTY_STRING(buf, length, conv, name, type, val) \ 142d62bc4baSyz (snprintf((buf), (length), "%s=%s%s" conv "%s", (name), \ 143d62bc4baSyz translators[(type)].type_name, \ 144d62bc4baSyz LINK_PROPERTY_TYPE_VALUE_SEP, (val), LINK_PROPERTY_DELIMINATOR)) 145d62bc4baSyz 146d62bc4baSyz /* 147d62bc4baSyz * Name of the cache file to keep the active <link name, linkid> mapping 148d62bc4baSyz */ 149*2b24ab6bSSebastien Roy char cachefile[MAXPATHLEN]; 150d62bc4baSyz 151d62bc4baSyz #define DLMGMT_PERSISTENT_DB_PATH "/etc/dladm/datalink.conf" 152d62bc4baSyz #define DLMGMT_MAKE_FILE_DB_PATH(buffer, persistent) \ 153d62bc4baSyz (void) snprintf((buffer), MAXPATHLEN, "%s", \ 154d62bc4baSyz (persistent) ? DLMGMT_PERSISTENT_DB_PATH : cachefile); 155d62bc4baSyz 156*2b24ab6bSSebastien Roy typedef struct zopen_arg { 157*2b24ab6bSSebastien Roy const char *zopen_modestr; 158*2b24ab6bSSebastien Roy int *zopen_pipe; 159*2b24ab6bSSebastien Roy int zopen_fd; 160*2b24ab6bSSebastien Roy } zopen_arg_t; 161*2b24ab6bSSebastien Roy 162*2b24ab6bSSebastien Roy typedef struct zrename_arg { 163*2b24ab6bSSebastien Roy const char *zrename_newname; 164*2b24ab6bSSebastien Roy } zrename_arg_t; 165*2b24ab6bSSebastien Roy 166*2b24ab6bSSebastien Roy typedef union zfoparg { 167*2b24ab6bSSebastien Roy zopen_arg_t zfop_openarg; 168*2b24ab6bSSebastien Roy zrename_arg_t zfop_renamearg; 169*2b24ab6bSSebastien Roy } zfoparg_t; 170*2b24ab6bSSebastien Roy 171*2b24ab6bSSebastien Roy typedef struct zfcbarg { 172*2b24ab6bSSebastien Roy boolean_t zfarg_inglobalzone; /* is callback in global zone? */ 173*2b24ab6bSSebastien Roy zoneid_t zfarg_finglobalzone; /* is file in global zone? */ 174*2b24ab6bSSebastien Roy const char *zfarg_filename; 175*2b24ab6bSSebastien Roy zfoparg_t *zfarg_oparg; 176*2b24ab6bSSebastien Roy } zfarg_t; 177*2b24ab6bSSebastien Roy #define zfarg_openarg zfarg_oparg->zfop_openarg 178*2b24ab6bSSebastien Roy #define zfarg_renamearg zfarg_oparg->zfop_renamearg 179*2b24ab6bSSebastien Roy 180*2b24ab6bSSebastien Roy /* zone file callback */ 181*2b24ab6bSSebastien Roy typedef int zfcb_t(zfarg_t *); 182*2b24ab6bSSebastien Roy 183*2b24ab6bSSebastien Roy /* 184*2b24ab6bSSebastien Roy * Execute an operation on filename relative to zoneid's zone root. If the 185*2b24ab6bSSebastien Roy * file is in the global zone, then the zfcb() callback will simply be called 186*2b24ab6bSSebastien Roy * directly. If the file is in a non-global zone, then zfcb() will be called 187*2b24ab6bSSebastien Roy * both from the global zone's context, and from the non-global zone's context 188*2b24ab6bSSebastien Roy * (from a fork()'ed child that has entered the non-global zone). This is 189*2b24ab6bSSebastien Roy * done to allow the callback to communicate with itself if needed (e.g. to 190*2b24ab6bSSebastien Roy * pass back the file descriptor of an opened file). 191*2b24ab6bSSebastien Roy */ 192*2b24ab6bSSebastien Roy static int 193*2b24ab6bSSebastien Roy dlmgmt_zfop(const char *filename, zoneid_t zoneid, zfcb_t *zfcb, 194*2b24ab6bSSebastien Roy zfoparg_t *zfoparg) 195*2b24ab6bSSebastien Roy { 196*2b24ab6bSSebastien Roy int ctfd; 197*2b24ab6bSSebastien Roy int err; 198*2b24ab6bSSebastien Roy pid_t childpid; 199*2b24ab6bSSebastien Roy siginfo_t info; 200*2b24ab6bSSebastien Roy zfarg_t zfarg; 201*2b24ab6bSSebastien Roy 202*2b24ab6bSSebastien Roy if (zoneid != GLOBAL_ZONEID) { 203*2b24ab6bSSebastien Roy /* 204*2b24ab6bSSebastien Roy * We need to access a file that isn't in the global zone. 205*2b24ab6bSSebastien Roy * Accessing non-global zone files from the global zone is 206*2b24ab6bSSebastien Roy * unsafe (due to symlink attacks), we'll need to fork a child 207*2b24ab6bSSebastien Roy * that enters the zone in question and executes the callback 208*2b24ab6bSSebastien Roy * that will operate on the file. 209*2b24ab6bSSebastien Roy * 210*2b24ab6bSSebastien Roy * Before we proceed with this zone tango, we need to create a 211*2b24ab6bSSebastien Roy * new process contract for the child, as required by 212*2b24ab6bSSebastien Roy * zone_enter(). 213*2b24ab6bSSebastien Roy */ 214*2b24ab6bSSebastien Roy errno = 0; 215*2b24ab6bSSebastien Roy ctfd = open64("/system/contract/process/template", O_RDWR); 216*2b24ab6bSSebastien Roy if (ctfd == -1) 217*2b24ab6bSSebastien Roy return (errno); 218*2b24ab6bSSebastien Roy if ((err = ct_tmpl_set_critical(ctfd, 0)) != 0 || 219*2b24ab6bSSebastien Roy (err = ct_tmpl_set_informative(ctfd, 0)) != 0 || 220*2b24ab6bSSebastien Roy (err = ct_pr_tmpl_set_fatal(ctfd, CT_PR_EV_HWERR)) != 0 || 221*2b24ab6bSSebastien Roy (err = ct_pr_tmpl_set_param(ctfd, CT_PR_PGRPONLY)) != 0 || 222*2b24ab6bSSebastien Roy (err = ct_tmpl_activate(ctfd)) != 0) { 223*2b24ab6bSSebastien Roy return (err); 224*2b24ab6bSSebastien Roy } 225*2b24ab6bSSebastien Roy childpid = fork(); 226*2b24ab6bSSebastien Roy (void) ct_tmpl_clear(ctfd); 227*2b24ab6bSSebastien Roy (void) close(ctfd); 228*2b24ab6bSSebastien Roy switch (childpid) { 229*2b24ab6bSSebastien Roy case -1: 230*2b24ab6bSSebastien Roy return (err); 231*2b24ab6bSSebastien Roy case 0: 232*2b24ab6bSSebastien Roy /* 233*2b24ab6bSSebastien Roy * Elevate our privileges as zone_enter() requires all 234*2b24ab6bSSebastien Roy * privileges. 235*2b24ab6bSSebastien Roy */ 236*2b24ab6bSSebastien Roy if ((err = dlmgmt_elevate_privileges()) != 0) 237*2b24ab6bSSebastien Roy _exit(err); 238*2b24ab6bSSebastien Roy if (zone_enter(zoneid) == -1) 239*2b24ab6bSSebastien Roy _exit(errno); 240*2b24ab6bSSebastien Roy if ((err = dlmgmt_drop_privileges()) != 0) 241*2b24ab6bSSebastien Roy _exit(err); 242*2b24ab6bSSebastien Roy break; 243*2b24ab6bSSebastien Roy default: 244*2b24ab6bSSebastien Roy if (waitid(P_PID, childpid, &info, WEXITED) == -1) 245*2b24ab6bSSebastien Roy return (errno); 246*2b24ab6bSSebastien Roy if (info.si_status != 0) 247*2b24ab6bSSebastien Roy return (info.si_status); 248*2b24ab6bSSebastien Roy } 249*2b24ab6bSSebastien Roy } 250*2b24ab6bSSebastien Roy 251*2b24ab6bSSebastien Roy zfarg.zfarg_inglobalzone = (zoneid == GLOBAL_ZONEID || childpid != 0); 252*2b24ab6bSSebastien Roy zfarg.zfarg_finglobalzone = (zoneid == GLOBAL_ZONEID); 253*2b24ab6bSSebastien Roy zfarg.zfarg_filename = filename; 254*2b24ab6bSSebastien Roy zfarg.zfarg_oparg = zfoparg; 255*2b24ab6bSSebastien Roy err = zfcb(&zfarg); 256*2b24ab6bSSebastien Roy if (!zfarg.zfarg_inglobalzone) 257*2b24ab6bSSebastien Roy _exit(err); 258*2b24ab6bSSebastien Roy return (err); 259*2b24ab6bSSebastien Roy } 260*2b24ab6bSSebastien Roy 261*2b24ab6bSSebastien Roy static int 262*2b24ab6bSSebastien Roy dlmgmt_zopen_cb(zfarg_t *zfarg) 263*2b24ab6bSSebastien Roy { 264*2b24ab6bSSebastien Roy struct strrecvfd recvfd; 265*2b24ab6bSSebastien Roy boolean_t newfile = B_FALSE; 266*2b24ab6bSSebastien Roy boolean_t inglobalzone = zfarg->zfarg_inglobalzone; 267*2b24ab6bSSebastien Roy zoneid_t finglobalzone = zfarg->zfarg_finglobalzone; 268*2b24ab6bSSebastien Roy const char *filename = zfarg->zfarg_filename; 269*2b24ab6bSSebastien Roy const char *modestr = zfarg->zfarg_openarg.zopen_modestr; 270*2b24ab6bSSebastien Roy int *p = zfarg->zfarg_openarg.zopen_pipe; 271*2b24ab6bSSebastien Roy struct stat statbuf; 272*2b24ab6bSSebastien Roy int oflags; 273*2b24ab6bSSebastien Roy mode_t mode; 274*2b24ab6bSSebastien Roy int fd = -1; 275*2b24ab6bSSebastien Roy int err; 276*2b24ab6bSSebastien Roy 277*2b24ab6bSSebastien Roy /* We only ever open a file for reading or writing, not both. */ 278*2b24ab6bSSebastien Roy oflags = (modestr[0] == 'r') ? O_RDONLY : O_WRONLY | O_CREAT | O_TRUNC; 279*2b24ab6bSSebastien Roy mode = (modestr[0] == 'r') ? 0 : S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 280*2b24ab6bSSebastien Roy 281*2b24ab6bSSebastien Roy /* Open the file if we're in the same zone as the file. */ 282*2b24ab6bSSebastien Roy if (inglobalzone == finglobalzone) { 283*2b24ab6bSSebastien Roy /* 284*2b24ab6bSSebastien Roy * First determine if we will be creating the file as part of 285*2b24ab6bSSebastien Roy * opening it. If so, then we'll need to ensure that it has 286*2b24ab6bSSebastien Roy * the proper ownership after having opened it. 287*2b24ab6bSSebastien Roy */ 288*2b24ab6bSSebastien Roy if (oflags & O_CREAT) { 289*2b24ab6bSSebastien Roy if (stat(filename, &statbuf) == -1) { 290*2b24ab6bSSebastien Roy if (errno == ENOENT) 291*2b24ab6bSSebastien Roy newfile = B_TRUE; 292*2b24ab6bSSebastien Roy else 293*2b24ab6bSSebastien Roy return (errno); 294*2b24ab6bSSebastien Roy } 295*2b24ab6bSSebastien Roy } 296*2b24ab6bSSebastien Roy if ((fd = open(filename, oflags, mode)) == -1) 297*2b24ab6bSSebastien Roy return (errno); 298*2b24ab6bSSebastien Roy if (newfile) { 299*2b24ab6bSSebastien Roy if (chown(filename, UID_DLADM, GID_SYS) == -1) { 300*2b24ab6bSSebastien Roy err = errno; 301*2b24ab6bSSebastien Roy (void) close(fd); 302*2b24ab6bSSebastien Roy return (err); 303*2b24ab6bSSebastien Roy } 304*2b24ab6bSSebastien Roy } 305*2b24ab6bSSebastien Roy } 306*2b24ab6bSSebastien Roy 307*2b24ab6bSSebastien Roy /* 308*2b24ab6bSSebastien Roy * If we're not in the global zone, send the file-descriptor back to 309*2b24ab6bSSebastien Roy * our parent in the global zone. 310*2b24ab6bSSebastien Roy */ 311*2b24ab6bSSebastien Roy if (!inglobalzone) { 312*2b24ab6bSSebastien Roy assert(!finglobalzone); 313*2b24ab6bSSebastien Roy assert(fd != -1); 314*2b24ab6bSSebastien Roy return (ioctl(p[1], I_SENDFD, fd) == -1 ? errno : 0); 315*2b24ab6bSSebastien Roy } 316*2b24ab6bSSebastien Roy 317*2b24ab6bSSebastien Roy /* 318*2b24ab6bSSebastien Roy * At this point, we know we're in the global zone. If the file was 319*2b24ab6bSSebastien Roy * in a non-global zone, receive the file-descriptor from our child in 320*2b24ab6bSSebastien Roy * the non-global zone. 321*2b24ab6bSSebastien Roy */ 322*2b24ab6bSSebastien Roy if (!finglobalzone) { 323*2b24ab6bSSebastien Roy if (ioctl(p[0], I_RECVFD, &recvfd) == -1) 324*2b24ab6bSSebastien Roy return (errno); 325*2b24ab6bSSebastien Roy fd = recvfd.fd; 326*2b24ab6bSSebastien Roy } 327*2b24ab6bSSebastien Roy 328*2b24ab6bSSebastien Roy zfarg->zfarg_openarg.zopen_fd = fd; 329*2b24ab6bSSebastien Roy return (0); 330*2b24ab6bSSebastien Roy } 331*2b24ab6bSSebastien Roy 332*2b24ab6bSSebastien Roy static int 333*2b24ab6bSSebastien Roy dlmgmt_zunlink_cb(zfarg_t *zfarg) 334*2b24ab6bSSebastien Roy { 335*2b24ab6bSSebastien Roy if (zfarg->zfarg_inglobalzone != zfarg->zfarg_finglobalzone) 336*2b24ab6bSSebastien Roy return (0); 337*2b24ab6bSSebastien Roy return (unlink(zfarg->zfarg_filename) == 0 ? 0 : errno); 338*2b24ab6bSSebastien Roy } 339*2b24ab6bSSebastien Roy 340*2b24ab6bSSebastien Roy static int 341*2b24ab6bSSebastien Roy dlmgmt_zrename_cb(zfarg_t *zfarg) 342*2b24ab6bSSebastien Roy { 343*2b24ab6bSSebastien Roy if (zfarg->zfarg_inglobalzone != zfarg->zfarg_finglobalzone) 344*2b24ab6bSSebastien Roy return (0); 345*2b24ab6bSSebastien Roy return (rename(zfarg->zfarg_filename, 346*2b24ab6bSSebastien Roy zfarg->zfarg_renamearg.zrename_newname) == 0 ? 0 : errno); 347*2b24ab6bSSebastien Roy } 348*2b24ab6bSSebastien Roy 349*2b24ab6bSSebastien Roy /* 350*2b24ab6bSSebastien Roy * Same as fopen(3C), except that it opens the file relative to zoneid's zone 351*2b24ab6bSSebastien Roy * root. 352*2b24ab6bSSebastien Roy */ 353*2b24ab6bSSebastien Roy static FILE * 354*2b24ab6bSSebastien Roy dlmgmt_zfopen(const char *filename, const char *modestr, zoneid_t zoneid, 355*2b24ab6bSSebastien Roy int *err) 356*2b24ab6bSSebastien Roy { 357*2b24ab6bSSebastien Roy int p[2]; 358*2b24ab6bSSebastien Roy zfoparg_t zfoparg; 359*2b24ab6bSSebastien Roy FILE *fp = NULL; 360*2b24ab6bSSebastien Roy 361*2b24ab6bSSebastien Roy if (zoneid != GLOBAL_ZONEID && pipe(p) == -1) { 362*2b24ab6bSSebastien Roy *err = errno; 363*2b24ab6bSSebastien Roy return (NULL); 364*2b24ab6bSSebastien Roy } 365*2b24ab6bSSebastien Roy 366*2b24ab6bSSebastien Roy zfoparg.zfop_openarg.zopen_modestr = modestr; 367*2b24ab6bSSebastien Roy zfoparg.zfop_openarg.zopen_pipe = p; 368*2b24ab6bSSebastien Roy *err = dlmgmt_zfop(filename, zoneid, dlmgmt_zopen_cb, &zfoparg); 369*2b24ab6bSSebastien Roy if (zoneid != GLOBAL_ZONEID) { 370*2b24ab6bSSebastien Roy (void) close(p[0]); 371*2b24ab6bSSebastien Roy (void) close(p[1]); 372*2b24ab6bSSebastien Roy } 373*2b24ab6bSSebastien Roy if (*err == 0) { 374*2b24ab6bSSebastien Roy fp = fdopen(zfoparg.zfop_openarg.zopen_fd, modestr); 375*2b24ab6bSSebastien Roy if (fp == NULL) { 376*2b24ab6bSSebastien Roy *err = errno; 377*2b24ab6bSSebastien Roy (void) close(zfoparg.zfop_openarg.zopen_fd); 378*2b24ab6bSSebastien Roy } 379*2b24ab6bSSebastien Roy } 380*2b24ab6bSSebastien Roy return (fp); 381*2b24ab6bSSebastien Roy } 382*2b24ab6bSSebastien Roy 383*2b24ab6bSSebastien Roy /* 384*2b24ab6bSSebastien Roy * Same as rename(2), except that old and new are relative to zoneid's zone 385*2b24ab6bSSebastien Roy * root. 386*2b24ab6bSSebastien Roy */ 387*2b24ab6bSSebastien Roy static int 388*2b24ab6bSSebastien Roy dlmgmt_zrename(const char *old, const char *new, zoneid_t zoneid) 389*2b24ab6bSSebastien Roy { 390*2b24ab6bSSebastien Roy zfoparg_t zfoparg; 391*2b24ab6bSSebastien Roy 392*2b24ab6bSSebastien Roy zfoparg.zfop_renamearg.zrename_newname = new; 393*2b24ab6bSSebastien Roy return (dlmgmt_zfop(old, zoneid, dlmgmt_zrename_cb, &zfoparg)); 394*2b24ab6bSSebastien Roy } 395*2b24ab6bSSebastien Roy 396*2b24ab6bSSebastien Roy /* 397*2b24ab6bSSebastien Roy * Same as unlink(2), except that filename is relative to zoneid's zone root. 398*2b24ab6bSSebastien Roy */ 399*2b24ab6bSSebastien Roy static int 400*2b24ab6bSSebastien Roy dlmgmt_zunlink(const char *filename, zoneid_t zoneid) 401*2b24ab6bSSebastien Roy { 402*2b24ab6bSSebastien Roy return (dlmgmt_zfop(filename, zoneid, dlmgmt_zunlink_cb, NULL)); 403*2b24ab6bSSebastien Roy } 404*2b24ab6bSSebastien Roy 405d62bc4baSyz static size_t 406d62bc4baSyz write_str(char *buffer, size_t buffer_length, char *name, void *value) 407d62bc4baSyz { 408d62bc4baSyz char *ptr = value; 409d62bc4baSyz size_t data_length = strnlen(ptr, buffer_length); 410d62bc4baSyz 411d62bc4baSyz /* 412d62bc4baSyz * Strings are assumed to be NULL terminated. In order to fit in 413d62bc4baSyz * the buffer, the string's length must be less then buffer_length. 414d62bc4baSyz * If the value is empty, there's no point in writing it, in fact, 415d62bc4baSyz * we shouldn't even see that case. 416d62bc4baSyz */ 417d62bc4baSyz if (data_length + BASE_PROPERTY_LENGTH(DLADM_TYPE_STR, name) == 418d62bc4baSyz buffer_length || data_length == 0) 419d62bc4baSyz return (0); 420d62bc4baSyz 421d62bc4baSyz /* 422d62bc4baSyz * Since we know the string will fit in the buffer, snprintf will 423d62bc4baSyz * always return less than buffer_length, so we can just return 424d62bc4baSyz * whatever snprintf returns. 425d62bc4baSyz */ 426d62bc4baSyz return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%s", 427d62bc4baSyz name, DLADM_TYPE_STR, ptr)); 428d62bc4baSyz } 429d62bc4baSyz 430d62bc4baSyz static size_t 431d62bc4baSyz write_boolean(char *buffer, size_t buffer_length, char *name, void *value) 432d62bc4baSyz { 433d62bc4baSyz boolean_t *ptr = value; 434d62bc4baSyz 435d62bc4baSyz /* 436d62bc4baSyz * Booleans are either zero or one, so we only need room for two 437d62bc4baSyz * characters in the buffer. 438d62bc4baSyz */ 439d62bc4baSyz if (buffer_length <= 1 + BASE_PROPERTY_LENGTH(DLADM_TYPE_BOOLEAN, name)) 440d62bc4baSyz return (0); 441d62bc4baSyz 442d62bc4baSyz return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%d", 443d62bc4baSyz name, DLADM_TYPE_BOOLEAN, *ptr)); 444d62bc4baSyz } 445d62bc4baSyz 446d62bc4baSyz static size_t 447d62bc4baSyz write_uint64(char *buffer, size_t buffer_length, char *name, void *value) 448d62bc4baSyz { 449d62bc4baSyz uint64_t *ptr = value; 450d62bc4baSyz 451d62bc4baSyz /* 452d62bc4baSyz * Limit checking for uint64_t is a little trickier. 453d62bc4baSyz */ 454d62bc4baSyz if (snprintf(NULL, 0, "%lld", *ptr) + 455d62bc4baSyz BASE_PROPERTY_LENGTH(DLADM_TYPE_UINT64, name) >= buffer_length) 456d62bc4baSyz return (0); 457d62bc4baSyz 458d62bc4baSyz return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%lld", 459d62bc4baSyz name, DLADM_TYPE_UINT64, *ptr)); 460d62bc4baSyz } 461d62bc4baSyz 462d62bc4baSyz static size_t 463d62bc4baSyz read_str(char *buffer, void **value) 464d62bc4baSyz { 465024b0a25Sseb char *ptr = calloc(MAXLINKATTRVALLEN, sizeof (char)); 466d62bc4baSyz ssize_t len; 467d62bc4baSyz 468024b0a25Sseb if (ptr == NULL || (len = strlcpy(ptr, buffer, MAXLINKATTRVALLEN)) 469024b0a25Sseb >= MAXLINKATTRVALLEN) { 470d62bc4baSyz free(ptr); 471d62bc4baSyz return (0); 472d62bc4baSyz } 473d62bc4baSyz 474d62bc4baSyz *(char **)value = ptr; 475d62bc4baSyz 476d62bc4baSyz /* Account for NULL terminator */ 477d62bc4baSyz return (len + 1); 478d62bc4baSyz } 479d62bc4baSyz 480d62bc4baSyz static size_t 481d62bc4baSyz read_boolean(char *buffer, void **value) 482d62bc4baSyz { 483d62bc4baSyz boolean_t *ptr = calloc(1, sizeof (boolean_t)); 484d62bc4baSyz 485d62bc4baSyz if (ptr == NULL) 486d62bc4baSyz return (0); 487d62bc4baSyz 488d62bc4baSyz *ptr = atoi(buffer); 489d62bc4baSyz *(boolean_t **)value = ptr; 490d62bc4baSyz 491d62bc4baSyz return (sizeof (boolean_t)); 492d62bc4baSyz } 493d62bc4baSyz 494d62bc4baSyz static size_t 495d62bc4baSyz read_int64(char *buffer, void **value) 496d62bc4baSyz { 497d62bc4baSyz int64_t *ptr = calloc(1, sizeof (int64_t)); 498d62bc4baSyz 499d62bc4baSyz if (ptr == NULL) 500d62bc4baSyz return (0); 501d62bc4baSyz 502d62bc4baSyz *ptr = (int64_t)atoll(buffer); 503d62bc4baSyz *(int64_t **)value = ptr; 504d62bc4baSyz 505d62bc4baSyz return (sizeof (int64_t)); 506d62bc4baSyz } 507d62bc4baSyz 508*2b24ab6bSSebastien Roy static dlmgmt_db_req_t * 509*2b24ab6bSSebastien Roy dlmgmt_db_req_alloc(dlmgmt_db_op_t op, const char *linkname, 510*2b24ab6bSSebastien Roy datalink_id_t linkid, zoneid_t zoneid, uint32_t flags, int *err) 511*2b24ab6bSSebastien Roy { 512*2b24ab6bSSebastien Roy dlmgmt_db_req_t *req; 513*2b24ab6bSSebastien Roy 514*2b24ab6bSSebastien Roy if ((req = calloc(1, sizeof (dlmgmt_db_req_t))) == NULL) { 515*2b24ab6bSSebastien Roy *err = errno; 516*2b24ab6bSSebastien Roy } else { 517*2b24ab6bSSebastien Roy req->ls_op = op; 518*2b24ab6bSSebastien Roy if (linkname != NULL) 519*2b24ab6bSSebastien Roy (void) strlcpy(req->ls_link, linkname, MAXLINKNAMELEN); 520*2b24ab6bSSebastien Roy req->ls_linkid = linkid; 521*2b24ab6bSSebastien Roy req->ls_zoneid = zoneid; 522*2b24ab6bSSebastien Roy req->ls_flags = flags; 523*2b24ab6bSSebastien Roy } 524*2b24ab6bSSebastien Roy return (req); 525*2b24ab6bSSebastien Roy } 526*2b24ab6bSSebastien Roy 527*2b24ab6bSSebastien Roy /* 528*2b24ab6bSSebastien Roy * Update the db entry with name "entryname" using information from "linkp". 529*2b24ab6bSSebastien Roy */ 530d62bc4baSyz static int 531*2b24ab6bSSebastien Roy dlmgmt_db_update(dlmgmt_db_op_t op, const char *entryname, dlmgmt_link_t *linkp, 532*2b24ab6bSSebastien Roy uint32_t flags) 533d62bc4baSyz { 534d62bc4baSyz dlmgmt_db_req_t *req; 535d62bc4baSyz int err; 536d62bc4baSyz 537*2b24ab6bSSebastien Roy /* It is either a persistent request or an active request, not both. */ 538d62bc4baSyz assert((flags == DLMGMT_PERSIST) || (flags == DLMGMT_ACTIVE)); 539d62bc4baSyz 540*2b24ab6bSSebastien Roy if ((req = dlmgmt_db_req_alloc(op, entryname, linkp->ll_linkid, 541*2b24ab6bSSebastien Roy linkp->ll_zoneid, flags, &err)) == NULL) 542*2b24ab6bSSebastien Roy return (err); 543d62bc4baSyz 544d62bc4baSyz /* 545d62bc4baSyz * If the return error is EINPROGRESS, this request is handled 546d62bc4baSyz * asynchronously; return success. 547d62bc4baSyz */ 548d62bc4baSyz err = dlmgmt_process_db_req(req); 549d62bc4baSyz if (err != EINPROGRESS) 550d62bc4baSyz free(req); 551d62bc4baSyz else 552d62bc4baSyz err = 0; 553d62bc4baSyz return (err); 554d62bc4baSyz } 555d62bc4baSyz 556d62bc4baSyz #define DLMGMT_DB_OP_STR(op) \ 557d62bc4baSyz (((op) == DLMGMT_DB_OP_READ) ? "read" : \ 558d62bc4baSyz (((op) == DLMGMT_DB_OP_WRITE) ? "write" : "delete")) 559d62bc4baSyz 560d62bc4baSyz #define DLMGMT_DB_CONF_STR(flag) \ 561d62bc4baSyz (((flag) == DLMGMT_ACTIVE) ? "active" : \ 562d62bc4baSyz (((flag) == DLMGMT_PERSIST) ? "persistent" : "")) 563d62bc4baSyz 564d62bc4baSyz static int 565d62bc4baSyz dlmgmt_process_db_req(dlmgmt_db_req_t *req) 566d62bc4baSyz { 567d62bc4baSyz pthread_t tid; 568d62bc4baSyz boolean_t writeop; 569d62bc4baSyz int err; 570d62bc4baSyz 571d62bc4baSyz /* 572d62bc4baSyz * If there are already pending "write" requests, queue this request in 573d62bc4baSyz * the pending list. Note that this function is called while the 574d62bc4baSyz * dlmgmt_rw_lock is held, so it is safe to access the global variables. 575d62bc4baSyz */ 576d62bc4baSyz writeop = (req->ls_op != DLMGMT_DB_OP_READ); 577d62bc4baSyz if (writeop && (req->ls_flags == DLMGMT_PERSIST) && 578d62bc4baSyz (dlmgmt_db_req_head != NULL)) { 579d62bc4baSyz dlmgmt_db_req_tail->ls_next = req; 580d62bc4baSyz dlmgmt_db_req_tail = req; 581d62bc4baSyz return (EINPROGRESS); 582d62bc4baSyz } 583d62bc4baSyz 584d62bc4baSyz err = dlmgmt_process_db_onereq(req, writeop); 585*2b24ab6bSSebastien Roy if (err != EINPROGRESS && err != 0 && err != ENOENT) { 586d62bc4baSyz /* 587*2b24ab6bSSebastien Roy * Log the error unless the request processing is still in 588*2b24ab6bSSebastien Roy * progress or if the configuration file hasn't been created 589*2b24ab6bSSebastien Roy * yet (ENOENT). 590d62bc4baSyz */ 591d62bc4baSyz dlmgmt_log(LOG_WARNING, "dlmgmt_process_db_onereq() %s " 592d62bc4baSyz "operation on %s configuration failed: %s", 593d62bc4baSyz DLMGMT_DB_OP_STR(req->ls_op), 594d62bc4baSyz DLMGMT_DB_CONF_STR(req->ls_flags), strerror(err)); 595d62bc4baSyz } 596d62bc4baSyz 597d62bc4baSyz if (err == EINPROGRESS) { 598d62bc4baSyz assert(req->ls_flags == DLMGMT_PERSIST); 599d62bc4baSyz assert(writeop && dlmgmt_db_req_head == NULL); 600d62bc4baSyz dlmgmt_db_req_tail = dlmgmt_db_req_head = req; 601d62bc4baSyz err = pthread_create(&tid, NULL, dlmgmt_db_update_thread, NULL); 602d62bc4baSyz if (err == 0) 603d62bc4baSyz return (EINPROGRESS); 604d62bc4baSyz } 605d62bc4baSyz return (err); 606d62bc4baSyz } 607d62bc4baSyz 608d62bc4baSyz static int 609d62bc4baSyz dlmgmt_process_db_onereq(dlmgmt_db_req_t *req, boolean_t writeop) 610d62bc4baSyz { 611d62bc4baSyz int err = 0; 612d62bc4baSyz FILE *fp, *nfp = NULL; 613d62bc4baSyz char file[MAXPATHLEN]; 614d62bc4baSyz char newfile[MAXPATHLEN]; 615d62bc4baSyz 616d62bc4baSyz DLMGMT_MAKE_FILE_DB_PATH(file, (req->ls_flags == DLMGMT_PERSIST)); 617*2b24ab6bSSebastien Roy fp = dlmgmt_zfopen(file, "r", req->ls_zoneid, &err); 618*2b24ab6bSSebastien Roy /* 619*2b24ab6bSSebastien Roy * Note that it is not an error if the file doesn't exist. If we're 620*2b24ab6bSSebastien Roy * reading, we treat this case the same way as an empty file. If 621*2b24ab6bSSebastien Roy * we're writing, the file will be created when we open the file for 622*2b24ab6bSSebastien Roy * writing below. 623*2b24ab6bSSebastien Roy */ 624*2b24ab6bSSebastien Roy if (fp == NULL && !writeop) 625*2b24ab6bSSebastien Roy return (err); 626d62bc4baSyz 627d62bc4baSyz if (writeop) { 628d62bc4baSyz (void) snprintf(newfile, MAXPATHLEN, "%s.new", file); 629*2b24ab6bSSebastien Roy nfp = dlmgmt_zfopen(newfile, "w", req->ls_zoneid, &err); 630*2b24ab6bSSebastien Roy if (nfp == NULL) { 631*2b24ab6bSSebastien Roy /* 632*2b24ab6bSSebastien Roy * EROFS can happen at boot when the file system is 633*2b24ab6bSSebastien Roy * read-only. Return EINPROGRESS so that the caller 634*2b24ab6bSSebastien Roy * can add this request to the pending request list 635*2b24ab6bSSebastien Roy * and start a retry thread. 636*2b24ab6bSSebastien Roy */ 637*2b24ab6bSSebastien Roy err = (errno == EROFS ? EINPROGRESS : errno); 638*2b24ab6bSSebastien Roy goto done; 639d62bc4baSyz } 640d62bc4baSyz } 641*2b24ab6bSSebastien Roy if (writeop) { 642*2b24ab6bSSebastien Roy if ((err = process_db_write(req, fp, nfp)) == 0) 643*2b24ab6bSSebastien Roy err = dlmgmt_zrename(newfile, file, req->ls_zoneid); 644*2b24ab6bSSebastien Roy } else { 645*2b24ab6bSSebastien Roy err = process_db_read(req, fp); 646d62bc4baSyz } 647d62bc4baSyz 648d62bc4baSyz done: 649d62bc4baSyz if (nfp != NULL) { 650d62bc4baSyz (void) fclose(nfp); 651d62bc4baSyz if (err != 0) 652*2b24ab6bSSebastien Roy (void) dlmgmt_zunlink(newfile, req->ls_zoneid); 653d62bc4baSyz } 654d62bc4baSyz (void) fclose(fp); 655d62bc4baSyz return (err); 656d62bc4baSyz } 657d62bc4baSyz 658d62bc4baSyz /*ARGSUSED*/ 659d62bc4baSyz static void * 660d62bc4baSyz dlmgmt_db_update_thread(void *arg) 661d62bc4baSyz { 662d62bc4baSyz dlmgmt_db_req_t *req; 663d62bc4baSyz 664d62bc4baSyz dlmgmt_table_lock(B_TRUE); 665d62bc4baSyz 666d62bc4baSyz assert(dlmgmt_db_req_head != NULL); 667d62bc4baSyz while ((req = dlmgmt_db_req_head) != NULL) { 668d62bc4baSyz assert(req->ls_flags == DLMGMT_PERSIST); 669*2b24ab6bSSebastien Roy if (dlmgmt_process_db_onereq(req, B_TRUE) == EINPROGRESS) { 670d62bc4baSyz /* 671d62bc4baSyz * The filesystem is still read only. Go to sleep and 672d62bc4baSyz * try again. 673d62bc4baSyz */ 674d62bc4baSyz dlmgmt_table_unlock(); 675d62bc4baSyz (void) sleep(5); 676d62bc4baSyz dlmgmt_table_lock(B_TRUE); 677d62bc4baSyz continue; 678d62bc4baSyz } 679d62bc4baSyz 680d62bc4baSyz /* 681d62bc4baSyz * The filesystem is no longer read only. Continue processing 682d62bc4baSyz * and remove the request from the pending list. 683d62bc4baSyz */ 684d62bc4baSyz dlmgmt_db_req_head = req->ls_next; 685d62bc4baSyz if (dlmgmt_db_req_tail == req) { 686d62bc4baSyz assert(dlmgmt_db_req_head == NULL); 687d62bc4baSyz dlmgmt_db_req_tail = NULL; 688d62bc4baSyz } 689d62bc4baSyz free(req); 690d62bc4baSyz } 691d62bc4baSyz 692d62bc4baSyz dlmgmt_table_unlock(); 693d62bc4baSyz return (NULL); 694d62bc4baSyz } 695d62bc4baSyz 696d62bc4baSyz static int 697d62bc4baSyz parse_linkprops(char *buf, dlmgmt_link_t *linkp) 698d62bc4baSyz { 699d62bc4baSyz boolean_t found_type = B_FALSE; 700d62bc4baSyz dladm_datatype_t type = DLADM_TYPE_STR; 701d62bc4baSyz int i, len; 702d62bc4baSyz int err = 0; 703d62bc4baSyz char *curr; 704d62bc4baSyz char attr_name[MAXLINKATTRLEN]; 705d62bc4baSyz size_t attr_buf_len = 0; 706d62bc4baSyz void *attr_buf = NULL; 707d62bc4baSyz 708d62bc4baSyz curr = buf; 709d62bc4baSyz len = strlen(buf); 710d62bc4baSyz attr_name[0] = '\0'; 711d62bc4baSyz for (i = 0; i < len && err == 0; i++) { 712d62bc4baSyz char c = buf[i]; 713d62bc4baSyz boolean_t match = (c == '=' || 714d62bc4baSyz (c == ',' && !found_type) || c == ';'); 715d62bc4baSyz 716d62bc4baSyz /* 717d62bc4baSyz * Move to the next character if there is no match and 718d62bc4baSyz * if we have not reached the last character. 719d62bc4baSyz */ 720d62bc4baSyz if (!match && i != len - 1) 721d62bc4baSyz continue; 722d62bc4baSyz 723d62bc4baSyz if (match) { 724d62bc4baSyz /* 725d62bc4baSyz * NUL-terminate the string pointed to by 'curr'. 726d62bc4baSyz */ 727d62bc4baSyz buf[i] = '\0'; 728d62bc4baSyz if (*curr == '\0') 729d62bc4baSyz goto parse_fail; 730d62bc4baSyz } 731d62bc4baSyz 732d62bc4baSyz if (attr_name[0] != '\0' && found_type) { 733d62bc4baSyz /* 734d62bc4baSyz * We get here after we have processed the "<prop>=" 735d62bc4baSyz * pattern. The pattern we are now interested in is 736d62bc4baSyz * "<val>;". 737d62bc4baSyz */ 738d62bc4baSyz if (c == '=') 739d62bc4baSyz goto parse_fail; 740d62bc4baSyz 741*2b24ab6bSSebastien Roy if (strcmp(attr_name, "linkid") == 0) { 742*2b24ab6bSSebastien Roy (void) read_int64(curr, &attr_buf); 743*2b24ab6bSSebastien Roy linkp->ll_linkid = 744*2b24ab6bSSebastien Roy (datalink_class_t)*(int64_t *)attr_buf; 745*2b24ab6bSSebastien Roy } else if (strcmp(attr_name, "name") == 0) { 746d62bc4baSyz (void) read_str(curr, &attr_buf); 747d62bc4baSyz (void) snprintf(linkp->ll_link, 748d62bc4baSyz MAXLINKNAMELEN, "%s", attr_buf); 749d62bc4baSyz } else if (strcmp(attr_name, "class") == 0) { 750d62bc4baSyz (void) read_int64(curr, &attr_buf); 751d62bc4baSyz linkp->ll_class = 752d62bc4baSyz (datalink_class_t)*(int64_t *)attr_buf; 753d62bc4baSyz } else if (strcmp(attr_name, "media") == 0) { 754d62bc4baSyz (void) read_int64(curr, &attr_buf); 755d62bc4baSyz linkp->ll_media = 756d62bc4baSyz (uint32_t)*(int64_t *)attr_buf; 757d62bc4baSyz } else { 758d62bc4baSyz attr_buf_len = translators[type].read_func(curr, 759d62bc4baSyz &attr_buf); 760d62bc4baSyz err = linkattr_set(&(linkp->ll_head), attr_name, 761d62bc4baSyz attr_buf, attr_buf_len, type); 762d62bc4baSyz } 763d62bc4baSyz 764d62bc4baSyz free(attr_buf); 765d62bc4baSyz attr_name[0] = '\0'; 766d62bc4baSyz found_type = B_FALSE; 767d62bc4baSyz } else if (attr_name[0] != '\0') { 768d62bc4baSyz /* 769d62bc4baSyz * Non-zero length attr_name and found_type of false 770d62bc4baSyz * indicates that we have not found the type for this 771d62bc4baSyz * attribute. The pattern now is "<type>,<val>;", we 772d62bc4baSyz * want the <type> part of the pattern. 773d62bc4baSyz */ 774d62bc4baSyz for (type = 0; type < ntranslators; type++) { 775d62bc4baSyz if (strcmp(curr, 776d62bc4baSyz translators[type].type_name) == 0) { 777d62bc4baSyz found_type = B_TRUE; 778d62bc4baSyz break; 779d62bc4baSyz } 780d62bc4baSyz } 781d62bc4baSyz 782d62bc4baSyz if (!found_type) 783d62bc4baSyz goto parse_fail; 784d62bc4baSyz } else { 785d62bc4baSyz /* 786d62bc4baSyz * A zero length attr_name indicates we are looking 787d62bc4baSyz * at the beginning of a link attribute. 788d62bc4baSyz */ 789d62bc4baSyz if (c != '=') 790d62bc4baSyz goto parse_fail; 791d62bc4baSyz 792d62bc4baSyz (void) snprintf(attr_name, MAXLINKATTRLEN, "%s", curr); 793d62bc4baSyz } 794d62bc4baSyz curr = buf + i + 1; 795d62bc4baSyz } 796d62bc4baSyz 797d62bc4baSyz return (err); 798d62bc4baSyz 799d62bc4baSyz parse_fail: 800d62bc4baSyz return (-1); 801d62bc4baSyz } 802d62bc4baSyz 803d62bc4baSyz static boolean_t 804*2b24ab6bSSebastien Roy process_link_line(char *buf, dlmgmt_link_t *linkp) 805d62bc4baSyz { 806*2b24ab6bSSebastien Roy int i, len, llen; 807*2b24ab6bSSebastien Roy char *str, *lasts; 808*2b24ab6bSSebastien Roy char tmpbuf[MAXLINELEN]; 809*2b24ab6bSSebastien Roy 810*2b24ab6bSSebastien Roy bzero(linkp, sizeof (*linkp)); 811*2b24ab6bSSebastien Roy linkp->ll_linkid = DATALINK_INVALID_LINKID; 812d62bc4baSyz 813d62bc4baSyz /* 814d62bc4baSyz * Use a copy of buf for parsing so that we can do whatever we want. 815d62bc4baSyz */ 816d62bc4baSyz (void) strlcpy(tmpbuf, buf, MAXLINELEN); 817d62bc4baSyz 818d62bc4baSyz /* 819d62bc4baSyz * Skip leading spaces, blank lines, and comments. 820d62bc4baSyz */ 821d62bc4baSyz len = strlen(tmpbuf); 822d62bc4baSyz for (i = 0; i < len; i++) { 823d62bc4baSyz if (!isspace(tmpbuf[i])) 824d62bc4baSyz break; 825d62bc4baSyz } 826*2b24ab6bSSebastien Roy if (i == len || tmpbuf[i] == '#') 827d62bc4baSyz return (B_TRUE); 828d62bc4baSyz 829d62bc4baSyz str = tmpbuf + i; 830d62bc4baSyz /* 831*2b24ab6bSSebastien Roy * Find the link name and assign it to the link structure. 832d62bc4baSyz */ 833d62bc4baSyz if (strtok_r(str, " \n\t", &lasts) == NULL) 834d62bc4baSyz goto fail; 835d62bc4baSyz 836d62bc4baSyz llen = strlen(str); 837*2b24ab6bSSebastien Roy /* 838*2b24ab6bSSebastien Roy * Note that a previous version of the persistent datalink.conf file 839*2b24ab6bSSebastien Roy * stored the linkid as the first field. In that case, the name will 840*2b24ab6bSSebastien Roy * be obtained through parse_linkprops from a property with the format 841*2b24ab6bSSebastien Roy * "name=<linkname>". If we encounter such a format, we set 842*2b24ab6bSSebastien Roy * rewrite_needed so that dlmgmt_db_init() can rewrite the file with 843*2b24ab6bSSebastien Roy * the new format after it's done reading in the data. 844*2b24ab6bSSebastien Roy */ 845*2b24ab6bSSebastien Roy if (isdigit(str[0])) { 846*2b24ab6bSSebastien Roy linkp->ll_linkid = atoi(str); 847*2b24ab6bSSebastien Roy rewrite_needed = B_TRUE; 848*2b24ab6bSSebastien Roy } else { 849*2b24ab6bSSebastien Roy if (strlcpy(linkp->ll_link, str, sizeof (linkp->ll_link)) >= 850*2b24ab6bSSebastien Roy sizeof (linkp->ll_link)) 851*2b24ab6bSSebastien Roy goto fail; 852*2b24ab6bSSebastien Roy } 853d62bc4baSyz 854d62bc4baSyz str += llen + 1; 855d62bc4baSyz if (str >= tmpbuf + len) 856d62bc4baSyz goto fail; 857d62bc4baSyz 858d62bc4baSyz /* 859d62bc4baSyz * Now find the list of link properties. 860d62bc4baSyz */ 861d62bc4baSyz if ((str = strtok_r(str, " \n\t", &lasts)) == NULL) 862d62bc4baSyz goto fail; 863d62bc4baSyz 864d62bc4baSyz if (parse_linkprops(str, linkp) < 0) 865d62bc4baSyz goto fail; 866d62bc4baSyz 867d62bc4baSyz return (B_TRUE); 868d62bc4baSyz 869d62bc4baSyz fail: 870d62bc4baSyz /* 871d62bc4baSyz * Delete corrupted line. 872d62bc4baSyz */ 873d62bc4baSyz buf[0] = '\0'; 874d62bc4baSyz return (B_FALSE); 875d62bc4baSyz } 876d62bc4baSyz 877*2b24ab6bSSebastien Roy /* 878*2b24ab6bSSebastien Roy * Find any properties in linkp that refer to "old", and rename to "new". 879*2b24ab6bSSebastien Roy * Return B_TRUE if any renaming occurred. 880*2b24ab6bSSebastien Roy */ 881*2b24ab6bSSebastien Roy static int 882*2b24ab6bSSebastien Roy dlmgmt_attr_rename(dlmgmt_link_t *linkp, const char *old, const char *new, 883*2b24ab6bSSebastien Roy boolean_t *renamed) 884*2b24ab6bSSebastien Roy { 885*2b24ab6bSSebastien Roy dlmgmt_linkattr_t *attrp; 886*2b24ab6bSSebastien Roy char *newval = NULL, *pname; 887*2b24ab6bSSebastien Roy char valcp[MAXLINKATTRVALLEN]; 888*2b24ab6bSSebastien Roy size_t newsize; 889*2b24ab6bSSebastien Roy 890*2b24ab6bSSebastien Roy *renamed = B_FALSE; 891*2b24ab6bSSebastien Roy 892*2b24ab6bSSebastien Roy if ((attrp = linkattr_find(linkp->ll_head, "linkover")) != NULL || 893*2b24ab6bSSebastien Roy (attrp = linkattr_find(linkp->ll_head, "simnetpeer")) != NULL) { 894*2b24ab6bSSebastien Roy if (strcmp(old, (char *)attrp->lp_val) == 0) { 895*2b24ab6bSSebastien Roy newsize = strlen(new) + 1; 896*2b24ab6bSSebastien Roy if ((newval = malloc(newsize)) == NULL) 897*2b24ab6bSSebastien Roy return (errno); 898*2b24ab6bSSebastien Roy (void) strcpy(newval, new); 899*2b24ab6bSSebastien Roy free(attrp->lp_val); 900*2b24ab6bSSebastien Roy attrp->lp_val = newval; 901*2b24ab6bSSebastien Roy attrp->lp_sz = newsize; 902*2b24ab6bSSebastien Roy *renamed = B_TRUE; 903*2b24ab6bSSebastien Roy } 904*2b24ab6bSSebastien Roy return (0); 905*2b24ab6bSSebastien Roy } 906*2b24ab6bSSebastien Roy 907*2b24ab6bSSebastien Roy if ((attrp = linkattr_find(linkp->ll_head, "portnames")) == NULL) 908*2b24ab6bSSebastien Roy return (0); 909*2b24ab6bSSebastien Roy 910*2b24ab6bSSebastien Roy /* <linkname>:[<linkname>:]... */ 911*2b24ab6bSSebastien Roy if ((newval = calloc(MAXLINKATTRVALLEN, sizeof (char))) == NULL) 912*2b24ab6bSSebastien Roy return (errno); 913*2b24ab6bSSebastien Roy 914*2b24ab6bSSebastien Roy bcopy(attrp->lp_val, valcp, sizeof (valcp)); 915*2b24ab6bSSebastien Roy pname = strtok(valcp, ":"); 916*2b24ab6bSSebastien Roy while (pname != NULL) { 917*2b24ab6bSSebastien Roy if (strcmp(pname, old) == 0) { 918*2b24ab6bSSebastien Roy (void) strcat(newval, new); 919*2b24ab6bSSebastien Roy *renamed = B_TRUE; 920*2b24ab6bSSebastien Roy } else { 921*2b24ab6bSSebastien Roy (void) strcat(newval, pname); 922*2b24ab6bSSebastien Roy } 923*2b24ab6bSSebastien Roy (void) strcat(newval, ":"); 924*2b24ab6bSSebastien Roy pname = strtok(NULL, ":"); 925*2b24ab6bSSebastien Roy } 926*2b24ab6bSSebastien Roy if (*renamed) { 927*2b24ab6bSSebastien Roy free(attrp->lp_val); 928*2b24ab6bSSebastien Roy attrp->lp_val = newval; 929*2b24ab6bSSebastien Roy attrp->lp_sz = strlen(newval) + 1; 930*2b24ab6bSSebastien Roy } else { 931*2b24ab6bSSebastien Roy free(newval); 932*2b24ab6bSSebastien Roy } 933*2b24ab6bSSebastien Roy return (0); 934*2b24ab6bSSebastien Roy } 935*2b24ab6bSSebastien Roy 936d62bc4baSyz static int 937d62bc4baSyz process_db_write(dlmgmt_db_req_t *req, FILE *fp, FILE *nfp) 938d62bc4baSyz { 939d62bc4baSyz boolean_t done = B_FALSE; 940d62bc4baSyz int err = 0; 941*2b24ab6bSSebastien Roy dlmgmt_link_t link_in_file, *linkp = NULL, *dblinkp; 942*2b24ab6bSSebastien Roy boolean_t persist = (req->ls_flags == DLMGMT_PERSIST); 943*2b24ab6bSSebastien Roy boolean_t writeall, rename, attr_renamed; 944d62bc4baSyz char buf[MAXLINELEN]; 945d62bc4baSyz 946*2b24ab6bSSebastien Roy writeall = (req->ls_linkid == DATALINK_ALL_LINKID); 947*2b24ab6bSSebastien Roy 948*2b24ab6bSSebastien Roy if (req->ls_op == DLMGMT_DB_OP_WRITE && !writeall) { 949d62bc4baSyz /* 950d62bc4baSyz * find the link in the avl tree with the given linkid. 951d62bc4baSyz */ 952*2b24ab6bSSebastien Roy linkp = link_by_id(req->ls_linkid, req->ls_zoneid); 953d62bc4baSyz if (linkp == NULL || (linkp->ll_flags & req->ls_flags) == 0) { 954d62bc4baSyz /* 955d62bc4baSyz * This link has already been changed. This could 956d62bc4baSyz * happen if the request is pending because of 957d62bc4baSyz * read-only file-system. If so, we are done. 958d62bc4baSyz */ 959d62bc4baSyz return (0); 960d62bc4baSyz } 961*2b24ab6bSSebastien Roy /* 962*2b24ab6bSSebastien Roy * In the case of a rename, linkp's name has been updated to 963*2b24ab6bSSebastien Roy * the new name, and req->ls_link is the old link name. 964*2b24ab6bSSebastien Roy */ 965*2b24ab6bSSebastien Roy rename = (strcmp(req->ls_link, linkp->ll_link) != 0); 966d62bc4baSyz } 967d62bc4baSyz 968*2b24ab6bSSebastien Roy /* 969*2b24ab6bSSebastien Roy * fp can be NULL if the file didn't initially exist and we're 970*2b24ab6bSSebastien Roy * creating it as part of this write operation. 971*2b24ab6bSSebastien Roy */ 972*2b24ab6bSSebastien Roy if (fp == NULL) 973*2b24ab6bSSebastien Roy goto write; 974*2b24ab6bSSebastien Roy 975d62bc4baSyz while (err == 0 && fgets(buf, sizeof (buf), fp) != NULL && 976d62bc4baSyz process_link_line(buf, &link_in_file)) { 977*2b24ab6bSSebastien Roy if (link_in_file.ll_link[0] == '\0' || done) { 978d62bc4baSyz /* 9790dc974a9SCathy Zhou * this is a comment line or we are done updating the 980*2b24ab6bSSebastien Roy * line for the specified link, write the rest of 981*2b24ab6bSSebastien Roy * lines out. 982d62bc4baSyz */ 983d62bc4baSyz if (fputs(buf, nfp) == EOF) 984d62bc4baSyz err = errno; 985d62bc4baSyz continue; 986d62bc4baSyz } 987d62bc4baSyz 988d62bc4baSyz switch (req->ls_op) { 989d62bc4baSyz case DLMGMT_DB_OP_WRITE: 990d62bc4baSyz /* 991*2b24ab6bSSebastien Roy * For write operations, we generate a new output line 992*2b24ab6bSSebastien Roy * if we're either writing all links (writeall) or if 993*2b24ab6bSSebastien Roy * the name of the link in the file matches the one 994*2b24ab6bSSebastien Roy * we're looking for. Otherwise, we write out the 995*2b24ab6bSSebastien Roy * buffer as-is. 996*2b24ab6bSSebastien Roy * 997*2b24ab6bSSebastien Roy * If we're doing a rename operation, ensure that any 998*2b24ab6bSSebastien Roy * references to the link being renamed in link 999*2b24ab6bSSebastien Roy * properties are also updated before we write 1000*2b24ab6bSSebastien Roy * anything. 1001d62bc4baSyz */ 1002*2b24ab6bSSebastien Roy if (writeall) { 1003*2b24ab6bSSebastien Roy linkp = link_by_name(link_in_file.ll_link, 1004*2b24ab6bSSebastien Roy req->ls_zoneid); 1005d62bc4baSyz } 1006*2b24ab6bSSebastien Roy if (writeall || strcmp(req->ls_link, 1007*2b24ab6bSSebastien Roy link_in_file.ll_link) == 0) { 1008*2b24ab6bSSebastien Roy generate_link_line(linkp, persist, buf); 1009*2b24ab6bSSebastien Roy if (!writeall && !rename) 1010*2b24ab6bSSebastien Roy done = B_TRUE; 1011*2b24ab6bSSebastien Roy } else if (rename && persist) { 1012*2b24ab6bSSebastien Roy dblinkp = link_by_name(link_in_file.ll_link, 1013*2b24ab6bSSebastien Roy req->ls_zoneid); 1014*2b24ab6bSSebastien Roy err = dlmgmt_attr_rename(dblinkp, req->ls_link, 1015*2b24ab6bSSebastien Roy linkp->ll_link, &attr_renamed); 1016*2b24ab6bSSebastien Roy if (err != 0) 1017*2b24ab6bSSebastien Roy break; 1018*2b24ab6bSSebastien Roy if (attr_renamed) { 1019*2b24ab6bSSebastien Roy generate_link_line(dblinkp, persist, 1020*2b24ab6bSSebastien Roy buf); 1021*2b24ab6bSSebastien Roy } 1022*2b24ab6bSSebastien Roy } 1023*2b24ab6bSSebastien Roy if (fputs(buf, nfp) == EOF) 1024*2b24ab6bSSebastien Roy err = errno; 1025d62bc4baSyz break; 1026d62bc4baSyz case DLMGMT_DB_OP_DELETE: 1027d62bc4baSyz /* 1028d62bc4baSyz * Delete is simple. If buf does not represent the 1029d62bc4baSyz * link we're deleting, write it out. 1030d62bc4baSyz */ 1031*2b24ab6bSSebastien Roy if (strcmp(req->ls_link, link_in_file.ll_link) != 0) { 1032d62bc4baSyz if (fputs(buf, nfp) == EOF) 1033d62bc4baSyz err = errno; 1034d62bc4baSyz } else { 1035d62bc4baSyz done = B_TRUE; 1036d62bc4baSyz } 1037d62bc4baSyz break; 1038d62bc4baSyz case DLMGMT_DB_OP_READ: 1039d62bc4baSyz default: 1040d62bc4baSyz err = EINVAL; 1041d62bc4baSyz break; 1042d62bc4baSyz } 1043d62bc4baSyz } 1044d62bc4baSyz 1045*2b24ab6bSSebastien Roy write: 1046d62bc4baSyz /* 1047*2b24ab6bSSebastien Roy * If we get to the end of the file and have not seen what linkid 1048*2b24ab6bSSebastien Roy * points to, write it out then. 1049d62bc4baSyz */ 1050*2b24ab6bSSebastien Roy if (req->ls_op == DLMGMT_DB_OP_WRITE && !writeall && !rename && !done) { 1051*2b24ab6bSSebastien Roy generate_link_line(linkp, persist, buf); 1052d62bc4baSyz done = B_TRUE; 1053d62bc4baSyz if (fputs(buf, nfp) == EOF) 1054d62bc4baSyz err = errno; 1055d62bc4baSyz } 1056d62bc4baSyz 1057d62bc4baSyz return (err); 1058d62bc4baSyz } 1059d62bc4baSyz 1060d62bc4baSyz static int 1061*2b24ab6bSSebastien Roy process_db_read(dlmgmt_db_req_t *req, FILE *fp) 1062d62bc4baSyz { 1063d62bc4baSyz avl_index_t name_where, id_where; 1064*2b24ab6bSSebastien Roy dlmgmt_link_t link_in_file, *newlink, *link_in_db; 1065d62bc4baSyz char buf[MAXLINELEN]; 1066d62bc4baSyz int err = 0; 1067d62bc4baSyz 1068d62bc4baSyz /* 1069d62bc4baSyz * This loop processes each line of the configuration file. 1070d62bc4baSyz */ 1071d62bc4baSyz while (fgets(buf, MAXLINELEN, fp) != NULL) { 1072d62bc4baSyz if (!process_link_line(buf, &link_in_file)) { 1073d62bc4baSyz err = EINVAL; 1074d62bc4baSyz break; 1075d62bc4baSyz } 1076d62bc4baSyz 1077d62bc4baSyz /* 1078d62bc4baSyz * Skip the comment line. 1079d62bc4baSyz */ 1080*2b24ab6bSSebastien Roy if (link_in_file.ll_link[0] == '\0') 1081*2b24ab6bSSebastien Roy continue; 1082*2b24ab6bSSebastien Roy 1083*2b24ab6bSSebastien Roy if ((req->ls_flags & DLMGMT_ACTIVE) && 1084*2b24ab6bSSebastien Roy link_in_file.ll_linkid == DATALINK_INVALID_LINKID) 1085d62bc4baSyz continue; 1086d62bc4baSyz 1087*2b24ab6bSSebastien Roy link_in_file.ll_zoneid = req->ls_zoneid; 1088*2b24ab6bSSebastien Roy link_in_db = avl_find(&dlmgmt_name_avl, &link_in_file, 1089*2b24ab6bSSebastien Roy &name_where); 1090*2b24ab6bSSebastien Roy if (link_in_db != NULL) { 1091d62bc4baSyz /* 1092*2b24ab6bSSebastien Roy * If the link in the database already has the flag 1093*2b24ab6bSSebastien Roy * for this request set, then the entry is a 1094*2b24ab6bSSebastien Roy * duplicate. If it's not a duplicate, then simply 1095*2b24ab6bSSebastien Roy * turn on the appropriate flag on the existing link. 1096d62bc4baSyz */ 1097*2b24ab6bSSebastien Roy if (link_in_db->ll_flags & req->ls_flags) { 1098*2b24ab6bSSebastien Roy dlmgmt_log(LOG_WARNING, "Duplicate links " 1099*2b24ab6bSSebastien Roy "in the repository: %s", 1100*2b24ab6bSSebastien Roy link_in_file.ll_link); 1101d62bc4baSyz } else { 1102*2b24ab6bSSebastien Roy if (req->ls_flags & DLMGMT_PERSIST) { 1103*2b24ab6bSSebastien Roy /* 1104*2b24ab6bSSebastien Roy * Save the newly read properties into 1105*2b24ab6bSSebastien Roy * the existing link. 1106*2b24ab6bSSebastien Roy */ 1107*2b24ab6bSSebastien Roy assert(link_in_db->ll_head == NULL); 1108*2b24ab6bSSebastien Roy link_in_db->ll_head = 1109*2b24ab6bSSebastien Roy link_in_file.ll_head; 1110*2b24ab6bSSebastien Roy } 1111*2b24ab6bSSebastien Roy link_in_db->ll_flags |= req->ls_flags; 1112d62bc4baSyz } 1113d62bc4baSyz } else { 1114*2b24ab6bSSebastien Roy /* 1115*2b24ab6bSSebastien Roy * This is a new link. Allocate a new dlmgmt_link_t 1116*2b24ab6bSSebastien Roy * and add it to the trees. 1117*2b24ab6bSSebastien Roy */ 1118*2b24ab6bSSebastien Roy newlink = calloc(1, sizeof (*newlink)); 1119*2b24ab6bSSebastien Roy if (newlink == NULL) { 1120*2b24ab6bSSebastien Roy dlmgmt_log(LOG_WARNING, "Unable to allocate " 1121*2b24ab6bSSebastien Roy "memory to create new link %s", 1122*2b24ab6bSSebastien Roy link_in_file.ll_link); 1123*2b24ab6bSSebastien Roy continue; 1124*2b24ab6bSSebastien Roy } 1125*2b24ab6bSSebastien Roy bcopy(&link_in_file, newlink, sizeof (*newlink)); 1126*2b24ab6bSSebastien Roy 1127*2b24ab6bSSebastien Roy if (newlink->ll_linkid == DATALINK_INVALID_LINKID) 1128*2b24ab6bSSebastien Roy newlink->ll_linkid = dlmgmt_nextlinkid; 1129*2b24ab6bSSebastien Roy if (avl_find(&dlmgmt_id_avl, newlink, &id_where) != 1130*2b24ab6bSSebastien Roy NULL) { 1131*2b24ab6bSSebastien Roy link_destroy(newlink); 1132*2b24ab6bSSebastien Roy continue; 1133*2b24ab6bSSebastien Roy } 1134*2b24ab6bSSebastien Roy if ((req->ls_flags & DLMGMT_ACTIVE) && 1135*2b24ab6bSSebastien Roy link_activate(newlink) != 0) { 1136*2b24ab6bSSebastien Roy dlmgmt_log(LOG_WARNING, "Unable to activate %s", 1137*2b24ab6bSSebastien Roy newlink->ll_link); 1138*2b24ab6bSSebastien Roy link_destroy(newlink); 1139*2b24ab6bSSebastien Roy continue; 1140*2b24ab6bSSebastien Roy } 1141*2b24ab6bSSebastien Roy avl_insert(&dlmgmt_name_avl, newlink, name_where); 1142*2b24ab6bSSebastien Roy avl_insert(&dlmgmt_id_avl, newlink, id_where); 1143*2b24ab6bSSebastien Roy dlmgmt_advance(newlink); 1144*2b24ab6bSSebastien Roy newlink->ll_flags |= req->ls_flags; 1145d62bc4baSyz } 1146d62bc4baSyz } 1147d62bc4baSyz 1148d62bc4baSyz return (err); 1149d62bc4baSyz } 1150d62bc4baSyz 1151d62bc4baSyz /* 1152d62bc4baSyz * Generate an entry in the link database. 1153d62bc4baSyz * Each entry has this format: 1154*2b24ab6bSSebastien Roy * <link name> <prop0>=<type>,<val>;...;<propn>=<type>,<val>; 1155d62bc4baSyz */ 1156d62bc4baSyz static void 1157d62bc4baSyz generate_link_line(dlmgmt_link_t *linkp, boolean_t persist, char *buf) 1158d62bc4baSyz { 1159d62bc4baSyz char tmpbuf[MAXLINELEN]; 1160*2b24ab6bSSebastien Roy char *ptr = tmpbuf; 1161d62bc4baSyz char *lim = tmpbuf + MAXLINELEN; 1162d62bc4baSyz dlmgmt_linkattr_t *cur_p = NULL; 1163d62bc4baSyz uint64_t u64; 1164d62bc4baSyz 1165*2b24ab6bSSebastien Roy ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t", linkp->ll_link); 1166*2b24ab6bSSebastien Roy if (!persist) { 1167*2b24ab6bSSebastien Roy /* 1168*2b24ab6bSSebastien Roy * We store the linkid in the active database so that dlmgmtd 1169*2b24ab6bSSebastien Roy * can recover in the event that it is restarted. 1170*2b24ab6bSSebastien Roy */ 1171*2b24ab6bSSebastien Roy u64 = linkp->ll_linkid; 1172*2b24ab6bSSebastien Roy ptr += write_uint64(ptr, BUFLEN(lim, ptr), "linkid", &u64); 1173*2b24ab6bSSebastien Roy } 1174d62bc4baSyz u64 = linkp->ll_class; 1175d62bc4baSyz ptr += write_uint64(ptr, BUFLEN(lim, ptr), "class", &u64); 1176d62bc4baSyz u64 = linkp->ll_media; 1177d62bc4baSyz ptr += write_uint64(ptr, BUFLEN(lim, ptr), "media", &u64); 1178d62bc4baSyz 1179d62bc4baSyz /* 1180*2b24ab6bSSebastien Roy * The daemon does not keep any active link attribute. Only store the 1181*2b24ab6bSSebastien Roy * attributes if this request is for persistent configuration, 1182d62bc4baSyz */ 1183*2b24ab6bSSebastien Roy if (persist) { 1184*2b24ab6bSSebastien Roy for (cur_p = linkp->ll_head; cur_p != NULL; 1185*2b24ab6bSSebastien Roy cur_p = cur_p->lp_next) { 1186*2b24ab6bSSebastien Roy ptr += translators[cur_p->lp_type].write_func(ptr, 1187*2b24ab6bSSebastien Roy BUFLEN(lim, ptr), cur_p->lp_name, cur_p->lp_val); 1188*2b24ab6bSSebastien Roy } 1189d62bc4baSyz } 1190*2b24ab6bSSebastien Roy 1191*2b24ab6bSSebastien Roy if (ptr <= lim) 1192*2b24ab6bSSebastien Roy (void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf); 1193d62bc4baSyz } 1194d62bc4baSyz 1195d62bc4baSyz int 1196*2b24ab6bSSebastien Roy dlmgmt_delete_db_entry(dlmgmt_link_t *linkp, uint32_t flags) 1197d62bc4baSyz { 1198*2b24ab6bSSebastien Roy return (dlmgmt_db_update(DLMGMT_DB_OP_DELETE, linkp->ll_link, linkp, 1199*2b24ab6bSSebastien Roy flags)); 1200d62bc4baSyz } 1201d62bc4baSyz 1202d62bc4baSyz int 1203*2b24ab6bSSebastien Roy dlmgmt_write_db_entry(const char *entryname, dlmgmt_link_t *linkp, 1204*2b24ab6bSSebastien Roy uint32_t flags) 1205d62bc4baSyz { 1206*2b24ab6bSSebastien Roy int err; 1207d62bc4baSyz 1208d62bc4baSyz if (flags & DLMGMT_PERSIST) { 1209*2b24ab6bSSebastien Roy if ((err = dlmgmt_db_update(DLMGMT_DB_OP_WRITE, entryname, 1210*2b24ab6bSSebastien Roy linkp, DLMGMT_PERSIST)) != 0) { 1211d62bc4baSyz return (err); 1212d62bc4baSyz } 1213d62bc4baSyz } 1214d62bc4baSyz 1215d62bc4baSyz if (flags & DLMGMT_ACTIVE) { 1216*2b24ab6bSSebastien Roy if (((err = dlmgmt_db_update(DLMGMT_DB_OP_WRITE, entryname, 1217*2b24ab6bSSebastien Roy linkp, DLMGMT_ACTIVE)) != 0) && (flags & DLMGMT_PERSIST)) { 1218*2b24ab6bSSebastien Roy (void) dlmgmt_db_update(DLMGMT_DB_OP_DELETE, entryname, 1219*2b24ab6bSSebastien Roy linkp, DLMGMT_PERSIST); 1220d62bc4baSyz return (err); 1221d62bc4baSyz } 1222d62bc4baSyz } 1223d62bc4baSyz 1224d62bc4baSyz return (0); 1225d62bc4baSyz } 1226d62bc4baSyz 1227*2b24ab6bSSebastien Roy /* 1228*2b24ab6bSSebastien Roy * Upgrade properties that have link IDs as values to link names. Because '.' 1229*2b24ab6bSSebastien Roy * is a valid linkname character, the port separater for link aggregations 1230*2b24ab6bSSebastien Roy * must be changed to ':'.4 1231*2b24ab6bSSebastien Roy */ 1232*2b24ab6bSSebastien Roy static void 1233*2b24ab6bSSebastien Roy linkattr_upgrade(dlmgmt_linkattr_t *attrp) 1234*2b24ab6bSSebastien Roy { 1235*2b24ab6bSSebastien Roy datalink_id_t linkid; 1236*2b24ab6bSSebastien Roy char *portidstr; 1237*2b24ab6bSSebastien Roy char portname[MAXLINKNAMELEN + 1]; 1238*2b24ab6bSSebastien Roy dlmgmt_link_t *linkp; 1239*2b24ab6bSSebastien Roy char *new_attr_val; 1240*2b24ab6bSSebastien Roy size_t new_attr_sz; 1241*2b24ab6bSSebastien Roy boolean_t upgraded = B_FALSE; 1242*2b24ab6bSSebastien Roy 1243*2b24ab6bSSebastien Roy if (strcmp(attrp->lp_name, "linkover") == 0 || 1244*2b24ab6bSSebastien Roy strcmp(attrp->lp_name, "simnetpeer") == 0) { 1245*2b24ab6bSSebastien Roy if (attrp->lp_type == DLADM_TYPE_UINT64) { 1246*2b24ab6bSSebastien Roy linkid = *(datalink_id_t *)attrp->lp_val; 1247*2b24ab6bSSebastien Roy if ((linkp = link_by_id(linkid, GLOBAL_ZONEID)) == NULL) 1248*2b24ab6bSSebastien Roy return; 1249*2b24ab6bSSebastien Roy new_attr_sz = strlen(linkp->ll_link) + 1; 1250*2b24ab6bSSebastien Roy if ((new_attr_val = malloc(new_attr_sz)) == NULL) 1251*2b24ab6bSSebastien Roy return; 1252*2b24ab6bSSebastien Roy (void) strcpy(new_attr_val, linkp->ll_link); 1253*2b24ab6bSSebastien Roy upgraded = B_TRUE; 1254*2b24ab6bSSebastien Roy } 1255*2b24ab6bSSebastien Roy } else if (strcmp(attrp->lp_name, "portnames") == 0) { 1256*2b24ab6bSSebastien Roy /* 1257*2b24ab6bSSebastien Roy * The old format for "portnames" was 1258*2b24ab6bSSebastien Roy * "<linkid>.[<linkid>.]...". The new format is 1259*2b24ab6bSSebastien Roy * "<linkname>:[<linkname>:]...". 1260*2b24ab6bSSebastien Roy */ 1261*2b24ab6bSSebastien Roy if (!isdigit(((char *)attrp->lp_val)[0])) 1262*2b24ab6bSSebastien Roy return; 1263*2b24ab6bSSebastien Roy new_attr_val = calloc(MAXLINKATTRVALLEN, sizeof (char)); 1264*2b24ab6bSSebastien Roy if (new_attr_val == NULL) 1265*2b24ab6bSSebastien Roy return; 1266*2b24ab6bSSebastien Roy portidstr = (char *)attrp->lp_val; 1267*2b24ab6bSSebastien Roy while (*portidstr != '\0') { 1268*2b24ab6bSSebastien Roy errno = 0; 1269*2b24ab6bSSebastien Roy linkid = strtol(portidstr, &portidstr, 10); 1270*2b24ab6bSSebastien Roy if (linkid == 0 || *portidstr != '.' || 1271*2b24ab6bSSebastien Roy (linkp = link_by_id(linkid, GLOBAL_ZONEID)) == 1272*2b24ab6bSSebastien Roy NULL) { 1273*2b24ab6bSSebastien Roy free(new_attr_val); 1274*2b24ab6bSSebastien Roy return; 1275*2b24ab6bSSebastien Roy } 1276*2b24ab6bSSebastien Roy (void) snprintf(portname, sizeof (portname), "%s:", 1277*2b24ab6bSSebastien Roy linkp->ll_link); 1278*2b24ab6bSSebastien Roy if (strlcat(new_attr_val, portname, 1279*2b24ab6bSSebastien Roy MAXLINKATTRVALLEN) >= MAXLINKATTRVALLEN) { 1280*2b24ab6bSSebastien Roy free(new_attr_val); 1281*2b24ab6bSSebastien Roy return; 1282*2b24ab6bSSebastien Roy } 1283*2b24ab6bSSebastien Roy /* skip the '.' delimiter */ 1284*2b24ab6bSSebastien Roy portidstr++; 1285*2b24ab6bSSebastien Roy } 1286*2b24ab6bSSebastien Roy new_attr_sz = strlen(new_attr_val) + 1; 1287*2b24ab6bSSebastien Roy upgraded = B_TRUE; 1288*2b24ab6bSSebastien Roy } 1289*2b24ab6bSSebastien Roy 1290*2b24ab6bSSebastien Roy if (upgraded) { 1291*2b24ab6bSSebastien Roy attrp->lp_type = DLADM_TYPE_STR; 1292*2b24ab6bSSebastien Roy attrp->lp_sz = new_attr_sz; 1293*2b24ab6bSSebastien Roy free(attrp->lp_val); 1294*2b24ab6bSSebastien Roy attrp->lp_val = new_attr_val; 1295*2b24ab6bSSebastien Roy } 1296*2b24ab6bSSebastien Roy } 1297*2b24ab6bSSebastien Roy 1298*2b24ab6bSSebastien Roy static void 1299*2b24ab6bSSebastien Roy dlmgmt_db_upgrade(dlmgmt_link_t *linkp) 1300*2b24ab6bSSebastien Roy { 1301*2b24ab6bSSebastien Roy dlmgmt_linkattr_t *attrp; 1302*2b24ab6bSSebastien Roy 1303*2b24ab6bSSebastien Roy for (attrp = linkp->ll_head; attrp != NULL; attrp = attrp->lp_next) 1304*2b24ab6bSSebastien Roy linkattr_upgrade(attrp); 1305*2b24ab6bSSebastien Roy } 1306*2b24ab6bSSebastien Roy 1307*2b24ab6bSSebastien Roy static void 1308*2b24ab6bSSebastien Roy dlmgmt_db_phys_activate(dlmgmt_link_t *linkp) 1309*2b24ab6bSSebastien Roy { 1310*2b24ab6bSSebastien Roy linkp->ll_flags |= DLMGMT_ACTIVE; 1311*2b24ab6bSSebastien Roy (void) dlmgmt_write_db_entry(linkp->ll_link, linkp, DLMGMT_ACTIVE); 1312*2b24ab6bSSebastien Roy } 1313*2b24ab6bSSebastien Roy 1314*2b24ab6bSSebastien Roy static void 1315*2b24ab6bSSebastien Roy dlmgmt_db_walk(zoneid_t zoneid, datalink_class_t class, db_walk_func_t *func) 1316*2b24ab6bSSebastien Roy { 1317*2b24ab6bSSebastien Roy dlmgmt_link_t *linkp; 1318*2b24ab6bSSebastien Roy 1319*2b24ab6bSSebastien Roy for (linkp = avl_first(&dlmgmt_id_avl); linkp != NULL; 1320*2b24ab6bSSebastien Roy linkp = AVL_NEXT(&dlmgmt_id_avl, linkp)) { 1321*2b24ab6bSSebastien Roy if (linkp->ll_zoneid == zoneid && (linkp->ll_class & class)) 1322*2b24ab6bSSebastien Roy func(linkp); 1323*2b24ab6bSSebastien Roy } 1324*2b24ab6bSSebastien Roy } 1325*2b24ab6bSSebastien Roy 1326d62bc4baSyz /* 1327d62bc4baSyz * Initialize the datalink <link name, linkid> mapping and the link's 1328d62bc4baSyz * attributes list based on the configuration file /etc/dladm/datalink.conf 1329d62bc4baSyz * and the active configuration cache file 1330b9e076dcSyz * /etc/svc/volatile/dladm/datalink-management:default.cache. 1331d62bc4baSyz */ 1332d62bc4baSyz int 1333*2b24ab6bSSebastien Roy dlmgmt_db_init(zoneid_t zoneid) 1334d62bc4baSyz { 1335*2b24ab6bSSebastien Roy dlmgmt_db_req_t *req; 1336d62bc4baSyz int err; 1337*2b24ab6bSSebastien Roy boolean_t boot = B_FALSE; 1338d62bc4baSyz 1339*2b24ab6bSSebastien Roy if ((req = dlmgmt_db_req_alloc(DLMGMT_DB_OP_READ, NULL, 1340*2b24ab6bSSebastien Roy DATALINK_INVALID_LINKID, zoneid, DLMGMT_ACTIVE, &err)) == NULL) 1341*2b24ab6bSSebastien Roy return (err); 1342d62bc4baSyz 1343*2b24ab6bSSebastien Roy if ((err = dlmgmt_process_db_req(req)) != 0) { 1344d62bc4baSyz /* 1345*2b24ab6bSSebastien Roy * If we get back ENOENT, that means that the active 1346*2b24ab6bSSebastien Roy * configuration file doesn't exist yet, and is not an error. 1347*2b24ab6bSSebastien Roy * We'll create it down below after we've loaded the 1348*2b24ab6bSSebastien Roy * persistent configuration. 1349d62bc4baSyz */ 1350*2b24ab6bSSebastien Roy if (err != ENOENT) 1351*2b24ab6bSSebastien Roy goto done; 1352*2b24ab6bSSebastien Roy boot = B_TRUE; 1353d62bc4baSyz } 1354d62bc4baSyz 1355*2b24ab6bSSebastien Roy req->ls_flags = DLMGMT_PERSIST; 1356*2b24ab6bSSebastien Roy err = dlmgmt_process_db_req(req); 1357*2b24ab6bSSebastien Roy if (err != 0 && err != ENOENT) 1358d62bc4baSyz goto done; 1359*2b24ab6bSSebastien Roy err = 0; 1360*2b24ab6bSSebastien Roy if (rewrite_needed) { 1361d62bc4baSyz /* 1362*2b24ab6bSSebastien Roy * First update links in memory, then dump the entire db to 1363*2b24ab6bSSebastien Roy * disk. 1364d62bc4baSyz */ 1365*2b24ab6bSSebastien Roy dlmgmt_db_walk(zoneid, DATALINK_CLASS_ALL, dlmgmt_db_upgrade); 1366*2b24ab6bSSebastien Roy req->ls_op = DLMGMT_DB_OP_WRITE; 1367*2b24ab6bSSebastien Roy req->ls_linkid = DATALINK_ALL_LINKID; 1368*2b24ab6bSSebastien Roy if ((err = dlmgmt_process_db_req(req)) != 0 && 1369*2b24ab6bSSebastien Roy err != EINPROGRESS) 1370*2b24ab6bSSebastien Roy goto done; 1371*2b24ab6bSSebastien Roy } 1372*2b24ab6bSSebastien Roy if (boot) { 1373*2b24ab6bSSebastien Roy dlmgmt_db_walk(zoneid, DATALINK_CLASS_PHYS, 1374*2b24ab6bSSebastien Roy dlmgmt_db_phys_activate); 1375d62bc4baSyz } 1376d62bc4baSyz 1377d62bc4baSyz done: 1378*2b24ab6bSSebastien Roy if (err == EINPROGRESS) 1379*2b24ab6bSSebastien Roy err = 0; 1380*2b24ab6bSSebastien Roy else 1381*2b24ab6bSSebastien Roy free(req); 1382d62bc4baSyz return (err); 1383d62bc4baSyz } 1384*2b24ab6bSSebastien Roy 1385*2b24ab6bSSebastien Roy /* 1386*2b24ab6bSSebastien Roy * Remove all links in the given zoneid. 1387*2b24ab6bSSebastien Roy */ 1388*2b24ab6bSSebastien Roy void 1389*2b24ab6bSSebastien Roy dlmgmt_db_fini(zoneid_t zoneid) 1390*2b24ab6bSSebastien Roy { 1391*2b24ab6bSSebastien Roy dlmgmt_link_t *linkp = avl_first(&dlmgmt_name_avl), *next_linkp; 1392*2b24ab6bSSebastien Roy 1393*2b24ab6bSSebastien Roy while (linkp != NULL) { 1394*2b24ab6bSSebastien Roy next_linkp = AVL_NEXT(&dlmgmt_name_avl, linkp); 1395*2b24ab6bSSebastien Roy if (linkp->ll_zoneid == zoneid) { 1396*2b24ab6bSSebastien Roy (void) dlmgmt_destroy_common(linkp, 1397*2b24ab6bSSebastien Roy DLMGMT_ACTIVE | DLMGMT_PERSIST); 1398*2b24ab6bSSebastien Roy } 1399*2b24ab6bSSebastien Roy linkp = next_linkp; 1400*2b24ab6bSSebastien Roy } 1401*2b24ab6bSSebastien Roy } 1402