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