xref: /titanic_41/usr/src/lib/libdevinfo/devinfo_devlink.c (revision fd9cb95cbb2f626355a60efb9d02c5f0a33c10e6)
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, *result;
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 	entp = malloc(sizeof (struct dirent) + PATH_MAX + 1);
2431 	if (entp == NULL) {
2432 		SET_DB_ERR(hdp);
2433 		(void) closedir(dp);
2434 		*retp = -1;
2435 		return (DI_WALK_TERMINATE);
2436 	}
2437 
2438 	(void) snprintf(cur, sizeof (cur), "%s/", dir);
2439 	len = strlen(cur);
2440 	cp = cur + len;
2441 	len = sizeof (cur) - len;
2442 
2443 	while (readdir_r(dp, entp, &result) == 0) {
2444 
2445 		if (result == NULL)
2446 			break;
2447 
2448 		if (strcmp(entp->d_name, ".") == 0 ||
2449 		    strcmp(entp->d_name, "..") == 0) {
2450 			continue;
2451 		}
2452 
2453 		(void) snprintf(cp, len, "%s", entp->d_name);
2454 
2455 		/*
2456 		 * Skip files we are not interested in.
2457 		 */
2458 		for (i = 0; i < N_SKIP_FILES; i++) {
2459 
2460 			rel = rel_path(hdp, cur);
2461 			if (rel == NULL || strcmp(rel, skip_files[i]) == 0) {
2462 				(void) dprintf(DBG_STEP,
2463 				    "do_recurse: skipping %s\n", cur);
2464 				goto next_entry;
2465 			}
2466 		}
2467 
2468 		if (lstat(cur, &sbuf) == 0) {
2469 			if (S_ISDIR(sbuf.st_mode)) {
2470 				rv = do_recurse(cur, hdp, rp, retp);
2471 			} else if (S_ISLNK(sbuf.st_mode)) {
2472 				rv = rp->fcn(hdp, rp->data, cur);
2473 			} else {
2474 				(void) dprintf(DBG_STEP,
2475 				    "do_recurse: Skipping entry: %s\n", cur);
2476 			}
2477 		} else {
2478 			(void) dprintf(DBG_ERR, "do_recurse: cur(%s): lstat"
2479 			    " failed: %s\n", cur, strerror(errno));
2480 		}
2481 
2482 next_entry:
2483 		*cp = '\0';
2484 
2485 		if (rv != DI_WALK_CONTINUE)
2486 			break;
2487 	}
2488 
2489 	free(entp);
2490 	(void) closedir(dp);
2491 
2492 	return (rv);
2493 }
2494 
2495 
2496 static int
2497 check_attr(uint32_t attr)
2498 {
2499 	switch (attr & A_LINK_TYPES) {
2500 		case A_PRIMARY:
2501 		case A_SECONDARY:
2502 			return (1);
2503 		default:
2504 			dprintf(DBG_ERR, "check_attr: incorrect attr(%u)\n",
2505 			    attr);
2506 			return (0);
2507 	}
2508 }
2509 
2510 static int
2511 attr2type(uint32_t attr)
2512 {
2513 	switch (attr & A_LINK_TYPES) {
2514 		case A_PRIMARY:
2515 			return (DI_PRIMARY_LINK);
2516 		case A_SECONDARY:
2517 			return (DI_SECONDARY_LINK);
2518 		default:
2519 			dprintf(DBG_ERR, "attr2type: incorrect attr(%u)\n",
2520 			    attr);
2521 			return (0);
2522 	}
2523 }
2524 
2525 /* Allocate new node and link it in */
2526 static cache_node_t *
2527 node_insert(
2528 	struct di_devlink_handle *hdp,
2529 	cache_node_t *pcnp,
2530 	const char *path,
2531 	int insert)
2532 {
2533 	cache_node_t *cnp;
2534 
2535 	if (path == NULL) {
2536 		errno = EINVAL;
2537 		SET_DB_ERR(hdp);
2538 		return (NULL);
2539 	}
2540 
2541 	if ((cnp = calloc(1, sizeof (cache_node_t))) == NULL) {
2542 		SET_DB_ERR(hdp);
2543 		return (NULL);
2544 	}
2545 
2546 	if ((cnp->path = strdup(path)) == NULL) {
2547 		SET_DB_ERR(hdp);
2548 		free(cnp);
2549 		return (NULL);
2550 	}
2551 
2552 	cnp->parent = pcnp;
2553 
2554 	if (pcnp == NULL) {
2555 		assert(strcmp(path, "/") == 0);
2556 		assert(CACHE(hdp)->root == NULL);
2557 		CACHE(hdp)->root = cnp;
2558 	} else if (insert == INSERT_HEAD) {
2559 		cnp->sib = pcnp->child;
2560 		pcnp->child = cnp;
2561 	} else if (CACHE_LAST(hdp) && CACHE_LAST(hdp)->node &&
2562 	    CACHE_LAST(hdp)->node->parent == pcnp &&
2563 	    CACHE_LAST(hdp)->node->sib == NULL) {
2564 
2565 		CACHE_LAST(hdp)->node->sib = cnp;
2566 
2567 	} else {
2568 		cache_node_t **pp;
2569 
2570 		for (pp = &pcnp->child; *pp != NULL; pp = &(*pp)->sib)
2571 			;
2572 		*pp = cnp;
2573 	}
2574 
2575 	return (cnp);
2576 }
2577 
2578 /*
2579  * Allocate a new minor and link it in either at the tail or head
2580  * of the minor list depending on the value of "prev".
2581  */
2582 static cache_minor_t *
2583 minor_insert(
2584 	struct di_devlink_handle *hdp,
2585 	cache_node_t *pcnp,
2586 	const char *name,
2587 	const char *nodetype,
2588 	cache_minor_t **prev)
2589 {
2590 	cache_minor_t *cmnp;
2591 
2592 	if (pcnp == NULL || name == NULL) {
2593 		errno = EINVAL;
2594 		SET_DB_ERR(hdp);
2595 		return (NULL);
2596 	}
2597 
2598 	/*
2599 	 * Some pseudo drivers don't specify nodetype. Assume pseudo if
2600 	 * nodetype is not specified.
2601 	 */
2602 	if (nodetype == NULL)
2603 		nodetype = DDI_PSEUDO;
2604 
2605 	if ((cmnp = calloc(1, sizeof (cache_minor_t))) == NULL) {
2606 		SET_DB_ERR(hdp);
2607 		return (NULL);
2608 	}
2609 
2610 	cmnp->name = strdup(name);
2611 	cmnp->nodetype = strdup(nodetype);
2612 	if (cmnp->name == NULL || cmnp->nodetype == NULL) {
2613 		SET_DB_ERR(hdp);
2614 		free(cmnp->name);
2615 		free(cmnp->nodetype);
2616 		free(cmnp);
2617 		return (NULL);
2618 	}
2619 
2620 	cmnp->node = pcnp;
2621 
2622 	/* Add to node's minor list */
2623 	if (prev == NULL) {
2624 		cmnp->sib = pcnp->minor;
2625 		pcnp->minor = cmnp;
2626 	} else {
2627 		assert(*prev == NULL);
2628 		*prev = cmnp;
2629 	}
2630 
2631 	return (cmnp);
2632 }
2633 
2634 static cache_link_t *
2635 link_insert(
2636 	struct di_devlink_handle *hdp,
2637 	cache_minor_t *cmnp,
2638 	const char *path,
2639 	const char *content,
2640 	uint32_t attr)
2641 {
2642 	cache_link_t *clp;
2643 
2644 	if (path == NULL || content == NULL || !check_attr(attr)) {
2645 		errno = EINVAL;
2646 		SET_DB_ERR(hdp);
2647 		return (NULL);
2648 	}
2649 
2650 	if ((clp = calloc(1, sizeof (cache_link_t))) == NULL) {
2651 		SET_DB_ERR(hdp);
2652 		return (NULL);
2653 	}
2654 
2655 	clp->path = strdup(path);
2656 	clp->content = strdup(content);
2657 	if (clp->path == NULL || clp->content == NULL) {
2658 		SET_DB_ERR(hdp);
2659 		link_free(&clp);
2660 		return (NULL);
2661 	}
2662 
2663 	clp->attr = attr;
2664 	hash_insert(hdp, clp);
2665 	clp->minor = cmnp;
2666 
2667 	/* Add to minor's link list */
2668 	if (cmnp != NULL) {
2669 		clp->sib = cmnp->link;
2670 		cmnp->link = clp;
2671 	} else {
2672 		clp->sib = CACHE(hdp)->dngl;
2673 		CACHE(hdp)->dngl = clp;
2674 	}
2675 
2676 	return (clp);
2677 }
2678 
2679 static void
2680 hash_insert(struct di_devlink_handle *hdp, cache_link_t *clp)
2681 {
2682 	uint_t hval;
2683 
2684 	hval = hashfn(hdp, clp->path);
2685 	clp->hash = CACHE_HASH(hdp, hval);
2686 	CACHE_HASH(hdp, hval) = clp;
2687 }
2688 
2689 
2690 static struct db_node *
2691 get_node(struct di_devlink_handle *hdp, uint32_t idx)
2692 {
2693 	return (map_seg(hdp, idx, PROT_READ, DB_NODE));
2694 }
2695 
2696 static struct db_node *
2697 set_node(struct di_devlink_handle *hdp, uint32_t idx)
2698 {
2699 	return (map_seg(hdp, idx, PROT_READ | PROT_WRITE, DB_NODE));
2700 }
2701 
2702 static struct db_minor *
2703 get_minor(struct di_devlink_handle *hdp, uint32_t idx)
2704 {
2705 	return (map_seg(hdp, idx, PROT_READ, DB_MINOR));
2706 }
2707 
2708 static struct db_minor *
2709 set_minor(struct di_devlink_handle *hdp, uint32_t idx)
2710 {
2711 	return (map_seg(hdp, idx, PROT_READ | PROT_WRITE, DB_MINOR));
2712 }
2713 
2714 static struct db_link *
2715 get_link(struct di_devlink_handle *hdp, uint32_t idx)
2716 {
2717 	return (map_seg(hdp, idx, PROT_READ, DB_LINK));
2718 }
2719 
2720 static struct db_link *
2721 set_link(struct di_devlink_handle *hdp, uint32_t idx)
2722 {
2723 	return (map_seg(hdp, idx, PROT_READ | PROT_WRITE, DB_LINK));
2724 }
2725 
2726 static char *
2727 get_string(struct di_devlink_handle *hdp, uint32_t idx)
2728 {
2729 	return (map_seg(hdp, idx, PROT_READ, DB_STR));
2730 }
2731 
2732 static char *
2733 set_string(struct di_devlink_handle *hdp, uint32_t idx)
2734 {
2735 	return (map_seg(hdp, idx, PROT_READ | PROT_WRITE, DB_STR));
2736 }
2737 
2738 
2739 /*
2740  * Returns the element corresponding to idx. If the portion of file involved
2741  * is not yet mapped, does an mmap() as well. Existing mappings are not changed.
2742  */
2743 static void *
2744 map_seg(
2745 	struct di_devlink_handle *hdp,
2746 	uint32_t idx,
2747 	int prot,
2748 	db_seg_t seg)
2749 {
2750 	int s;
2751 	off_t off;
2752 	size_t slen;
2753 	caddr_t addr;
2754 
2755 	if (idx == DB_NIL) {
2756 		return (NULL);
2757 	}
2758 
2759 	if (!VALID_INDEX(hdp, seg, idx)) {
2760 		(void) dprintf(DBG_ERR, "map_seg: seg(%d): invalid idx(%u)\n",
2761 		    seg, idx);
2762 		return (NULL);
2763 	}
2764 
2765 	/*
2766 	 * If the seg is already mapped in, use it if the access type is
2767 	 * valid.
2768 	 */
2769 	if (DB_SEG(hdp, seg) != NULL) {
2770 		if (DB_SEG_PROT(hdp, seg) != prot) {
2771 			(void) dprintf(DBG_ERR, "map_seg: illegal access: "
2772 			    "seg[%d]: idx=%u, seg_prot=%d, access=%d\n",
2773 			    seg, idx, DB_SEG_PROT(hdp, seg), prot);
2774 			return (NULL);
2775 		}
2776 		return (DB_SEG(hdp, seg) + idx * elem_sizes[seg]);
2777 	}
2778 
2779 	/*
2780 	 * Segment is not mapped. Mmap() the segment.
2781 	 */
2782 	off = seg_size(hdp, DB_HEADER);
2783 	for (s = 0; s < seg; s++) {
2784 		off += seg_size(hdp, s);
2785 	}
2786 	slen = seg_size(hdp, seg);
2787 
2788 	addr = mmap(0, slen, prot, MAP_SHARED, DB(hdp)->db_fd, off);
2789 	if (addr == MAP_FAILED) {
2790 		(void) dprintf(DBG_ERR, "map_seg: seg[%d]: mmap failed: %s\n",
2791 		    seg, strerror(errno));
2792 		(void) dprintf(DBG_ERR, "map_seg: args: len=%lu, prot=%d,"
2793 		    " fd=%d, off=%ld\n", (ulong_t)slen, prot, DB(hdp)->db_fd,
2794 		    off);
2795 		return (NULL);
2796 	}
2797 
2798 	DB_SEG(hdp, seg) = addr;
2799 	DB_SEG_PROT(hdp, seg) = prot;
2800 
2801 	(void) dprintf(DBG_STEP, "map_seg: seg[%d]: len=%lu, prot=%d, fd=%d, "
2802 	    "off=%ld, seg_base=%p\n", seg, (ulong_t)slen, prot, DB(hdp)->db_fd,
2803 	    off, (void *)addr);
2804 
2805 	return (DB_SEG(hdp, seg) + idx * elem_sizes[seg]);
2806 }
2807 
2808 /*
2809  * Computes the size of a segment rounded up to the nearest page boundary.
2810  */
2811 static size_t
2812 seg_size(struct di_devlink_handle *hdp, int seg)
2813 {
2814 	size_t sz;
2815 
2816 	assert(DB_HDR(hdp)->page_sz);
2817 
2818 	if (seg == DB_HEADER) {
2819 		sz = HDR_LEN;
2820 	} else {
2821 		assert(DB_NUM(hdp, seg) >= 1);
2822 		sz = DB_NUM(hdp, seg) * elem_sizes[seg];
2823 	}
2824 
2825 	sz = (sz / DB_HDR(hdp)->page_sz) + 1;
2826 
2827 	sz *= DB_HDR(hdp)->page_sz;
2828 
2829 	return (sz);
2830 }
2831 
2832 static size_t
2833 size_db(struct di_devlink_handle *hdp, long page_sz, uint32_t *count)
2834 {
2835 	int i;
2836 	size_t sz;
2837 	cache_link_t *clp;
2838 
2839 	assert(page_sz > 0);
2840 
2841 	/* Take "NIL" element into account */
2842 	for (i = 0; i < DB_TYPES; i++) {
2843 		count[i] = 1;
2844 	}
2845 
2846 	count_node(CACHE(hdp)->root, count);
2847 
2848 	for (clp = CACHE(hdp)->dngl; clp != NULL; clp = clp->sib) {
2849 		count_link(clp, count);
2850 	}
2851 
2852 	sz = ((HDR_LEN / page_sz) + 1) * page_sz;
2853 	for (i = 0; i < DB_TYPES; i++) {
2854 		assert(count[i] >= 1);
2855 		sz += (((count[i] * elem_sizes[i]) / page_sz) + 1) * page_sz;
2856 		(void) dprintf(DBG_INFO, "N[%u]=%u\n", i, count[i]);
2857 	}
2858 	(void) dprintf(DBG_INFO, "DB size=%lu\n", (ulong_t)sz);
2859 
2860 	return (sz);
2861 }
2862 
2863 
2864 static void
2865 count_node(cache_node_t *cnp, uint32_t *count)
2866 {
2867 	cache_minor_t *cmnp;
2868 
2869 	if (cnp == NULL)
2870 		return;
2871 
2872 	count[DB_NODE]++;
2873 	count_string(cnp->path, count);
2874 
2875 	for (cmnp = cnp->minor; cmnp != NULL; cmnp = cmnp->sib) {
2876 		count_minor(cmnp, count);
2877 	}
2878 
2879 	for (cnp = cnp->child; cnp != NULL; cnp = cnp->sib) {
2880 		count_node(cnp, count);
2881 	}
2882 
2883 }
2884 
2885 static void
2886 count_minor(cache_minor_t *cmnp, uint32_t *count)
2887 {
2888 	cache_link_t *clp;
2889 
2890 	if (cmnp == NULL)
2891 		return;
2892 
2893 	count[DB_MINOR]++;
2894 	count_string(cmnp->name, count);
2895 	count_string(cmnp->nodetype, count);
2896 
2897 	for (clp = cmnp->link; clp != NULL; clp = clp->sib) {
2898 		count_link(clp, count);
2899 	}
2900 }
2901 
2902 static void
2903 count_link(cache_link_t *clp, uint32_t *count)
2904 {
2905 	if (clp == NULL)
2906 		return;
2907 
2908 	count[DB_LINK]++;
2909 	count_string(clp->path, count);
2910 	count_string(clp->content, count);
2911 }
2912 
2913 
2914 static void
2915 count_string(const char *str, uint32_t *count)
2916 {
2917 	if (str == NULL) {
2918 		(void) dprintf(DBG_ERR, "count_string: NULL argument\n");
2919 		return;
2920 	}
2921 
2922 	count[DB_STR] += strlen(str) + 1;
2923 }
2924 
2925 static uint_t
2926 hashfn(struct di_devlink_handle *hdp, const char *str)
2927 {
2928 	const char *cp;
2929 	ulong_t hval = 0;
2930 
2931 	if (str == NULL) {
2932 		return (0);
2933 	}
2934 
2935 	assert(CACHE(hdp)->hash_sz >= MIN_HASH_SIZE);
2936 
2937 	for (cp = str; *cp != '\0'; cp++) {
2938 		hval += *cp;
2939 	}
2940 
2941 	return (hval % CACHE(hdp)->hash_sz);
2942 }
2943 
2944 static int
2945 enter_update_lock(struct di_devlink_handle *hdp)
2946 {
2947 	int i, fd, rv;
2948 	struct flock lock;
2949 	char lockfile[PATH_MAX];
2950 
2951 	assert(hdp->lock_fd < 0);
2952 
2953 	get_db_path(hdp, DB_LOCK, lockfile, sizeof (lockfile));
2954 
2955 	/*
2956 	 * Record locks are per-process. Protect against multiple threads.
2957 	 */
2958 	(void) mutex_lock(&update_mutex);
2959 
2960 	if ((fd = open(lockfile, O_RDWR|O_CREAT, DB_LOCK_PERMS)) < 0) {
2961 		goto error;
2962 	}
2963 
2964 	lock.l_type = F_WRLCK;
2965 	lock.l_whence = SEEK_SET;
2966 	lock.l_start = 0;
2967 	lock.l_len = 0;
2968 
2969 	i = 1;
2970 	while ((rv = fcntl(fd, F_SETLKW, &lock)) == -1 && errno == EINTR) {
2971 		if (i < MAX_LOCK_RETRY) {
2972 			i++;
2973 		} else {
2974 			break;
2975 		}
2976 	}
2977 
2978 	if (rv == 0) {
2979 		hdp->lock_fd = fd;
2980 		return (0);
2981 	} else {
2982 		(void) close(fd);
2983 	}
2984 
2985 error:
2986 	(void) mutex_unlock(&update_mutex);
2987 
2988 	dprintf(DBG_ERR, "lockfile(%s): lock failed: %s\n", lockfile,
2989 	    strerror(errno));
2990 	return (-1);
2991 }
2992 
2993 /*
2994  * Close and re-open lock file every time so that it is recreated if deleted.
2995  */
2996 static void
2997 exit_update_lock(struct di_devlink_handle *hdp)
2998 {
2999 	struct flock unlock;
3000 
3001 	if (hdp->lock_fd < 0) {
3002 		return;
3003 	}
3004 
3005 	unlock.l_type = F_UNLCK;
3006 	unlock.l_whence = SEEK_SET;
3007 	unlock.l_start = 0;
3008 	unlock.l_len = 0;
3009 
3010 	if (fcntl(hdp->lock_fd, F_SETLK, &unlock) == -1) {
3011 		dprintf(DBG_ERR, "update lockfile: unlock failed: %s\n",
3012 		    strerror(errno));
3013 	}
3014 
3015 	(void) close(hdp->lock_fd);
3016 
3017 	hdp->lock_fd = -1;
3018 
3019 	(void) mutex_unlock(&update_mutex);
3020 }
3021 
3022 /*
3023  * returns 1 if contents is a minor node in /devices.
3024  * If mn_root is not NULL, mn_root is set to:
3025  *	if contents is a /dev node, mn_root = contents
3026  * 			OR
3027  *	if contents is a /devices node, mn_root set to the '/'
3028  *	following /devices.
3029  */
3030 int
3031 is_minor_node(const char *contents, const char **mn_root)
3032 {
3033 	char *ptr, *prefix;
3034 
3035 	prefix = "../devices/";
3036 
3037 	if ((ptr = strstr(contents, prefix)) != NULL) {
3038 
3039 		/* mn_root should point to the / following /devices */
3040 		if (mn_root != NULL) {
3041 			*mn_root = ptr += strlen(prefix) - 1;
3042 		}
3043 		return (1);
3044 	}
3045 
3046 	prefix = "/devices/";
3047 
3048 	if (strncmp(contents, prefix, strlen(prefix)) == 0) {
3049 
3050 		/* mn_root should point to the / following /devices/ */
3051 		if (mn_root != NULL) {
3052 			*mn_root = contents + strlen(prefix) - 1;
3053 		}
3054 		return (1);
3055 	}
3056 
3057 	if (mn_root != NULL) {
3058 		*mn_root = contents;
3059 	}
3060 	return (0);
3061 }
3062 
3063 static int
3064 s_readlink(const char *link, char *buf, size_t blen)
3065 {
3066 	int rv;
3067 
3068 	if ((rv = readlink(link, buf, blen)) == -1)
3069 		goto bad;
3070 
3071 	if (rv >= blen && buf[blen - 1] != '\0') {
3072 		errno = ENAMETOOLONG;
3073 		goto bad;
3074 	} else if (rv < blen) {
3075 		buf[rv] = '\0';
3076 	}
3077 
3078 	return (0);
3079 bad:
3080 	dprintf(DBG_ERR, "s_readlink: %s: failed: %s\n",
3081 	    link, strerror(errno));
3082 	return (-1);
3083 }
3084 
3085 /*
3086  * Synchronous link creation interface routines
3087  * The scope of the operation is determined by the "name" arg.
3088  * "name" can be NULL, a driver name or a devfs pathname (without /devices)
3089  *
3090  *	"name"				creates
3091  *	======				=======
3092  *
3093  *	NULL		=>		All devlinks in system
3094  *	<driver>	=>		devlinks for named driver
3095  *	/pci@1		=>		devlinks for subtree rooted at pci@1
3096  *	/pseudo/foo@0:X	=>		devlinks for minor X
3097  *
3098  * devlink_create() returns 0 on success or an errno value on failure
3099  */
3100 
3101 #define	MAX_DAEMON_ATTEMPTS 2
3102 
3103 static int
3104 devlink_create(const char *root, const char *name)
3105 {
3106 	int i;
3107 	struct dca_off dca;
3108 
3109 	assert(root);
3110 
3111 	/*
3112 	 * Convert name into arg for door_call
3113 	 */
3114 	if (dca_init(name, &dca) != 0)
3115 		return (EINVAL);
3116 
3117 	/*
3118 	 * Attempt to use the daemon first
3119 	 */
3120 	i = 0;
3121 	do {
3122 		daemon_call(root, &dca);
3123 
3124 		dprintf(DBG_INFO, "daemon_call() retval=%d\n", dca.dca_error);
3125 
3126 		/*
3127 		 * Retry only if door server isn't running
3128 		 */
3129 		if (dca.dca_error != ENOENT && dca.dca_error != EBADF) {
3130 			return (dca.dca_error);
3131 		}
3132 
3133 		dca.dca_error = 0;
3134 
3135 		/*
3136 		 * To improve performance defer this check until the first
3137 		 * failure. Safe to defer as door server checks perms.
3138 		 */
3139 		if (geteuid() != 0)
3140 			return (EPERM);
3141 	/*
3142 	 * Daemon may not be running. Try to start it.
3143 	 */
3144 	} while ((++i < MAX_DAEMON_ATTEMPTS) && start_daemon(root) == 0);
3145 
3146 	dprintf(DBG_INFO, "devlink_create: can't start daemon\n");
3147 
3148 	assert(dca.dca_error == 0);
3149 
3150 	/*
3151 	 * If the daemon cannot be started execute the devfsadm command.
3152 	 */
3153 	exec_cmd(root, &dca);
3154 
3155 	return (dca.dca_error);
3156 }
3157 
3158 /*
3159  * The "name" member of "struct dca" contains data in the following order
3160  *	root'\0'minor'\0'driver'\0'
3161  * The root component is always present at offset 0 in the "name" field.
3162  * The driver and minor are optional. If present they have a non-zero
3163  * offset in the "name" member.
3164  */
3165 static int
3166 dca_init(const char *name, struct dca_off *dcp)
3167 {
3168 	char *cp;
3169 
3170 	dcp->dca_root = 0;
3171 	dcp->dca_minor = 0;
3172 	dcp->dca_driver = 0;
3173 	dcp->dca_error = 0;
3174 	dcp->dca_flags = 0;
3175 	dcp->dca_name[0] = '\0';
3176 
3177 	name = name ? name : "/";
3178 
3179 	/*
3180 	 *  Check if name is a driver name
3181 	 */
3182 	if (*name != '/') {
3183 		(void) snprintf(dcp->dca_name, sizeof (dcp->dca_name),
3184 		    "/ %s", name);
3185 		dcp->dca_root = 0;
3186 		*(dcp->dca_name + 1) = '\0';
3187 		dcp->dca_driver = 2;
3188 		return (0);
3189 	}
3190 
3191 	(void) snprintf(dcp->dca_name, sizeof (dcp->dca_name), "%s", name);
3192 
3193 	/*
3194 	 * "/devices" not allowed in devfs pathname
3195 	 */
3196 	if (is_minor_node(name, NULL))
3197 		return (-1);
3198 
3199 	dcp->dca_root = 0;
3200 	if (cp = strrchr(dcp->dca_name, ':')) {
3201 		*cp++ = '\0';
3202 		dcp->dca_minor = cp - dcp->dca_name;
3203 	}
3204 
3205 	return (0);
3206 }
3207 
3208 
3209 #define	DAEMON_STARTUP_TIME	1 /* 1 second. This may need to be adjusted */
3210 
3211 static void
3212 daemon_call(const char *root, struct dca_off *dcp)
3213 {
3214 	door_arg_t	arg;
3215 	int		fd, door_error;
3216 	sigset_t	oset, nset;
3217 	char		synch_door[PATH_MAX];
3218 
3219 	(void) snprintf(synch_door, sizeof (synch_door),
3220 	    "%s/dev/%s", root, DEVFSADM_SYNCH_DOOR);
3221 
3222 	if ((fd = open(synch_door, O_RDONLY)) == -1) {
3223 		dcp->dca_error = errno;
3224 		dprintf(DBG_ERR, "open of %s failed: %s\n",
3225 		    synch_door, strerror(errno));
3226 		return;
3227 	}
3228 
3229 	arg.data_ptr = (char *)dcp;
3230 	arg.data_size = sizeof (*dcp);
3231 	arg.desc_ptr = NULL;
3232 	arg.desc_num = 0;
3233 	arg.rbuf = (char *)dcp;
3234 	arg.rsize = sizeof (*dcp);
3235 
3236 	/*
3237 	 * Block signals to this thread until door call
3238 	 * completes.
3239 	 */
3240 	(void) sigfillset(&nset);
3241 	(void) sigemptyset(&oset);
3242 	(void) sigprocmask(SIG_SETMASK, &nset, &oset);
3243 	if (door_call(fd, &arg)) {
3244 		door_error = 1;
3245 		dcp->dca_error = errno;
3246 	}
3247 	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
3248 
3249 	(void) close(fd);
3250 
3251 	if (door_error)
3252 		return;
3253 
3254 	assert(arg.data_ptr);
3255 
3256 	/*LINTED*/
3257 	dcp->dca_error = ((struct dca_off *)arg.data_ptr)->dca_error;
3258 
3259 	/*
3260 	 * The doors interface may return data in a different buffer
3261 	 * If that happens, deallocate buffer via munmap()
3262 	 */
3263 	if (arg.rbuf != (char *)dcp)
3264 		(void) munmap(arg.rbuf, arg.rsize);
3265 }
3266 
3267 #define	DEVFSADM_PATH	"/usr/sbin/devfsadm"
3268 #define	DEVFSADM	"devfsadm"
3269 
3270 #define	DEVFSADMD_PATH	"/usr/lib/devfsadm/devfsadmd"
3271 #define	DEVFSADM_DAEMON	"devfsadmd"
3272 
3273 static int
3274 start_daemon(const char *root)
3275 {
3276 	int rv, i = 0;
3277 	char *argv[20];
3278 
3279 	argv[i++] = DEVFSADM_DAEMON;
3280 	if (strcmp(root, "/")) {
3281 		argv[i++] = "-r";
3282 		argv[i++] = (char *)root;
3283 	}
3284 	argv[i++] = NULL;
3285 
3286 	rv = do_exec(DEVFSADMD_PATH, argv);
3287 
3288 	(void) sleep(DAEMON_STARTUP_TIME);
3289 
3290 	return (rv);
3291 }
3292 
3293 static void
3294 exec_cmd(const char *root, struct dca_off *dcp)
3295 {
3296 	int i;
3297 	char *argv[20];
3298 
3299 	i = 0;
3300 	argv[i++] = DEVFSADM;
3301 
3302 	/*
3303 	 * Load drivers only if -i is specified
3304 	 */
3305 	if (dcp->dca_driver) {
3306 		argv[i++] = "-i";
3307 		argv[i++] = &dcp->dca_name[dcp->dca_driver];
3308 	} else {
3309 		argv[i++] = "-n";
3310 	}
3311 
3312 	if (root != NULL && strcmp(root, "/") != 0) {
3313 		argv[i++] = "-r";
3314 		argv[i++] = (char *)root;
3315 	}
3316 
3317 	argv[i] = NULL;
3318 
3319 	if (do_exec(DEVFSADM_PATH, argv))
3320 		dcp->dca_error = errno;
3321 }
3322 
3323 static int
3324 do_exec(const char *path, char *const argv[])
3325 {
3326 	int i;
3327 	pid_t cpid;
3328 
3329 #ifdef	DEBUG
3330 	dprintf(DBG_INFO, "Executing %s\n\tArgument list:", path);
3331 	for (i = 0; argv[i] != NULL; i++) {
3332 		dprintf(DBG_INFO, " %s", argv[i]);
3333 	}
3334 	dprintf(DBG_INFO, "\n");
3335 #endif
3336 
3337 	if ((cpid = fork1()) == -1) {
3338 		dprintf(DBG_ERR, "fork1 failed: %s\n", strerror(errno));
3339 		return (-1);
3340 	}
3341 
3342 	if (cpid == 0) { /* child process */
3343 		int fd;
3344 
3345 		if ((fd = open("/dev/null", O_RDWR)) >= 0) {
3346 			(void) dup2(fd, fileno(stdout));
3347 			(void) dup2(fd, fileno(stderr));
3348 			(void) close(fd);
3349 
3350 			(void) execv(path, argv);
3351 		} else {
3352 			dprintf(DBG_ERR, "open of /dev/null failed: %s\n",
3353 			    strerror(errno));
3354 		}
3355 
3356 		_exit(-1);
3357 	}
3358 
3359 	/* Parent process */
3360 	if (waitpid(cpid, &i, 0) == cpid) {
3361 		if (WIFEXITED(i)) {
3362 			if (WEXITSTATUS(i) == 0) {
3363 				dprintf(DBG_STEP,
3364 				    "do_exec: child exited normally\n");
3365 				return (0);
3366 			} else
3367 				errno = EINVAL;
3368 		} else {
3369 			/*
3370 			 * The child was interrupted by a signal
3371 			 */
3372 			errno = EINTR;
3373 		}
3374 		dprintf(DBG_ERR, "child terminated abnormally: %s\n",
3375 		    strerror(errno));
3376 	} else {
3377 		dprintf(DBG_ERR, "waitpid failed: %s\n", strerror(errno));
3378 	}
3379 
3380 	return (-1);
3381 }
3382 
3383 static int
3384 walk_cache_links(di_devlink_handle_t hdp, cache_link_t *clp, link_desc_t *linkp)
3385 {
3386 	int i;
3387 
3388 	assert(HDL_RDWR(hdp) || HDL_RDONLY(hdp));
3389 
3390 	dprintf(DBG_INFO, "walk_cache_links: initial link: %s\n",
3391 	    clp ? clp->path : "<NULL>");
3392 
3393 	/*
3394 	 * First search the links under the specified minor. On the
3395 	 * 2nd pass, search the dangling list - secondary links may
3396 	 * exist on this list since they are not resolved during the
3397 	 * /dev walk.
3398 	 */
3399 	for (i = 0; i < 2; i++) {
3400 		for (; clp != NULL; clp = clp->sib) {
3401 			struct di_devlink vlink = {NULL};
3402 
3403 			assert(clp->path[0] != '/');
3404 
3405 			vlink.rel_path = clp->path;
3406 			vlink.content = clp->content;
3407 			vlink.type = attr2type(clp->attr);
3408 
3409 			if (visit_link(hdp, linkp, &vlink)
3410 			    != DI_WALK_CONTINUE) {
3411 				dprintf(DBG_INFO, "walk_cache_links: "
3412 				    "terminating at link: %s\n", clp->path);
3413 				goto out;
3414 			}
3415 		}
3416 
3417 		clp = CACHE(hdp)->dngl;
3418 	}
3419 
3420 out:
3421 
3422 	/* If i < 2, we terminated the walk prematurely */
3423 	return (i < 2 ? DI_WALK_TERMINATE : DI_WALK_CONTINUE);
3424 }
3425 
3426 static void
3427 walk_all_cache(di_devlink_handle_t hdp, link_desc_t *linkp)
3428 {
3429 	int i;
3430 	cache_link_t *clp;
3431 
3432 	dprintf(DBG_INFO, "walk_all_cache: entered\n");
3433 
3434 	for (i = 0; i < CACHE(hdp)->hash_sz; i++) {
3435 		clp = CACHE_HASH(hdp, i);
3436 		for (; clp; clp = clp->hash) {
3437 			struct di_devlink vlink = {NULL};
3438 
3439 			assert(clp->path[0] != '/');
3440 
3441 			vlink.rel_path = clp->path;
3442 			vlink.content = clp->content;
3443 			vlink.type = attr2type(clp->attr);
3444 			if (visit_link(hdp, linkp, &vlink) !=
3445 			    DI_WALK_CONTINUE) {
3446 				dprintf(DBG_INFO, "walk_all_cache: terminating "
3447 				    "walk at link: %s\n", clp->path);
3448 				return;
3449 			}
3450 		}
3451 	}
3452 }
3453 
3454 static void
3455 walk_cache_minor(di_devlink_handle_t hdp, const char *mpath, link_desc_t *linkp)
3456 {
3457 	cache_minor_t *cmnp;
3458 
3459 	assert(mpath);
3460 
3461 	if ((cmnp = lookup_minor(hdp, mpath, NULL, TYPE_CACHE)) != NULL) {
3462 		(void) walk_cache_links(hdp, cmnp->link, linkp);
3463 	} else {
3464 		dprintf(DBG_ERR, "lookup minor failed: %s\n", mpath);
3465 	}
3466 }
3467 
3468 static void
3469 walk_cache_node(di_devlink_handle_t hdp, const char *path, link_desc_t *linkp)
3470 {
3471 	cache_minor_t *cmnp;
3472 	cache_node_t *cnp;
3473 
3474 	assert(path);
3475 
3476 	if ((cnp = lookup_node(hdp, (char *)path, TYPE_CACHE)) == NULL) {
3477 		dprintf(DBG_ERR, "lookup node failed: %s\n", path);
3478 		return;
3479 	}
3480 
3481 	for (cmnp = cnp->minor; cmnp != NULL; cmnp = cmnp->sib) {
3482 		if (walk_cache_links(hdp, cmnp->link, linkp)
3483 		    == DI_WALK_TERMINATE)
3484 			break;
3485 	}
3486 }
3487 
3488 /*
3489  * Private function
3490  *
3491  * Walk cached links corresponding to the given path.
3492  *
3493  * path		path to a node or minor node.
3494  *
3495  * flags	specifies the type of devlinks to be selected.
3496  *		If DI_PRIMARY_LINK is used, only primary links are selected.
3497  *		If DI_SECONDARY_LINK is specified, only secondary links
3498  *		are selected.
3499  *		If neither flag is specified, all devlinks are selected.
3500  *
3501  * re		An extended regular expression in regex(5) format which
3502  *		selects the /dev links to be returned. The regular
3503  *		expression should use link pathnames relative to
3504  *		/dev. i.e. without the leading "/dev/" prefix.
3505  *		A NULL value matches all devlinks.
3506  */
3507 int
3508 di_devlink_cache_walk(di_devlink_handle_t hdp,
3509 	const char *re,
3510 	const char *path,
3511 	uint_t flags,
3512 	void *arg,
3513 	int (*devlink_callback)(di_devlink_t, void *))
3514 {
3515 	regex_t reg;
3516 	link_desc_t linkd = {NULL};
3517 
3518 	if (hdp == NULL || path == NULL || !link_flag(flags) ||
3519 	    !HDL_RDWR(hdp) || devlink_callback == NULL) {
3520 		errno = EINVAL;
3521 		return (-1);
3522 	}
3523 
3524 	linkd.flags = flags;
3525 	linkd.arg = arg;
3526 	linkd.fcn = devlink_callback;
3527 
3528 	if (re) {
3529 		if (regcomp(&reg, re, REG_EXTENDED) != 0)
3530 			return (-1);
3531 		linkd.regp = &reg;
3532 	}
3533 
3534 	if (minor_colon(path) == NULL) {
3535 		walk_cache_node(hdp, path, &linkd);
3536 	} else {
3537 		walk_cache_minor(hdp, path, &linkd);
3538 	}
3539 
3540 	if (re)
3541 		regfree(&reg);
3542 
3543 	return (0);
3544 }
3545 
3546 #define	DEBUG_ENV_VAR	"_DEVLINK_DEBUG"
3547 static int _devlink_debug = -1;
3548 
3549 /*
3550  * debug level is initialized to -1.
3551  * On first call into this routine, debug level is set.
3552  * If debug level is zero, debugging msgs are disabled.
3553  */
3554 static void
3555 debug_print(debug_level_t msglevel, const char *fmt, va_list ap)
3556 {
3557 	char	*cp;
3558 	int	save;
3559 
3560 	/*
3561 	 * We shouldn't be here if debug is disabled
3562 	 */
3563 	assert(_devlink_debug != 0);
3564 
3565 	/*
3566 	 * Set debug level on first call into this routine
3567 	 */
3568 	if (_devlink_debug < 0) {
3569 		if ((cp = getenv(DEBUG_ENV_VAR)) == NULL) {
3570 			_devlink_debug = 0;
3571 			return;
3572 		}
3573 
3574 		save = errno;
3575 		errno = 0;
3576 		_devlink_debug = strtol(cp, NULL, 10);
3577 		if (errno != 0 || _devlink_debug < 0)  {
3578 			_devlink_debug = 0;
3579 			errno = save;
3580 			return;
3581 		}
3582 		errno = save;
3583 
3584 		if (!_devlink_debug)
3585 			return;
3586 	}
3587 
3588 	/* debug msgs are enabled */
3589 	assert(_devlink_debug > 0);
3590 
3591 	if (_devlink_debug < msglevel)
3592 		return;
3593 
3594 
3595 	/* Print a distinctive label for error msgs */
3596 	if (msglevel == DBG_ERR) {
3597 		(void) fprintf(stderr, "[ERROR]: ");
3598 	}
3599 
3600 	(void) vfprintf(stderr, fmt, ap);
3601 }
3602 
3603 /* ARGSUSED */
3604 /* PRINTFLIKE2 */
3605 void
3606 dprintf(debug_level_t msglevel, const char *fmt, ...)
3607 {
3608 	va_list ap;
3609 
3610 	assert(msglevel > 0);
3611 
3612 	if (!_devlink_debug)
3613 		return;
3614 
3615 	va_start(ap, fmt);
3616 	debug_print(msglevel, fmt, ap);
3617 	va_end(ap);
3618 }
3619