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