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.
2485dff7a0SAndy Fiddaman * Copyright 2023 Oxide Computer Company
25d62bc4baSyz147064 */
26d62bc4baSyz147064
27d62bc4baSyz147064 #include <assert.h>
28d62bc4baSyz147064 #include <ctype.h>
29d62bc4baSyz147064 #include <errno.h>
30d62bc4baSyz147064 #include <fcntl.h>
31d62bc4baSyz147064 #include <stdio.h>
32d62bc4baSyz147064 #include <stdlib.h>
332b24ab6bSSebastien Roy #include <string.h>
34d62bc4baSyz147064 #include <strings.h>
35d62bc4baSyz147064 #include <syslog.h>
362b24ab6bSSebastien Roy #include <zone.h>
372b24ab6bSSebastien Roy #include <sys/types.h>
38d62bc4baSyz147064 #include <sys/stat.h>
392b24ab6bSSebastien Roy #include <stropts.h>
402b24ab6bSSebastien Roy #include <sys/conf.h>
41d62bc4baSyz147064 #include <pthread.h>
42d62bc4baSyz147064 #include <unistd.h>
432b24ab6bSSebastien Roy #include <wait.h>
442b24ab6bSSebastien Roy #include <libcontract.h>
455b310668SDarren Reed #include <libcontract_priv.h>
462b24ab6bSSebastien Roy #include <sys/contract/process.h>
47d62bc4baSyz147064 #include "dlmgmt_impl.h"
48d62bc4baSyz147064
49d62bc4baSyz147064 typedef enum dlmgmt_db_op {
50d62bc4baSyz147064 DLMGMT_DB_OP_WRITE,
51d62bc4baSyz147064 DLMGMT_DB_OP_DELETE,
52d62bc4baSyz147064 DLMGMT_DB_OP_READ
53d62bc4baSyz147064 } dlmgmt_db_op_t;
54d62bc4baSyz147064
55d62bc4baSyz147064 typedef struct dlmgmt_db_req_s {
56d62bc4baSyz147064 struct dlmgmt_db_req_s *ls_next;
57d62bc4baSyz147064 dlmgmt_db_op_t ls_op;
582b24ab6bSSebastien Roy char ls_link[MAXLINKNAMELEN];
59d62bc4baSyz147064 datalink_id_t ls_linkid;
602b24ab6bSSebastien Roy zoneid_t ls_zoneid;
61d62bc4baSyz147064 uint32_t ls_flags; /* Either DLMGMT_ACTIVE or */
62d62bc4baSyz147064 /* DLMGMT_PERSIST, not both. */
63d62bc4baSyz147064 } dlmgmt_db_req_t;
64d62bc4baSyz147064
65d62bc4baSyz147064 /*
66d62bc4baSyz147064 * List of pending db updates (e.g., because of a read-only filesystem).
67d62bc4baSyz147064 */
68d62bc4baSyz147064 static dlmgmt_db_req_t *dlmgmt_db_req_head = NULL;
69d62bc4baSyz147064 static dlmgmt_db_req_t *dlmgmt_db_req_tail = NULL;
70d62bc4baSyz147064
712b24ab6bSSebastien Roy /*
722b24ab6bSSebastien Roy * rewrite_needed is set to B_TRUE by process_link_line() if it encounters a
732b24ab6bSSebastien Roy * line with an old format. This will cause the file being read to be
742b24ab6bSSebastien Roy * re-written with the current format.
752b24ab6bSSebastien Roy */
762b24ab6bSSebastien Roy static boolean_t rewrite_needed;
772b24ab6bSSebastien Roy
782b24ab6bSSebastien Roy static int dlmgmt_db_update(dlmgmt_db_op_t, const char *,
792b24ab6bSSebastien Roy dlmgmt_link_t *, uint32_t);
80d62bc4baSyz147064 static int dlmgmt_process_db_req(dlmgmt_db_req_t *);
81d62bc4baSyz147064 static int dlmgmt_process_db_onereq(dlmgmt_db_req_t *, boolean_t);
82d62bc4baSyz147064 static void *dlmgmt_db_update_thread(void *);
832b24ab6bSSebastien Roy static boolean_t process_link_line(char *, dlmgmt_link_t *);
84d62bc4baSyz147064 static int process_db_write(dlmgmt_db_req_t *, FILE *, FILE *);
852b24ab6bSSebastien Roy static int process_db_read(dlmgmt_db_req_t *, FILE *);
86d62bc4baSyz147064 static void generate_link_line(dlmgmt_link_t *, boolean_t, char *);
87d62bc4baSyz147064
88d62bc4baSyz147064 #define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0)
89d62bc4baSyz147064 #define MAXLINELEN 1024
90d62bc4baSyz147064
912b24ab6bSSebastien Roy typedef void db_walk_func_t(dlmgmt_link_t *);
922b24ab6bSSebastien Roy
93d62bc4baSyz147064 /*
94d62bc4baSyz147064 * Translator functions to go from dladm_datatype_t to character strings.
95d62bc4baSyz147064 * Each function takes a pointer to a buffer, the size of the buffer,
96d62bc4baSyz147064 * the name of the attribute, and the value to be written. The functions
97d62bc4baSyz147064 * return the number of bytes written to the buffer. If the buffer is not big
98d62bc4baSyz147064 * enough to hold the string representing the value, then nothing is written
99d62bc4baSyz147064 * and 0 is returned.
100d62bc4baSyz147064 */
101d62bc4baSyz147064 typedef size_t write_func_t(char *, size_t, char *, void *);
102d62bc4baSyz147064
103d62bc4baSyz147064 /*
104d62bc4baSyz147064 * Translator functions to read from a NULL terminated string buffer into
105d62bc4baSyz147064 * something of the given DLADM_TYPE_*. The functions each return the number
106d62bc4baSyz147064 * of bytes read from the string buffer. If there is an error reading data
107d62bc4baSyz147064 * from the buffer, then 0 is returned. It is the caller's responsibility
108d62bc4baSyz147064 * to free the data allocated by these functions.
109d62bc4baSyz147064 */
110d62bc4baSyz147064 typedef size_t read_func_t(char *, void **);
111d62bc4baSyz147064
112d62bc4baSyz147064 typedef struct translator_s {
113d62bc4baSyz147064 const char *type_name;
114d62bc4baSyz147064 write_func_t *write_func;
115d62bc4baSyz147064 read_func_t *read_func;
116d62bc4baSyz147064 } translator_t;
117d62bc4baSyz147064
118d62bc4baSyz147064 /*
119d62bc4baSyz147064 * Translator functions, defined later but declared here so that
120d62bc4baSyz147064 * the translator table can be defined.
121d62bc4baSyz147064 */
122d62bc4baSyz147064 static write_func_t write_str, write_boolean, write_uint64;
123d62bc4baSyz147064 static read_func_t read_str, read_boolean, read_int64;
124d62bc4baSyz147064
125d62bc4baSyz147064 /*
126d62bc4baSyz147064 * Translator table, indexed by dladm_datatype_t.
127d62bc4baSyz147064 */
128d62bc4baSyz147064 static translator_t translators[] = {
129d62bc4baSyz147064 { "string", write_str, read_str },
130d62bc4baSyz147064 { "boolean", write_boolean, read_boolean },
131d62bc4baSyz147064 { "int", write_uint64, read_int64 }
132d62bc4baSyz147064 };
133d62bc4baSyz147064
134d62bc4baSyz147064 static size_t ntranslators = sizeof (translators) / sizeof (translator_t);
135d62bc4baSyz147064
136d62bc4baSyz147064 #define LINK_PROPERTY_DELIMINATOR ";"
137d62bc4baSyz147064 #define LINK_PROPERTY_TYPE_VALUE_SEP ","
138d62bc4baSyz147064 #define BASE_PROPERTY_LENGTH(t, n) (strlen(translators[(t)].type_name) +\
139d62bc4baSyz147064 strlen(LINK_PROPERTY_TYPE_VALUE_SEP) +\
140d62bc4baSyz147064 strlen(LINK_PROPERTY_DELIMINATOR) +\
141d62bc4baSyz147064 strlen((n)))
142d62bc4baSyz147064 #define GENERATE_PROPERTY_STRING(buf, length, conv, name, type, val) \
143d62bc4baSyz147064 (snprintf((buf), (length), "%s=%s%s" conv "%s", (name), \
144d62bc4baSyz147064 translators[(type)].type_name, \
145d62bc4baSyz147064 LINK_PROPERTY_TYPE_VALUE_SEP, (val), LINK_PROPERTY_DELIMINATOR))
146d62bc4baSyz147064
147d62bc4baSyz147064 /*
148d62bc4baSyz147064 * Name of the cache file to keep the active <link name, linkid> mapping
149d62bc4baSyz147064 */
1502b24ab6bSSebastien Roy char cachefile[MAXPATHLEN];
151d62bc4baSyz147064
152d62bc4baSyz147064 #define DLMGMT_PERSISTENT_DB_PATH "/etc/dladm/datalink.conf"
153d62bc4baSyz147064 #define DLMGMT_MAKE_FILE_DB_PATH(buffer, persistent) \
154d62bc4baSyz147064 (void) snprintf((buffer), MAXPATHLEN, "%s", \
155d62bc4baSyz147064 (persistent) ? DLMGMT_PERSISTENT_DB_PATH : cachefile);
156d62bc4baSyz147064
1572b24ab6bSSebastien Roy typedef struct zopen_arg {
1582b24ab6bSSebastien Roy const char *zopen_modestr;
1592b24ab6bSSebastien Roy int *zopen_pipe;
1602b24ab6bSSebastien Roy int zopen_fd;
1612b24ab6bSSebastien Roy } zopen_arg_t;
1622b24ab6bSSebastien Roy
1632b24ab6bSSebastien Roy typedef struct zrename_arg {
1642b24ab6bSSebastien Roy const char *zrename_newname;
1652b24ab6bSSebastien Roy } zrename_arg_t;
1662b24ab6bSSebastien Roy
1672b24ab6bSSebastien Roy typedef union zfoparg {
1682b24ab6bSSebastien Roy zopen_arg_t zfop_openarg;
1692b24ab6bSSebastien Roy zrename_arg_t zfop_renamearg;
1702b24ab6bSSebastien Roy } zfoparg_t;
1712b24ab6bSSebastien Roy
1722b24ab6bSSebastien Roy typedef struct zfcbarg {
1732b24ab6bSSebastien Roy boolean_t zfarg_inglobalzone; /* is callback in global zone? */
1742b24ab6bSSebastien Roy zoneid_t zfarg_finglobalzone; /* is file in global zone? */
1752b24ab6bSSebastien Roy const char *zfarg_filename;
1762b24ab6bSSebastien Roy zfoparg_t *zfarg_oparg;
1772b24ab6bSSebastien Roy } zfarg_t;
1782b24ab6bSSebastien Roy #define zfarg_openarg zfarg_oparg->zfop_openarg
1792b24ab6bSSebastien Roy #define zfarg_renamearg zfarg_oparg->zfop_renamearg
1802b24ab6bSSebastien Roy
1812b24ab6bSSebastien Roy /* zone file callback */
1822b24ab6bSSebastien Roy typedef int zfcb_t(zfarg_t *);
1832b24ab6bSSebastien Roy
1842b24ab6bSSebastien Roy /*
1852b24ab6bSSebastien Roy * Execute an operation on filename relative to zoneid's zone root. If the
1862b24ab6bSSebastien Roy * file is in the global zone, then the zfcb() callback will simply be called
1872b24ab6bSSebastien Roy * directly. If the file is in a non-global zone, then zfcb() will be called
1882b24ab6bSSebastien Roy * both from the global zone's context, and from the non-global zone's context
1892b24ab6bSSebastien Roy * (from a fork()'ed child that has entered the non-global zone). This is
1902b24ab6bSSebastien Roy * done to allow the callback to communicate with itself if needed (e.g. to
1912b24ab6bSSebastien Roy * pass back the file descriptor of an opened file).
1922b24ab6bSSebastien Roy */
1932b24ab6bSSebastien Roy static int
dlmgmt_zfop(const char * filename,zoneid_t zoneid,zfcb_t * zfcb,zfoparg_t * zfoparg)1942b24ab6bSSebastien Roy dlmgmt_zfop(const char *filename, zoneid_t zoneid, zfcb_t *zfcb,
1952b24ab6bSSebastien Roy zfoparg_t *zfoparg)
1962b24ab6bSSebastien Roy {
1972b24ab6bSSebastien Roy int ctfd;
1982b24ab6bSSebastien Roy int err;
1992b24ab6bSSebastien Roy pid_t childpid;
2002b24ab6bSSebastien Roy siginfo_t info;
2012b24ab6bSSebastien Roy zfarg_t zfarg;
2020572408dSDarren Reed ctid_t ct;
2032b24ab6bSSebastien Roy
2042b24ab6bSSebastien Roy if (zoneid != GLOBAL_ZONEID) {
2052b24ab6bSSebastien Roy /*
2062b24ab6bSSebastien Roy * We need to access a file that isn't in the global zone.
2072b24ab6bSSebastien Roy * Accessing non-global zone files from the global zone is
2082b24ab6bSSebastien Roy * unsafe (due to symlink attacks), we'll need to fork a child
2092b24ab6bSSebastien Roy * that enters the zone in question and executes the callback
2102b24ab6bSSebastien Roy * that will operate on the file.
2112b24ab6bSSebastien Roy *
2122b24ab6bSSebastien Roy * Before we proceed with this zone tango, we need to create a
2132b24ab6bSSebastien Roy * new process contract for the child, as required by
2142b24ab6bSSebastien Roy * zone_enter().
2152b24ab6bSSebastien Roy */
2162b24ab6bSSebastien Roy errno = 0;
2172b24ab6bSSebastien Roy ctfd = open64("/system/contract/process/template", O_RDWR);
2182b24ab6bSSebastien Roy if (ctfd == -1)
2192b24ab6bSSebastien Roy return (errno);
2202b24ab6bSSebastien Roy if ((err = ct_tmpl_set_critical(ctfd, 0)) != 0 ||
2212b24ab6bSSebastien Roy (err = ct_tmpl_set_informative(ctfd, 0)) != 0 ||
2222b24ab6bSSebastien Roy (err = ct_pr_tmpl_set_fatal(ctfd, CT_PR_EV_HWERR)) != 0 ||
2232b24ab6bSSebastien Roy (err = ct_pr_tmpl_set_param(ctfd, CT_PR_PGRPONLY)) != 0 ||
2242b24ab6bSSebastien Roy (err = ct_tmpl_activate(ctfd)) != 0) {
2250572408dSDarren Reed (void) close(ctfd);
2262b24ab6bSSebastien Roy return (err);
2272b24ab6bSSebastien Roy }
2282b24ab6bSSebastien Roy childpid = fork();
2292b24ab6bSSebastien Roy switch (childpid) {
2302b24ab6bSSebastien Roy case -1:
2310572408dSDarren Reed (void) ct_tmpl_clear(ctfd);
2320572408dSDarren Reed (void) close(ctfd);
2332b24ab6bSSebastien Roy return (err);
2342b24ab6bSSebastien Roy case 0:
2350572408dSDarren Reed (void) ct_tmpl_clear(ctfd);
2360572408dSDarren Reed (void) close(ctfd);
2372b24ab6bSSebastien Roy /*
2382b24ab6bSSebastien Roy * Elevate our privileges as zone_enter() requires all
2392b24ab6bSSebastien Roy * privileges.
2402b24ab6bSSebastien Roy */
2412b24ab6bSSebastien Roy if ((err = dlmgmt_elevate_privileges()) != 0)
2422b24ab6bSSebastien Roy _exit(err);
2432b24ab6bSSebastien Roy if (zone_enter(zoneid) == -1)
2442b24ab6bSSebastien Roy _exit(errno);
2452b24ab6bSSebastien Roy if ((err = dlmgmt_drop_privileges()) != 0)
2462b24ab6bSSebastien Roy _exit(err);
2472b24ab6bSSebastien Roy break;
2482b24ab6bSSebastien Roy default:
2490572408dSDarren Reed if (contract_latest(&ct) == -1)
2500572408dSDarren Reed ct = -1;
2510572408dSDarren Reed (void) ct_tmpl_clear(ctfd);
2520572408dSDarren Reed (void) close(ctfd);
2530572408dSDarren Reed if (waitid(P_PID, childpid, &info, WEXITED) == -1) {
2540572408dSDarren Reed (void) contract_abandon_id(ct);
2552b24ab6bSSebastien Roy return (errno);
2560572408dSDarren Reed }
2570572408dSDarren Reed (void) contract_abandon_id(ct);
2582b24ab6bSSebastien Roy if (info.si_status != 0)
2592b24ab6bSSebastien Roy return (info.si_status);
2602b24ab6bSSebastien Roy }
2612b24ab6bSSebastien Roy }
2622b24ab6bSSebastien Roy
2632b24ab6bSSebastien Roy zfarg.zfarg_inglobalzone = (zoneid == GLOBAL_ZONEID || childpid != 0);
2642b24ab6bSSebastien Roy zfarg.zfarg_finglobalzone = (zoneid == GLOBAL_ZONEID);
2652b24ab6bSSebastien Roy zfarg.zfarg_filename = filename;
2662b24ab6bSSebastien Roy zfarg.zfarg_oparg = zfoparg;
2672b24ab6bSSebastien Roy err = zfcb(&zfarg);
2682b24ab6bSSebastien Roy if (!zfarg.zfarg_inglobalzone)
2692b24ab6bSSebastien Roy _exit(err);
2702b24ab6bSSebastien Roy return (err);
2712b24ab6bSSebastien Roy }
2722b24ab6bSSebastien Roy
2732b24ab6bSSebastien Roy static int
dlmgmt_zopen_cb(zfarg_t * zfarg)2742b24ab6bSSebastien Roy dlmgmt_zopen_cb(zfarg_t *zfarg)
2752b24ab6bSSebastien Roy {
2762b24ab6bSSebastien Roy struct strrecvfd recvfd;
2772b24ab6bSSebastien Roy boolean_t newfile = B_FALSE;
2782b24ab6bSSebastien Roy boolean_t inglobalzone = zfarg->zfarg_inglobalzone;
2792b24ab6bSSebastien Roy zoneid_t finglobalzone = zfarg->zfarg_finglobalzone;
2802b24ab6bSSebastien Roy const char *filename = zfarg->zfarg_filename;
2812b24ab6bSSebastien Roy const char *modestr = zfarg->zfarg_openarg.zopen_modestr;
2822b24ab6bSSebastien Roy int *p = zfarg->zfarg_openarg.zopen_pipe;
2832b24ab6bSSebastien Roy struct stat statbuf;
2842b24ab6bSSebastien Roy int oflags;
2852b24ab6bSSebastien Roy mode_t mode;
2862b24ab6bSSebastien Roy int fd = -1;
2872b24ab6bSSebastien Roy int err;
2882b24ab6bSSebastien Roy
2892b24ab6bSSebastien Roy /* We only ever open a file for reading or writing, not both. */
2902b24ab6bSSebastien Roy oflags = (modestr[0] == 'r') ? O_RDONLY : O_WRONLY | O_CREAT | O_TRUNC;
2912b24ab6bSSebastien Roy mode = (modestr[0] == 'r') ? 0 : S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
2922b24ab6bSSebastien Roy
2932b24ab6bSSebastien Roy /* Open the file if we're in the same zone as the file. */
2942b24ab6bSSebastien Roy if (inglobalzone == finglobalzone) {
2952b24ab6bSSebastien Roy /*
2962b24ab6bSSebastien Roy * First determine if we will be creating the file as part of
2972b24ab6bSSebastien Roy * opening it. If so, then we'll need to ensure that it has
2982b24ab6bSSebastien Roy * the proper ownership after having opened it.
2992b24ab6bSSebastien Roy */
3002b24ab6bSSebastien Roy if (oflags & O_CREAT) {
3012b24ab6bSSebastien Roy if (stat(filename, &statbuf) == -1) {
3022b24ab6bSSebastien Roy if (errno == ENOENT)
3032b24ab6bSSebastien Roy newfile = B_TRUE;
3042b24ab6bSSebastien Roy else
3052b24ab6bSSebastien Roy return (errno);
3062b24ab6bSSebastien Roy }
3072b24ab6bSSebastien Roy }
3082b24ab6bSSebastien Roy if ((fd = open(filename, oflags, mode)) == -1)
3092b24ab6bSSebastien Roy return (errno);
3102b24ab6bSSebastien Roy if (newfile) {
3116ba597c5SAnurag S. Maskey if (chown(filename, UID_DLADM, GID_NETADM) == -1) {
3122b24ab6bSSebastien Roy err = errno;
3132b24ab6bSSebastien Roy (void) close(fd);
3142b24ab6bSSebastien Roy return (err);
3152b24ab6bSSebastien Roy }
3162b24ab6bSSebastien Roy }
3172b24ab6bSSebastien Roy }
3182b24ab6bSSebastien Roy
3192b24ab6bSSebastien Roy /*
3202b24ab6bSSebastien Roy * If we're not in the global zone, send the file-descriptor back to
3212b24ab6bSSebastien Roy * our parent in the global zone.
3222b24ab6bSSebastien Roy */
3232b24ab6bSSebastien Roy if (!inglobalzone) {
3242b24ab6bSSebastien Roy assert(!finglobalzone);
3252b24ab6bSSebastien Roy assert(fd != -1);
3262b24ab6bSSebastien Roy return (ioctl(p[1], I_SENDFD, fd) == -1 ? errno : 0);
3272b24ab6bSSebastien Roy }
3282b24ab6bSSebastien Roy
3292b24ab6bSSebastien Roy /*
3302b24ab6bSSebastien Roy * At this point, we know we're in the global zone. If the file was
3312b24ab6bSSebastien Roy * in a non-global zone, receive the file-descriptor from our child in
3322b24ab6bSSebastien Roy * the non-global zone.
3332b24ab6bSSebastien Roy */
3342b24ab6bSSebastien Roy if (!finglobalzone) {
3352b24ab6bSSebastien Roy if (ioctl(p[0], I_RECVFD, &recvfd) == -1)
3362b24ab6bSSebastien Roy return (errno);
3372b24ab6bSSebastien Roy fd = recvfd.fd;
3382b24ab6bSSebastien Roy }
3392b24ab6bSSebastien Roy
3402b24ab6bSSebastien Roy zfarg->zfarg_openarg.zopen_fd = fd;
3412b24ab6bSSebastien Roy return (0);
3422b24ab6bSSebastien Roy }
3432b24ab6bSSebastien Roy
3442b24ab6bSSebastien Roy static int
dlmgmt_zunlink_cb(zfarg_t * zfarg)3452b24ab6bSSebastien Roy dlmgmt_zunlink_cb(zfarg_t *zfarg)
3462b24ab6bSSebastien Roy {
3472b24ab6bSSebastien Roy if (zfarg->zfarg_inglobalzone != zfarg->zfarg_finglobalzone)
3482b24ab6bSSebastien Roy return (0);
3492b24ab6bSSebastien Roy return (unlink(zfarg->zfarg_filename) == 0 ? 0 : errno);
3502b24ab6bSSebastien Roy }
3512b24ab6bSSebastien Roy
3522b24ab6bSSebastien Roy static int
dlmgmt_zrename_cb(zfarg_t * zfarg)3532b24ab6bSSebastien Roy dlmgmt_zrename_cb(zfarg_t *zfarg)
3542b24ab6bSSebastien Roy {
3552b24ab6bSSebastien Roy if (zfarg->zfarg_inglobalzone != zfarg->zfarg_finglobalzone)
3562b24ab6bSSebastien Roy return (0);
3572b24ab6bSSebastien Roy return (rename(zfarg->zfarg_filename,
3582b24ab6bSSebastien Roy zfarg->zfarg_renamearg.zrename_newname) == 0 ? 0 : errno);
3592b24ab6bSSebastien Roy }
3602b24ab6bSSebastien Roy
3612b24ab6bSSebastien Roy /*
3622b24ab6bSSebastien Roy * Same as fopen(3C), except that it opens the file relative to zoneid's zone
3632b24ab6bSSebastien Roy * root.
3642b24ab6bSSebastien Roy */
3652b24ab6bSSebastien Roy static FILE *
dlmgmt_zfopen(const char * filename,const char * modestr,zoneid_t zoneid,int * err)3662b24ab6bSSebastien Roy dlmgmt_zfopen(const char *filename, const char *modestr, zoneid_t zoneid,
3672b24ab6bSSebastien Roy int *err)
3682b24ab6bSSebastien Roy {
3692b24ab6bSSebastien Roy int p[2];
3702b24ab6bSSebastien Roy zfoparg_t zfoparg;
3712b24ab6bSSebastien Roy FILE *fp = NULL;
3722b24ab6bSSebastien Roy
3732b24ab6bSSebastien Roy if (zoneid != GLOBAL_ZONEID && pipe(p) == -1) {
3742b24ab6bSSebastien Roy *err = errno;
3752b24ab6bSSebastien Roy return (NULL);
3762b24ab6bSSebastien Roy }
3772b24ab6bSSebastien Roy
3782b24ab6bSSebastien Roy zfoparg.zfop_openarg.zopen_modestr = modestr;
3792b24ab6bSSebastien Roy zfoparg.zfop_openarg.zopen_pipe = p;
3802b24ab6bSSebastien Roy *err = dlmgmt_zfop(filename, zoneid, dlmgmt_zopen_cb, &zfoparg);
3812b24ab6bSSebastien Roy if (zoneid != GLOBAL_ZONEID) {
3822b24ab6bSSebastien Roy (void) close(p[0]);
3832b24ab6bSSebastien Roy (void) close(p[1]);
3842b24ab6bSSebastien Roy }
3852b24ab6bSSebastien Roy if (*err == 0) {
3862b24ab6bSSebastien Roy fp = fdopen(zfoparg.zfop_openarg.zopen_fd, modestr);
3872b24ab6bSSebastien Roy if (fp == NULL) {
3882b24ab6bSSebastien Roy *err = errno;
3892b24ab6bSSebastien Roy (void) close(zfoparg.zfop_openarg.zopen_fd);
3902b24ab6bSSebastien Roy }
3912b24ab6bSSebastien Roy }
3922b24ab6bSSebastien Roy return (fp);
3932b24ab6bSSebastien Roy }
3942b24ab6bSSebastien Roy
3952b24ab6bSSebastien Roy /*
3962b24ab6bSSebastien Roy * Same as rename(2), except that old and new are relative to zoneid's zone
3972b24ab6bSSebastien Roy * root.
3982b24ab6bSSebastien Roy */
3992b24ab6bSSebastien Roy static int
dlmgmt_zrename(const char * old,const char * new,zoneid_t zoneid)4002b24ab6bSSebastien Roy dlmgmt_zrename(const char *old, const char *new, zoneid_t zoneid)
4012b24ab6bSSebastien Roy {
4022b24ab6bSSebastien Roy zfoparg_t zfoparg;
4032b24ab6bSSebastien Roy
4042b24ab6bSSebastien Roy zfoparg.zfop_renamearg.zrename_newname = new;
4052b24ab6bSSebastien Roy return (dlmgmt_zfop(old, zoneid, dlmgmt_zrename_cb, &zfoparg));
4062b24ab6bSSebastien Roy }
4072b24ab6bSSebastien Roy
4082b24ab6bSSebastien Roy /*
4092b24ab6bSSebastien Roy * Same as unlink(2), except that filename is relative to zoneid's zone root.
4102b24ab6bSSebastien Roy */
4112b24ab6bSSebastien Roy static int
dlmgmt_zunlink(const char * filename,zoneid_t zoneid)4122b24ab6bSSebastien Roy dlmgmt_zunlink(const char *filename, zoneid_t zoneid)
4132b24ab6bSSebastien Roy {
4142b24ab6bSSebastien Roy return (dlmgmt_zfop(filename, zoneid, dlmgmt_zunlink_cb, NULL));
4152b24ab6bSSebastien Roy }
4162b24ab6bSSebastien Roy
417d62bc4baSyz147064 static size_t
write_str(char * buffer,size_t buffer_length,char * name,void * value)418d62bc4baSyz147064 write_str(char *buffer, size_t buffer_length, char *name, void *value)
419d62bc4baSyz147064 {
420d62bc4baSyz147064 char *ptr = value;
421d62bc4baSyz147064 size_t data_length = strnlen(ptr, buffer_length);
422d62bc4baSyz147064
423d62bc4baSyz147064 /*
424d62bc4baSyz147064 * Strings are assumed to be NULL terminated. In order to fit in
425d62bc4baSyz147064 * the buffer, the string's length must be less then buffer_length.
426d62bc4baSyz147064 * If the value is empty, there's no point in writing it, in fact,
427d62bc4baSyz147064 * we shouldn't even see that case.
428d62bc4baSyz147064 */
429d62bc4baSyz147064 if (data_length + BASE_PROPERTY_LENGTH(DLADM_TYPE_STR, name) ==
430d62bc4baSyz147064 buffer_length || data_length == 0)
431d62bc4baSyz147064 return (0);
432d62bc4baSyz147064
433d62bc4baSyz147064 /*
434d62bc4baSyz147064 * Since we know the string will fit in the buffer, snprintf will
435d62bc4baSyz147064 * always return less than buffer_length, so we can just return
436d62bc4baSyz147064 * whatever snprintf returns.
437d62bc4baSyz147064 */
438d62bc4baSyz147064 return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%s",
439d62bc4baSyz147064 name, DLADM_TYPE_STR, ptr));
440d62bc4baSyz147064 }
441d62bc4baSyz147064
442d62bc4baSyz147064 static size_t
write_boolean(char * buffer,size_t buffer_length,char * name,void * value)443d62bc4baSyz147064 write_boolean(char *buffer, size_t buffer_length, char *name, void *value)
444d62bc4baSyz147064 {
445d62bc4baSyz147064 boolean_t *ptr = value;
446d62bc4baSyz147064
447d62bc4baSyz147064 /*
448d62bc4baSyz147064 * Booleans are either zero or one, so we only need room for two
449d62bc4baSyz147064 * characters in the buffer.
450d62bc4baSyz147064 */
451d62bc4baSyz147064 if (buffer_length <= 1 + BASE_PROPERTY_LENGTH(DLADM_TYPE_BOOLEAN, name))
452d62bc4baSyz147064 return (0);
453d62bc4baSyz147064
454d62bc4baSyz147064 return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%d",
455d62bc4baSyz147064 name, DLADM_TYPE_BOOLEAN, *ptr));
456d62bc4baSyz147064 }
457d62bc4baSyz147064
458d62bc4baSyz147064 static size_t
write_uint64(char * buffer,size_t buffer_length,char * name,void * value)459d62bc4baSyz147064 write_uint64(char *buffer, size_t buffer_length, char *name, void *value)
460d62bc4baSyz147064 {
461d62bc4baSyz147064 uint64_t *ptr = value;
462d62bc4baSyz147064
463d62bc4baSyz147064 /*
464d62bc4baSyz147064 * Limit checking for uint64_t is a little trickier.
465d62bc4baSyz147064 */
466d62bc4baSyz147064 if (snprintf(NULL, 0, "%lld", *ptr) +
467d62bc4baSyz147064 BASE_PROPERTY_LENGTH(DLADM_TYPE_UINT64, name) >= buffer_length)
468d62bc4baSyz147064 return (0);
469d62bc4baSyz147064
470d62bc4baSyz147064 return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%lld",
471d62bc4baSyz147064 name, DLADM_TYPE_UINT64, *ptr));
472d62bc4baSyz147064 }
473d62bc4baSyz147064
474d62bc4baSyz147064 static size_t
read_str(char * buffer,void ** value)475d62bc4baSyz147064 read_str(char *buffer, void **value)
476d62bc4baSyz147064 {
477024b0a25Sseb char *ptr = calloc(MAXLINKATTRVALLEN, sizeof (char));
478d62bc4baSyz147064 ssize_t len;
479d62bc4baSyz147064
480024b0a25Sseb if (ptr == NULL || (len = strlcpy(ptr, buffer, MAXLINKATTRVALLEN))
481024b0a25Sseb >= MAXLINKATTRVALLEN) {
482d62bc4baSyz147064 free(ptr);
483d62bc4baSyz147064 return (0);
484d62bc4baSyz147064 }
485d62bc4baSyz147064
486d62bc4baSyz147064 *(char **)value = ptr;
487d62bc4baSyz147064
488d62bc4baSyz147064 /* Account for NULL terminator */
489d62bc4baSyz147064 return (len + 1);
490d62bc4baSyz147064 }
491d62bc4baSyz147064
492d62bc4baSyz147064 static size_t
read_boolean(char * buffer,void ** value)493d62bc4baSyz147064 read_boolean(char *buffer, void **value)
494d62bc4baSyz147064 {
495d62bc4baSyz147064 boolean_t *ptr = calloc(1, sizeof (boolean_t));
496d62bc4baSyz147064
497d62bc4baSyz147064 if (ptr == NULL)
498d62bc4baSyz147064 return (0);
499d62bc4baSyz147064
500d62bc4baSyz147064 *ptr = atoi(buffer);
501d62bc4baSyz147064 *(boolean_t **)value = ptr;
502d62bc4baSyz147064
503d62bc4baSyz147064 return (sizeof (boolean_t));
504d62bc4baSyz147064 }
505d62bc4baSyz147064
506d62bc4baSyz147064 static size_t
read_int64(char * buffer,void ** value)507d62bc4baSyz147064 read_int64(char *buffer, void **value)
508d62bc4baSyz147064 {
509d62bc4baSyz147064 int64_t *ptr = calloc(1, sizeof (int64_t));
510d62bc4baSyz147064
511d62bc4baSyz147064 if (ptr == NULL)
512d62bc4baSyz147064 return (0);
513d62bc4baSyz147064
514d62bc4baSyz147064 *ptr = (int64_t)atoll(buffer);
515d62bc4baSyz147064 *(int64_t **)value = ptr;
516d62bc4baSyz147064
517d62bc4baSyz147064 return (sizeof (int64_t));
518d62bc4baSyz147064 }
519d62bc4baSyz147064
5202b24ab6bSSebastien Roy static dlmgmt_db_req_t *
dlmgmt_db_req_alloc(dlmgmt_db_op_t op,const char * linkname,datalink_id_t linkid,zoneid_t zoneid,uint32_t flags,int * err)5212b24ab6bSSebastien Roy dlmgmt_db_req_alloc(dlmgmt_db_op_t op, const char *linkname,
5222b24ab6bSSebastien Roy datalink_id_t linkid, zoneid_t zoneid, uint32_t flags, int *err)
5232b24ab6bSSebastien Roy {
5242b24ab6bSSebastien Roy dlmgmt_db_req_t *req;
5252b24ab6bSSebastien Roy
5262b24ab6bSSebastien Roy if ((req = calloc(1, sizeof (dlmgmt_db_req_t))) == NULL) {
5272b24ab6bSSebastien Roy *err = errno;
5282b24ab6bSSebastien Roy } else {
5292b24ab6bSSebastien Roy req->ls_op = op;
5302b24ab6bSSebastien Roy if (linkname != NULL)
5312b24ab6bSSebastien Roy (void) strlcpy(req->ls_link, linkname, MAXLINKNAMELEN);
5322b24ab6bSSebastien Roy req->ls_linkid = linkid;
5332b24ab6bSSebastien Roy req->ls_zoneid = zoneid;
5342b24ab6bSSebastien Roy req->ls_flags = flags;
5352b24ab6bSSebastien Roy }
5362b24ab6bSSebastien Roy return (req);
5372b24ab6bSSebastien Roy }
5382b24ab6bSSebastien Roy
5392b24ab6bSSebastien Roy /*
5402b24ab6bSSebastien Roy * Update the db entry with name "entryname" using information from "linkp".
5412b24ab6bSSebastien Roy */
542d62bc4baSyz147064 static int
dlmgmt_db_update(dlmgmt_db_op_t op,const char * entryname,dlmgmt_link_t * linkp,uint32_t flags)5432b24ab6bSSebastien Roy dlmgmt_db_update(dlmgmt_db_op_t op, const char *entryname, dlmgmt_link_t *linkp,
5442b24ab6bSSebastien Roy uint32_t flags)
545d62bc4baSyz147064 {
546d62bc4baSyz147064 dlmgmt_db_req_t *req;
547d62bc4baSyz147064 int err;
548d62bc4baSyz147064
5492b24ab6bSSebastien Roy /* It is either a persistent request or an active request, not both. */
550d62bc4baSyz147064 assert((flags == DLMGMT_PERSIST) || (flags == DLMGMT_ACTIVE));
551d62bc4baSyz147064
5522b24ab6bSSebastien Roy if ((req = dlmgmt_db_req_alloc(op, entryname, linkp->ll_linkid,
55385dff7a0SAndy Fiddaman linkp->ll_zoneid, flags, &err)) == NULL) {
5542b24ab6bSSebastien Roy return (err);
55585dff7a0SAndy Fiddaman }
55685dff7a0SAndy Fiddaman
55785dff7a0SAndy Fiddaman /*
55885dff7a0SAndy Fiddaman * If this is a transient link, then use the global zone cache file.
55985dff7a0SAndy Fiddaman * This is in order to allow recovery from a dlmgmtd failure that
56085dff7a0SAndy Fiddaman * leaves a zone in a 'down' state. In that state it is not possible
56185dff7a0SAndy Fiddaman * to read the zone's cache file (since it is always done from a sub
56285dff7a0SAndy Fiddaman * process running in the zone's context). As a result, datalinks would
56385dff7a0SAndy Fiddaman * otherwise remain stuck in the zone.
56485dff7a0SAndy Fiddaman */
56585dff7a0SAndy Fiddaman if (flags == DLMGMT_ACTIVE && linkp->ll_transient)
56685dff7a0SAndy Fiddaman req->ls_zoneid = GLOBAL_ZONEID;
567d62bc4baSyz147064
568d62bc4baSyz147064 /*
569d62bc4baSyz147064 * If the return error is EINPROGRESS, this request is handled
570d62bc4baSyz147064 * asynchronously; return success.
571d62bc4baSyz147064 */
572d62bc4baSyz147064 err = dlmgmt_process_db_req(req);
573d62bc4baSyz147064 if (err != EINPROGRESS)
574d62bc4baSyz147064 free(req);
575d62bc4baSyz147064 else
576d62bc4baSyz147064 err = 0;
577d62bc4baSyz147064 return (err);
578d62bc4baSyz147064 }
579d62bc4baSyz147064
580d62bc4baSyz147064 #define DLMGMT_DB_OP_STR(op) \
581d62bc4baSyz147064 (((op) == DLMGMT_DB_OP_READ) ? "read" : \
582d62bc4baSyz147064 (((op) == DLMGMT_DB_OP_WRITE) ? "write" : "delete"))
583d62bc4baSyz147064
584d62bc4baSyz147064 #define DLMGMT_DB_CONF_STR(flag) \
585d62bc4baSyz147064 (((flag) == DLMGMT_ACTIVE) ? "active" : \
586d62bc4baSyz147064 (((flag) == DLMGMT_PERSIST) ? "persistent" : ""))
587d62bc4baSyz147064
588d62bc4baSyz147064 static int
dlmgmt_process_db_req(dlmgmt_db_req_t * req)589d62bc4baSyz147064 dlmgmt_process_db_req(dlmgmt_db_req_t *req)
590d62bc4baSyz147064 {
591d62bc4baSyz147064 pthread_t tid;
592d62bc4baSyz147064 boolean_t writeop;
593d62bc4baSyz147064 int err;
594d62bc4baSyz147064
595d62bc4baSyz147064 /*
596d62bc4baSyz147064 * If there are already pending "write" requests, queue this request in
597d62bc4baSyz147064 * the pending list. Note that this function is called while the
598d62bc4baSyz147064 * dlmgmt_rw_lock is held, so it is safe to access the global variables.
599d62bc4baSyz147064 */
600d62bc4baSyz147064 writeop = (req->ls_op != DLMGMT_DB_OP_READ);
601d62bc4baSyz147064 if (writeop && (req->ls_flags == DLMGMT_PERSIST) &&
602d62bc4baSyz147064 (dlmgmt_db_req_head != NULL)) {
603d62bc4baSyz147064 dlmgmt_db_req_tail->ls_next = req;
604d62bc4baSyz147064 dlmgmt_db_req_tail = req;
605d62bc4baSyz147064 return (EINPROGRESS);
606d62bc4baSyz147064 }
607d62bc4baSyz147064
608d62bc4baSyz147064 err = dlmgmt_process_db_onereq(req, writeop);
6092b24ab6bSSebastien Roy if (err != EINPROGRESS && err != 0 && err != ENOENT) {
610d62bc4baSyz147064 /*
6112b24ab6bSSebastien Roy * Log the error unless the request processing is still in
6122b24ab6bSSebastien Roy * progress or if the configuration file hasn't been created
6132b24ab6bSSebastien Roy * yet (ENOENT).
614d62bc4baSyz147064 */
615d62bc4baSyz147064 dlmgmt_log(LOG_WARNING, "dlmgmt_process_db_onereq() %s "
616d62bc4baSyz147064 "operation on %s configuration failed: %s",
617d62bc4baSyz147064 DLMGMT_DB_OP_STR(req->ls_op),
618d62bc4baSyz147064 DLMGMT_DB_CONF_STR(req->ls_flags), strerror(err));
619d62bc4baSyz147064 }
620d62bc4baSyz147064
621d62bc4baSyz147064 if (err == EINPROGRESS) {
622d62bc4baSyz147064 assert(req->ls_flags == DLMGMT_PERSIST);
623d62bc4baSyz147064 assert(writeop && dlmgmt_db_req_head == NULL);
624d62bc4baSyz147064 dlmgmt_db_req_tail = dlmgmt_db_req_head = req;
625d62bc4baSyz147064 err = pthread_create(&tid, NULL, dlmgmt_db_update_thread, NULL);
626d62bc4baSyz147064 if (err == 0)
627d62bc4baSyz147064 return (EINPROGRESS);
628d62bc4baSyz147064 }
629d62bc4baSyz147064 return (err);
630d62bc4baSyz147064 }
631d62bc4baSyz147064
632d62bc4baSyz147064 static int
dlmgmt_process_db_onereq(dlmgmt_db_req_t * req,boolean_t writeop)633d62bc4baSyz147064 dlmgmt_process_db_onereq(dlmgmt_db_req_t *req, boolean_t writeop)
634d62bc4baSyz147064 {
635d62bc4baSyz147064 int err = 0;
636d62bc4baSyz147064 FILE *fp, *nfp = NULL;
637d62bc4baSyz147064 char file[MAXPATHLEN];
638d62bc4baSyz147064 char newfile[MAXPATHLEN];
639d62bc4baSyz147064
640d62bc4baSyz147064 DLMGMT_MAKE_FILE_DB_PATH(file, (req->ls_flags == DLMGMT_PERSIST));
6412b24ab6bSSebastien Roy fp = dlmgmt_zfopen(file, "r", req->ls_zoneid, &err);
642d62bc4baSyz147064 /*
6432b24ab6bSSebastien Roy * Note that it is not an error if the file doesn't exist. If we're
6442b24ab6bSSebastien Roy * reading, we treat this case the same way as an empty file. If
6452b24ab6bSSebastien Roy * we're writing, the file will be created when we open the file for
6462b24ab6bSSebastien Roy * writing below.
647d62bc4baSyz147064 */
6482b24ab6bSSebastien Roy if (fp == NULL && !writeop)
6492b24ab6bSSebastien Roy return (err);
650d62bc4baSyz147064
651d62bc4baSyz147064 if (writeop) {
652d62bc4baSyz147064 (void) snprintf(newfile, MAXPATHLEN, "%s.new", file);
6532b24ab6bSSebastien Roy nfp = dlmgmt_zfopen(newfile, "w", req->ls_zoneid, &err);
6542b24ab6bSSebastien Roy if (nfp == NULL) {
6552b24ab6bSSebastien Roy /*
6562b24ab6bSSebastien Roy * EROFS can happen at boot when the file system is
6572b24ab6bSSebastien Roy * read-only. Return EINPROGRESS so that the caller
6582b24ab6bSSebastien Roy * can add this request to the pending request list
6592b24ab6bSSebastien Roy * and start a retry thread.
6602b24ab6bSSebastien Roy */
6612b24ab6bSSebastien Roy err = (errno == EROFS ? EINPROGRESS : errno);
662d62bc4baSyz147064 goto done;
663d62bc4baSyz147064 }
664d62bc4baSyz147064 }
6652b24ab6bSSebastien Roy if (writeop) {
6662b24ab6bSSebastien Roy if ((err = process_db_write(req, fp, nfp)) == 0)
6672b24ab6bSSebastien Roy err = dlmgmt_zrename(newfile, file, req->ls_zoneid);
6682b24ab6bSSebastien Roy } else {
6692b24ab6bSSebastien Roy err = process_db_read(req, fp);
6702b24ab6bSSebastien Roy }
671d62bc4baSyz147064
672d62bc4baSyz147064 done:
673d62bc4baSyz147064 if (nfp != NULL) {
674d62bc4baSyz147064 (void) fclose(nfp);
675d62bc4baSyz147064 if (err != 0)
6762b24ab6bSSebastien Roy (void) dlmgmt_zunlink(newfile, req->ls_zoneid);
677d62bc4baSyz147064 }
678d62bc4baSyz147064 (void) fclose(fp);
679d62bc4baSyz147064 return (err);
680d62bc4baSyz147064 }
681d62bc4baSyz147064
682d62bc4baSyz147064 /*ARGSUSED*/
683d62bc4baSyz147064 static void *
dlmgmt_db_update_thread(void * arg)684d62bc4baSyz147064 dlmgmt_db_update_thread(void *arg)
685d62bc4baSyz147064 {
686d62bc4baSyz147064 dlmgmt_db_req_t *req;
687d62bc4baSyz147064
688d62bc4baSyz147064 dlmgmt_table_lock(B_TRUE);
689d62bc4baSyz147064
690d62bc4baSyz147064 assert(dlmgmt_db_req_head != NULL);
691d62bc4baSyz147064 while ((req = dlmgmt_db_req_head) != NULL) {
692d62bc4baSyz147064 assert(req->ls_flags == DLMGMT_PERSIST);
6932b24ab6bSSebastien Roy if (dlmgmt_process_db_onereq(req, B_TRUE) == EINPROGRESS) {
694d62bc4baSyz147064 /*
695d62bc4baSyz147064 * The filesystem is still read only. Go to sleep and
696d62bc4baSyz147064 * try again.
697d62bc4baSyz147064 */
698d62bc4baSyz147064 dlmgmt_table_unlock();
699d62bc4baSyz147064 (void) sleep(5);
700d62bc4baSyz147064 dlmgmt_table_lock(B_TRUE);
701d62bc4baSyz147064 continue;
702d62bc4baSyz147064 }
703d62bc4baSyz147064
704d62bc4baSyz147064 /*
705d62bc4baSyz147064 * The filesystem is no longer read only. Continue processing
706d62bc4baSyz147064 * and remove the request from the pending list.
707d62bc4baSyz147064 */
708d62bc4baSyz147064 dlmgmt_db_req_head = req->ls_next;
709d62bc4baSyz147064 if (dlmgmt_db_req_tail == req) {
710d62bc4baSyz147064 assert(dlmgmt_db_req_head == NULL);
711d62bc4baSyz147064 dlmgmt_db_req_tail = NULL;
712d62bc4baSyz147064 }
713d62bc4baSyz147064 free(req);
714d62bc4baSyz147064 }
715d62bc4baSyz147064
716d62bc4baSyz147064 dlmgmt_table_unlock();
717d62bc4baSyz147064 return (NULL);
718d62bc4baSyz147064 }
719d62bc4baSyz147064
720d62bc4baSyz147064 static int
parse_linkprops(char * buf,dlmgmt_link_t * linkp)721d62bc4baSyz147064 parse_linkprops(char *buf, dlmgmt_link_t *linkp)
722d62bc4baSyz147064 {
723d62bc4baSyz147064 boolean_t found_type = B_FALSE;
724d62bc4baSyz147064 dladm_datatype_t type = DLADM_TYPE_STR;
725d62bc4baSyz147064 int i, len;
726d62bc4baSyz147064 char *curr;
727d62bc4baSyz147064 char attr_name[MAXLINKATTRLEN];
728d62bc4baSyz147064 size_t attr_buf_len = 0;
729d62bc4baSyz147064 void *attr_buf = NULL;
730d62bc4baSyz147064
731d62bc4baSyz147064 curr = buf;
732d62bc4baSyz147064 len = strlen(buf);
733d62bc4baSyz147064 attr_name[0] = '\0';
73432715170SCathy Zhou for (i = 0; i < len; i++) {
735d62bc4baSyz147064 char c = buf[i];
736d62bc4baSyz147064 boolean_t match = (c == '=' ||
737d62bc4baSyz147064 (c == ',' && !found_type) || c == ';');
73885dff7a0SAndy Fiddaman boolean_t rename = B_FALSE;
739d62bc4baSyz147064
740d62bc4baSyz147064 /*
741d62bc4baSyz147064 * Move to the next character if there is no match and
742d62bc4baSyz147064 * if we have not reached the last character.
743d62bc4baSyz147064 */
744d62bc4baSyz147064 if (!match && i != len - 1)
745d62bc4baSyz147064 continue;
746d62bc4baSyz147064
747d62bc4baSyz147064 if (match) {
748d62bc4baSyz147064 /*
749d62bc4baSyz147064 * NUL-terminate the string pointed to by 'curr'.
750d62bc4baSyz147064 */
751d62bc4baSyz147064 buf[i] = '\0';
752d62bc4baSyz147064 if (*curr == '\0')
753d62bc4baSyz147064 goto parse_fail;
754d62bc4baSyz147064 }
755d62bc4baSyz147064
756d62bc4baSyz147064 if (attr_name[0] != '\0' && found_type) {
757d62bc4baSyz147064 /*
758d62bc4baSyz147064 * We get here after we have processed the "<prop>="
759d62bc4baSyz147064 * pattern. The pattern we are now interested in is
760d62bc4baSyz147064 * "<val>;".
761d62bc4baSyz147064 */
762d62bc4baSyz147064 if (c == '=')
763d62bc4baSyz147064 goto parse_fail;
764d62bc4baSyz147064
7652b24ab6bSSebastien Roy if (strcmp(attr_name, "linkid") == 0) {
76632715170SCathy Zhou if (read_int64(curr, &attr_buf) == 0)
76732715170SCathy Zhou goto parse_fail;
7682b24ab6bSSebastien Roy linkp->ll_linkid =
7692b24ab6bSSebastien Roy (datalink_class_t)*(int64_t *)attr_buf;
7702b24ab6bSSebastien Roy } else if (strcmp(attr_name, "name") == 0) {
77132715170SCathy Zhou if (read_str(curr, &attr_buf) == 0)
77232715170SCathy Zhou goto parse_fail;
773d62bc4baSyz147064 (void) snprintf(linkp->ll_link,
774d62bc4baSyz147064 MAXLINKNAMELEN, "%s", attr_buf);
775d62bc4baSyz147064 } else if (strcmp(attr_name, "class") == 0) {
77632715170SCathy Zhou if (read_int64(curr, &attr_buf) == 0)
77732715170SCathy Zhou goto parse_fail;
778d62bc4baSyz147064 linkp->ll_class =
779d62bc4baSyz147064 (datalink_class_t)*(int64_t *)attr_buf;
780d62bc4baSyz147064 } else if (strcmp(attr_name, "media") == 0) {
78132715170SCathy Zhou if (read_int64(curr, &attr_buf) == 0)
78232715170SCathy Zhou goto parse_fail;
783d62bc4baSyz147064 linkp->ll_media =
784d62bc4baSyz147064 (uint32_t)*(int64_t *)attr_buf;
78585dff7a0SAndy Fiddaman } else if (strcmp(attr_name, "zone") == 0) {
78685dff7a0SAndy Fiddaman if (read_str(curr, &attr_buf) == 0)
78785dff7a0SAndy Fiddaman goto parse_fail;
78885dff7a0SAndy Fiddaman linkp->ll_zoneid = getzoneidbyname(attr_buf);
78985dff7a0SAndy Fiddaman if (linkp->ll_zoneid == -1) {
79085dff7a0SAndy Fiddaman if (errno == EFAULT)
79185dff7a0SAndy Fiddaman abort();
79285dff7a0SAndy Fiddaman /*
79385dff7a0SAndy Fiddaman * If we can't find the zone, assign the
79485dff7a0SAndy Fiddaman * link to the GZ and mark it for being
79585dff7a0SAndy Fiddaman * renamed.
79685dff7a0SAndy Fiddaman */
79785dff7a0SAndy Fiddaman linkp->ll_zoneid = 0;
79885dff7a0SAndy Fiddaman rename = B_TRUE;
79985dff7a0SAndy Fiddaman }
80085dff7a0SAndy Fiddaman } else if (strcmp(attr_name, "transient") == 0) {
80185dff7a0SAndy Fiddaman if (read_boolean(curr, &attr_buf) == 0)
80285dff7a0SAndy Fiddaman goto parse_fail;
80385dff7a0SAndy Fiddaman linkp->ll_transient = *(boolean_t *)attr_buf;
804d62bc4baSyz147064 } else {
805d62bc4baSyz147064 attr_buf_len = translators[type].read_func(curr,
806d62bc4baSyz147064 &attr_buf);
80732715170SCathy Zhou if (attr_buf_len == 0)
80832715170SCathy Zhou goto parse_fail;
80932715170SCathy Zhou
81032715170SCathy Zhou if (linkattr_set(&(linkp->ll_head), attr_name,
81132715170SCathy Zhou attr_buf, attr_buf_len, type) != 0) {
81232715170SCathy Zhou free(attr_buf);
81332715170SCathy Zhou goto parse_fail;
81432715170SCathy Zhou }
815d62bc4baSyz147064 }
816d62bc4baSyz147064
817d62bc4baSyz147064 free(attr_buf);
818d62bc4baSyz147064 attr_name[0] = '\0';
819d62bc4baSyz147064 found_type = B_FALSE;
820d62bc4baSyz147064 } else if (attr_name[0] != '\0') {
821d62bc4baSyz147064 /*
822d62bc4baSyz147064 * Non-zero length attr_name and found_type of false
823d62bc4baSyz147064 * indicates that we have not found the type for this
824d62bc4baSyz147064 * attribute. The pattern now is "<type>,<val>;", we
825d62bc4baSyz147064 * want the <type> part of the pattern.
826d62bc4baSyz147064 */
827d62bc4baSyz147064 for (type = 0; type < ntranslators; type++) {
828d62bc4baSyz147064 if (strcmp(curr,
829d62bc4baSyz147064 translators[type].type_name) == 0) {
830d62bc4baSyz147064 found_type = B_TRUE;
831d62bc4baSyz147064 break;
832d62bc4baSyz147064 }
833d62bc4baSyz147064 }
834d62bc4baSyz147064
835d62bc4baSyz147064 if (!found_type)
836d62bc4baSyz147064 goto parse_fail;
837d62bc4baSyz147064 } else {
838d62bc4baSyz147064 /*
839d62bc4baSyz147064 * A zero length attr_name indicates we are looking
840d62bc4baSyz147064 * at the beginning of a link attribute.
841d62bc4baSyz147064 */
842d62bc4baSyz147064 if (c != '=')
843d62bc4baSyz147064 goto parse_fail;
844d62bc4baSyz147064
845d62bc4baSyz147064 (void) snprintf(attr_name, MAXLINKATTRLEN, "%s", curr);
846d62bc4baSyz147064 }
84785dff7a0SAndy Fiddaman
84885dff7a0SAndy Fiddaman /*
84985dff7a0SAndy Fiddaman * The zone that this link belongs to has died, we are
85085dff7a0SAndy Fiddaman * reparenting it to the GZ and renaming it to avoid name
85185dff7a0SAndy Fiddaman * collisions.
85285dff7a0SAndy Fiddaman */
85385dff7a0SAndy Fiddaman if (rename) {
85485dff7a0SAndy Fiddaman (void) snprintf(linkp->ll_link, MAXLINKNAMELEN,
85585dff7a0SAndy Fiddaman "SUNWorphan%u", (uint16_t)(gethrtime() / 1000));
85685dff7a0SAndy Fiddaman }
85785dff7a0SAndy Fiddaman
858d62bc4baSyz147064 curr = buf + i + 1;
859d62bc4baSyz147064 }
860d62bc4baSyz147064
861f689bed1SRishi Srivatsavai /* Correct any erroneous IPTUN datalink class constant in the file */
862f689bed1SRishi Srivatsavai if (linkp->ll_class == 0x60) {
863f689bed1SRishi Srivatsavai linkp->ll_class = DATALINK_CLASS_IPTUN;
864f689bed1SRishi Srivatsavai rewrite_needed = B_TRUE;
865f689bed1SRishi Srivatsavai }
866f689bed1SRishi Srivatsavai
86732715170SCathy Zhou return (0);
868d62bc4baSyz147064
869d62bc4baSyz147064 parse_fail:
87032715170SCathy Zhou /*
87132715170SCathy Zhou * Free linkp->ll_head (link attribute list)
87232715170SCathy Zhou */
87332715170SCathy Zhou linkattr_destroy(linkp);
874d62bc4baSyz147064 return (-1);
875d62bc4baSyz147064 }
876d62bc4baSyz147064
877d62bc4baSyz147064 static boolean_t
process_link_line(char * buf,dlmgmt_link_t * linkp)8782b24ab6bSSebastien Roy process_link_line(char *buf, dlmgmt_link_t *linkp)
879d62bc4baSyz147064 {
880d62bc4baSyz147064 int i, len, llen;
881d62bc4baSyz147064 char *str, *lasts;
882d62bc4baSyz147064 char tmpbuf[MAXLINELEN];
883d62bc4baSyz147064
8842b24ab6bSSebastien Roy bzero(linkp, sizeof (*linkp));
8852b24ab6bSSebastien Roy linkp->ll_linkid = DATALINK_INVALID_LINKID;
886*f222df41SAndy Fiddaman linkp->ll_zoneid = ALL_ZONES;
8872b24ab6bSSebastien Roy
888d62bc4baSyz147064 /*
889d62bc4baSyz147064 * Use a copy of buf for parsing so that we can do whatever we want.
890d62bc4baSyz147064 */
891d62bc4baSyz147064 (void) strlcpy(tmpbuf, buf, MAXLINELEN);
892d62bc4baSyz147064
893d62bc4baSyz147064 /*
894d62bc4baSyz147064 * Skip leading spaces, blank lines, and comments.
895d62bc4baSyz147064 */
896d62bc4baSyz147064 len = strlen(tmpbuf);
897d62bc4baSyz147064 for (i = 0; i < len; i++) {
898d62bc4baSyz147064 if (!isspace(tmpbuf[i]))
899d62bc4baSyz147064 break;
900d62bc4baSyz147064 }
9012b24ab6bSSebastien Roy if (i == len || tmpbuf[i] == '#')
902d62bc4baSyz147064 return (B_TRUE);
903d62bc4baSyz147064
904d62bc4baSyz147064 str = tmpbuf + i;
905d62bc4baSyz147064 /*
9062b24ab6bSSebastien Roy * Find the link name and assign it to the link structure.
907d62bc4baSyz147064 */
908d62bc4baSyz147064 if (strtok_r(str, " \n\t", &lasts) == NULL)
909d62bc4baSyz147064 goto fail;
910d62bc4baSyz147064
911d62bc4baSyz147064 llen = strlen(str);
9122b24ab6bSSebastien Roy /*
9132b24ab6bSSebastien Roy * Note that a previous version of the persistent datalink.conf file
9142b24ab6bSSebastien Roy * stored the linkid as the first field. In that case, the name will
9152b24ab6bSSebastien Roy * be obtained through parse_linkprops from a property with the format
9162b24ab6bSSebastien Roy * "name=<linkname>". If we encounter such a format, we set
9172b24ab6bSSebastien Roy * rewrite_needed so that dlmgmt_db_init() can rewrite the file with
9182b24ab6bSSebastien Roy * the new format after it's done reading in the data.
9192b24ab6bSSebastien Roy */
9202b24ab6bSSebastien Roy if (isdigit(str[0])) {
921d62bc4baSyz147064 linkp->ll_linkid = atoi(str);
9222b24ab6bSSebastien Roy rewrite_needed = B_TRUE;
9232b24ab6bSSebastien Roy } else {
9242b24ab6bSSebastien Roy if (strlcpy(linkp->ll_link, str, sizeof (linkp->ll_link)) >=
9252b24ab6bSSebastien Roy sizeof (linkp->ll_link))
9262b24ab6bSSebastien Roy goto fail;
9272b24ab6bSSebastien Roy }
928d62bc4baSyz147064
929d62bc4baSyz147064 str += llen + 1;
930d62bc4baSyz147064 if (str >= tmpbuf + len)
931d62bc4baSyz147064 goto fail;
932d62bc4baSyz147064
933d62bc4baSyz147064 /*
934d62bc4baSyz147064 * Now find the list of link properties.
935d62bc4baSyz147064 */
936d62bc4baSyz147064 if ((str = strtok_r(str, " \n\t", &lasts)) == NULL)
937d62bc4baSyz147064 goto fail;
938d62bc4baSyz147064
939d62bc4baSyz147064 if (parse_linkprops(str, linkp) < 0)
940d62bc4baSyz147064 goto fail;
941d62bc4baSyz147064
942d62bc4baSyz147064 return (B_TRUE);
943d62bc4baSyz147064
944d62bc4baSyz147064 fail:
945d62bc4baSyz147064 /*
946d62bc4baSyz147064 * Delete corrupted line.
947d62bc4baSyz147064 */
948d62bc4baSyz147064 buf[0] = '\0';
949d62bc4baSyz147064 return (B_FALSE);
950d62bc4baSyz147064 }
951d62bc4baSyz147064
9522b24ab6bSSebastien Roy /*
9532b24ab6bSSebastien Roy * Find any properties in linkp that refer to "old", and rename to "new".
9542b24ab6bSSebastien Roy * Return B_TRUE if any renaming occurred.
9552b24ab6bSSebastien Roy */
9562b24ab6bSSebastien Roy static int
dlmgmt_attr_rename(dlmgmt_link_t * linkp,const char * old,const char * new,boolean_t * renamed)9572b24ab6bSSebastien Roy dlmgmt_attr_rename(dlmgmt_link_t *linkp, const char *old, const char *new,
9582b24ab6bSSebastien Roy boolean_t *renamed)
9592b24ab6bSSebastien Roy {
9602b24ab6bSSebastien Roy dlmgmt_linkattr_t *attrp;
9612b24ab6bSSebastien Roy char *newval = NULL, *pname;
9622b24ab6bSSebastien Roy char valcp[MAXLINKATTRVALLEN];
9632b24ab6bSSebastien Roy size_t newsize;
9642b24ab6bSSebastien Roy
9652b24ab6bSSebastien Roy *renamed = B_FALSE;
9662b24ab6bSSebastien Roy
9672b24ab6bSSebastien Roy if ((attrp = linkattr_find(linkp->ll_head, "linkover")) != NULL ||
9682b24ab6bSSebastien Roy (attrp = linkattr_find(linkp->ll_head, "simnetpeer")) != NULL) {
9692b24ab6bSSebastien Roy if (strcmp(old, (char *)attrp->lp_val) == 0) {
9702b24ab6bSSebastien Roy newsize = strlen(new) + 1;
9712b24ab6bSSebastien Roy if ((newval = malloc(newsize)) == NULL)
9722b24ab6bSSebastien Roy return (errno);
9732b24ab6bSSebastien Roy (void) strcpy(newval, new);
9742b24ab6bSSebastien Roy free(attrp->lp_val);
9752b24ab6bSSebastien Roy attrp->lp_val = newval;
9762b24ab6bSSebastien Roy attrp->lp_sz = newsize;
9772b24ab6bSSebastien Roy *renamed = B_TRUE;
9782b24ab6bSSebastien Roy }
9792b24ab6bSSebastien Roy return (0);
9802b24ab6bSSebastien Roy }
9812b24ab6bSSebastien Roy
9822b24ab6bSSebastien Roy if ((attrp = linkattr_find(linkp->ll_head, "portnames")) == NULL)
9832b24ab6bSSebastien Roy return (0);
9842b24ab6bSSebastien Roy
9852b24ab6bSSebastien Roy /* <linkname>:[<linkname>:]... */
9862b24ab6bSSebastien Roy if ((newval = calloc(MAXLINKATTRVALLEN, sizeof (char))) == NULL)
9872b24ab6bSSebastien Roy return (errno);
9882b24ab6bSSebastien Roy
9892b24ab6bSSebastien Roy bcopy(attrp->lp_val, valcp, sizeof (valcp));
9902b24ab6bSSebastien Roy pname = strtok(valcp, ":");
9912b24ab6bSSebastien Roy while (pname != NULL) {
9922b24ab6bSSebastien Roy if (strcmp(pname, old) == 0) {
9932b24ab6bSSebastien Roy (void) strcat(newval, new);
9942b24ab6bSSebastien Roy *renamed = B_TRUE;
9952b24ab6bSSebastien Roy } else {
9962b24ab6bSSebastien Roy (void) strcat(newval, pname);
9972b24ab6bSSebastien Roy }
9982b24ab6bSSebastien Roy (void) strcat(newval, ":");
9992b24ab6bSSebastien Roy pname = strtok(NULL, ":");
10002b24ab6bSSebastien Roy }
10012b24ab6bSSebastien Roy if (*renamed) {
10022b24ab6bSSebastien Roy free(attrp->lp_val);
10032b24ab6bSSebastien Roy attrp->lp_val = newval;
10042b24ab6bSSebastien Roy attrp->lp_sz = strlen(newval) + 1;
10052b24ab6bSSebastien Roy } else {
10062b24ab6bSSebastien Roy free(newval);
10072b24ab6bSSebastien Roy }
10082b24ab6bSSebastien Roy return (0);
10092b24ab6bSSebastien Roy }
10102b24ab6bSSebastien Roy
1011d62bc4baSyz147064 static int
process_db_write(dlmgmt_db_req_t * req,FILE * fp,FILE * nfp)1012d62bc4baSyz147064 process_db_write(dlmgmt_db_req_t *req, FILE *fp, FILE *nfp)
1013d62bc4baSyz147064 {
1014d62bc4baSyz147064 boolean_t done = B_FALSE;
1015d62bc4baSyz147064 int err = 0;
10162b24ab6bSSebastien Roy dlmgmt_link_t link_in_file, *linkp = NULL, *dblinkp;
10172b24ab6bSSebastien Roy boolean_t persist = (req->ls_flags == DLMGMT_PERSIST);
10182b24ab6bSSebastien Roy boolean_t writeall, rename, attr_renamed;
1019d62bc4baSyz147064 char buf[MAXLINELEN];
1020d62bc4baSyz147064
10212b24ab6bSSebastien Roy writeall = (req->ls_linkid == DATALINK_ALL_LINKID);
10222b24ab6bSSebastien Roy
10232b24ab6bSSebastien Roy if (req->ls_op == DLMGMT_DB_OP_WRITE && !writeall) {
1024d62bc4baSyz147064 /*
1025d62bc4baSyz147064 * find the link in the avl tree with the given linkid.
1026d62bc4baSyz147064 */
10272b24ab6bSSebastien Roy linkp = link_by_id(req->ls_linkid, req->ls_zoneid);
1028d62bc4baSyz147064 if (linkp == NULL || (linkp->ll_flags & req->ls_flags) == 0) {
1029d62bc4baSyz147064 /*
1030d62bc4baSyz147064 * This link has already been changed. This could
1031d62bc4baSyz147064 * happen if the request is pending because of
1032d62bc4baSyz147064 * read-only file-system. If so, we are done.
1033d62bc4baSyz147064 */
1034d62bc4baSyz147064 return (0);
1035d62bc4baSyz147064 }
10362b24ab6bSSebastien Roy /*
10372b24ab6bSSebastien Roy * In the case of a rename, linkp's name has been updated to
10382b24ab6bSSebastien Roy * the new name, and req->ls_link is the old link name.
10392b24ab6bSSebastien Roy */
10402b24ab6bSSebastien Roy rename = (strcmp(req->ls_link, linkp->ll_link) != 0);
1041d62bc4baSyz147064 }
1042d62bc4baSyz147064
10432b24ab6bSSebastien Roy /*
10442b24ab6bSSebastien Roy * fp can be NULL if the file didn't initially exist and we're
10452b24ab6bSSebastien Roy * creating it as part of this write operation.
10462b24ab6bSSebastien Roy */
10472b24ab6bSSebastien Roy if (fp == NULL)
10482b24ab6bSSebastien Roy goto write;
10492b24ab6bSSebastien Roy
1050d62bc4baSyz147064 while (err == 0 && fgets(buf, sizeof (buf), fp) != NULL &&
1051d62bc4baSyz147064 process_link_line(buf, &link_in_file)) {
105232715170SCathy Zhou /*
105332715170SCathy Zhou * Only the link name is needed. Free the memory allocated for
105432715170SCathy Zhou * the link attributes list of link_in_file.
105532715170SCathy Zhou */
105632715170SCathy Zhou linkattr_destroy(&link_in_file);
105732715170SCathy Zhou
10582b24ab6bSSebastien Roy if (link_in_file.ll_link[0] == '\0' || done) {
1059d62bc4baSyz147064 /*
10600dc974a9SCathy Zhou * this is a comment line or we are done updating the
10612b24ab6bSSebastien Roy * line for the specified link, write the rest of
10622b24ab6bSSebastien Roy * lines out.
1063d62bc4baSyz147064 */
1064d62bc4baSyz147064 if (fputs(buf, nfp) == EOF)
1065d62bc4baSyz147064 err = errno;
1066d62bc4baSyz147064 continue;
1067d62bc4baSyz147064 }
1068d62bc4baSyz147064
1069d62bc4baSyz147064 switch (req->ls_op) {
1070d62bc4baSyz147064 case DLMGMT_DB_OP_WRITE:
1071d62bc4baSyz147064 /*
10722b24ab6bSSebastien Roy * For write operations, we generate a new output line
10732b24ab6bSSebastien Roy * if we're either writing all links (writeall) or if
10742b24ab6bSSebastien Roy * the name of the link in the file matches the one
10752b24ab6bSSebastien Roy * we're looking for. Otherwise, we write out the
10762b24ab6bSSebastien Roy * buffer as-is.
10772b24ab6bSSebastien Roy *
10782b24ab6bSSebastien Roy * If we're doing a rename operation, ensure that any
10792b24ab6bSSebastien Roy * references to the link being renamed in link
10802b24ab6bSSebastien Roy * properties are also updated before we write
10812b24ab6bSSebastien Roy * anything.
1082d62bc4baSyz147064 */
10832b24ab6bSSebastien Roy if (writeall) {
10842b24ab6bSSebastien Roy linkp = link_by_name(link_in_file.ll_link,
10852b24ab6bSSebastien Roy req->ls_zoneid);
1086d62bc4baSyz147064 }
10872b24ab6bSSebastien Roy if (writeall || strcmp(req->ls_link,
10882b24ab6bSSebastien Roy link_in_file.ll_link) == 0) {
10892b24ab6bSSebastien Roy generate_link_line(linkp, persist, buf);
10902b24ab6bSSebastien Roy if (!writeall && !rename)
10912b24ab6bSSebastien Roy done = B_TRUE;
10922b24ab6bSSebastien Roy } else if (rename && persist) {
10932b24ab6bSSebastien Roy dblinkp = link_by_name(link_in_file.ll_link,
10942b24ab6bSSebastien Roy req->ls_zoneid);
10952b24ab6bSSebastien Roy err = dlmgmt_attr_rename(dblinkp, req->ls_link,
10962b24ab6bSSebastien Roy linkp->ll_link, &attr_renamed);
10972b24ab6bSSebastien Roy if (err != 0)
10982b24ab6bSSebastien Roy break;
10992b24ab6bSSebastien Roy if (attr_renamed) {
11002b24ab6bSSebastien Roy generate_link_line(dblinkp, persist,
11012b24ab6bSSebastien Roy buf);
11022b24ab6bSSebastien Roy }
11032b24ab6bSSebastien Roy }
11042b24ab6bSSebastien Roy if (fputs(buf, nfp) == EOF)
11052b24ab6bSSebastien Roy err = errno;
1106d62bc4baSyz147064 break;
1107d62bc4baSyz147064 case DLMGMT_DB_OP_DELETE:
1108d62bc4baSyz147064 /*
1109d62bc4baSyz147064 * Delete is simple. If buf does not represent the
1110d62bc4baSyz147064 * link we're deleting, write it out.
1111d62bc4baSyz147064 */
11122b24ab6bSSebastien Roy if (strcmp(req->ls_link, link_in_file.ll_link) != 0) {
1113d62bc4baSyz147064 if (fputs(buf, nfp) == EOF)
1114d62bc4baSyz147064 err = errno;
1115d62bc4baSyz147064 } else {
1116d62bc4baSyz147064 done = B_TRUE;
1117d62bc4baSyz147064 }
1118d62bc4baSyz147064 break;
1119d62bc4baSyz147064 case DLMGMT_DB_OP_READ:
1120d62bc4baSyz147064 default:
1121d62bc4baSyz147064 err = EINVAL;
1122d62bc4baSyz147064 break;
1123d62bc4baSyz147064 }
1124d62bc4baSyz147064 }
1125d62bc4baSyz147064
11262b24ab6bSSebastien Roy write:
1127d62bc4baSyz147064 /*
11282b24ab6bSSebastien Roy * If we get to the end of the file and have not seen what linkid
11292b24ab6bSSebastien Roy * points to, write it out then.
1130d62bc4baSyz147064 */
11312b24ab6bSSebastien Roy if (req->ls_op == DLMGMT_DB_OP_WRITE && !writeall && !rename && !done) {
11322b24ab6bSSebastien Roy generate_link_line(linkp, persist, buf);
1133d62bc4baSyz147064 done = B_TRUE;
1134d62bc4baSyz147064 if (fputs(buf, nfp) == EOF)
1135d62bc4baSyz147064 err = errno;
1136d62bc4baSyz147064 }
1137d62bc4baSyz147064
1138d62bc4baSyz147064 return (err);
1139d62bc4baSyz147064 }
1140d62bc4baSyz147064
1141d62bc4baSyz147064 static int
process_db_read(dlmgmt_db_req_t * req,FILE * fp)11422b24ab6bSSebastien Roy process_db_read(dlmgmt_db_req_t *req, FILE *fp)
1143d62bc4baSyz147064 {
1144d62bc4baSyz147064 avl_index_t name_where, id_where;
11452b24ab6bSSebastien Roy dlmgmt_link_t link_in_file, *newlink, *link_in_db;
1146d62bc4baSyz147064 char buf[MAXLINELEN];
1147d62bc4baSyz147064 int err = 0;
1148d62bc4baSyz147064
1149d62bc4baSyz147064 /*
1150d62bc4baSyz147064 * This loop processes each line of the configuration file.
1151d62bc4baSyz147064 */
1152d62bc4baSyz147064 while (fgets(buf, MAXLINELEN, fp) != NULL) {
1153d62bc4baSyz147064 if (!process_link_line(buf, &link_in_file)) {
1154d62bc4baSyz147064 err = EINVAL;
1155d62bc4baSyz147064 break;
1156d62bc4baSyz147064 }
1157d62bc4baSyz147064
1158d62bc4baSyz147064 /*
1159d62bc4baSyz147064 * Skip the comment line.
1160d62bc4baSyz147064 */
116132715170SCathy Zhou if (link_in_file.ll_link[0] == '\0') {
116232715170SCathy Zhou linkattr_destroy(&link_in_file);
1163d62bc4baSyz147064 continue;
116432715170SCathy Zhou }
1165d62bc4baSyz147064
11662b24ab6bSSebastien Roy if ((req->ls_flags & DLMGMT_ACTIVE) &&
116732715170SCathy Zhou link_in_file.ll_linkid == DATALINK_INVALID_LINKID) {
116832715170SCathy Zhou linkattr_destroy(&link_in_file);
11692b24ab6bSSebastien Roy continue;
117032715170SCathy Zhou }
11712b24ab6bSSebastien Roy
1172*f222df41SAndy Fiddaman /*
1173*f222df41SAndy Fiddaman * Persistent configuration files do not include the "zone"
1174*f222df41SAndy Fiddaman * attribute. In that case, ll_zoneid will have the the
1175*f222df41SAndy Fiddaman * ALL_ZONES sentinel value. Adjust it here to the requesting
1176*f222df41SAndy Fiddaman * zone's ID.
1177*f222df41SAndy Fiddaman */
1178*f222df41SAndy Fiddaman if (link_in_file.ll_zoneid == ALL_ZONES)
1179*f222df41SAndy Fiddaman link_in_file.ll_zoneid = req->ls_zoneid;
1180*f222df41SAndy Fiddaman
118185dff7a0SAndy Fiddaman assert(req->ls_zoneid == 0 ||
118285dff7a0SAndy Fiddaman link_in_file.ll_zoneid == req->ls_zoneid);
1183f689bed1SRishi Srivatsavai link_in_db = link_by_name(link_in_file.ll_link,
1184f689bed1SRishi Srivatsavai link_in_file.ll_zoneid);
11852b24ab6bSSebastien Roy if (link_in_db != NULL) {
1186d62bc4baSyz147064 /*
11872b24ab6bSSebastien Roy * If the link in the database already has the flag
11882b24ab6bSSebastien Roy * for this request set, then the entry is a
11892b24ab6bSSebastien Roy * duplicate. If it's not a duplicate, then simply
11902b24ab6bSSebastien Roy * turn on the appropriate flag on the existing link.
1191d62bc4baSyz147064 */
11922b24ab6bSSebastien Roy if (link_in_db->ll_flags & req->ls_flags) {
11932b24ab6bSSebastien Roy dlmgmt_log(LOG_WARNING, "Duplicate links "
11942b24ab6bSSebastien Roy "in the repository: %s",
11952b24ab6bSSebastien Roy link_in_file.ll_link);
119632715170SCathy Zhou linkattr_destroy(&link_in_file);
1197d62bc4baSyz147064 } else {
11982b24ab6bSSebastien Roy if (req->ls_flags & DLMGMT_PERSIST) {
11992b24ab6bSSebastien Roy /*
12002b24ab6bSSebastien Roy * Save the newly read properties into
12012b24ab6bSSebastien Roy * the existing link.
12022b24ab6bSSebastien Roy */
12032b24ab6bSSebastien Roy assert(link_in_db->ll_head == NULL);
12042b24ab6bSSebastien Roy link_in_db->ll_head =
12052b24ab6bSSebastien Roy link_in_file.ll_head;
120632715170SCathy Zhou } else {
120732715170SCathy Zhou linkattr_destroy(&link_in_file);
1208d62bc4baSyz147064 }
12092b24ab6bSSebastien Roy link_in_db->ll_flags |= req->ls_flags;
12102b24ab6bSSebastien Roy }
1211d62bc4baSyz147064 } else {
12122b24ab6bSSebastien Roy /*
12132b24ab6bSSebastien Roy * This is a new link. Allocate a new dlmgmt_link_t
12142b24ab6bSSebastien Roy * and add it to the trees.
12152b24ab6bSSebastien Roy */
12162b24ab6bSSebastien Roy newlink = calloc(1, sizeof (*newlink));
12172b24ab6bSSebastien Roy if (newlink == NULL) {
12182b24ab6bSSebastien Roy dlmgmt_log(LOG_WARNING, "Unable to allocate "
12192b24ab6bSSebastien Roy "memory to create new link %s",
12202b24ab6bSSebastien Roy link_in_file.ll_link);
122132715170SCathy Zhou linkattr_destroy(&link_in_file);
12222b24ab6bSSebastien Roy continue;
12232b24ab6bSSebastien Roy }
12242b24ab6bSSebastien Roy bcopy(&link_in_file, newlink, sizeof (*newlink));
12252b24ab6bSSebastien Roy
12262b24ab6bSSebastien Roy if (newlink->ll_linkid == DATALINK_INVALID_LINKID)
12272b24ab6bSSebastien Roy newlink->ll_linkid = dlmgmt_nextlinkid;
12282b24ab6bSSebastien Roy if (avl_find(&dlmgmt_id_avl, newlink, &id_where) !=
12292b24ab6bSSebastien Roy NULL) {
1230f689bed1SRishi Srivatsavai dlmgmt_log(LOG_WARNING, "Link ID %d is already"
1231f689bed1SRishi Srivatsavai " in use, destroying link %s",
1232f689bed1SRishi Srivatsavai newlink->ll_linkid, newlink->ll_link);
12332b24ab6bSSebastien Roy link_destroy(newlink);
12342b24ab6bSSebastien Roy continue;
12352b24ab6bSSebastien Roy }
1236f689bed1SRishi Srivatsavai
12372b24ab6bSSebastien Roy if ((req->ls_flags & DLMGMT_ACTIVE) &&
12382b24ab6bSSebastien Roy link_activate(newlink) != 0) {
12392b24ab6bSSebastien Roy dlmgmt_log(LOG_WARNING, "Unable to activate %s",
12402b24ab6bSSebastien Roy newlink->ll_link);
12412b24ab6bSSebastien Roy link_destroy(newlink);
12422b24ab6bSSebastien Roy continue;
12432b24ab6bSSebastien Roy }
1244f689bed1SRishi Srivatsavai
12452b24ab6bSSebastien Roy avl_insert(&dlmgmt_id_avl, newlink, id_where);
1246f689bed1SRishi Srivatsavai /*
1247f689bed1SRishi Srivatsavai * link_activate call above can insert newlink in
1248f689bed1SRishi Srivatsavai * dlmgmt_name_avl tree when activating a link that is
1249f689bed1SRishi Srivatsavai * assigned to a NGZ.
1250f689bed1SRishi Srivatsavai */
1251f689bed1SRishi Srivatsavai if (avl_find(&dlmgmt_name_avl, newlink,
1252f689bed1SRishi Srivatsavai &name_where) == NULL)
1253f689bed1SRishi Srivatsavai avl_insert(&dlmgmt_name_avl, newlink,
1254f689bed1SRishi Srivatsavai name_where);
1255f689bed1SRishi Srivatsavai
12562b24ab6bSSebastien Roy dlmgmt_advance(newlink);
12572b24ab6bSSebastien Roy newlink->ll_flags |= req->ls_flags;
1258d62bc4baSyz147064 }
1259d62bc4baSyz147064 }
1260d62bc4baSyz147064
1261d62bc4baSyz147064 return (err);
1262d62bc4baSyz147064 }
1263d62bc4baSyz147064
1264d62bc4baSyz147064 /*
1265d62bc4baSyz147064 * Generate an entry in the link database.
1266d62bc4baSyz147064 * Each entry has this format:
12672b24ab6bSSebastien Roy * <link name> <prop0>=<type>,<val>;...;<propn>=<type>,<val>;
1268d62bc4baSyz147064 */
1269d62bc4baSyz147064 static void
generate_link_line(dlmgmt_link_t * linkp,boolean_t persist,char * buf)1270d62bc4baSyz147064 generate_link_line(dlmgmt_link_t *linkp, boolean_t persist, char *buf)
1271d62bc4baSyz147064 {
1272d62bc4baSyz147064 char tmpbuf[MAXLINELEN];
12732b24ab6bSSebastien Roy char *ptr = tmpbuf;
1274d62bc4baSyz147064 char *lim = tmpbuf + MAXLINELEN;
1275d62bc4baSyz147064 dlmgmt_linkattr_t *cur_p = NULL;
1276d62bc4baSyz147064 uint64_t u64;
1277d62bc4baSyz147064
12782b24ab6bSSebastien Roy ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t", linkp->ll_link);
12792b24ab6bSSebastien Roy if (!persist) {
128085dff7a0SAndy Fiddaman char zname[ZONENAME_MAX];
128185dff7a0SAndy Fiddaman
12822b24ab6bSSebastien Roy /*
128385dff7a0SAndy Fiddaman * We store the linkid and the zone name in the active database
128485dff7a0SAndy Fiddaman * so that dlmgmtd can recover in the event that it is
128585dff7a0SAndy Fiddaman * restarted.
12862b24ab6bSSebastien Roy */
12872b24ab6bSSebastien Roy u64 = linkp->ll_linkid;
12882b24ab6bSSebastien Roy ptr += write_uint64(ptr, BUFLEN(lim, ptr), "linkid", &u64);
128985dff7a0SAndy Fiddaman
129085dff7a0SAndy Fiddaman if (getzonenamebyid(linkp->ll_zoneid, zname,
129185dff7a0SAndy Fiddaman sizeof (zname)) != -1) {
129285dff7a0SAndy Fiddaman ptr += write_str(ptr, BUFLEN(lim, ptr), "zone", zname);
129385dff7a0SAndy Fiddaman }
12942b24ab6bSSebastien Roy }
1295d62bc4baSyz147064 u64 = linkp->ll_class;
1296d62bc4baSyz147064 ptr += write_uint64(ptr, BUFLEN(lim, ptr), "class", &u64);
1297d62bc4baSyz147064 u64 = linkp->ll_media;
1298d62bc4baSyz147064 ptr += write_uint64(ptr, BUFLEN(lim, ptr), "media", &u64);
1299d62bc4baSyz147064
130085dff7a0SAndy Fiddaman if (!persist && linkp->ll_transient) {
130185dff7a0SAndy Fiddaman boolean_t b = B_TRUE;
130285dff7a0SAndy Fiddaman ptr += write_boolean(ptr, BUFLEN(lim, ptr), "transient", &b);
130385dff7a0SAndy Fiddaman }
130485dff7a0SAndy Fiddaman
1305d62bc4baSyz147064 /*
13062b24ab6bSSebastien Roy * The daemon does not keep any active link attribute. Only store the
13072b24ab6bSSebastien Roy * attributes if this request is for persistent configuration,
1308d62bc4baSyz147064 */
13092b24ab6bSSebastien Roy if (persist) {
13102b24ab6bSSebastien Roy for (cur_p = linkp->ll_head; cur_p != NULL;
13112b24ab6bSSebastien Roy cur_p = cur_p->lp_next) {
1312d62bc4baSyz147064 ptr += translators[cur_p->lp_type].write_func(ptr,
1313d62bc4baSyz147064 BUFLEN(lim, ptr), cur_p->lp_name, cur_p->lp_val);
1314d62bc4baSyz147064 }
13152b24ab6bSSebastien Roy }
13162b24ab6bSSebastien Roy
13172b24ab6bSSebastien Roy if (ptr <= lim)
1318d62bc4baSyz147064 (void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf);
1319d62bc4baSyz147064 }
1320d62bc4baSyz147064
1321d62bc4baSyz147064 int
dlmgmt_delete_db_entry(dlmgmt_link_t * linkp,uint32_t flags)13222b24ab6bSSebastien Roy dlmgmt_delete_db_entry(dlmgmt_link_t *linkp, uint32_t flags)
1323d62bc4baSyz147064 {
13242b24ab6bSSebastien Roy return (dlmgmt_db_update(DLMGMT_DB_OP_DELETE, linkp->ll_link, linkp,
13252b24ab6bSSebastien Roy flags));
1326d62bc4baSyz147064 }
1327d62bc4baSyz147064
1328d62bc4baSyz147064 int
dlmgmt_write_db_entry(const char * entryname,dlmgmt_link_t * linkp,uint32_t flags)13292b24ab6bSSebastien Roy dlmgmt_write_db_entry(const char *entryname, dlmgmt_link_t *linkp,
13302b24ab6bSSebastien Roy uint32_t flags)
1331d62bc4baSyz147064 {
1332d62bc4baSyz147064 int err;
1333d62bc4baSyz147064
1334d62bc4baSyz147064 if (flags & DLMGMT_PERSIST) {
13352b24ab6bSSebastien Roy if ((err = dlmgmt_db_update(DLMGMT_DB_OP_WRITE, entryname,
13362b24ab6bSSebastien Roy linkp, DLMGMT_PERSIST)) != 0) {
1337d62bc4baSyz147064 return (err);
1338d62bc4baSyz147064 }
1339d62bc4baSyz147064 }
1340d62bc4baSyz147064
1341d62bc4baSyz147064 if (flags & DLMGMT_ACTIVE) {
13422b24ab6bSSebastien Roy if (((err = dlmgmt_db_update(DLMGMT_DB_OP_WRITE, entryname,
13432b24ab6bSSebastien Roy linkp, DLMGMT_ACTIVE)) != 0) && (flags & DLMGMT_PERSIST)) {
13442b24ab6bSSebastien Roy (void) dlmgmt_db_update(DLMGMT_DB_OP_DELETE, entryname,
13452b24ab6bSSebastien Roy linkp, DLMGMT_PERSIST);
1346d62bc4baSyz147064 return (err);
1347d62bc4baSyz147064 }
1348d62bc4baSyz147064 }
1349d62bc4baSyz147064
1350d62bc4baSyz147064 return (0);
1351d62bc4baSyz147064 }
1352d62bc4baSyz147064
1353d62bc4baSyz147064 /*
13542b24ab6bSSebastien Roy * Upgrade properties that have link IDs as values to link names. Because '.'
13552b24ab6bSSebastien Roy * is a valid linkname character, the port separater for link aggregations
1356d501bbfeSSebastien Roy * must be changed to ':'.
13572b24ab6bSSebastien Roy */
13582b24ab6bSSebastien Roy static void
linkattr_upgrade(dlmgmt_linkattr_t * attrp)13592b24ab6bSSebastien Roy linkattr_upgrade(dlmgmt_linkattr_t *attrp)
13602b24ab6bSSebastien Roy {
13612b24ab6bSSebastien Roy datalink_id_t linkid;
13622b24ab6bSSebastien Roy char *portidstr;
13632b24ab6bSSebastien Roy char portname[MAXLINKNAMELEN + 1];
13642b24ab6bSSebastien Roy dlmgmt_link_t *linkp;
13652b24ab6bSSebastien Roy char *new_attr_val;
13662b24ab6bSSebastien Roy size_t new_attr_sz;
13672b24ab6bSSebastien Roy boolean_t upgraded = B_FALSE;
13682b24ab6bSSebastien Roy
13692b24ab6bSSebastien Roy if (strcmp(attrp->lp_name, "linkover") == 0 ||
13702b24ab6bSSebastien Roy strcmp(attrp->lp_name, "simnetpeer") == 0) {
13712b24ab6bSSebastien Roy if (attrp->lp_type == DLADM_TYPE_UINT64) {
1372d501bbfeSSebastien Roy linkid = (datalink_id_t)*(uint64_t *)attrp->lp_val;
13732b24ab6bSSebastien Roy if ((linkp = link_by_id(linkid, GLOBAL_ZONEID)) == NULL)
13742b24ab6bSSebastien Roy return;
13752b24ab6bSSebastien Roy new_attr_sz = strlen(linkp->ll_link) + 1;
13762b24ab6bSSebastien Roy if ((new_attr_val = malloc(new_attr_sz)) == NULL)
13772b24ab6bSSebastien Roy return;
13782b24ab6bSSebastien Roy (void) strcpy(new_attr_val, linkp->ll_link);
13792b24ab6bSSebastien Roy upgraded = B_TRUE;
13802b24ab6bSSebastien Roy }
13812b24ab6bSSebastien Roy } else if (strcmp(attrp->lp_name, "portnames") == 0) {
13822b24ab6bSSebastien Roy /*
13832b24ab6bSSebastien Roy * The old format for "portnames" was
13842b24ab6bSSebastien Roy * "<linkid>.[<linkid>.]...". The new format is
13852b24ab6bSSebastien Roy * "<linkname>:[<linkname>:]...".
13862b24ab6bSSebastien Roy */
13872b24ab6bSSebastien Roy if (!isdigit(((char *)attrp->lp_val)[0]))
13882b24ab6bSSebastien Roy return;
13892b24ab6bSSebastien Roy new_attr_val = calloc(MAXLINKATTRVALLEN, sizeof (char));
13902b24ab6bSSebastien Roy if (new_attr_val == NULL)
13912b24ab6bSSebastien Roy return;
13922b24ab6bSSebastien Roy portidstr = (char *)attrp->lp_val;
13932b24ab6bSSebastien Roy while (*portidstr != '\0') {
13942b24ab6bSSebastien Roy errno = 0;
13952b24ab6bSSebastien Roy linkid = strtol(portidstr, &portidstr, 10);
13962b24ab6bSSebastien Roy if (linkid == 0 || *portidstr != '.' ||
13972b24ab6bSSebastien Roy (linkp = link_by_id(linkid, GLOBAL_ZONEID)) ==
13982b24ab6bSSebastien Roy NULL) {
13992b24ab6bSSebastien Roy free(new_attr_val);
14002b24ab6bSSebastien Roy return;
14012b24ab6bSSebastien Roy }
14022b24ab6bSSebastien Roy (void) snprintf(portname, sizeof (portname), "%s:",
14032b24ab6bSSebastien Roy linkp->ll_link);
14042b24ab6bSSebastien Roy if (strlcat(new_attr_val, portname,
14052b24ab6bSSebastien Roy MAXLINKATTRVALLEN) >= MAXLINKATTRVALLEN) {
14062b24ab6bSSebastien Roy free(new_attr_val);
14072b24ab6bSSebastien Roy return;
14082b24ab6bSSebastien Roy }
14092b24ab6bSSebastien Roy /* skip the '.' delimiter */
14102b24ab6bSSebastien Roy portidstr++;
14112b24ab6bSSebastien Roy }
14122b24ab6bSSebastien Roy new_attr_sz = strlen(new_attr_val) + 1;
14132b24ab6bSSebastien Roy upgraded = B_TRUE;
14142b24ab6bSSebastien Roy }
14152b24ab6bSSebastien Roy
14162b24ab6bSSebastien Roy if (upgraded) {
14172b24ab6bSSebastien Roy attrp->lp_type = DLADM_TYPE_STR;
14182b24ab6bSSebastien Roy attrp->lp_sz = new_attr_sz;
14192b24ab6bSSebastien Roy free(attrp->lp_val);
14202b24ab6bSSebastien Roy attrp->lp_val = new_attr_val;
14212b24ab6bSSebastien Roy }
14222b24ab6bSSebastien Roy }
14232b24ab6bSSebastien Roy
14242b24ab6bSSebastien Roy static void
dlmgmt_db_upgrade(dlmgmt_link_t * linkp)14252b24ab6bSSebastien Roy dlmgmt_db_upgrade(dlmgmt_link_t *linkp)
14262b24ab6bSSebastien Roy {
14272b24ab6bSSebastien Roy dlmgmt_linkattr_t *attrp;
14282b24ab6bSSebastien Roy
14292b24ab6bSSebastien Roy for (attrp = linkp->ll_head; attrp != NULL; attrp = attrp->lp_next)
14302b24ab6bSSebastien Roy linkattr_upgrade(attrp);
14312b24ab6bSSebastien Roy }
14322b24ab6bSSebastien Roy
14332b24ab6bSSebastien Roy static void
dlmgmt_db_phys_activate(dlmgmt_link_t * linkp)14342b24ab6bSSebastien Roy dlmgmt_db_phys_activate(dlmgmt_link_t *linkp)
14352b24ab6bSSebastien Roy {
14362b24ab6bSSebastien Roy linkp->ll_flags |= DLMGMT_ACTIVE;
14372b24ab6bSSebastien Roy (void) dlmgmt_write_db_entry(linkp->ll_link, linkp, DLMGMT_ACTIVE);
14382b24ab6bSSebastien Roy }
14392b24ab6bSSebastien Roy
14402b24ab6bSSebastien Roy static void
dlmgmt_db_walk(zoneid_t zoneid,datalink_class_t class,db_walk_func_t * func)14412b24ab6bSSebastien Roy dlmgmt_db_walk(zoneid_t zoneid, datalink_class_t class, db_walk_func_t *func)
14422b24ab6bSSebastien Roy {
14432b24ab6bSSebastien Roy dlmgmt_link_t *linkp;
14442b24ab6bSSebastien Roy
14452b24ab6bSSebastien Roy for (linkp = avl_first(&dlmgmt_id_avl); linkp != NULL;
14462b24ab6bSSebastien Roy linkp = AVL_NEXT(&dlmgmt_id_avl, linkp)) {
14472b24ab6bSSebastien Roy if (linkp->ll_zoneid == zoneid && (linkp->ll_class & class))
14482b24ab6bSSebastien Roy func(linkp);
14492b24ab6bSSebastien Roy }
14502b24ab6bSSebastien Roy }
14512b24ab6bSSebastien Roy
14522b24ab6bSSebastien Roy /*
145385dff7a0SAndy Fiddaman * Attempt to mitigate one of the deadlocks in the dlmgmtd architecture.
145485dff7a0SAndy Fiddaman *
145585dff7a0SAndy Fiddaman * dlmgmt_db_init() calls dlmgmt_process_db_req() which eventually gets to
145685dff7a0SAndy Fiddaman * dlmgmt_zfop() which tries to fork, enter the zone and read the file.
145785dff7a0SAndy Fiddaman * Because of the upcall architecture of dlmgmtd this can lead to deadlock
145885dff7a0SAndy Fiddaman * with the following scenario:
145985dff7a0SAndy Fiddaman * a) the thread preparing to fork will have acquired the malloc locks
146085dff7a0SAndy Fiddaman * then attempt to suspend every thread in preparation to fork.
146185dff7a0SAndy Fiddaman * b) all of the upcalls will be blocked in door_ucred() trying to malloc()
146285dff7a0SAndy Fiddaman * and get the credentials of their caller.
146385dff7a0SAndy Fiddaman * c) we can't suspend the in-kernel thread making the upcall.
146485dff7a0SAndy Fiddaman *
146585dff7a0SAndy Fiddaman * Thus, we cannot serve door requests because we're blocked in malloc()
146685dff7a0SAndy Fiddaman * which fork() owns, but fork() is in turn blocked on the in-kernel thread
146785dff7a0SAndy Fiddaman * making the door upcall. This is a fundamental architectural problem with
146885dff7a0SAndy Fiddaman * any server handling upcalls and also trying to fork().
146985dff7a0SAndy Fiddaman *
147085dff7a0SAndy Fiddaman * To minimize the chance of this deadlock occuring, we check ahead of time to
147185dff7a0SAndy Fiddaman * see if the file we want to read actually exists in the zone (which it almost
147285dff7a0SAndy Fiddaman * never does), so we don't need fork in that case (i.e. rarely to never).
147385dff7a0SAndy Fiddaman */
147485dff7a0SAndy Fiddaman static boolean_t
zone_file_exists(char * zoneroot,char * filename)147585dff7a0SAndy Fiddaman zone_file_exists(char *zoneroot, char *filename)
147685dff7a0SAndy Fiddaman {
147785dff7a0SAndy Fiddaman struct stat sb;
147885dff7a0SAndy Fiddaman char fname[MAXPATHLEN];
147985dff7a0SAndy Fiddaman
148085dff7a0SAndy Fiddaman (void) snprintf(fname, sizeof (fname), "%s/%s", zoneroot, filename);
148185dff7a0SAndy Fiddaman
148285dff7a0SAndy Fiddaman if (stat(fname, &sb) == -1)
148385dff7a0SAndy Fiddaman return (B_FALSE);
148485dff7a0SAndy Fiddaman
148585dff7a0SAndy Fiddaman return (B_TRUE);
148685dff7a0SAndy Fiddaman }
148785dff7a0SAndy Fiddaman
148885dff7a0SAndy Fiddaman /*
1489d62bc4baSyz147064 * Initialize the datalink <link name, linkid> mapping and the link's
1490d62bc4baSyz147064 * attributes list based on the configuration file /etc/dladm/datalink.conf
1491d62bc4baSyz147064 * and the active configuration cache file
1492b9e076dcSyz147064 * /etc/svc/volatile/dladm/datalink-management:default.cache.
1493d62bc4baSyz147064 */
1494d62bc4baSyz147064 int
dlmgmt_db_init(zoneid_t zoneid,char * zoneroot)149585dff7a0SAndy Fiddaman dlmgmt_db_init(zoneid_t zoneid, char *zoneroot)
1496d62bc4baSyz147064 {
14972b24ab6bSSebastien Roy dlmgmt_db_req_t *req;
1498d62bc4baSyz147064 int err;
14992b24ab6bSSebastien Roy boolean_t boot = B_FALSE;
1500d62bc4baSyz147064
15012b24ab6bSSebastien Roy if ((req = dlmgmt_db_req_alloc(DLMGMT_DB_OP_READ, NULL,
15022b24ab6bSSebastien Roy DATALINK_INVALID_LINKID, zoneid, DLMGMT_ACTIVE, &err)) == NULL)
15032b24ab6bSSebastien Roy return (err);
15042b24ab6bSSebastien Roy
150585dff7a0SAndy Fiddaman if (zone_file_exists(zoneroot, cachefile)) {
15062b24ab6bSSebastien Roy if ((err = dlmgmt_process_db_req(req)) != 0) {
1507d62bc4baSyz147064 /*
15082b24ab6bSSebastien Roy * If we get back ENOENT, that means that the active
150985dff7a0SAndy Fiddaman * configuration file doesn't exist yet, and is not an
151085dff7a0SAndy Fiddaman * error. We'll create it down below after we've
151185dff7a0SAndy Fiddaman * loaded the persistent configuration.
1512d62bc4baSyz147064 */
15132b24ab6bSSebastien Roy if (err != ENOENT)
1514d62bc4baSyz147064 goto done;
15152b24ab6bSSebastien Roy boot = B_TRUE;
15162b24ab6bSSebastien Roy }
151785dff7a0SAndy Fiddaman } else {
151885dff7a0SAndy Fiddaman boot = B_TRUE;
151985dff7a0SAndy Fiddaman }
1520d62bc4baSyz147064
152185dff7a0SAndy Fiddaman if (zone_file_exists(zoneroot, DLMGMT_PERSISTENT_DB_PATH)) {
15222b24ab6bSSebastien Roy req->ls_flags = DLMGMT_PERSIST;
15232b24ab6bSSebastien Roy err = dlmgmt_process_db_req(req);
15242b24ab6bSSebastien Roy if (err != 0 && err != ENOENT)
15252b24ab6bSSebastien Roy goto done;
152685dff7a0SAndy Fiddaman }
1527d62bc4baSyz147064 err = 0;
15282b24ab6bSSebastien Roy if (rewrite_needed) {
15292b24ab6bSSebastien Roy /*
15302b24ab6bSSebastien Roy * First update links in memory, then dump the entire db to
15312b24ab6bSSebastien Roy * disk.
15322b24ab6bSSebastien Roy */
15332b24ab6bSSebastien Roy dlmgmt_db_walk(zoneid, DATALINK_CLASS_ALL, dlmgmt_db_upgrade);
15342b24ab6bSSebastien Roy req->ls_op = DLMGMT_DB_OP_WRITE;
15352b24ab6bSSebastien Roy req->ls_linkid = DATALINK_ALL_LINKID;
15362b24ab6bSSebastien Roy if ((err = dlmgmt_process_db_req(req)) != 0 &&
15372b24ab6bSSebastien Roy err != EINPROGRESS)
15382b24ab6bSSebastien Roy goto done;
15392b24ab6bSSebastien Roy }
15402b24ab6bSSebastien Roy if (boot) {
15412b24ab6bSSebastien Roy dlmgmt_db_walk(zoneid, DATALINK_CLASS_PHYS,
15422b24ab6bSSebastien Roy dlmgmt_db_phys_activate);
1543d62bc4baSyz147064 }
1544d62bc4baSyz147064
1545d62bc4baSyz147064 done:
15462b24ab6bSSebastien Roy if (err == EINPROGRESS)
15472b24ab6bSSebastien Roy err = 0;
15482b24ab6bSSebastien Roy else
15492b24ab6bSSebastien Roy free(req);
1550d62bc4baSyz147064 return (err);
1551d62bc4baSyz147064 }
15522b24ab6bSSebastien Roy
15532b24ab6bSSebastien Roy /*
15542b24ab6bSSebastien Roy * Remove all links in the given zoneid.
15552b24ab6bSSebastien Roy */
15562b24ab6bSSebastien Roy void
dlmgmt_db_fini(zoneid_t zoneid)15572b24ab6bSSebastien Roy dlmgmt_db_fini(zoneid_t zoneid)
15582b24ab6bSSebastien Roy {
15592b24ab6bSSebastien Roy dlmgmt_link_t *linkp = avl_first(&dlmgmt_name_avl), *next_linkp;
15602b24ab6bSSebastien Roy
15612b24ab6bSSebastien Roy while (linkp != NULL) {
15622b24ab6bSSebastien Roy next_linkp = AVL_NEXT(&dlmgmt_name_avl, linkp);
15632b24ab6bSSebastien Roy if (linkp->ll_zoneid == zoneid) {
15642b24ab6bSSebastien Roy (void) dlmgmt_destroy_common(linkp,
15652b24ab6bSSebastien Roy DLMGMT_ACTIVE | DLMGMT_PERSIST);
15662b24ab6bSSebastien Roy }
15672b24ab6bSSebastien Roy linkp = next_linkp;
15682b24ab6bSSebastien Roy }
15692b24ab6bSSebastien Roy }
1570