xref: /titanic_41/usr/src/lib/libdevinfo/devinfo_devlink.c (revision 86aa80977b878fdd7d76a9ee3f2119010f4b8ec0)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include "devinfo_devlink.h"
30 
31 #undef DEBUG
32 #ifndef DEBUG
33 #define	NDEBUG 1
34 #else
35 #undef	NDEBUG
36 #endif
37 
38 #include <assert.h>
39 
40 static mutex_t update_mutex = DEFAULTMUTEX; /* Protects update record lock */
41 
42 static const size_t elem_sizes[DB_TYPES] = {
43 	sizeof (struct db_node),
44 	sizeof (struct db_minor),
45 	sizeof (struct db_link),
46 	sizeof (char)
47 };
48 
49 /*
50  * List of directories/files skipped while physically walking /dev
51  * Paths are relative to "<root>/dev/"
52  */
53 static const char *skip_dirs[] = {"fd"};
54 static const char *skip_files[] = {
55 	"stdout",
56 	"stdin",
57 	"stderr"
58 };
59 
60 #define	N_SKIP_DIRS	(sizeof (skip_dirs) / sizeof (skip_dirs[0]))
61 #define	N_SKIP_FILES	(sizeof (skip_files) / sizeof (skip_files[0]))
62 
63 /*
64  *
65  * This file contains two sets of interfaces which operate on the reverse
66  * links database. One set (which includes di_devlink_open()/_close())
67  * allows link generators like devfsadm(1M) and ucblinks(1B) (writers) to
68  * populate the database with /devices -> /dev mappings. Another set
69  * of interfaces (which includes di_devlink_init()/_fini()) allows
70  * applications (readers) to lookup the database for /dev links corresponding
71  * to a given minor.
72  *
73  * Writers operate on a cached version of the database. The cache is created
74  * when di_devlink_open() is called. As links in /dev are created and removed,
75  * the cache is updated to keep it in synch with /dev. When the /dev updates
76  * are complete, the link generator calls di_devlink_close() which writes
77  * out the cache to the database.
78  *
79  * Applications which need to lookup the database, call di_devlink_init().
80  * di_devlink_init() checks the database file (if one exists). If the
81  * database is valid, it is mapped into the address space of the
82  * application. The database file consists of several segments. Each
83  * segment can be mapped in independently and is mapped on demand.
84  *
85  *		   Database Layout
86  *
87  *		---------------------
88  *		|	Magic #     |
89  *		| ----------------- |
90  *		|       Version	    |	HEADER
91  *		| ----------------- |
92  *		|        ...        |
93  *		---------------------
94  *		|		    |
95  *		|		    |	NODES
96  *		|	            |
97  *		|		    |
98  *		---------------------
99  *		|		    |
100  *		|		    |	MINORS
101  *		|	            |
102  *		|		    |
103  *		---------------------
104  *		|		    |
105  *		|		    |   LINKS
106  *		|	            |
107  *		|		    |
108  *		---------------------
109  *		|		    |
110  *		|		    |	STRINGS
111  *		|	            |
112  *		|		    |
113  *		---------------------
114  *
115  * Readers can lookup /dev links for a specific minor or
116  * lookup all /dev links. In the latter case, the node
117  * and minor segments are not mapped in and the reader
118  * walks through every link in the link segment.
119  *
120  */
121 
122 di_devlink_handle_t
123 di_devlink_open(const char *root_dir, uint_t flags)
124 {
125 	int err;
126 	char path[PATH_MAX];
127 	struct di_devlink_handle *hdp;
128 	int retried = 0;
129 
130 retry:
131 	/*
132 	 * Allocate a read-write handle but open the DB in readonly
133 	 * mode. We do writes only to a temporary copy of the database.
134 	 */
135 	if ((hdp = handle_alloc(root_dir, OPEN_RDWR)) == NULL) {
136 		return (NULL);
137 	}
138 
139 	err = open_db(hdp, OPEN_RDONLY);
140 
141 	/*
142 	 * Unlink the database, so that consumers don't get
143 	 * out of date information as the database is being updated.
144 	 */
145 	get_db_path(hdp, DB_FILE, path, sizeof (path));
146 	(void) unlink(path);
147 
148 	/*
149 	 * The flags argument is reserved for future use.
150 	 */
151 	if (flags != 0) {
152 		handle_free(&hdp); /* also closes the DB */
153 		errno = EINVAL;
154 		return (NULL);
155 	}
156 
157 	if (cache_alloc(hdp) != 0) {
158 		handle_free(&hdp);
159 		return (NULL);
160 	}
161 
162 	if (err) {
163 		/*
164 		 * Failed to open DB.
165 		 * The most likely cause is that DB file did not exist.
166 		 * Call di_devlink_close() to recreate the DB file and
167 		 * retry di_devlink_open().
168 		 */
169 		if (retried == 0) {
170 			(void) di_devlink_close(&hdp, 0);
171 			retried = 1;
172 			goto retry;
173 		}
174 
175 		/*
176 		 * DB cannot be opened, just return the
177 		 * handle. We will recreate the DB later.
178 		 */
179 		return (hdp);
180 	}
181 
182 	/* Read the database into the cache */
183 	CACHE(hdp)->update_count = DB_HDR(hdp)->update_count;
184 	(void) read_nodes(hdp, NULL, DB_HDR(hdp)->root_idx);
185 	(void) read_links(hdp, NULL, DB_HDR(hdp)->dngl_idx);
186 
187 	(void) close_db(hdp);
188 
189 	return (hdp);
190 }
191 
192 static void
193 get_db_path(
194 	struct di_devlink_handle *hdp,
195 	const char *fname,
196 	char *buf,
197 	size_t blen)
198 {
199 	char *dir = NULL;
200 
201 #ifdef	DEBUG
202 	if (dir = getenv(ALT_DB_DIR)) {
203 		(void) dprintf(DBG_INFO, "get_db_path: alternate db dir: %s\n",
204 		    dir);
205 	}
206 #endif
207 	if (dir == NULL) {
208 		dir = hdp->dev_dir;
209 	}
210 
211 	(void) snprintf(buf, blen, "%s/%s", dir, fname);
212 }
213 
214 static int
215 open_db(struct di_devlink_handle *hdp, int flags)
216 {
217 	size_t sz;
218 	long page_sz;
219 	int fd, rv, flg;
220 	struct stat sbuf;
221 	uint32_t count[DB_TYPES] = {0};
222 	char path[PATH_MAX];
223 	void *cp;
224 
225 	assert(!DB_OPEN(hdp));
226 
227 #ifdef	DEBUG
228 	if (getenv(SKIP_DB)) {
229 		(void) dprintf(DBG_INFO, "open_db: skipping database\n");
230 		return (-1);
231 	}
232 #endif
233 	if ((page_sz = sysconf(_SC_PAGE_SIZE)) == -1) {
234 		return (-1);
235 	}
236 
237 	/*
238 	 * Use O_TRUNC flag for write access, so that the subsequent ftruncate()
239 	 * call will zero-fill the entire file
240 	 */
241 	if (IS_RDONLY(flags)) {
242 		flg = O_RDONLY;
243 		get_db_path(hdp, DB_FILE, path, sizeof (path));
244 	} else {
245 		flg = O_RDWR|O_CREAT|O_TRUNC;
246 		get_db_path(hdp, DB_TMP, path, sizeof (path));
247 	}
248 
249 	if ((fd = open(path, flg, DB_PERMS)) == -1) {
250 		return (-1);
251 	}
252 
253 	if (IS_RDONLY(flags)) {
254 		flg = PROT_READ;
255 		rv = fstat(fd, &sbuf);
256 		sz = sbuf.st_size;
257 	} else {
258 		flg = PROT_READ | PROT_WRITE;
259 		sz = size_db(hdp, page_sz, count);
260 		rv = ftruncate(fd, sz);
261 	}
262 
263 	if (rv == -1 || sz < HDR_LEN) {
264 		if (rv != -1)
265 			errno = EINVAL;
266 		(void) close(fd);
267 		return (-1);
268 	}
269 
270 	cp = mmap(0, HDR_LEN, flg, MAP_SHARED, fd, 0);
271 	if (cp == MAP_FAILED) {
272 		(void) close(fd);
273 		return (-1);
274 	}
275 	DB(hdp)->hdr = (struct db_hdr *)cp;
276 	DB(hdp)->db_fd = fd;
277 	DB(hdp)->flags = flags;
278 
279 	if (IS_RDONLY(flags)) {
280 		rv = invalid_db(hdp, sz, page_sz);
281 	} else {
282 		rv = init_hdr(hdp, page_sz, count);
283 	}
284 
285 	if (rv) {
286 		(void) dprintf(DBG_ERR, "open_db: invalid DB(%s)\n", path);
287 		(void) close_db(hdp);
288 		return (-1);
289 	} else {
290 		(void) dprintf(DBG_STEP, "open_db: DB(%s): opened\n", path);
291 		return (0);
292 	}
293 }
294 
295 /*
296  * A handle can be allocated for read-only or read-write access
297  */
298 static struct di_devlink_handle *
299 handle_alloc(const char *root_dir, uint_t flags)
300 {
301 	char dev_dir[PATH_MAX], path[PATH_MAX];
302 	struct di_devlink_handle *hdp, proto = {0};
303 
304 	assert(flags == OPEN_RDWR || flags == OPEN_RDONLY);
305 
306 	dev_dir[0] = '\0';
307 
308 	/*
309 	 * NULL and the empty string are equivalent to "/"
310 	 */
311 	if (root_dir && root_dir[0] != '\0') {
312 
313 		if (root_dir[0] != '/') {
314 			errno = EINVAL;
315 			return (NULL);
316 		}
317 
318 #ifdef	DEBUG
319 		/*LINTED*/
320 		assert(sizeof (dev_dir) >= PATH_MAX);
321 #endif
322 		if (realpath(root_dir, dev_dir) == NULL) {
323 			return (NULL);
324 		}
325 	}
326 
327 	if (strcmp(dev_dir, "/") == 0) {
328 		(void) strlcpy(dev_dir, DEV, sizeof (dev_dir));
329 	} else {
330 		(void) strlcat(dev_dir, DEV, sizeof (dev_dir));
331 	}
332 
333 	proto.dev_dir = dev_dir;
334 	proto.flags = flags;
335 	proto.lock_fd = -1;
336 
337 	/*
338 	 * Lock database if a read-write handle is being allocated.
339 	 * Locks are needed to protect against multiple writers.
340 	 * Readers don't need locks.
341 	 */
342 	if (HDL_RDWR(&proto)) {
343 		if (enter_update_lock(&proto) != 0) {
344 			return (NULL);
345 		}
346 	}
347 
348 	DB(&proto)->db_fd = -1;
349 
350 	hdp = calloc(1, sizeof (struct di_devlink_handle));
351 	if (hdp == NULL) {
352 		goto error;
353 	}
354 
355 	*hdp = proto;
356 
357 	/*
358 	 * The handle hdp now contains a pointer to local storage
359 	 * in the dev_dir field (obtained from the proto handle).
360 	 * In the following line, a dynamically allocated version
361 	 * is substituted.
362 	 */
363 
364 	if ((hdp->dev_dir = strdup(proto.dev_dir)) == NULL) {
365 		free(hdp);
366 		goto error;
367 	}
368 
369 
370 	return (hdp);
371 
372 error:
373 	if (HDL_RDWR(&proto)) {
374 		/* Unlink DB file on error */
375 		get_db_path(&proto, DB_FILE, path, sizeof (path));
376 		(void) unlink(path);
377 		exit_update_lock(&proto);
378 	}
379 	return (NULL);
380 }
381 
382 
383 static int
384 cache_alloc(struct di_devlink_handle *hdp)
385 {
386 	size_t hash_sz = 0;
387 
388 	assert(HDL_RDWR(hdp));
389 
390 	if (DB_OPEN(hdp)) {
391 		hash_sz = DB_NUM(hdp, DB_LINK) / AVG_CHAIN_SIZE;
392 	}
393 	hash_sz = (hash_sz >= MIN_HASH_SIZE) ? hash_sz : MIN_HASH_SIZE;
394 
395 	CACHE(hdp)->hash = calloc(hash_sz, sizeof (cache_link_t *));
396 	if (CACHE(hdp)->hash == NULL) {
397 		return (-1);
398 	}
399 	CACHE(hdp)->hash_sz = hash_sz;
400 
401 	return (0);
402 }
403 
404 
405 static int
406 invalid_db(struct di_devlink_handle *hdp, size_t fsize, long page_sz)
407 {
408 	int i;
409 	char *cp;
410 	size_t sz;
411 
412 	if (DB_HDR(hdp)->magic != DB_MAGIC || DB_HDR(hdp)->vers != DB_VERSION) {
413 		return (1);
414 	}
415 
416 	if (DB_HDR(hdp)->page_sz == 0 || DB_HDR(hdp)->page_sz != page_sz) {
417 		return (1);
418 	}
419 
420 	sz = seg_size(hdp, DB_HEADER);
421 	for (i = 0; i < DB_TYPES; i++) {
422 		(void) dprintf(DBG_INFO, "N[%u] = %u\n", i, DB_NUM(hdp, i));
423 		/* There must be at least 1 element of each type */
424 		if (DB_NUM(hdp, i) < 1) {
425 			return (1);
426 		}
427 		sz += seg_size(hdp, i);
428 		assert(sz % page_sz == 0);
429 	}
430 
431 	if (sz != fsize) {
432 		return (1);
433 	}
434 
435 	if (!VALID_INDEX(hdp, DB_NODE, DB_HDR(hdp)->root_idx)) {
436 		return (1);
437 	}
438 
439 	if (!VALID_INDEX(hdp, DB_LINK, DB_HDR(hdp)->dngl_idx)) {
440 		return (1);
441 	}
442 
443 	if (DB_EMPTY(hdp)) {
444 		return (1);
445 	}
446 
447 	/*
448 	 * The last character in the string segment must be a NUL char.
449 	 */
450 	cp = get_string(hdp, DB_NUM(hdp, DB_STR) - 1);
451 	if (cp == NULL || *cp != '\0') {
452 		return (1);
453 	}
454 
455 	return (0);
456 }
457 
458 static int
459 read_nodes(struct di_devlink_handle *hdp, cache_node_t *pcnp, uint32_t nidx)
460 {
461 	char *path;
462 	cache_node_t *cnp;
463 	struct db_node *dnp;
464 	const char *fcn = "read_nodes";
465 
466 	assert(HDL_RDWR(hdp));
467 
468 	/*
469 	 * parent node should be NULL only for the root node
470 	 */
471 	if ((pcnp == NULL) ^ (nidx == DB_HDR(hdp)->root_idx)) {
472 		(void) dprintf(DBG_ERR, "%s: invalid parent or index(%u)\n",
473 		    fcn, nidx);
474 		SET_DB_ERR(hdp);
475 		return (-1);
476 	}
477 
478 	for (; dnp = get_node(hdp, nidx); nidx = dnp->sib) {
479 
480 		path = get_string(hdp, dnp->path);
481 
482 		/*
483 		 * Insert at head of list to recreate original order
484 		 */
485 		cnp = node_insert(hdp, pcnp, path, INSERT_HEAD);
486 		if (cnp == NULL) {
487 			SET_DB_ERR(hdp);
488 			break;
489 		}
490 
491 		assert(strcmp(path, "/") ^ (nidx == DB_HDR(hdp)->root_idx));
492 		assert(strcmp(path, "/") != 0 || dnp->sib == DB_NIL);
493 
494 		if (read_minors(hdp, cnp, dnp->minor) != 0 ||
495 		    read_nodes(hdp, cnp, dnp->child) != 0) {
496 			break;
497 		}
498 
499 		(void) dprintf(DBG_STEP, "%s: node[%u]: %s\n", fcn, nidx,
500 		    cnp->path);
501 	}
502 
503 	return (dnp ? -1 : 0);
504 }
505 
506 static int
507 read_minors(struct di_devlink_handle *hdp, cache_node_t *pcnp, uint32_t nidx)
508 {
509 	cache_minor_t *cmnp;
510 	struct db_minor *dmp;
511 	char *name, *nodetype;
512 	const char *fcn = "read_minors";
513 
514 	assert(HDL_RDWR(hdp));
515 
516 	if (pcnp == NULL) {
517 		(void) dprintf(DBG_ERR, "%s: minor[%u]: orphan minor\n", fcn,
518 		    nidx);
519 		SET_DB_ERR(hdp);
520 		return (-1);
521 	}
522 
523 	for (; dmp = get_minor(hdp, nidx); nidx = dmp->sib) {
524 
525 		name = get_string(hdp, dmp->name);
526 		nodetype = get_string(hdp, dmp->nodetype);
527 
528 		cmnp = minor_insert(hdp, pcnp, name, nodetype, NULL);
529 		if (cmnp == NULL) {
530 			SET_DB_ERR(hdp);
531 			break;
532 		}
533 
534 		(void) dprintf(DBG_STEP, "%s: minor[%u]: %s\n", fcn, nidx,
535 		    cmnp->name);
536 
537 		if (read_links(hdp, cmnp, dmp->link) != 0) {
538 			break;
539 		}
540 	}
541 
542 	return (dmp ? -1 : 0);
543 }
544 
545 /*
546  * If the link is dangling the corresponding minor will be absent.
547  */
548 static int
549 read_links(struct di_devlink_handle *hdp, cache_minor_t *pcmp, uint32_t nidx)
550 {
551 	cache_link_t *clp;
552 	struct db_link *dlp;
553 	char *path, *content;
554 
555 	assert(HDL_RDWR(hdp));
556 
557 	if (nidx != DB_NIL &&
558 	    ((pcmp == NULL) ^ (nidx == DB_HDR(hdp)->dngl_idx))) {
559 		(void) dprintf(DBG_ERR, "read_links: invalid minor or"
560 		    " index(%u)\n", nidx);
561 		SET_DB_ERR(hdp);
562 		return (-1);
563 	}
564 
565 	for (; dlp = get_link(hdp, nidx); nidx = dlp->sib) {
566 
567 		path = get_string(hdp, dlp->path);
568 		content = get_string(hdp, dlp->content);
569 
570 		clp = link_insert(hdp, pcmp, path, content, dlp->attr);
571 		if (clp == NULL) {
572 			SET_DB_ERR(hdp);
573 			break;
574 		}
575 
576 		(void) dprintf(DBG_STEP, "read_links: link[%u]: %s%s\n",
577 		    nidx, clp->path, pcmp == NULL ? "(DANGLING)" : "");
578 	}
579 
580 	return (dlp ? -1 : 0);
581 }
582 
583 int
584 di_devlink_close(di_devlink_handle_t *pp, int flag)
585 {
586 	int i, rv;
587 	char tmp[PATH_MAX];
588 	char file[PATH_MAX];
589 	uint32_t next[DB_TYPES] = {0};
590 	struct di_devlink_handle *hdp;
591 
592 	if (pp == NULL || *pp == NULL || !HDL_RDWR(*pp)) {
593 		errno = EINVAL;
594 		return (-1);
595 	}
596 
597 	hdp = *pp;
598 	*pp = NULL;
599 
600 	/*
601 	 * The caller encountered some error in their processing.
602 	 * so handle isn't valid. Discard it and return success.
603 	 */
604 	if (flag == DI_LINK_ERROR) {
605 		handle_free(&hdp);
606 		return (0);
607 	}
608 
609 	if (DB_ERR(hdp)) {
610 		handle_free(&hdp);
611 		errno = EINVAL;
612 		return (-1);
613 	}
614 
615 	/*
616 	 * Extract the DB path before the handle is freed.
617 	 */
618 	get_db_path(hdp, DB_FILE, file, sizeof (file));
619 	get_db_path(hdp, DB_TMP, tmp, sizeof (tmp));
620 
621 	/*
622 	 * update database with actual contents of /dev
623 	 */
624 	(void) dprintf(DBG_INFO, "di_devlink_close: update_count = %u\n",
625 	    CACHE(hdp)->update_count);
626 
627 	/*
628 	 * For performance reasons, synchronization of the database
629 	 * with /dev is turned off by default. However, applications
630 	 * with appropriate permissions can request a "sync" by
631 	 * calling di_devlink_update().
632 	 */
633 	if (CACHE(hdp)->update_count == 0) {
634 		CACHE(hdp)->update_count = 1;
635 		(void) dprintf(DBG_INFO,
636 		    "di_devlink_close: synchronizing DB\n");
637 		(void) synchronize_db(hdp);
638 	}
639 
640 	/*
641 	 * Resolve dangling links AFTER synchronizing DB with /dev as the
642 	 * synchronization process may create dangling links.
643 	 */
644 	resolve_dangling_links(hdp);
645 
646 	/*
647 	 * All changes to the cache are complete. Write out the cache
648 	 * to the database only if it is not empty.
649 	 */
650 	if (CACHE_EMPTY(hdp)) {
651 		(void) dprintf(DBG_INFO, "di_devlink_close: skipping write\n");
652 		(void) unlink(file);
653 		handle_free(&hdp);
654 		return (0);
655 	}
656 
657 	if (open_db(hdp, OPEN_RDWR) != 0) {
658 		handle_free(&hdp);
659 		return (-1);
660 	}
661 
662 	/*
663 	 * Keep track of array assignments. There is atleast
664 	 * 1 element (the "NIL" element) per type.
665 	 */
666 	for (i = 0; i < DB_TYPES; i++) {
667 		next[i] = 1;
668 	}
669 
670 	(void) write_nodes(hdp, NULL, CACHE_ROOT(hdp), next);
671 	(void) write_links(hdp, NULL, CACHE(hdp)->dngl, next);
672 	DB_HDR(hdp)->update_count = CACHE(hdp)->update_count;
673 
674 	rv = close_db(hdp);
675 
676 	if (rv != 0 || DB_ERR(hdp) || rename(tmp, file) != 0) {
677 		(void) dprintf(DBG_ERR, "di_devlink_close: %s error: %s\n",
678 		    rv ? "close_db" : "DB or rename", strerror(errno));
679 		(void) unlink(tmp);
680 		(void) unlink(file);
681 		handle_free(&hdp);
682 		return (-1);
683 	}
684 
685 	handle_free(&hdp);
686 
687 	(void) dprintf(DBG_INFO, "di_devlink_close: wrote DB(%s)\n", file);
688 
689 	return (0);
690 }
691 
692 /*
693  * Inits the database header.
694  */
695 static int
696 init_hdr(struct di_devlink_handle *hdp, long page_sz, uint32_t *count)
697 {
698 	int i;
699 
700 	DB_HDR(hdp)->magic = DB_MAGIC;
701 	DB_HDR(hdp)->vers = DB_VERSION;
702 	DB_HDR(hdp)->root_idx = DB_NIL;
703 	DB_HDR(hdp)->dngl_idx = DB_NIL;
704 	DB_HDR(hdp)->page_sz = (uint32_t)page_sz;
705 
706 	for (i = 0; i < DB_TYPES; i++) {
707 		assert(count[i] >= 1);
708 		DB_NUM(hdp, i) = count[i];
709 	}
710 
711 	return (0);
712 }
713 
714 static int
715 write_nodes(
716 	struct di_devlink_handle *hdp,
717 	struct db_node *pdnp,
718 	cache_node_t *cnp,
719 	uint32_t *next)
720 {
721 	uint32_t idx;
722 	struct db_node *dnp;
723 	const char *fcn = "write_nodes";
724 
725 	assert(HDL_RDWR(hdp));
726 
727 	for (; cnp != NULL; cnp = cnp->sib) {
728 
729 		assert(cnp->path != NULL);
730 
731 		/* parent node should only be NULL for root node */
732 		if ((pdnp == NULL) ^ (cnp == CACHE_ROOT(hdp))) {
733 			(void) dprintf(DBG_ERR, "%s: invalid parent for: %s\n",
734 			    fcn, cnp->path);
735 			SET_DB_ERR(hdp);
736 			break;
737 		}
738 
739 		assert((strcmp(cnp->path, "/") != 0) ^
740 		    (cnp == CACHE_ROOT(hdp)));
741 
742 		idx = next[DB_NODE];
743 		if ((dnp = set_node(hdp, idx)) == NULL) {
744 			SET_DB_ERR(hdp);
745 			break;
746 		}
747 
748 		dnp->path = write_string(hdp, cnp->path, next);
749 		if (dnp->path == DB_NIL) {
750 			SET_DB_ERR(hdp);
751 			break;
752 		}
753 		/* commit write for this node */
754 		next[DB_NODE]++;
755 
756 		if (pdnp == NULL) {
757 			assert(DB_HDR(hdp)->root_idx == DB_NIL);
758 			DB_HDR(hdp)->root_idx = idx;
759 		} else {
760 			dnp->sib = pdnp->child;
761 			pdnp->child = idx;
762 		}
763 
764 		(void) dprintf(DBG_STEP, "%s: node[%u]: %s\n", fcn, idx,
765 		    cnp->path);
766 
767 		if (write_minors(hdp, dnp, cnp->minor, next) != 0 ||
768 		    write_nodes(hdp, dnp, cnp->child, next) != 0) {
769 			break;
770 		}
771 	}
772 
773 	return (cnp ? -1 : 0);
774 }
775 
776 static int
777 write_minors(
778 	struct di_devlink_handle *hdp,
779 	struct db_node *pdnp,
780 	cache_minor_t *cmnp,
781 	uint32_t *next)
782 {
783 	uint32_t idx;
784 	struct db_minor *dmp;
785 	const char *fcn = "write_minors";
786 
787 	assert(HDL_RDWR(hdp));
788 
789 	if (pdnp == NULL) {
790 		(void) dprintf(DBG_ERR, "%s: no node for minor: %s\n", fcn,
791 		    cmnp ? cmnp->name : "<NULL>");
792 		SET_DB_ERR(hdp);
793 		return (-1);
794 	}
795 
796 	for (; cmnp != NULL; cmnp = cmnp->sib) {
797 
798 		assert(cmnp->name != NULL);
799 
800 		idx = next[DB_MINOR];
801 		if ((dmp = set_minor(hdp, idx)) == NULL) {
802 			SET_DB_ERR(hdp);
803 			break;
804 		}
805 
806 		dmp->name = write_string(hdp, cmnp->name, next);
807 		dmp->nodetype = write_string(hdp, cmnp->nodetype, next);
808 		if (dmp->name == DB_NIL || dmp->nodetype == DB_NIL) {
809 			dmp->name = dmp->nodetype = DB_NIL;
810 			SET_DB_ERR(hdp);
811 			break;
812 		}
813 
814 		/* Commit writes to this minor */
815 		next[DB_MINOR]++;
816 
817 		dmp->sib = pdnp->minor;
818 		pdnp->minor = idx;
819 
820 		(void) dprintf(DBG_STEP, "%s: minor[%u]: %s\n", fcn, idx,
821 		    cmnp->name);
822 
823 		if (write_links(hdp, dmp, cmnp->link, next) != 0) {
824 			break;
825 		}
826 	}
827 
828 	return (cmnp ? -1 : 0);
829 }
830 
831 static int
832 write_links(
833 	struct di_devlink_handle *hdp,
834 	struct db_minor *pdmp,
835 	cache_link_t *clp,
836 	uint32_t *next)
837 {
838 	uint32_t idx;
839 	struct db_link *dlp;
840 	const char *fcn = "write_links";
841 
842 	assert(HDL_RDWR(hdp));
843 
844 	/* A NULL minor if and only if the links are dangling */
845 	if (clp != NULL && ((pdmp == NULL) ^ (clp == CACHE(hdp)->dngl))) {
846 		(void) dprintf(DBG_ERR, "%s: invalid minor for link\n", fcn);
847 		SET_DB_ERR(hdp);
848 		return (-1);
849 	}
850 
851 	for (; clp != NULL; clp = clp->sib) {
852 
853 		assert(clp->path != NULL);
854 
855 		if ((pdmp == NULL) ^ (clp->minor == NULL)) {
856 			(void) dprintf(DBG_ERR, "%s: invalid minor for link"
857 			    "(%s)\n", fcn, clp->path);
858 			SET_DB_ERR(hdp);
859 			break;
860 		}
861 
862 		idx = next[DB_LINK];
863 		if ((dlp = set_link(hdp, idx)) == NULL) {
864 			SET_DB_ERR(hdp);
865 			break;
866 		}
867 
868 		dlp->path = write_string(hdp, clp->path, next);
869 		dlp->content = write_string(hdp, clp->content, next);
870 		if (dlp->path == DB_NIL || dlp->content == DB_NIL) {
871 			dlp->path = dlp->content = DB_NIL;
872 			SET_DB_ERR(hdp);
873 			break;
874 		}
875 
876 		dlp->attr = clp->attr;
877 
878 		/* Commit writes to this link */
879 		next[DB_LINK]++;
880 
881 		if (pdmp != NULL) {
882 			dlp->sib = pdmp->link;
883 			pdmp->link = idx;
884 		} else {
885 			dlp->sib = DB_HDR(hdp)->dngl_idx;
886 			DB_HDR(hdp)->dngl_idx = idx;
887 		}
888 
889 		(void) dprintf(DBG_STEP, "%s: link[%u]: %s%s\n", fcn, idx,
890 		    clp->path, pdmp == NULL ? "(DANGLING)" : "");
891 	}
892 
893 	return (clp ? -1 : 0);
894 }
895 
896 
897 static uint32_t
898 write_string(struct di_devlink_handle *hdp, const char *str, uint32_t *next)
899 {
900 	char *dstr;
901 	uint32_t idx;
902 
903 	assert(HDL_RDWR(hdp));
904 
905 	if (str == NULL) {
906 		(void) dprintf(DBG_ERR, "write_string: NULL argument\n");
907 		return (DB_NIL);
908 	}
909 
910 	idx = next[DB_STR];
911 	if (!VALID_STR(hdp, idx, str)) {
912 		(void) dprintf(DBG_ERR, "write_string: invalid index[%u],"
913 		    " string(%s)\n", idx, str);
914 		return (DB_NIL);
915 	}
916 
917 	if ((dstr = set_string(hdp, idx)) == NULL) {
918 		return (DB_NIL);
919 	}
920 
921 	(void) strcpy(dstr, str);
922 
923 	next[DB_STR] += strlen(dstr) + 1;
924 
925 	return (idx);
926 }
927 
928 static int
929 close_db(struct di_devlink_handle *hdp)
930 {
931 	int i, rv = 0;
932 	size_t sz;
933 
934 	if (!DB_OPEN(hdp)) {
935 #ifdef	DEBUG
936 		assert(DB(hdp)->db_fd == -1);
937 		assert(DB(hdp)->flags == 0);
938 		for (i = 0; i < DB_TYPES; i++) {
939 			assert(DB_SEG(hdp, i) == NULL);
940 			assert(DB_SEG_PROT(hdp, i) == 0);
941 		}
942 #endif
943 		return (0);
944 	}
945 
946 	/* Unmap header after unmapping all other mapped segments */
947 	for (i = 0; i < DB_TYPES; i++) {
948 		if (DB_SEG(hdp, i)) {
949 			sz = seg_size(hdp, i);
950 			if (DB_RDWR(hdp))
951 				rv += msync(DB_SEG(hdp, i), sz, MS_SYNC);
952 			(void) munmap(DB_SEG(hdp, i), sz);
953 			DB_SEG(hdp, i) = NULL;
954 			DB_SEG_PROT(hdp, i) = 0;
955 		}
956 	}
957 
958 	if (DB_RDWR(hdp))
959 		rv += msync((caddr_t)DB_HDR(hdp), HDR_LEN, MS_SYNC);
960 	(void) munmap((caddr_t)DB_HDR(hdp), HDR_LEN);
961 	DB(hdp)->hdr = NULL;
962 
963 	(void) close(DB(hdp)->db_fd);
964 	DB(hdp)->db_fd = -1;
965 	DB(hdp)->flags = 0;
966 
967 	return (rv ? -1 : 0);
968 }
969 
970 
971 static void
972 cache_free(struct di_devlink_handle *hdp)
973 {
974 	cache_link_t *clp;
975 
976 	subtree_free(hdp, &(CACHE_ROOT(hdp)));
977 	assert(CACHE_LAST(hdp) == NULL);
978 
979 	/*
980 	 * Don't bother removing links from hash table chains,
981 	 * as we are freeing the hash table itself.
982 	 */
983 	while (CACHE(hdp)->dngl != NULL) {
984 		clp = CACHE(hdp)->dngl;
985 		CACHE(hdp)->dngl = clp->sib;
986 		assert(clp->minor == NULL);
987 		link_free(&clp);
988 	}
989 
990 	assert((CACHE(hdp)->hash == NULL) ^ (CACHE(hdp)->hash_sz != 0));
991 
992 	free(CACHE(hdp)->hash);
993 	CACHE(hdp)->hash = NULL;
994 	CACHE(hdp)->hash_sz = 0;
995 }
996 
997 static void
998 handle_free(struct di_devlink_handle **pp)
999 {
1000 	struct di_devlink_handle *hdp = *pp;
1001 
1002 	*pp = NULL;
1003 
1004 	if (hdp == NULL)
1005 		return;
1006 
1007 	(void) close_db(hdp);
1008 	cache_free(hdp);
1009 
1010 	if (HDL_RDWR(hdp))
1011 		exit_update_lock(hdp);
1012 	assert(hdp->lock_fd == -1);
1013 
1014 	free(hdp->dev_dir);
1015 	free(hdp);
1016 }
1017 
1018 /*
1019  * Frees the tree rooted at a node. Siblings of the subtree root
1020  * have to be handled by the caller.
1021  */
1022 static void
1023 subtree_free(struct di_devlink_handle *hdp, cache_node_t **pp)
1024 {
1025 	cache_node_t *np;
1026 	cache_link_t *clp;
1027 	cache_minor_t *cmnp;
1028 
1029 	if (pp == NULL || *pp == NULL)
1030 		return;
1031 
1032 	while ((*pp)->child != NULL) {
1033 		np = (*pp)->child;
1034 		(*pp)->child = np->sib;
1035 		subtree_free(hdp, &np);
1036 	}
1037 
1038 	while ((*pp)->minor != NULL) {
1039 		cmnp = (*pp)->minor;
1040 		(*pp)->minor = cmnp->sib;
1041 
1042 		while (cmnp->link != NULL) {
1043 			clp = cmnp->link;
1044 			cmnp->link = clp->sib;
1045 			rm_link_from_hash(hdp, clp);
1046 			link_free(&clp);
1047 		}
1048 		minor_free(hdp, &cmnp);
1049 	}
1050 
1051 	node_free(pp);
1052 }
1053 
1054 static void
1055 rm_link_from_hash(struct di_devlink_handle *hdp, cache_link_t *clp)
1056 {
1057 	int hval;
1058 	cache_link_t **pp;
1059 
1060 	if (clp == NULL)
1061 		return;
1062 
1063 	if (clp->path == NULL)
1064 		return;
1065 
1066 	hval = hashfn(hdp, clp->path);
1067 	pp = &(CACHE_HASH(hdp, hval));
1068 	for (; *pp != NULL; pp = &(*pp)->hash) {
1069 		if (*pp == clp) {
1070 			*pp = clp->hash;
1071 			clp->hash = NULL;
1072 			return;
1073 		}
1074 	}
1075 
1076 	dprintf(DBG_ERR, "rm_link_from_hash: link(%s) not found\n", clp->path);
1077 }
1078 
1079 static cache_link_t *
1080 link_hash(di_devlink_handle_t hdp, const char *link, uint_t flags)
1081 {
1082 	int hval;
1083 	cache_link_t **pp, *clp;
1084 
1085 	if (link == NULL)
1086 		return (NULL);
1087 
1088 	hval = hashfn(hdp, link);
1089 	pp = &(CACHE_HASH(hdp, hval));
1090 	for (; (clp = *pp) != NULL; pp = &clp->hash) {
1091 		if (strcmp(clp->path, link) == 0) {
1092 			break;
1093 		}
1094 	}
1095 
1096 	if (clp == NULL)
1097 		return (NULL);
1098 
1099 	if ((flags & UNLINK_FROM_HASH) == UNLINK_FROM_HASH) {
1100 		*pp = clp->hash;
1101 		clp->hash = NULL;
1102 	}
1103 
1104 	return (clp);
1105 }
1106 
1107 static cache_minor_t *
1108 link2minor(struct di_devlink_handle *hdp, cache_link_t *clp)
1109 {
1110 	cache_link_t *plp;
1111 	const char *minor_path;
1112 	char *cp, buf[PATH_MAX], link[PATH_MAX];
1113 
1114 	if (TYPE_PRI(attr2type(clp->attr))) {
1115 		/*
1116 		 * For primary link, content should point to a /devices node.
1117 		 */
1118 		if (!is_minor_node(clp->content, &minor_path)) {
1119 			return (NULL);
1120 		}
1121 
1122 		return (lookup_minor(hdp, minor_path, NULL,
1123 		    TYPE_CACHE|CREATE_FLAG));
1124 
1125 	}
1126 
1127 	/*
1128 	 * If secondary, the primary link is derived from the secondary
1129 	 * link contents. Secondary link contents can have two formats:
1130 	 * 	audio -> /dev/sound/0
1131 	 *	fb0 -> fbs/afb0
1132 	 */
1133 
1134 	buf[0] = '\0';
1135 	if (strncmp(clp->content, DEV"/", strlen(DEV"/")) == 0) {
1136 		cp = &clp->content[strlen(DEV"/")];
1137 	} else if (clp->content[0] != '/') {
1138 		if ((cp = strrchr(clp->path, '/')) != NULL) {
1139 			char savechar = *(cp + 1);
1140 			*(cp + 1) = '\0';
1141 			(void) snprintf(buf, sizeof (buf), "%s", clp->path);
1142 			*(cp + 1) = savechar;
1143 		}
1144 		(void) strlcat(buf, clp->content, sizeof (buf));
1145 		cp = buf;
1146 	} else {
1147 		goto follow_link;
1148 	}
1149 
1150 	/*
1151 	 * Lookup the primary link if possible and find its minor.
1152 	 */
1153 	if ((plp = link_hash(hdp, cp, 0)) != NULL && plp->minor != NULL) {
1154 		return (plp->minor);
1155 	}
1156 
1157 	/* realpath() used only as a last resort because it is expensive */
1158 follow_link:
1159 	(void) snprintf(link, sizeof (link), "%s/%s", hdp->dev_dir, clp->path);
1160 
1161 #ifdef	DEBUG
1162 	/*LINTED*/
1163 	assert(sizeof (buf) >= PATH_MAX);
1164 #endif
1165 	if (realpath(link, buf) == NULL || !is_minor_node(buf, &minor_path)) {
1166 		return (NULL);
1167 	}
1168 	return (lookup_minor(hdp, minor_path, NULL, TYPE_CACHE|CREATE_FLAG));
1169 }
1170 
1171 
1172 static void
1173 resolve_dangling_links(struct di_devlink_handle *hdp)
1174 {
1175 	cache_minor_t *cmnp;
1176 	cache_link_t *clp, **pp;
1177 
1178 	for (pp = &(CACHE(hdp)->dngl); *pp != NULL; ) {
1179 		clp = *pp;
1180 		if ((cmnp = link2minor(hdp, clp)) != NULL) {
1181 			*pp = clp->sib;
1182 			clp->sib = cmnp->link;
1183 			cmnp->link = clp;
1184 			assert(clp->minor == NULL);
1185 			clp->minor = cmnp;
1186 		} else {
1187 			dprintf(DBG_INFO, "resolve_dangling_links: link(%s):"
1188 			    " unresolved\n", clp->path);
1189 			pp = &clp->sib;
1190 		}
1191 	}
1192 }
1193 
1194 
1195 /*
1196  * The elements are assumed to be detached from the cache tree.
1197  */
1198 static void
1199 node_free(cache_node_t **pp)
1200 {
1201 	cache_node_t *cnp = *pp;
1202 
1203 	*pp = NULL;
1204 
1205 	if (cnp == NULL)
1206 		return;
1207 
1208 	free(cnp->path);
1209 	free(cnp);
1210 }
1211 
1212 static void
1213 minor_free(struct di_devlink_handle *hdp, cache_minor_t **pp)
1214 {
1215 	cache_minor_t *cmnp = *pp;
1216 
1217 	*pp = NULL;
1218 
1219 	if (cmnp == NULL)
1220 		return;
1221 
1222 	if (CACHE_LAST(hdp) == cmnp) {
1223 		dprintf(DBG_STEP, "minor_free: last_minor(%s)\n", cmnp->name);
1224 		CACHE_LAST(hdp) = NULL;
1225 	}
1226 
1227 	free(cmnp->name);
1228 	free(cmnp->nodetype);
1229 	free(cmnp);
1230 }
1231 
1232 static void
1233 link_free(cache_link_t **pp)
1234 {
1235 	cache_link_t *clp = *pp;
1236 
1237 	*pp = NULL;
1238 
1239 	if (clp == NULL)
1240 		return;
1241 
1242 	free(clp->path);
1243 	free(clp->content);
1244 	free(clp);
1245 }
1246 
1247 /*
1248  * Returns the ':' preceding the minor name
1249  */
1250 static char *
1251 minor_colon(const char *path)
1252 {
1253 	char *cp;
1254 
1255 	if ((cp = strrchr(path, '/')) == NULL) {
1256 		return (NULL);
1257 	}
1258 
1259 	return (strchr(cp, ':'));
1260 }
1261 
1262 static void *
1263 lookup_minor(
1264 	struct di_devlink_handle *hdp,
1265 	const char *minor_path,
1266 	const char *nodetype,
1267 	const int flags)
1268 {
1269 	void *vp;
1270 	char *colon;
1271 	char pdup[PATH_MAX];
1272 	const char *fcn = "lookup_minor";
1273 
1274 	if (minor_path == NULL) {
1275 		errno = EINVAL;
1276 		return (NULL);
1277 	}
1278 
1279 	(void) snprintf(pdup, sizeof (pdup), "%s", minor_path);
1280 
1281 	if ((colon = minor_colon(pdup)) == NULL) {
1282 		(void) dprintf(DBG_ERR, "%s: invalid minor path(%s)\n", fcn,
1283 		    minor_path);
1284 		errno = EINVAL;
1285 		return (NULL);
1286 	}
1287 	*colon = '\0';
1288 
1289 	if ((vp = get_last_minor(hdp, pdup, colon + 1, flags)) != NULL) {
1290 		return (vp);
1291 	}
1292 
1293 	if ((vp = lookup_node(hdp, pdup, flags)) == NULL) {
1294 		(void) dprintf(DBG_ERR, "%s: node(%s) not found\n", fcn, pdup);
1295 		return (NULL);
1296 	}
1297 	*colon = ':';
1298 
1299 	if (LOOKUP_CACHE(flags)) {
1300 		cache_minor_t **pp;
1301 
1302 		pp = &((cache_node_t *)vp)->minor;
1303 		for (; *pp != NULL; pp = &(*pp)->sib) {
1304 			if (strcmp((*pp)->name, colon + 1) == 0)
1305 				break;
1306 		}
1307 
1308 		if (*pp == NULL && CREATE_ELEM(flags)) {
1309 			*pp = minor_insert(hdp, vp, colon + 1, nodetype, pp);
1310 		}
1311 		set_last_minor(hdp, *pp, flags);
1312 
1313 		return (*pp);
1314 	} else {
1315 		char *cp;
1316 		uint32_t nidx;
1317 		struct db_minor *dmp;
1318 
1319 		nidx = (((struct db_node *)vp)->minor);
1320 		for (; dmp = get_minor(hdp, nidx); nidx = dmp->sib) {
1321 			cp = get_string(hdp, dmp->name);
1322 			if (cp && strcmp(cp, colon + 1) == 0)
1323 				break;
1324 		}
1325 		return (dmp);
1326 	}
1327 }
1328 
1329 static void *
1330 lookup_node(struct di_devlink_handle *hdp, char *path, const int flags)
1331 {
1332 	struct tnode tnd = {NULL};
1333 
1334 	if (tnd.node = get_last_node(hdp, path, flags))
1335 		return (tnd.node);
1336 
1337 	tnd.handle = hdp;
1338 	tnd.flags = flags;
1339 
1340 	if (walk_tree(path, &tnd, visit_node) != 0)
1341 		return (NULL);
1342 
1343 	return (tnd.node);
1344 }
1345 
1346 /*
1347  * last_minor is used for nodes of TYPE_CACHE only.
1348  */
1349 static void *
1350 get_last_node(struct di_devlink_handle *hdp, const char *path, int flags)
1351 {
1352 	cache_node_t *cnp;
1353 
1354 #ifdef	DEBUG
1355 	if (getenv(SKIP_LAST_CACHE)) {
1356 		(void) dprintf(DBG_INFO, "get_last_node: SKIPPING \"last\" "
1357 		    "node cache\n");
1358 		return (NULL);
1359 	}
1360 #endif
1361 
1362 	if (!LOOKUP_CACHE(flags) || CACHE_LAST(hdp) == NULL ||
1363 	    CACHE_LAST(hdp)->node == NULL) {
1364 		return (NULL);
1365 	}
1366 
1367 	cnp = CACHE_LAST(hdp)->node;
1368 	if (strcmp(cnp->path, path) == 0) {
1369 		return (cnp);
1370 	}
1371 
1372 	cnp = cnp->sib;
1373 	if (cnp && strcmp(cnp->path, path) == 0) {
1374 		return (cnp);
1375 	}
1376 
1377 	return (NULL);
1378 }
1379 
1380 static void *
1381 get_last_minor(
1382 	struct di_devlink_handle *hdp,
1383 	const char *devfs_path,
1384 	const char *minor_name,
1385 	int flags)
1386 {
1387 	cache_minor_t *cmnp;
1388 
1389 #ifdef	DEBUG
1390 	if (getenv(SKIP_LAST_CACHE)) {
1391 		(void) dprintf(DBG_INFO, "get_last_minor: SKIPPING \"last\" "
1392 		    "minor cache\n");
1393 		return (NULL);
1394 	}
1395 #endif
1396 
1397 	if (!LOOKUP_CACHE(flags) || CACHE_LAST(hdp) == NULL) {
1398 		return (NULL);
1399 	}
1400 
1401 	cmnp = CACHE_LAST(hdp);
1402 	if (strcmp(cmnp->name, minor_name) == 0 && cmnp->node &&
1403 	    strcmp(cmnp->node->path, devfs_path) == 0) {
1404 		return (cmnp);
1405 	}
1406 
1407 	cmnp = cmnp->sib;
1408 	if (cmnp && strcmp(cmnp->name, minor_name) == 0 && cmnp->node &&
1409 	    strcmp(cmnp->node->path, devfs_path) == 0) {
1410 		set_last_minor(hdp, cmnp, TYPE_CACHE);
1411 		return (cmnp);
1412 	}
1413 
1414 	return (NULL);
1415 }
1416 
1417 static void
1418 set_last_minor(struct di_devlink_handle *hdp, cache_minor_t *cmnp, int flags)
1419 {
1420 #ifdef	DEBUG
1421 	if (getenv(SKIP_LAST_CACHE)) {
1422 		(void) dprintf(DBG_INFO, "set_last_minor: SKIPPING \"last\" "
1423 		    "minor cache\n");
1424 		return;
1425 	}
1426 #endif
1427 
1428 	if (LOOKUP_CACHE(flags) && cmnp) {
1429 		CACHE_LAST(hdp) = cmnp;
1430 	}
1431 }
1432 
1433 
1434 /*
1435  * Returns 0 if normal return or -1 otherwise.
1436  */
1437 static int
1438 walk_tree(
1439 	char *cur,
1440 	void *arg,
1441 	int (*node_callback)(const char *path, void *arg))
1442 {
1443 	char *slash, buf[PATH_MAX];
1444 
1445 	if (cur == NULL || cur[0] != '/' || strlen(cur) > sizeof (buf) - 1) {
1446 		errno = EINVAL;
1447 		return (-1);
1448 	}
1449 
1450 	(void) strcpy(buf, "/");
1451 
1452 	for (;;) {
1453 
1454 		if (node_callback(buf, arg) != DI_WALK_CONTINUE)
1455 			break;
1456 
1457 		while (*cur == '/')
1458 			cur++;
1459 
1460 		if (*cur == '\0')
1461 			break;
1462 
1463 		/*
1464 		 * There is a next component(s). Append a "/" separator for all
1465 		 * but the first (root) component.
1466 		 */
1467 		if (buf[1] != '\0') {
1468 			(void) strlcat(buf, "/", sizeof (buf));
1469 		}
1470 
1471 		if (slash = strchr(cur, '/')) {
1472 			*slash = '\0';
1473 			(void) strlcat(buf, cur, sizeof (buf));
1474 			*slash = '/';
1475 			cur = slash;
1476 		} else {
1477 			(void) strlcat(buf, cur, sizeof (buf));
1478 			cur += strlen(cur);
1479 		}
1480 
1481 	}
1482 
1483 	return (0);
1484 }
1485 
1486 
1487 static int
1488 visit_node(const char *path, void *arg)
1489 {
1490 	struct tnode *tnp = arg;
1491 
1492 	if (LOOKUP_CACHE(tnp->flags)) {
1493 
1494 		cache_node_t *cnp = tnp->node;
1495 
1496 		cnp = (cnp) ? cnp->child : CACHE_ROOT(tnp->handle);
1497 
1498 		for (; cnp != NULL; cnp = cnp->sib) {
1499 			if (strcmp(cnp->path, path) == 0)
1500 				break;
1501 		}
1502 		if (cnp == NULL && CREATE_ELEM(tnp->flags)) {
1503 			cnp = node_insert(tnp->handle, tnp->node, path,
1504 			    INSERT_TAIL);
1505 		}
1506 		tnp->node = cnp;
1507 	} else {
1508 		char *cp;
1509 		struct db_node *dnp = tnp->node;
1510 
1511 		dnp = (dnp) ? get_node(tnp->handle, dnp->child)
1512 		    : get_node(tnp->handle, DB_HDR(tnp->handle)->root_idx);
1513 
1514 		for (; dnp != NULL; dnp = get_node(tnp->handle, dnp->sib)) {
1515 			cp = get_string(tnp->handle, dnp->path);
1516 			if (cp && strcmp(cp, path) == 0) {
1517 				break;
1518 			}
1519 		}
1520 		tnp->node = dnp;
1521 	}
1522 
1523 	/*
1524 	 * Terminate walk if node is not found for a path component.
1525 	 */
1526 	return (tnp->node ? DI_WALK_CONTINUE : DI_WALK_TERMINATE);
1527 }
1528 
1529 static void
1530 minor_delete(di_devlink_handle_t hdp, cache_minor_t *cmnp)
1531 {
1532 	cache_link_t **lpp;
1533 	cache_minor_t **mpp;
1534 	const char *fcn = "minor_delete";
1535 
1536 	(void) dprintf(DBG_STEP, "%s: removing minor: %s\n", fcn, cmnp->name);
1537 
1538 	/* detach minor from node */
1539 	if (cmnp->node != NULL) {
1540 		mpp = &cmnp->node->minor;
1541 		for (; *mpp != NULL; mpp = &(*mpp)->sib) {
1542 			if (*mpp == cmnp)
1543 				break;
1544 		}
1545 
1546 		if (*mpp == NULL) {
1547 			(void) dprintf(DBG_ERR, "%s: dangling minor: %s\n",
1548 			    fcn, cmnp->name);
1549 		} else {
1550 			*mpp = cmnp->sib;
1551 		}
1552 	} else {
1553 		(void) dprintf(DBG_ERR, "%s: orphan minor(%s)\n", fcn,
1554 		    cmnp->name);
1555 	}
1556 
1557 	delete_unused_nodes(hdp, cmnp->node);
1558 
1559 	cmnp->node = NULL;
1560 	cmnp->sib = NULL;
1561 
1562 	/* Move all remaining links to dangling list */
1563 	for (lpp = &cmnp->link; *lpp != NULL; lpp = &(*lpp)->sib) {
1564 		(*lpp)->minor = NULL;
1565 	}
1566 	*lpp = CACHE(hdp)->dngl;
1567 	CACHE(hdp)->dngl = cmnp->link;
1568 	cmnp->link = NULL;
1569 
1570 	minor_free(hdp, &cmnp);
1571 }
1572 
1573 static void
1574 delete_unused_nodes(di_devlink_handle_t hdp, cache_node_t *cnp)
1575 {
1576 	cache_node_t **npp;
1577 	const char *fcn = "delete_unused_nodes";
1578 
1579 	if (cnp == NULL)
1580 		return;
1581 
1582 	if (cnp->minor != NULL || cnp->child != NULL)
1583 		return;
1584 
1585 	(void) dprintf(DBG_INFO, "%s: removing unused node: %s\n", fcn,
1586 	    cnp->path);
1587 
1588 	/* Unlink node from tree */
1589 	if (cnp->parent != NULL) {
1590 		npp = &cnp->parent->child;
1591 		for (; *npp != NULL; npp = &(*npp)->sib) {
1592 			if (*npp == cnp)
1593 				break;
1594 		}
1595 
1596 		if (*npp == NULL) {
1597 			(void) dprintf(DBG_ERR, "%s: dangling node: %s\n", fcn,
1598 			    cnp->path);
1599 		} else {
1600 			*npp = cnp->sib;
1601 		}
1602 	} else if (cnp == CACHE_ROOT(hdp)) {
1603 		CACHE_ROOT(hdp) = NULL;
1604 	} else {
1605 		(void) dprintf(DBG_ERR, "%s: orphan node (%s)\n", fcn,
1606 		    cnp->path);
1607 	}
1608 
1609 	delete_unused_nodes(hdp, cnp->parent);
1610 
1611 	cnp->parent = cnp->sib = NULL;
1612 
1613 	node_free(&cnp);
1614 }
1615 
1616 static int
1617 rm_link(di_devlink_handle_t hdp, const char *link)
1618 {
1619 	cache_link_t *clp;
1620 	const char *fcn = "rm_link";
1621 
1622 	if (hdp == NULL || DB_ERR(hdp) || link == NULL || link[0] == '/' ||
1623 	    (!HDL_RDWR(hdp) && !HDL_RDONLY(hdp))) {
1624 		dprintf(DBG_ERR, "%s: %s: invalid args\n",
1625 		    fcn, link ? link : "<NULL>");
1626 		errno = EINVAL;
1627 		return (-1);
1628 	}
1629 
1630 	dprintf(DBG_STEP, "%s: link(%s)\n", fcn, link);
1631 
1632 	if ((clp = link_hash(hdp, link, UNLINK_FROM_HASH)) == NULL) {
1633 		return (0);
1634 	}
1635 
1636 	link_delete(hdp, clp);
1637 
1638 	return (0);
1639 }
1640 
1641 int
1642 di_devlink_rm_link(di_devlink_handle_t hdp, const char *link)
1643 {
1644 	if (hdp == NULL || !HDL_RDWR(hdp)) {
1645 		errno = EINVAL;
1646 		return (-1);
1647 	}
1648 
1649 	return (rm_link(hdp, link));
1650 }
1651 
1652 static void
1653 link_delete(di_devlink_handle_t hdp, cache_link_t *clp)
1654 {
1655 	cache_link_t **pp;
1656 	const char *fcn = "link_delete";
1657 
1658 	(void) dprintf(DBG_STEP, "%s: removing link: %s\n", fcn, clp->path);
1659 
1660 	if (clp->minor == NULL)
1661 		pp = &(CACHE(hdp)->dngl);
1662 	else
1663 		pp = &clp->minor->link;
1664 
1665 	for (; *pp != NULL; pp = &(*pp)->sib) {
1666 		if (*pp == clp)
1667 			break;
1668 	}
1669 
1670 	if (*pp == NULL) {
1671 		(void) dprintf(DBG_ERR, "%s: link(%s) not on list\n",
1672 		    fcn, clp->path);
1673 	} else {
1674 		*pp = clp->sib;
1675 	}
1676 
1677 	delete_unused_minor(hdp, clp->minor);
1678 
1679 	clp->minor = NULL;
1680 
1681 	link_free(&clp);
1682 }
1683 
1684 static void
1685 delete_unused_minor(di_devlink_handle_t hdp, cache_minor_t *cmnp)
1686 {
1687 	if (cmnp == NULL)
1688 		return;
1689 
1690 	if (cmnp->link != NULL)
1691 		return;
1692 
1693 	dprintf(DBG_STEP, "delete_unused_minor: removing minor(%s)\n",
1694 	    cmnp->name);
1695 
1696 	minor_delete(hdp, cmnp);
1697 }
1698 
1699 int
1700 di_devlink_add_link(
1701 	di_devlink_handle_t hdp,
1702 	const char *link,
1703 	const char *content,
1704 	int flags)
1705 {
1706 	return (add_link(hdp, link, content, flags) != NULL ? 0 : -1);
1707 }
1708 
1709 static cache_link_t *
1710 add_link(
1711 	struct di_devlink_handle *hdp,
1712 	const char *link,
1713 	const char *content,
1714 	int flags)
1715 {
1716 	uint32_t attr;
1717 	cache_link_t *clp;
1718 	cache_minor_t *cmnp;
1719 	const char *fcn = "add_link";
1720 
1721 	if (hdp == NULL || DB_ERR(hdp) || link == NULL ||
1722 	    link[0] == '/' || content == NULL || !link_flag(flags) ||
1723 	    (!HDL_RDWR(hdp) && !HDL_RDONLY(hdp))) {
1724 		dprintf(DBG_ERR, "%s: %s: invalid args\n",
1725 		    fcn, link ? link : "<NULL>");
1726 		errno = EINVAL;
1727 		return (NULL);
1728 	}
1729 
1730 	if ((clp = link_hash(hdp, link, 0)) != NULL) {
1731 		if (link_cmp(clp, content, LINK_TYPE(flags)) != 0) {
1732 			(void) rm_link(hdp, link);
1733 		} else {
1734 			return (clp);
1735 		}
1736 	}
1737 
1738 	if (TYPE_PRI(flags)) {
1739 		const char *minor_path = NULL;
1740 
1741 		if (!is_minor_node(content, &minor_path)) {
1742 			(void) dprintf(DBG_ERR, "%s: invalid content(%s)"
1743 			    " for primary link\n", fcn, content);
1744 			errno = EINVAL;
1745 			return (NULL);
1746 		}
1747 		if ((cmnp = lookup_minor(hdp, minor_path, NULL,
1748 		    TYPE_CACHE|CREATE_FLAG)) == NULL) {
1749 			return (NULL);
1750 		}
1751 		attr = A_PRIMARY;
1752 	} else {
1753 		/*
1754 		 * Defer resolving a secondary link to a minor until the
1755 		 * database is closed. This ensures that the primary link
1756 		 * (required for a successful resolve) has also been created.
1757 		 */
1758 		cmnp = NULL;
1759 		attr = A_SECONDARY;
1760 	}
1761 
1762 	return (link_insert(hdp, cmnp, link, content, attr));
1763 }
1764 
1765 /*
1766  * Returns 0 on match or 1 otherwise.
1767  */
1768 static int
1769 link_cmp(cache_link_t *clp, const char *content, int type)
1770 {
1771 	if (strcmp(clp->content, content) != 0)
1772 		return (1);
1773 
1774 	if (attr2type(clp->attr) != type)
1775 		return (1);
1776 
1777 	return (0);
1778 }
1779 
1780 int
1781 di_devlink_update(di_devlink_handle_t hdp)
1782 {
1783 	if (hdp == NULL || !HDL_RDWR(hdp) || DB_ERR(hdp)) {
1784 		errno = EINVAL;
1785 		return (-1);
1786 	}
1787 
1788 	/*
1789 	 * Reset the counter to schedule a synchronization with /dev on the next
1790 	 * di_devlink_close().
1791 	 */
1792 	CACHE(hdp)->update_count = 0;
1793 
1794 	return (0);
1795 }
1796 
1797 static int
1798 synchronize_db(di_devlink_handle_t hdp)
1799 {
1800 	int hval;
1801 	cache_link_t *clp;
1802 	char pdup[PATH_MAX];
1803 	recurse_t rec = {NULL};
1804 	const char *fcn = "synchronize_db";
1805 
1806 	rec.data = NULL;
1807 	rec.fcn = cache_dev_link;
1808 
1809 	/*
1810 	 * Walk through $ROOT/dev, reading every link and marking the
1811 	 * corresponding cached version as valid(adding new links as needed).
1812 	 * Then walk through the cache and remove all unmarked links.
1813 	 */
1814 	if (recurse_dev(hdp, &rec) != 0) {
1815 		return (-1);
1816 	}
1817 
1818 	for (hval = 0; hval < CACHE(hdp)->hash_sz; hval++) {
1819 		for (clp = CACHE_HASH(hdp, hval); clp != NULL; ) {
1820 			if (GET_VALID_ATTR(clp->attr)) {
1821 				CLR_VALID_ATTR(clp->attr);
1822 				clp = clp->hash;
1823 				continue;
1824 			}
1825 
1826 			/*
1827 			 * The link is stale, so remove it. Since the link
1828 			 * will be destroyed, use a copy of the link path to
1829 			 * invoke the remove function.
1830 			 */
1831 			(void) snprintf(pdup, sizeof (pdup), "%s", clp->path);
1832 			clp = clp->hash;
1833 			(void) dprintf(DBG_STEP, "%s: removing invalid link:"
1834 			    " %s\n", fcn, pdup);
1835 			(void) di_devlink_rm_link(hdp, pdup);
1836 		}
1837 	}
1838 
1839 	(void) dprintf(DBG_STEP, "%s: update completed\n", fcn);
1840 
1841 	return (0);
1842 }
1843 
1844 static di_devlink_handle_t
1845 di_devlink_init_impl(const char *root, const char *name, uint_t flags)
1846 {
1847 	int	err = 0;
1848 
1849 	if ((flags != 0 && flags != DI_MAKE_LINK) ||
1850 	    (flags == 0 && name != NULL)) {
1851 		errno = EINVAL;
1852 		return (NULL);
1853 	}
1854 
1855 	if (flags == DI_MAKE_LINK && (err = devlink_create(root, name))) {
1856 		errno = err;
1857 		return (NULL);
1858 	}
1859 
1860 	(void) dprintf(DBG_INFO, "devlink_init_impl: success\n");
1861 
1862 	return (devlink_snapshot(root));
1863 }
1864 
1865 di_devlink_handle_t
1866 di_devlink_init(const char *name, uint_t flags)
1867 {
1868 	return (di_devlink_init_impl("/", name, flags));
1869 }
1870 
1871 di_devlink_handle_t
1872 di_devlink_init_root(const char *root, const char *name, uint_t flags)
1873 {
1874 	return (di_devlink_init_impl(root, name, flags));
1875 }
1876 
1877 static di_devlink_handle_t
1878 devlink_snapshot(const char *root_dir)
1879 {
1880 	struct di_devlink_handle *hdp;
1881 
1882 	if ((hdp = handle_alloc(root_dir, OPEN_RDONLY)) == NULL) {
1883 		return (NULL);
1884 	}
1885 
1886 	/*
1887 	 * If we cannot open the DB below, we will walk /dev
1888 	 * in di_devlink_walk.
1889 	 */
1890 	(void) open_db(hdp, OPEN_RDONLY);
1891 
1892 	return (hdp);
1893 }
1894 
1895 int
1896 di_devlink_fini(di_devlink_handle_t *pp)
1897 {
1898 	if (pp == NULL || *pp == NULL || !HDL_RDONLY(*pp)) {
1899 		errno = EINVAL;
1900 		return (-1);
1901 	}
1902 
1903 	/* Freeing the handle also closes the DB */
1904 	handle_free(pp);
1905 
1906 	return (0);
1907 }
1908 
1909 int
1910 di_devlink_walk(
1911 	di_devlink_handle_t hdp,
1912 	const char *re,
1913 	const char *minor_path,
1914 	uint_t flags,
1915 	void *arg,
1916 	int (*devlink_callback)(di_devlink_t, void *))
1917 {
1918 	int rv;
1919 	regex_t reg;
1920 	link_desc_t linkd = {NULL};
1921 
1922 	if (hdp == NULL || !HDL_RDONLY(hdp)) {
1923 		errno = EINVAL;
1924 		return (-1);
1925 	}
1926 
1927 	linkd.minor_path = minor_path;
1928 	linkd.flags = flags;
1929 	linkd.arg = arg;
1930 	linkd.fcn = devlink_callback;
1931 
1932 	if (re) {
1933 		if (regcomp(&reg, re, REG_EXTENDED) != 0)
1934 			return (-1);
1935 		linkd.regp = &reg;
1936 	}
1937 
1938 	if (check_args(&linkd)) {
1939 		errno = EINVAL;
1940 		rv = -1;
1941 		goto out;
1942 	}
1943 
1944 	if (DB_OPEN(hdp)) {
1945 		rv = walk_db(hdp, &linkd);
1946 	} else {
1947 		rv = walk_dev(hdp, &linkd);
1948 	}
1949 
1950 out:
1951 	if (re) {
1952 		regfree(&reg);
1953 	}
1954 
1955 	return (rv ? -1 : 0);
1956 }
1957 
1958 static int
1959 link_flag(uint_t flags)
1960 {
1961 	if (flags != 0 && flags != DI_PRIMARY_LINK &&
1962 	    flags != DI_SECONDARY_LINK) {
1963 		return (0);
1964 	}
1965 
1966 	return (1);
1967 }
1968 
1969 /*
1970  * Currently allowed flags are:
1971  *	DI_PRIMARY_LINK
1972  *	DI_SECONDARY_LINK
1973  */
1974 static int
1975 check_args(link_desc_t *linkp)
1976 {
1977 	if (linkp->fcn == NULL)
1978 		return (-1);
1979 
1980 	if (!link_flag(linkp->flags)) {
1981 		return (-1);
1982 	}
1983 
1984 	/*
1985 	 * Minor path can be NULL. In that case, all links will be
1986 	 * selected.
1987 	 */
1988 	if (linkp->minor_path) {
1989 		if (linkp->minor_path[0] != '/' ||
1990 		    minor_colon(linkp->minor_path) == NULL) {
1991 			return (-1);
1992 		}
1993 	}
1994 
1995 	return (0);
1996 }
1997 
1998 
1999 /*
2000  * Walk all links in database if no minor path is specified.
2001  */
2002 static int
2003 walk_db(struct di_devlink_handle *hdp, link_desc_t *linkp)
2004 {
2005 	assert(DB_OPEN(hdp));
2006 
2007 	if (linkp->minor_path == NULL) {
2008 		return (walk_all_links(hdp, linkp));
2009 	} else {
2010 		return (walk_matching_links(hdp, linkp));
2011 	}
2012 }
2013 
2014 static int
2015 cache_dev(struct di_devlink_handle *hdp)
2016 {
2017 	size_t sz;
2018 	recurse_t rec = {NULL};
2019 
2020 	assert(hdp);
2021 	assert(HDL_RDONLY(hdp));
2022 
2023 	if (hdp == NULL || !HDL_RDONLY(hdp)) {
2024 		dprintf(DBG_ERR, "cache_dev: invalid arg\n");
2025 		return (-1);
2026 	}
2027 
2028 	sz = MIN_HASH_SIZE;
2029 
2030 	CACHE(hdp)->hash = calloc(sz, sizeof (cache_link_t *));
2031 	if (CACHE(hdp)->hash == NULL) {
2032 		return (-1);
2033 	}
2034 	CACHE(hdp)->hash_sz = sz;
2035 
2036 	rec.data = NULL;
2037 	rec.fcn = cache_dev_link;
2038 
2039 	return (recurse_dev(hdp, &rec));
2040 }
2041 
2042 static int
2043 walk_dev(struct di_devlink_handle *hdp, link_desc_t *linkp)
2044 {
2045 	assert(hdp && linkp);
2046 	assert(!DB_OPEN(hdp));
2047 	assert(HDL_RDONLY(hdp));
2048 
2049 	if (hdp == NULL || !HDL_RDONLY(hdp) || DB_OPEN(hdp)) {
2050 		dprintf(DBG_ERR, "walk_dev: invalid args\n");
2051 		return (-1);
2052 	}
2053 
2054 	if (CACHE_EMPTY(hdp) && cache_dev(hdp) != 0) {
2055 		dprintf(DBG_ERR, "walk_dev: /dev caching failed\n");
2056 		return (-1);
2057 	}
2058 
2059 	if (linkp->minor_path)
2060 		walk_cache_minor(hdp, linkp->minor_path, linkp);
2061 	else
2062 		walk_all_cache(hdp, linkp);
2063 
2064 	return (linkp->retval);
2065 }
2066 
2067 /* ARGSUSED */
2068 static int
2069 cache_dev_link(struct di_devlink_handle *hdp, void *data, const char *link)
2070 {
2071 	int flags;
2072 	cache_link_t *clp;
2073 	char content[PATH_MAX];
2074 
2075 	assert(HDL_RDWR(hdp) || HDL_RDONLY(hdp));
2076 
2077 	if (s_readlink(link, content, sizeof (content)) < 0) {
2078 		return (DI_WALK_CONTINUE);
2079 	}
2080 
2081 	if (is_minor_node(content, NULL)) {
2082 		flags = DI_PRIMARY_LINK;
2083 	} else {
2084 		flags = DI_SECONDARY_LINK;
2085 	}
2086 
2087 	assert(strncmp(link, hdp->dev_dir, strlen(hdp->dev_dir)) == 0);
2088 
2089 	/*
2090 	 * Store only the part after <root-dir>/dev/
2091 	 */
2092 	link += strlen(hdp->dev_dir) + 1;
2093 
2094 	if ((clp = add_link(hdp, link, content, flags)) != NULL) {
2095 		SET_VALID_ATTR(clp->attr);
2096 	}
2097 
2098 	return (DI_WALK_CONTINUE);
2099 }
2100 
2101 
2102 static int
2103 walk_all_links(struct di_devlink_handle *hdp, link_desc_t *linkp)
2104 {
2105 	struct db_link *dlp;
2106 	uint32_t nidx, eidx;
2107 
2108 	assert(DB_NUM(hdp, DB_LINK) >= 1);
2109 
2110 	eidx = DB_NUM(hdp, DB_LINK);
2111 
2112 	/* Skip the "NIL" (index == 0) link. */
2113 	for (nidx = 1; nidx < eidx; nidx++) {
2114 		/*
2115 		 * Declare this local to the block with zero
2116 		 * initializer so that it gets rezeroed
2117 		 * for each iteration.
2118 		 */
2119 		struct di_devlink vlink = {NULL};
2120 
2121 		if ((dlp = get_link(hdp, nidx)) == NULL)
2122 			continue;
2123 
2124 		vlink.rel_path = get_string(hdp, dlp->path);
2125 		vlink.content = get_string(hdp, dlp->content);
2126 		vlink.type = attr2type(dlp->attr);
2127 
2128 		if (visit_link(hdp, linkp, &vlink) != DI_WALK_CONTINUE) {
2129 			break;
2130 		}
2131 	}
2132 
2133 	return (linkp->retval);
2134 }
2135 
2136 static int
2137 walk_matching_links(struct di_devlink_handle *hdp, link_desc_t *linkp)
2138 {
2139 	uint32_t nidx;
2140 	struct db_link *dlp;
2141 	struct db_minor *dmp;
2142 
2143 	assert(linkp->minor_path != NULL);
2144 
2145 	dmp = lookup_minor(hdp, linkp->minor_path, NULL, TYPE_DB);
2146 
2147 	/*
2148 	 * If a minor matching the path exists, walk that minor's devlinks list.
2149 	 * Then walk the dangling devlinks list. Non-matching devlinks will be
2150 	 * filtered out in visit_link.
2151 	 */
2152 	for (;;) {
2153 		nidx = dmp ? dmp->link : DB_HDR(hdp)->dngl_idx;
2154 		for (; dlp = get_link(hdp, nidx); nidx = dlp->sib) {
2155 			struct di_devlink vlink = {NULL};
2156 
2157 			vlink.rel_path = get_string(hdp, dlp->path);
2158 			vlink.content = get_string(hdp, dlp->content);
2159 			vlink.type = attr2type(dlp->attr);
2160 
2161 			if (visit_link(hdp, linkp, &vlink) != DI_WALK_CONTINUE)
2162 				goto out;
2163 		}
2164 		if (dmp == NULL) {
2165 			break;
2166 		} else {
2167 			dmp = NULL;
2168 		}
2169 	}
2170 
2171 out:
2172 	return (linkp->retval);
2173 }
2174 
2175 static int
2176 visit_link(
2177 	struct di_devlink_handle *hdp,
2178 	link_desc_t *linkp,
2179 	struct di_devlink *vlp)
2180 {
2181 	struct stat sbuf;
2182 	const char *minor_path = NULL;
2183 	char abs_path[PATH_MAX], cont[PATH_MAX];
2184 
2185 	/*
2186 	 * It is legal for the link's content and type to be unknown.
2187 	 * but one of absolute or relative path must be set.
2188 	 */
2189 	if (vlp->rel_path == NULL && vlp->abs_path == NULL) {
2190 		(void) dprintf(DBG_ERR, "visit_link: invalid arguments\n");
2191 		return (DI_WALK_CONTINUE);
2192 	}
2193 
2194 	if (vlp->rel_path == NULL) {
2195 		vlp->rel_path = (char *)rel_path(hdp, vlp->abs_path);
2196 		if (vlp->rel_path == NULL || vlp->rel_path[0] == '\0')
2197 			return (DI_WALK_CONTINUE);
2198 	}
2199 
2200 	if (linkp->regp) {
2201 		if (regexec(linkp->regp, vlp->rel_path, 0, NULL, 0) != 0)
2202 			return (DI_WALK_CONTINUE);
2203 	}
2204 
2205 	if (vlp->abs_path == NULL) {
2206 		assert(vlp->rel_path[0] != '/');
2207 		(void) snprintf(abs_path, sizeof (abs_path), "%s/%s",
2208 		    hdp->dev_dir, vlp->rel_path);
2209 		vlp->abs_path = abs_path;
2210 	}
2211 
2212 	if (vlp->content == NULL) {
2213 		if (s_readlink(vlp->abs_path, cont, sizeof (cont)) < 0) {
2214 			return (DI_WALK_CONTINUE);
2215 		}
2216 		vlp->content = cont;
2217 	}
2218 
2219 
2220 	if (vlp->type == 0) {
2221 		if (is_minor_node(vlp->content, &minor_path)) {
2222 			vlp->type = DI_PRIMARY_LINK;
2223 		} else {
2224 			vlp->type = DI_SECONDARY_LINK;
2225 		}
2226 	}
2227 
2228 	/*
2229 	 * Filter based on minor path
2230 	 */
2231 	if (linkp->minor_path) {
2232 		char tmp[PATH_MAX];
2233 
2234 		/*
2235 		 * derive minor path
2236 		 */
2237 		if (vlp->type == DI_SECONDARY_LINK) {
2238 
2239 #ifdef	DEBUG
2240 			/*LINTED*/
2241 			assert(sizeof (tmp) >= PATH_MAX);
2242 #endif
2243 			if (realpath(vlp->abs_path, tmp) == NULL)
2244 				return (DI_WALK_CONTINUE);
2245 
2246 			if (!is_minor_node(tmp, &minor_path))
2247 				return (DI_WALK_CONTINUE);
2248 
2249 		} else if (minor_path == NULL) {
2250 			if (!is_minor_node(vlp->content, &minor_path))
2251 				return (DI_WALK_CONTINUE);
2252 		}
2253 
2254 		assert(minor_path != NULL);
2255 
2256 		if (strcmp(linkp->minor_path, minor_path) != 0)
2257 			return (DI_WALK_CONTINUE);
2258 	}
2259 
2260 	/*
2261 	 * Filter based on link type
2262 	 */
2263 	if (!TYPE_NONE(linkp->flags) && LINK_TYPE(linkp->flags) != vlp->type) {
2264 		return (DI_WALK_CONTINUE);
2265 	}
2266 
2267 	if (lstat(vlp->abs_path, &sbuf) < 0) {
2268 		dprintf(DBG_ERR, "visit_link: %s: lstat failed: %s\n",
2269 		    vlp->abs_path, strerror(errno));
2270 		return (DI_WALK_CONTINUE);
2271 	}
2272 
2273 	return (linkp->fcn(vlp, linkp->arg));
2274 }
2275 
2276 static int
2277 devlink_valid(di_devlink_t devlink)
2278 {
2279 	if (devlink == NULL || devlink->rel_path == NULL ||
2280 	    devlink->abs_path == NULL || devlink->content == NULL ||
2281 	    TYPE_NONE(devlink->type)) {
2282 		return (0);
2283 	}
2284 
2285 	return (1);
2286 }
2287 
2288 const char *
2289 di_devlink_path(di_devlink_t devlink)
2290 {
2291 	if (!devlink_valid(devlink)) {
2292 		errno = EINVAL;
2293 		return (NULL);
2294 	}
2295 
2296 	return (devlink->abs_path);
2297 }
2298 
2299 const char *
2300 di_devlink_content(di_devlink_t devlink)
2301 {
2302 	if (!devlink_valid(devlink)) {
2303 		errno = EINVAL;
2304 		return (NULL);
2305 	}
2306 
2307 	return (devlink->content);
2308 }
2309 
2310 int
2311 di_devlink_type(di_devlink_t devlink)
2312 {
2313 	if (!devlink_valid(devlink)) {
2314 		errno = EINVAL;
2315 		return (-1);
2316 	}
2317 
2318 	return (devlink->type);
2319 }
2320 
2321 di_devlink_t
2322 di_devlink_dup(di_devlink_t devlink)
2323 {
2324 	struct di_devlink *duplink;
2325 
2326 	if (!devlink_valid(devlink)) {
2327 		errno = EINVAL;
2328 		return (NULL);
2329 	}
2330 
2331 	if ((duplink = calloc(1, sizeof (struct di_devlink))) == NULL) {
2332 		return (NULL);
2333 	}
2334 
2335 	duplink->rel_path = strdup(devlink->rel_path);
2336 	duplink->abs_path = strdup(devlink->abs_path);
2337 	duplink->content  = strdup(devlink->content);
2338 	duplink->type	  = devlink->type;
2339 
2340 	if (!devlink_valid(duplink)) {
2341 		(void) di_devlink_free(duplink);
2342 		errno = ENOMEM;
2343 		return (NULL);
2344 	}
2345 
2346 	return (duplink);
2347 }
2348 
2349 int
2350 di_devlink_free(di_devlink_t devlink)
2351 {
2352 	if (devlink == NULL) {
2353 		errno = EINVAL;
2354 		return (-1);
2355 	}
2356 
2357 	free(devlink->rel_path);
2358 	free(devlink->abs_path);
2359 	free(devlink->content);
2360 	free(devlink);
2361 
2362 	return (0);
2363 }
2364 
2365 /*
2366  * Obtain path relative to dev_dir
2367  */
2368 static const char *
2369 rel_path(struct di_devlink_handle *hdp, const char *path)
2370 {
2371 	const size_t len = strlen(hdp->dev_dir);
2372 
2373 	if (strncmp(path, hdp->dev_dir, len) != 0)
2374 		return (NULL);
2375 
2376 	if (path[len] == '\0')
2377 		return (&path[len]);
2378 
2379 	if (path[len] != '/')
2380 		return (NULL);
2381 
2382 	return (&path[len+1]);
2383 }
2384 
2385 static int
2386 recurse_dev(struct di_devlink_handle *hdp, recurse_t *rp)
2387 {
2388 	int ret = 0;
2389 
2390 	(void) do_recurse(hdp->dev_dir, hdp, rp, &ret);
2391 
2392 	return (ret);
2393 }
2394 
2395 static int
2396 do_recurse(
2397 	const char *dir,
2398 	struct di_devlink_handle *hdp,
2399 	recurse_t *rp,
2400 	int *retp)
2401 {
2402 	DIR *dp;
2403 	size_t len;
2404 	const char *rel;
2405 	struct stat sbuf;
2406 	char cur[PATH_MAX], *cp;
2407 	int i, rv = DI_WALK_CONTINUE;
2408 	struct dirent *entp;
2409 
2410 
2411 	if ((rel = rel_path(hdp, dir)) == NULL)
2412 		return (DI_WALK_CONTINUE);
2413 
2414 	/*
2415 	 * Skip directories we are not interested in.
2416 	 */
2417 	for (i = 0; i < N_SKIP_DIRS; i++) {
2418 		if (strcmp(rel, skip_dirs[i]) == 0) {
2419 			(void) dprintf(DBG_STEP, "do_recurse: skipping %s\n",
2420 			    dir);
2421 			return (DI_WALK_CONTINUE);
2422 		}
2423 	}
2424 
2425 	(void) dprintf(DBG_STEP, "do_recurse: dir = %s\n", dir);
2426 
2427 	if ((dp = opendir(dir)) == NULL)
2428 		return (DI_WALK_CONTINUE);
2429 
2430 	(void) snprintf(cur, sizeof (cur), "%s/", dir);
2431 	len = strlen(cur);
2432 	cp = cur + len;
2433 	len = sizeof (cur) - len;
2434 
2435 	while ((entp = readdir(dp)) != NULL) {
2436 
2437 		if (strcmp(entp->d_name, ".") == 0 ||
2438 		    strcmp(entp->d_name, "..") == 0) {
2439 			continue;
2440 		}
2441 
2442 		(void) snprintf(cp, len, "%s", entp->d_name);
2443 
2444 		/*
2445 		 * Skip files we are not interested in.
2446 		 */
2447 		for (i = 0; i < N_SKIP_FILES; i++) {
2448 
2449 			rel = rel_path(hdp, cur);
2450 			if (rel == NULL || strcmp(rel, skip_files[i]) == 0) {
2451 				(void) dprintf(DBG_STEP,
2452 				    "do_recurse: skipping %s\n", cur);
2453 				goto next_entry;
2454 			}
2455 		}
2456 
2457 		if (lstat(cur, &sbuf) == 0) {
2458 			if (S_ISDIR(sbuf.st_mode)) {
2459 				rv = do_recurse(cur, hdp, rp, retp);
2460 			} else if (S_ISLNK(sbuf.st_mode)) {
2461 				rv = rp->fcn(hdp, rp->data, cur);
2462 			} else {
2463 				(void) dprintf(DBG_STEP,
2464 				    "do_recurse: Skipping entry: %s\n", cur);
2465 			}
2466 		} else {
2467 			(void) dprintf(DBG_ERR, "do_recurse: cur(%s): lstat"
2468 			    " failed: %s\n", cur, strerror(errno));
2469 		}
2470 
2471 next_entry:
2472 		*cp = '\0';
2473 
2474 		if (rv != DI_WALK_CONTINUE)
2475 			break;
2476 	}
2477 
2478 	(void) closedir(dp);
2479 
2480 	return (rv);
2481 }
2482 
2483 
2484 static int
2485 check_attr(uint32_t attr)
2486 {
2487 	switch (attr & A_LINK_TYPES) {
2488 		case A_PRIMARY:
2489 		case A_SECONDARY:
2490 			return (1);
2491 		default:
2492 			dprintf(DBG_ERR, "check_attr: incorrect attr(%u)\n",
2493 			    attr);
2494 			return (0);
2495 	}
2496 }
2497 
2498 static int
2499 attr2type(uint32_t attr)
2500 {
2501 	switch (attr & A_LINK_TYPES) {
2502 		case A_PRIMARY:
2503 			return (DI_PRIMARY_LINK);
2504 		case A_SECONDARY:
2505 			return (DI_SECONDARY_LINK);
2506 		default:
2507 			dprintf(DBG_ERR, "attr2type: incorrect attr(%u)\n",
2508 			    attr);
2509 			return (0);
2510 	}
2511 }
2512 
2513 /* Allocate new node and link it in */
2514 static cache_node_t *
2515 node_insert(
2516 	struct di_devlink_handle *hdp,
2517 	cache_node_t *pcnp,
2518 	const char *path,
2519 	int insert)
2520 {
2521 	cache_node_t *cnp;
2522 
2523 	if (path == NULL) {
2524 		errno = EINVAL;
2525 		SET_DB_ERR(hdp);
2526 		return (NULL);
2527 	}
2528 
2529 	if ((cnp = calloc(1, sizeof (cache_node_t))) == NULL) {
2530 		SET_DB_ERR(hdp);
2531 		return (NULL);
2532 	}
2533 
2534 	if ((cnp->path = strdup(path)) == NULL) {
2535 		SET_DB_ERR(hdp);
2536 		free(cnp);
2537 		return (NULL);
2538 	}
2539 
2540 	cnp->parent = pcnp;
2541 
2542 	if (pcnp == NULL) {
2543 		assert(strcmp(path, "/") == 0);
2544 		assert(CACHE(hdp)->root == NULL);
2545 		CACHE(hdp)->root = cnp;
2546 	} else if (insert == INSERT_HEAD) {
2547 		cnp->sib = pcnp->child;
2548 		pcnp->child = cnp;
2549 	} else if (CACHE_LAST(hdp) && CACHE_LAST(hdp)->node &&
2550 	    CACHE_LAST(hdp)->node->parent == pcnp &&
2551 	    CACHE_LAST(hdp)->node->sib == NULL) {
2552 
2553 		CACHE_LAST(hdp)->node->sib = cnp;
2554 
2555 	} else {
2556 		cache_node_t **pp;
2557 
2558 		for (pp = &pcnp->child; *pp != NULL; pp = &(*pp)->sib)
2559 			;
2560 		*pp = cnp;
2561 	}
2562 
2563 	return (cnp);
2564 }
2565 
2566 /*
2567  * Allocate a new minor and link it in either at the tail or head
2568  * of the minor list depending on the value of "prev".
2569  */
2570 static cache_minor_t *
2571 minor_insert(
2572 	struct di_devlink_handle *hdp,
2573 	cache_node_t *pcnp,
2574 	const char *name,
2575 	const char *nodetype,
2576 	cache_minor_t **prev)
2577 {
2578 	cache_minor_t *cmnp;
2579 
2580 	if (pcnp == NULL || name == NULL) {
2581 		errno = EINVAL;
2582 		SET_DB_ERR(hdp);
2583 		return (NULL);
2584 	}
2585 
2586 	/*
2587 	 * Some pseudo drivers don't specify nodetype. Assume pseudo if
2588 	 * nodetype is not specified.
2589 	 */
2590 	if (nodetype == NULL)
2591 		nodetype = DDI_PSEUDO;
2592 
2593 	if ((cmnp = calloc(1, sizeof (cache_minor_t))) == NULL) {
2594 		SET_DB_ERR(hdp);
2595 		return (NULL);
2596 	}
2597 
2598 	cmnp->name = strdup(name);
2599 	cmnp->nodetype = strdup(nodetype);
2600 	if (cmnp->name == NULL || cmnp->nodetype == NULL) {
2601 		SET_DB_ERR(hdp);
2602 		free(cmnp->name);
2603 		free(cmnp->nodetype);
2604 		free(cmnp);
2605 		return (NULL);
2606 	}
2607 
2608 	cmnp->node = pcnp;
2609 
2610 	/* Add to node's minor list */
2611 	if (prev == NULL) {
2612 		cmnp->sib = pcnp->minor;
2613 		pcnp->minor = cmnp;
2614 	} else {
2615 		assert(*prev == NULL);
2616 		*prev = cmnp;
2617 	}
2618 
2619 	return (cmnp);
2620 }
2621 
2622 static cache_link_t *
2623 link_insert(
2624 	struct di_devlink_handle *hdp,
2625 	cache_minor_t *cmnp,
2626 	const char *path,
2627 	const char *content,
2628 	uint32_t attr)
2629 {
2630 	cache_link_t *clp;
2631 
2632 	if (path == NULL || content == NULL || !check_attr(attr)) {
2633 		errno = EINVAL;
2634 		SET_DB_ERR(hdp);
2635 		return (NULL);
2636 	}
2637 
2638 	if ((clp = calloc(1, sizeof (cache_link_t))) == NULL) {
2639 		SET_DB_ERR(hdp);
2640 		return (NULL);
2641 	}
2642 
2643 	clp->path = strdup(path);
2644 	clp->content = strdup(content);
2645 	if (clp->path == NULL || clp->content == NULL) {
2646 		SET_DB_ERR(hdp);
2647 		link_free(&clp);
2648 		return (NULL);
2649 	}
2650 
2651 	clp->attr = attr;
2652 	hash_insert(hdp, clp);
2653 	clp->minor = cmnp;
2654 
2655 	/* Add to minor's link list */
2656 	if (cmnp != NULL) {
2657 		clp->sib = cmnp->link;
2658 		cmnp->link = clp;
2659 	} else {
2660 		clp->sib = CACHE(hdp)->dngl;
2661 		CACHE(hdp)->dngl = clp;
2662 	}
2663 
2664 	return (clp);
2665 }
2666 
2667 static void
2668 hash_insert(struct di_devlink_handle *hdp, cache_link_t *clp)
2669 {
2670 	uint_t hval;
2671 
2672 	hval = hashfn(hdp, clp->path);
2673 	clp->hash = CACHE_HASH(hdp, hval);
2674 	CACHE_HASH(hdp, hval) = clp;
2675 }
2676 
2677 
2678 static struct db_node *
2679 get_node(struct di_devlink_handle *hdp, uint32_t idx)
2680 {
2681 	return (map_seg(hdp, idx, PROT_READ, DB_NODE));
2682 }
2683 
2684 static struct db_node *
2685 set_node(struct di_devlink_handle *hdp, uint32_t idx)
2686 {
2687 	return (map_seg(hdp, idx, PROT_READ | PROT_WRITE, DB_NODE));
2688 }
2689 
2690 static struct db_minor *
2691 get_minor(struct di_devlink_handle *hdp, uint32_t idx)
2692 {
2693 	return (map_seg(hdp, idx, PROT_READ, DB_MINOR));
2694 }
2695 
2696 static struct db_minor *
2697 set_minor(struct di_devlink_handle *hdp, uint32_t idx)
2698 {
2699 	return (map_seg(hdp, idx, PROT_READ | PROT_WRITE, DB_MINOR));
2700 }
2701 
2702 static struct db_link *
2703 get_link(struct di_devlink_handle *hdp, uint32_t idx)
2704 {
2705 	return (map_seg(hdp, idx, PROT_READ, DB_LINK));
2706 }
2707 
2708 static struct db_link *
2709 set_link(struct di_devlink_handle *hdp, uint32_t idx)
2710 {
2711 	return (map_seg(hdp, idx, PROT_READ | PROT_WRITE, DB_LINK));
2712 }
2713 
2714 static char *
2715 get_string(struct di_devlink_handle *hdp, uint32_t idx)
2716 {
2717 	return (map_seg(hdp, idx, PROT_READ, DB_STR));
2718 }
2719 
2720 static char *
2721 set_string(struct di_devlink_handle *hdp, uint32_t idx)
2722 {
2723 	return (map_seg(hdp, idx, PROT_READ | PROT_WRITE, DB_STR));
2724 }
2725 
2726 
2727 /*
2728  * Returns the element corresponding to idx. If the portion of file involved
2729  * is not yet mapped, does an mmap() as well. Existing mappings are not changed.
2730  */
2731 static void *
2732 map_seg(
2733 	struct di_devlink_handle *hdp,
2734 	uint32_t idx,
2735 	int prot,
2736 	db_seg_t seg)
2737 {
2738 	int s;
2739 	off_t off;
2740 	size_t slen;
2741 	caddr_t addr;
2742 
2743 	if (idx == DB_NIL) {
2744 		return (NULL);
2745 	}
2746 
2747 	if (!VALID_INDEX(hdp, seg, idx)) {
2748 		(void) dprintf(DBG_ERR, "map_seg: seg(%d): invalid idx(%u)\n",
2749 		    seg, idx);
2750 		return (NULL);
2751 	}
2752 
2753 	/*
2754 	 * If the seg is already mapped in, use it if the access type is
2755 	 * valid.
2756 	 */
2757 	if (DB_SEG(hdp, seg) != NULL) {
2758 		if (DB_SEG_PROT(hdp, seg) != prot) {
2759 			(void) dprintf(DBG_ERR, "map_seg: illegal access: "
2760 			    "seg[%d]: idx=%u, seg_prot=%d, access=%d\n",
2761 			    seg, idx, DB_SEG_PROT(hdp, seg), prot);
2762 			return (NULL);
2763 		}
2764 		return (DB_SEG(hdp, seg) + idx * elem_sizes[seg]);
2765 	}
2766 
2767 	/*
2768 	 * Segment is not mapped. Mmap() the segment.
2769 	 */
2770 	off = seg_size(hdp, DB_HEADER);
2771 	for (s = 0; s < seg; s++) {
2772 		off += seg_size(hdp, s);
2773 	}
2774 	slen = seg_size(hdp, seg);
2775 
2776 	addr = mmap(0, slen, prot, MAP_SHARED, DB(hdp)->db_fd, off);
2777 	if (addr == MAP_FAILED) {
2778 		(void) dprintf(DBG_ERR, "map_seg: seg[%d]: mmap failed: %s\n",
2779 		    seg, strerror(errno));
2780 		(void) dprintf(DBG_ERR, "map_seg: args: len=%lu, prot=%d,"
2781 		    " fd=%d, off=%ld\n", (ulong_t)slen, prot, DB(hdp)->db_fd,
2782 		    off);
2783 		return (NULL);
2784 	}
2785 
2786 	DB_SEG(hdp, seg) = addr;
2787 	DB_SEG_PROT(hdp, seg) = prot;
2788 
2789 	(void) dprintf(DBG_STEP, "map_seg: seg[%d]: len=%lu, prot=%d, fd=%d, "
2790 	    "off=%ld, seg_base=%p\n", seg, (ulong_t)slen, prot, DB(hdp)->db_fd,
2791 	    off, (void *)addr);
2792 
2793 	return (DB_SEG(hdp, seg) + idx * elem_sizes[seg]);
2794 }
2795 
2796 /*
2797  * Computes the size of a segment rounded up to the nearest page boundary.
2798  */
2799 static size_t
2800 seg_size(struct di_devlink_handle *hdp, int seg)
2801 {
2802 	size_t sz;
2803 
2804 	assert(DB_HDR(hdp)->page_sz);
2805 
2806 	if (seg == DB_HEADER) {
2807 		sz = HDR_LEN;
2808 	} else {
2809 		assert(DB_NUM(hdp, seg) >= 1);
2810 		sz = DB_NUM(hdp, seg) * elem_sizes[seg];
2811 	}
2812 
2813 	sz = (sz / DB_HDR(hdp)->page_sz) + 1;
2814 
2815 	sz *= DB_HDR(hdp)->page_sz;
2816 
2817 	return (sz);
2818 }
2819 
2820 static size_t
2821 size_db(struct di_devlink_handle *hdp, long page_sz, uint32_t *count)
2822 {
2823 	int i;
2824 	size_t sz;
2825 	cache_link_t *clp;
2826 
2827 	assert(page_sz > 0);
2828 
2829 	/* Take "NIL" element into account */
2830 	for (i = 0; i < DB_TYPES; i++) {
2831 		count[i] = 1;
2832 	}
2833 
2834 	count_node(CACHE(hdp)->root, count);
2835 
2836 	for (clp = CACHE(hdp)->dngl; clp != NULL; clp = clp->sib) {
2837 		count_link(clp, count);
2838 	}
2839 
2840 	sz = ((HDR_LEN / page_sz) + 1) * page_sz;
2841 	for (i = 0; i < DB_TYPES; i++) {
2842 		assert(count[i] >= 1);
2843 		sz += (((count[i] * elem_sizes[i]) / page_sz) + 1) * page_sz;
2844 		(void) dprintf(DBG_INFO, "N[%u]=%u\n", i, count[i]);
2845 	}
2846 	(void) dprintf(DBG_INFO, "DB size=%lu\n", (ulong_t)sz);
2847 
2848 	return (sz);
2849 }
2850 
2851 
2852 static void
2853 count_node(cache_node_t *cnp, uint32_t *count)
2854 {
2855 	cache_minor_t *cmnp;
2856 
2857 	if (cnp == NULL)
2858 		return;
2859 
2860 	count[DB_NODE]++;
2861 	count_string(cnp->path, count);
2862 
2863 	for (cmnp = cnp->minor; cmnp != NULL; cmnp = cmnp->sib) {
2864 		count_minor(cmnp, count);
2865 	}
2866 
2867 	for (cnp = cnp->child; cnp != NULL; cnp = cnp->sib) {
2868 		count_node(cnp, count);
2869 	}
2870 
2871 }
2872 
2873 static void
2874 count_minor(cache_minor_t *cmnp, uint32_t *count)
2875 {
2876 	cache_link_t *clp;
2877 
2878 	if (cmnp == NULL)
2879 		return;
2880 
2881 	count[DB_MINOR]++;
2882 	count_string(cmnp->name, count);
2883 	count_string(cmnp->nodetype, count);
2884 
2885 	for (clp = cmnp->link; clp != NULL; clp = clp->sib) {
2886 		count_link(clp, count);
2887 	}
2888 }
2889 
2890 static void
2891 count_link(cache_link_t *clp, uint32_t *count)
2892 {
2893 	if (clp == NULL)
2894 		return;
2895 
2896 	count[DB_LINK]++;
2897 	count_string(clp->path, count);
2898 	count_string(clp->content, count);
2899 }
2900 
2901 
2902 static void
2903 count_string(const char *str, uint32_t *count)
2904 {
2905 	if (str == NULL) {
2906 		(void) dprintf(DBG_ERR, "count_string: NULL argument\n");
2907 		return;
2908 	}
2909 
2910 	count[DB_STR] += strlen(str) + 1;
2911 }
2912 
2913 static uint_t
2914 hashfn(struct di_devlink_handle *hdp, const char *str)
2915 {
2916 	const char *cp;
2917 	ulong_t hval = 0;
2918 
2919 	if (str == NULL) {
2920 		return (0);
2921 	}
2922 
2923 	assert(CACHE(hdp)->hash_sz >= MIN_HASH_SIZE);
2924 
2925 	for (cp = str; *cp != '\0'; cp++) {
2926 		hval += *cp;
2927 	}
2928 
2929 	return (hval % CACHE(hdp)->hash_sz);
2930 }
2931 
2932 static int
2933 enter_update_lock(struct di_devlink_handle *hdp)
2934 {
2935 	int i, fd, rv;
2936 	struct flock lock;
2937 	char lockfile[PATH_MAX];
2938 
2939 	assert(hdp->lock_fd < 0);
2940 
2941 	get_db_path(hdp, DB_LOCK, lockfile, sizeof (lockfile));
2942 
2943 	/*
2944 	 * Record locks are per-process. Protect against multiple threads.
2945 	 */
2946 	(void) mutex_lock(&update_mutex);
2947 
2948 	if ((fd = open(lockfile, O_RDWR|O_CREAT, DB_LOCK_PERMS)) < 0) {
2949 		goto error;
2950 	}
2951 
2952 	lock.l_type = F_WRLCK;
2953 	lock.l_whence = SEEK_SET;
2954 	lock.l_start = 0;
2955 	lock.l_len = 0;
2956 
2957 	i = 1;
2958 	while ((rv = fcntl(fd, F_SETLKW, &lock)) == -1 && errno == EINTR) {
2959 		if (i < MAX_LOCK_RETRY) {
2960 			i++;
2961 		} else {
2962 			break;
2963 		}
2964 	}
2965 
2966 	if (rv == 0) {
2967 		hdp->lock_fd = fd;
2968 		return (0);
2969 	} else {
2970 		(void) close(fd);
2971 	}
2972 
2973 error:
2974 	(void) mutex_unlock(&update_mutex);
2975 
2976 	dprintf(DBG_ERR, "lockfile(%s): lock failed: %s\n", lockfile,
2977 	    strerror(errno));
2978 	return (-1);
2979 }
2980 
2981 /*
2982  * Close and re-open lock file every time so that it is recreated if deleted.
2983  */
2984 static void
2985 exit_update_lock(struct di_devlink_handle *hdp)
2986 {
2987 	struct flock unlock;
2988 
2989 	if (hdp->lock_fd < 0) {
2990 		return;
2991 	}
2992 
2993 	unlock.l_type = F_UNLCK;
2994 	unlock.l_whence = SEEK_SET;
2995 	unlock.l_start = 0;
2996 	unlock.l_len = 0;
2997 
2998 	if (fcntl(hdp->lock_fd, F_SETLK, &unlock) == -1) {
2999 		dprintf(DBG_ERR, "update lockfile: unlock failed: %s\n",
3000 		    strerror(errno));
3001 	}
3002 
3003 	(void) close(hdp->lock_fd);
3004 
3005 	hdp->lock_fd = -1;
3006 
3007 	(void) mutex_unlock(&update_mutex);
3008 }
3009 
3010 /*
3011  * returns 1 if contents is a minor node in /devices.
3012  * If mn_root is not NULL, mn_root is set to:
3013  *	if contents is a /dev node, mn_root = contents
3014  * 			OR
3015  *	if contents is a /devices node, mn_root set to the '/'
3016  *	following /devices.
3017  */
3018 int
3019 is_minor_node(const char *contents, const char **mn_root)
3020 {
3021 	char *ptr, *prefix;
3022 
3023 	prefix = "../devices/";
3024 
3025 	if ((ptr = strstr(contents, prefix)) != NULL) {
3026 
3027 		/* mn_root should point to the / following /devices */
3028 		if (mn_root != NULL) {
3029 			*mn_root = ptr += strlen(prefix) - 1;
3030 		}
3031 		return (1);
3032 	}
3033 
3034 	prefix = "/devices/";
3035 
3036 	if (strncmp(contents, prefix, strlen(prefix)) == 0) {
3037 
3038 		/* mn_root should point to the / following /devices/ */
3039 		if (mn_root != NULL) {
3040 			*mn_root = contents + strlen(prefix) - 1;
3041 		}
3042 		return (1);
3043 	}
3044 
3045 	if (mn_root != NULL) {
3046 		*mn_root = contents;
3047 	}
3048 	return (0);
3049 }
3050 
3051 static int
3052 s_readlink(const char *link, char *buf, size_t blen)
3053 {
3054 	int rv;
3055 
3056 	if ((rv = readlink(link, buf, blen)) == -1)
3057 		goto bad;
3058 
3059 	if (rv >= blen && buf[blen - 1] != '\0') {
3060 		errno = ENAMETOOLONG;
3061 		goto bad;
3062 	} else if (rv < blen) {
3063 		buf[rv] = '\0';
3064 	}
3065 
3066 	return (0);
3067 bad:
3068 	dprintf(DBG_ERR, "s_readlink: %s: failed: %s\n",
3069 	    link, strerror(errno));
3070 	return (-1);
3071 }
3072 
3073 /*
3074  * Synchronous link creation interface routines
3075  * The scope of the operation is determined by the "name" arg.
3076  * "name" can be NULL, a driver name or a devfs pathname (without /devices)
3077  *
3078  *	"name"				creates
3079  *	======				=======
3080  *
3081  *	NULL		=>		All devlinks in system
3082  *	<driver>	=>		devlinks for named driver
3083  *	/pci@1		=>		devlinks for subtree rooted at pci@1
3084  *	/pseudo/foo@0:X	=>		devlinks for minor X
3085  *
3086  * devlink_create() returns 0 on success or an errno value on failure
3087  */
3088 
3089 #define	MAX_DAEMON_ATTEMPTS 2
3090 
3091 static int
3092 devlink_create(const char *root, const char *name)
3093 {
3094 	int i;
3095 	struct dca_off dca;
3096 
3097 	assert(root);
3098 
3099 	/*
3100 	 * Convert name into arg for door_call
3101 	 */
3102 	if (dca_init(name, &dca) != 0)
3103 		return (EINVAL);
3104 
3105 	/*
3106 	 * Attempt to use the daemon first
3107 	 */
3108 	i = 0;
3109 	do {
3110 		daemon_call(root, &dca);
3111 
3112 		dprintf(DBG_INFO, "daemon_call() retval=%d\n", dca.dca_error);
3113 
3114 		/*
3115 		 * Retry only if door server isn't running
3116 		 */
3117 		if (dca.dca_error != ENOENT && dca.dca_error != EBADF) {
3118 			return (dca.dca_error);
3119 		}
3120 
3121 		dca.dca_error = 0;
3122 
3123 		/*
3124 		 * To improve performance defer this check until the first
3125 		 * failure. Safe to defer as door server checks perms.
3126 		 */
3127 		if (geteuid() != 0)
3128 			return (EPERM);
3129 	/*
3130 	 * Daemon may not be running. Try to start it.
3131 	 */
3132 	} while ((++i < MAX_DAEMON_ATTEMPTS) && start_daemon(root) == 0);
3133 
3134 	dprintf(DBG_INFO, "devlink_create: can't start daemon\n");
3135 
3136 	assert(dca.dca_error == 0);
3137 
3138 	/*
3139 	 * If the daemon cannot be started execute the devfsadm command.
3140 	 */
3141 	exec_cmd(root, &dca);
3142 
3143 	return (dca.dca_error);
3144 }
3145 
3146 /*
3147  * The "name" member of "struct dca" contains data in the following order
3148  *	root'\0'minor'\0'driver'\0'
3149  * The root component is always present at offset 0 in the "name" field.
3150  * The driver and minor are optional. If present they have a non-zero
3151  * offset in the "name" member.
3152  */
3153 static int
3154 dca_init(const char *name, struct dca_off *dcp)
3155 {
3156 	char *cp;
3157 
3158 	dcp->dca_root = 0;
3159 	dcp->dca_minor = 0;
3160 	dcp->dca_driver = 0;
3161 	dcp->dca_error = 0;
3162 	dcp->dca_flags = 0;
3163 	dcp->dca_name[0] = '\0';
3164 
3165 	name = name ? name : "/";
3166 
3167 	/*
3168 	 *  Check if name is a driver name
3169 	 */
3170 	if (*name != '/') {
3171 		(void) snprintf(dcp->dca_name, sizeof (dcp->dca_name),
3172 		    "/ %s", name);
3173 		dcp->dca_root = 0;
3174 		*(dcp->dca_name + 1) = '\0';
3175 		dcp->dca_driver = 2;
3176 		return (0);
3177 	}
3178 
3179 	(void) snprintf(dcp->dca_name, sizeof (dcp->dca_name), "%s", name);
3180 
3181 	/*
3182 	 * "/devices" not allowed in devfs pathname
3183 	 */
3184 	if (is_minor_node(name, NULL))
3185 		return (-1);
3186 
3187 	dcp->dca_root = 0;
3188 	if (cp = strrchr(dcp->dca_name, ':')) {
3189 		*cp++ = '\0';
3190 		dcp->dca_minor = cp - dcp->dca_name;
3191 	}
3192 
3193 	return (0);
3194 }
3195 
3196 
3197 #define	DAEMON_STARTUP_TIME	1 /* 1 second. This may need to be adjusted */
3198 
3199 static void
3200 daemon_call(const char *root, struct dca_off *dcp)
3201 {
3202 	door_arg_t	arg;
3203 	int		fd, door_error;
3204 	sigset_t	oset, nset;
3205 	char		synch_door[PATH_MAX];
3206 
3207 	(void) snprintf(synch_door, sizeof (synch_door),
3208 	    "%s/dev/%s", root, DEVFSADM_SYNCH_DOOR);
3209 
3210 	if ((fd = open(synch_door, O_RDONLY)) == -1) {
3211 		dcp->dca_error = errno;
3212 		dprintf(DBG_ERR, "open of %s failed: %s\n",
3213 		    synch_door, strerror(errno));
3214 		return;
3215 	}
3216 
3217 	arg.data_ptr = (char *)dcp;
3218 	arg.data_size = sizeof (*dcp);
3219 	arg.desc_ptr = NULL;
3220 	arg.desc_num = 0;
3221 	arg.rbuf = (char *)dcp;
3222 	arg.rsize = sizeof (*dcp);
3223 
3224 	/*
3225 	 * Block signals to this thread until door call
3226 	 * completes.
3227 	 */
3228 	(void) sigfillset(&nset);
3229 	(void) sigemptyset(&oset);
3230 	(void) sigprocmask(SIG_SETMASK, &nset, &oset);
3231 	if (door_call(fd, &arg)) {
3232 		door_error = 1;
3233 		dcp->dca_error = errno;
3234 	}
3235 	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
3236 
3237 	(void) close(fd);
3238 
3239 	if (door_error)
3240 		return;
3241 
3242 	assert(arg.data_ptr);
3243 
3244 	/*LINTED*/
3245 	dcp->dca_error = ((struct dca_off *)arg.data_ptr)->dca_error;
3246 
3247 	/*
3248 	 * The doors interface may return data in a different buffer
3249 	 * If that happens, deallocate buffer via munmap()
3250 	 */
3251 	if (arg.rbuf != (char *)dcp)
3252 		(void) munmap(arg.rbuf, arg.rsize);
3253 }
3254 
3255 #define	DEVFSADM_PATH	"/usr/sbin/devfsadm"
3256 #define	DEVFSADM	"devfsadm"
3257 
3258 #define	DEVFSADMD_PATH	"/usr/lib/devfsadm/devfsadmd"
3259 #define	DEVFSADM_DAEMON	"devfsadmd"
3260 
3261 static int
3262 start_daemon(const char *root)
3263 {
3264 	int rv, i = 0;
3265 	char *argv[20];
3266 
3267 	argv[i++] = DEVFSADM_DAEMON;
3268 	if (strcmp(root, "/")) {
3269 		argv[i++] = "-r";
3270 		argv[i++] = (char *)root;
3271 	}
3272 	argv[i++] = NULL;
3273 
3274 	rv = do_exec(DEVFSADMD_PATH, argv);
3275 
3276 	(void) sleep(DAEMON_STARTUP_TIME);
3277 
3278 	return (rv);
3279 }
3280 
3281 static void
3282 exec_cmd(const char *root, struct dca_off *dcp)
3283 {
3284 	int i;
3285 	char *argv[20];
3286 
3287 	i = 0;
3288 	argv[i++] = DEVFSADM;
3289 
3290 	/*
3291 	 * Load drivers only if -i is specified
3292 	 */
3293 	if (dcp->dca_driver) {
3294 		argv[i++] = "-i";
3295 		argv[i++] = &dcp->dca_name[dcp->dca_driver];
3296 	} else {
3297 		argv[i++] = "-n";
3298 	}
3299 
3300 	if (root != NULL && strcmp(root, "/") != 0) {
3301 		argv[i++] = "-r";
3302 		argv[i++] = (char *)root;
3303 	}
3304 
3305 	argv[i] = NULL;
3306 
3307 	if (do_exec(DEVFSADM_PATH, argv))
3308 		dcp->dca_error = errno;
3309 }
3310 
3311 static int
3312 do_exec(const char *path, char *const argv[])
3313 {
3314 	int i;
3315 	pid_t cpid;
3316 
3317 #ifdef	DEBUG
3318 	dprintf(DBG_INFO, "Executing %s\n\tArgument list:", path);
3319 	for (i = 0; argv[i] != NULL; i++) {
3320 		dprintf(DBG_INFO, " %s", argv[i]);
3321 	}
3322 	dprintf(DBG_INFO, "\n");
3323 #endif
3324 
3325 	if ((cpid = fork1()) == -1) {
3326 		dprintf(DBG_ERR, "fork1 failed: %s\n", strerror(errno));
3327 		return (-1);
3328 	}
3329 
3330 	if (cpid == 0) { /* child process */
3331 		int fd;
3332 
3333 		if ((fd = open("/dev/null", O_RDWR)) >= 0) {
3334 			(void) dup2(fd, fileno(stdout));
3335 			(void) dup2(fd, fileno(stderr));
3336 			(void) close(fd);
3337 
3338 			(void) execv(path, argv);
3339 		} else {
3340 			dprintf(DBG_ERR, "open of /dev/null failed: %s\n",
3341 			    strerror(errno));
3342 		}
3343 
3344 		_exit(-1);
3345 	}
3346 
3347 	/* Parent process */
3348 	if (waitpid(cpid, &i, 0) == cpid) {
3349 		if (WIFEXITED(i)) {
3350 			if (WEXITSTATUS(i) == 0) {
3351 				dprintf(DBG_STEP,
3352 				    "do_exec: child exited normally\n");
3353 				return (0);
3354 			} else
3355 				errno = EINVAL;
3356 		} else {
3357 			/*
3358 			 * The child was interrupted by a signal
3359 			 */
3360 			errno = EINTR;
3361 		}
3362 		dprintf(DBG_ERR, "child terminated abnormally: %s\n",
3363 		    strerror(errno));
3364 	} else {
3365 		dprintf(DBG_ERR, "waitpid failed: %s\n", strerror(errno));
3366 	}
3367 
3368 	return (-1);
3369 }
3370 
3371 static int
3372 walk_cache_links(di_devlink_handle_t hdp, cache_link_t *clp, link_desc_t *linkp)
3373 {
3374 	int i;
3375 
3376 	assert(HDL_RDWR(hdp) || HDL_RDONLY(hdp));
3377 
3378 	dprintf(DBG_INFO, "walk_cache_links: initial link: %s\n",
3379 	    clp ? clp->path : "<NULL>");
3380 
3381 	/*
3382 	 * First search the links under the specified minor. On the
3383 	 * 2nd pass, search the dangling list - secondary links may
3384 	 * exist on this list since they are not resolved during the
3385 	 * /dev walk.
3386 	 */
3387 	for (i = 0; i < 2; i++) {
3388 		for (; clp != NULL; clp = clp->sib) {
3389 			struct di_devlink vlink = {NULL};
3390 
3391 			assert(clp->path[0] != '/');
3392 
3393 			vlink.rel_path = clp->path;
3394 			vlink.content = clp->content;
3395 			vlink.type = attr2type(clp->attr);
3396 
3397 			if (visit_link(hdp, linkp, &vlink)
3398 			    != DI_WALK_CONTINUE) {
3399 				dprintf(DBG_INFO, "walk_cache_links: "
3400 				    "terminating at link: %s\n", clp->path);
3401 				goto out;
3402 			}
3403 		}
3404 
3405 		clp = CACHE(hdp)->dngl;
3406 	}
3407 
3408 out:
3409 
3410 	/* If i < 2, we terminated the walk prematurely */
3411 	return (i < 2 ? DI_WALK_TERMINATE : DI_WALK_CONTINUE);
3412 }
3413 
3414 static void
3415 walk_all_cache(di_devlink_handle_t hdp, link_desc_t *linkp)
3416 {
3417 	int i;
3418 	cache_link_t *clp;
3419 
3420 	dprintf(DBG_INFO, "walk_all_cache: entered\n");
3421 
3422 	for (i = 0; i < CACHE(hdp)->hash_sz; i++) {
3423 		clp = CACHE_HASH(hdp, i);
3424 		for (; clp; clp = clp->hash) {
3425 			struct di_devlink vlink = {NULL};
3426 
3427 			assert(clp->path[0] != '/');
3428 
3429 			vlink.rel_path = clp->path;
3430 			vlink.content = clp->content;
3431 			vlink.type = attr2type(clp->attr);
3432 			if (visit_link(hdp, linkp, &vlink) !=
3433 			    DI_WALK_CONTINUE) {
3434 				dprintf(DBG_INFO, "walk_all_cache: terminating "
3435 				    "walk at link: %s\n", clp->path);
3436 				return;
3437 			}
3438 		}
3439 	}
3440 }
3441 
3442 static void
3443 walk_cache_minor(di_devlink_handle_t hdp, const char *mpath, link_desc_t *linkp)
3444 {
3445 	cache_minor_t *cmnp;
3446 
3447 	assert(mpath);
3448 
3449 	if ((cmnp = lookup_minor(hdp, mpath, NULL, TYPE_CACHE)) != NULL) {
3450 		(void) walk_cache_links(hdp, cmnp->link, linkp);
3451 	} else {
3452 		dprintf(DBG_ERR, "lookup minor failed: %s\n", mpath);
3453 	}
3454 }
3455 
3456 static void
3457 walk_cache_node(di_devlink_handle_t hdp, const char *path, link_desc_t *linkp)
3458 {
3459 	cache_minor_t *cmnp;
3460 	cache_node_t *cnp;
3461 
3462 	assert(path);
3463 
3464 	if ((cnp = lookup_node(hdp, (char *)path, TYPE_CACHE)) == NULL) {
3465 		dprintf(DBG_ERR, "lookup node failed: %s\n", path);
3466 		return;
3467 	}
3468 
3469 	for (cmnp = cnp->minor; cmnp != NULL; cmnp = cmnp->sib) {
3470 		if (walk_cache_links(hdp, cmnp->link, linkp)
3471 		    == DI_WALK_TERMINATE)
3472 			break;
3473 	}
3474 }
3475 
3476 /*
3477  * Private function
3478  *
3479  * Walk cached links corresponding to the given path.
3480  *
3481  * path		path to a node or minor node.
3482  *
3483  * flags	specifies the type of devlinks to be selected.
3484  *		If DI_PRIMARY_LINK is used, only primary links are selected.
3485  *		If DI_SECONDARY_LINK is specified, only secondary links
3486  *		are selected.
3487  *		If neither flag is specified, all devlinks are selected.
3488  *
3489  * re		An extended regular expression in regex(5) format which
3490  *		selects the /dev links to be returned. The regular
3491  *		expression should use link pathnames relative to
3492  *		/dev. i.e. without the leading "/dev/" prefix.
3493  *		A NULL value matches all devlinks.
3494  */
3495 int
3496 di_devlink_cache_walk(di_devlink_handle_t hdp,
3497 	const char *re,
3498 	const char *path,
3499 	uint_t flags,
3500 	void *arg,
3501 	int (*devlink_callback)(di_devlink_t, void *))
3502 {
3503 	regex_t reg;
3504 	link_desc_t linkd = {NULL};
3505 
3506 	if (hdp == NULL || path == NULL || !link_flag(flags) ||
3507 	    !HDL_RDWR(hdp) || devlink_callback == NULL) {
3508 		errno = EINVAL;
3509 		return (-1);
3510 	}
3511 
3512 	linkd.flags = flags;
3513 	linkd.arg = arg;
3514 	linkd.fcn = devlink_callback;
3515 
3516 	if (re) {
3517 		if (regcomp(&reg, re, REG_EXTENDED) != 0)
3518 			return (-1);
3519 		linkd.regp = &reg;
3520 	}
3521 
3522 	if (minor_colon(path) == NULL) {
3523 		walk_cache_node(hdp, path, &linkd);
3524 	} else {
3525 		walk_cache_minor(hdp, path, &linkd);
3526 	}
3527 
3528 	if (re)
3529 		regfree(&reg);
3530 
3531 	return (0);
3532 }
3533 
3534 #define	DEBUG_ENV_VAR	"_DEVLINK_DEBUG"
3535 static int _devlink_debug = -1;
3536 
3537 /*
3538  * debug level is initialized to -1.
3539  * On first call into this routine, debug level is set.
3540  * If debug level is zero, debugging msgs are disabled.
3541  */
3542 static void
3543 debug_print(debug_level_t msglevel, const char *fmt, va_list ap)
3544 {
3545 	char	*cp;
3546 	int	save;
3547 
3548 	/*
3549 	 * We shouldn't be here if debug is disabled
3550 	 */
3551 	assert(_devlink_debug != 0);
3552 
3553 	/*
3554 	 * Set debug level on first call into this routine
3555 	 */
3556 	if (_devlink_debug < 0) {
3557 		if ((cp = getenv(DEBUG_ENV_VAR)) == NULL) {
3558 			_devlink_debug = 0;
3559 			return;
3560 		}
3561 
3562 		save = errno;
3563 		errno = 0;
3564 		_devlink_debug = strtol(cp, NULL, 10);
3565 		if (errno != 0 || _devlink_debug < 0)  {
3566 			_devlink_debug = 0;
3567 			errno = save;
3568 			return;
3569 		}
3570 		errno = save;
3571 
3572 		if (!_devlink_debug)
3573 			return;
3574 	}
3575 
3576 	/* debug msgs are enabled */
3577 	assert(_devlink_debug > 0);
3578 
3579 	if (_devlink_debug < msglevel)
3580 		return;
3581 
3582 
3583 	/* Print a distinctive label for error msgs */
3584 	if (msglevel == DBG_ERR) {
3585 		(void) fprintf(stderr, "[ERROR]: ");
3586 	}
3587 
3588 	(void) vfprintf(stderr, fmt, ap);
3589 }
3590 
3591 /* ARGSUSED */
3592 /* PRINTFLIKE2 */
3593 void
3594 dprintf(debug_level_t msglevel, const char *fmt, ...)
3595 {
3596 	va_list ap;
3597 
3598 	assert(msglevel > 0);
3599 
3600 	if (!_devlink_debug)
3601 		return;
3602 
3603 	va_start(ap, fmt);
3604 	debug_print(msglevel, fmt, ap);
3605 	va_end(ap);
3606 }
3607