4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright (c) 2016 by Delphix. All rights reserved.
27 #include "libdevinfo.h"
28 #include "devinfo_devlink.h"
29 #include "device_info.h"
40 static mutex_t update_mutex
= DEFAULTMUTEX
; /* Protects update record lock */
41 static mutex_t temp_file_mutex
= DEFAULTMUTEX
; /* for file creation tests */
43 static const size_t elem_sizes
[DB_TYPES
] = {
44 sizeof (struct db_node
),
45 sizeof (struct db_minor
),
46 sizeof (struct db_link
),
51 * List of directories/files skipped while physically walking /dev
52 * Paths are relative to "<root>/dev/"
54 static const char *skip_dirs
[] = {"fd"};
55 static const char *skip_files
[] = {
61 #define N_SKIP_DIRS (sizeof (skip_dirs) / sizeof (skip_dirs[0]))
62 #define N_SKIP_FILES (sizeof (skip_files) / sizeof (skip_files[0]))
64 #define DI_TEST_DB ETCDEV "di_test_db"
68 * This file contains two sets of interfaces which operate on the reverse
69 * links database. One set (which includes di_devlink_open()/_close())
70 * allows link generators like devfsadm(1M) and ucblinks(1B) (writers) to
71 * populate the database with /devices -> /dev mappings. Another set
72 * of interfaces (which includes di_devlink_init()/_fini()) allows
73 * applications (readers) to lookup the database for /dev links corresponding
76 * Writers operate on a cached version of the database. The cache is created
77 * when di_devlink_open() is called. As links in /dev are created and removed,
78 * the cache is updated to keep it in synch with /dev. When the /dev updates
79 * are complete, the link generator calls di_devlink_close() which writes
80 * out the cache to the database.
82 * Applications which need to lookup the database, call di_devlink_init().
83 * di_devlink_init() checks the database file (if one exists). If the
84 * database is valid, it is mapped into the address space of the
85 * application. The database file consists of several segments. Each
86 * segment can be mapped in independently and is mapped on demand.
90 * ---------------------
92 * | ----------------- |
94 * | ----------------- |
96 * ---------------------
101 * ---------------------
106 * ---------------------
111 * ---------------------
116 * ---------------------
118 * Readers can lookup /dev links for a specific minor or
119 * lookup all /dev links. In the latter case, the node
120 * and minor segments are not mapped in and the reader
121 * walks through every link in the link segment.
125 di_devlink_open(const char *root_dir
, uint_t flags
)
129 struct di_devlink_handle
*hdp
;
134 * Allocate a read-write handle but open the DB in readonly
135 * mode. We do writes only to a temporary copy of the database.
137 if ((hdp
= handle_alloc(root_dir
, OPEN_RDWR
)) == NULL
) {
141 err
= open_db(hdp
, OPEN_RDONLY
);
144 * We don't want to unlink the db at this point - if we did we
145 * would be creating a window where consumers would take a slow
146 * code path (and those consumers might also trigger requests for
147 * db creation, which we are already in the process of doing).
148 * When we are done with our update, we use rename to install the
149 * latest version of the db file.
151 get_db_path(hdp
, DB_FILE
, path
, sizeof (path
));
154 * The flags argument is reserved for future use.
157 handle_free(&hdp
); /* also closes the DB */
162 if (cache_alloc(hdp
) != 0) {
170 * The most likely cause is that DB file did not exist.
171 * Call di_devlink_close() to recreate the DB file and
172 * retry di_devlink_open().
175 (void) di_devlink_close(&hdp
, 0);
181 * DB cannot be opened, just return the
182 * handle. We will recreate the DB later.
187 /* Read the database into the cache */
188 CACHE(hdp
)->update_count
= DB_HDR(hdp
)->update_count
;
189 (void) read_nodes(hdp
, NULL
, DB_HDR(hdp
)->root_idx
);
190 (void) read_links(hdp
, NULL
, DB_HDR(hdp
)->dngl_idx
);
192 (void) close_db(hdp
);
199 struct di_devlink_handle
*hdp
,
207 if (dir
= getenv(ALT_DB_DIR
)) {
208 (void) dprintf(DBG_INFO
, "get_db_path: alternate db dir: %s\n",
216 (void) snprintf(buf
, blen
, "%s/%s", dir
, fname
);
220 open_db(struct di_devlink_handle
*hdp
, int flags
)
226 uint32_t count
[DB_TYPES
] = {0};
230 assert(!DB_OPEN(hdp
));
233 if (getenv(SKIP_DB
)) {
234 (void) dprintf(DBG_INFO
, "open_db: skipping database\n");
238 if ((page_sz
= sysconf(_SC_PAGE_SIZE
)) == -1) {
243 * Use O_TRUNC flag for write access, so that the subsequent ftruncate()
244 * call will zero-fill the entire file
246 if (IS_RDONLY(flags
)) {
248 get_db_path(hdp
, DB_FILE
, path
, sizeof (path
));
250 flg
= O_RDWR
|O_CREAT
|O_TRUNC
;
251 get_db_path(hdp
, DB_TMP
, path
, sizeof (path
));
255 * Avoid triggering /dev reconfigure for read when not present
257 if (IS_RDONLY(flags
) &&
258 (strncmp(path
, "/dev/", 5) == 0) && !device_exists(path
)) {
262 if ((fd
= open(path
, flg
, DB_PERMS
)) == -1) {
266 if (IS_RDONLY(flags
)) {
268 rv
= fstat(fd
, &sbuf
);
271 flg
= PROT_READ
| PROT_WRITE
;
272 sz
= size_db(hdp
, page_sz
, count
);
273 rv
= ftruncate(fd
, sz
);
276 if (rv
== -1 || sz
< HDR_LEN
) {
283 cp
= mmap(NULL
, HDR_LEN
, flg
, MAP_SHARED
, fd
, 0);
284 if (cp
== MAP_FAILED
) {
288 DB(hdp
)->hdr
= (struct db_hdr
*)cp
;
290 DB(hdp
)->flags
= flags
;
292 if (IS_RDONLY(flags
)) {
293 rv
= invalid_db(hdp
, sz
, page_sz
);
295 rv
= init_hdr(hdp
, page_sz
, count
);
299 (void) dprintf(DBG_ERR
, "open_db: invalid DB(%s)\n", path
);
300 (void) close_db(hdp
);
303 (void) dprintf(DBG_STEP
, "open_db: DB(%s): opened\n", path
);
309 * A handle can be allocated for read-only or read-write access
311 static struct di_devlink_handle
*
312 handle_alloc(const char *root_dir
, uint_t flags
)
314 char dev_dir
[PATH_MAX
], path
[PATH_MAX
], db_dir
[PATH_MAX
];
315 struct di_devlink_handle
*hdp
, proto
= {0};
319 char can_path
[PATH_MAX
];
321 assert(flags
== OPEN_RDWR
|| flags
== OPEN_RDONLY
);
327 * NULL and the empty string are equivalent to "/"
329 if (root_dir
&& root_dir
[0] != '\0') {
331 if (root_dir
[0] != '/') {
338 assert(sizeof (dev_dir
) >= PATH_MAX
);
340 if ((realpath(root_dir
, dev_dir
) == NULL
) ||
341 (realpath(root_dir
, db_dir
) == NULL
)) {
346 * The dev dir is at /dev i.e. we are not doing a -r /altroot
351 if (strcmp(dev_dir
, "/") == 0) {
355 (void) strlcpy(db_dir
, dev_dir
, sizeof (db_dir
));
358 (void) strlcat(dev_dir
, DEV
, sizeof (dev_dir
));
359 (void) strlcat(db_dir
, ETCDEV
, sizeof (db_dir
));
362 * The following code is for install. Readers and writers need
363 * to be redirected to /tmp/etc/dev for the database file.
364 * Note that we test for readonly /etc by actually creating a
365 * file since statvfs is not a reliable method for determining
366 * readonly filesystems.
369 (void) snprintf(can_path
, sizeof (can_path
), "%s/%s", ETCDEV
, DB_FILE
);
370 if (flags
== OPEN_RDWR
&& isroot
) {
371 char di_test_db
[PATH_MAX
];
373 (void) mutex_lock(&temp_file_mutex
);
374 (void) snprintf(di_test_db
, sizeof (di_test_db
), "%s.%d",
375 DI_TEST_DB
, getpid());
376 fd
= open(di_test_db
, O_CREAT
|O_RDWR
|O_EXCL
, 0644);
377 if (fd
== -1 && errno
== EROFS
&& stat(can_path
, &sb
) == -1)
381 (void) unlink(di_test_db
);
383 (void) mutex_unlock(&temp_file_mutex
);
386 * Readers can be non-privileged so we cannot test by creating
387 * a file in /etc/dev. Instead we check if the database
388 * file is missing in /etc/dev and is present in /tmp/etc/dev
389 * and is owned by root.
391 char install_path
[PATH_MAX
];
393 (void) snprintf(install_path
, sizeof (install_path
),
394 "/tmp%s/%s", ETCDEV
, DB_FILE
);
395 if (stat(can_path
, &sb
) == -1 && stat(install_path
, &sb
)
396 != -1 && sb
.st_uid
== 0) {
402 * Check if we are in install. If we are, the database will be in
406 (void) snprintf(db_dir
, sizeof (db_dir
), "/tmp%s", ETCDEV
);
408 proto
.dev_dir
= dev_dir
;
409 proto
.db_dir
= db_dir
;
414 * Lock database if a read-write handle is being allocated.
415 * Locks are needed to protect against multiple writers.
416 * Readers don't need locks.
418 if (HDL_RDWR(&proto
)) {
419 if (enter_db_lock(&proto
, root_dir
) != 1) {
424 DB(&proto
)->db_fd
= -1;
426 hdp
= calloc(1, sizeof (struct di_devlink_handle
));
434 * The handle hdp now contains a pointer to local storage
435 * in the dev_dir field (obtained from the proto handle).
436 * In the following line, a dynamically allocated version
440 if ((hdp
->dev_dir
= strdup(proto
.dev_dir
)) == NULL
) {
445 if ((hdp
->db_dir
= strdup(proto
.db_dir
)) == NULL
) {
454 if (HDL_RDWR(&proto
)) {
455 /* Unlink DB file on error */
456 get_db_path(&proto
, DB_FILE
, path
, sizeof (path
));
458 exit_db_lock(&proto
);
465 cache_alloc(struct di_devlink_handle
*hdp
)
469 assert(HDL_RDWR(hdp
));
472 hash_sz
= DB_NUM(hdp
, DB_LINK
) / AVG_CHAIN_SIZE
;
474 hash_sz
= (hash_sz
>= MIN_HASH_SIZE
) ? hash_sz
: MIN_HASH_SIZE
;
476 CACHE(hdp
)->hash
= calloc(hash_sz
, sizeof (cache_link_t
*));
477 if (CACHE(hdp
)->hash
== NULL
) {
480 CACHE(hdp
)->hash_sz
= hash_sz
;
487 invalid_db(struct di_devlink_handle
*hdp
, size_t fsize
, long page_sz
)
493 if (DB_HDR(hdp
)->magic
!= DB_MAGIC
|| DB_HDR(hdp
)->vers
!= DB_VERSION
) {
497 if (DB_HDR(hdp
)->page_sz
== 0 || DB_HDR(hdp
)->page_sz
!= page_sz
) {
501 sz
= seg_size(hdp
, DB_HEADER
);
502 for (i
= 0; i
< DB_TYPES
; i
++) {
503 (void) dprintf(DBG_INFO
, "N[%u] = %u\n", i
, DB_NUM(hdp
, i
));
504 /* There must be at least 1 element of each type */
505 if (DB_NUM(hdp
, i
) < 1) {
508 sz
+= seg_size(hdp
, i
);
509 assert(sz
% page_sz
== 0);
516 if (!VALID_INDEX(hdp
, DB_NODE
, DB_HDR(hdp
)->root_idx
)) {
520 if (!VALID_INDEX(hdp
, DB_LINK
, DB_HDR(hdp
)->dngl_idx
)) {
529 * The last character in the string segment must be a NUL char.
531 cp
= get_string(hdp
, DB_NUM(hdp
, DB_STR
) - 1);
532 if (cp
== NULL
|| *cp
!= '\0') {
540 read_nodes(struct di_devlink_handle
*hdp
, cache_node_t
*pcnp
, uint32_t nidx
)
545 const char *fcn
= "read_nodes";
547 assert(HDL_RDWR(hdp
));
550 * parent node should be NULL only for the root node
552 if ((pcnp
== NULL
) ^ (nidx
== DB_HDR(hdp
)->root_idx
)) {
553 (void) dprintf(DBG_ERR
, "%s: invalid parent or index(%u)\n",
559 for (; dnp
= get_node(hdp
, nidx
); nidx
= dnp
->sib
) {
561 path
= get_string(hdp
, dnp
->path
);
564 * Insert at head of list to recreate original order
566 cnp
= node_insert(hdp
, pcnp
, path
, INSERT_HEAD
);
572 assert(strcmp(path
, "/") ^ (nidx
== DB_HDR(hdp
)->root_idx
));
573 assert(strcmp(path
, "/") != 0 || dnp
->sib
== DB_NIL
);
575 if (read_minors(hdp
, cnp
, dnp
->minor
) != 0 ||
576 read_nodes(hdp
, cnp
, dnp
->child
) != 0) {
580 (void) dprintf(DBG_STEP
, "%s: node[%u]: %s\n", fcn
, nidx
,
584 return (dnp
? -1 : 0);
588 read_minors(struct di_devlink_handle
*hdp
, cache_node_t
*pcnp
, uint32_t nidx
)
591 struct db_minor
*dmp
;
592 char *name
, *nodetype
;
593 const char *fcn
= "read_minors";
595 assert(HDL_RDWR(hdp
));
598 (void) dprintf(DBG_ERR
, "%s: minor[%u]: orphan minor\n", fcn
,
604 for (; dmp
= get_minor(hdp
, nidx
); nidx
= dmp
->sib
) {
606 name
= get_string(hdp
, dmp
->name
);
607 nodetype
= get_string(hdp
, dmp
->nodetype
);
609 cmnp
= minor_insert(hdp
, pcnp
, name
, nodetype
, NULL
);
615 (void) dprintf(DBG_STEP
, "%s: minor[%u]: %s\n", fcn
, nidx
,
618 if (read_links(hdp
, cmnp
, dmp
->link
) != 0) {
623 return (dmp
? -1 : 0);
627 * If the link is dangling the corresponding minor will be absent.
630 read_links(struct di_devlink_handle
*hdp
, cache_minor_t
*pcmp
, uint32_t nidx
)
634 char *path
, *content
;
636 assert(HDL_RDWR(hdp
));
638 if (nidx
!= DB_NIL
&&
639 ((pcmp
== NULL
) ^ (nidx
== DB_HDR(hdp
)->dngl_idx
))) {
640 (void) dprintf(DBG_ERR
, "read_links: invalid minor or"
641 " index(%u)\n", nidx
);
646 for (; dlp
= get_link(hdp
, nidx
); nidx
= dlp
->sib
) {
648 path
= get_string(hdp
, dlp
->path
);
649 content
= get_string(hdp
, dlp
->content
);
651 clp
= link_insert(hdp
, pcmp
, path
, content
, dlp
->attr
);
657 (void) dprintf(DBG_STEP
, "read_links: link[%u]: %s%s\n",
658 nidx
, clp
->path
, pcmp
== NULL
? "(DANGLING)" : "");
661 return (dlp
? -1 : 0);
665 di_devlink_close(di_devlink_handle_t
*pp
, int flag
)
670 uint32_t next
[DB_TYPES
] = {0};
671 struct di_devlink_handle
*hdp
;
673 if (pp
== NULL
|| *pp
== NULL
|| !HDL_RDWR(*pp
)) {
682 * The caller encountered some error in their processing.
683 * so handle isn't valid. Discard it and return success.
685 if (flag
== DI_LINK_ERROR
) {
697 * Extract the DB path before the handle is freed.
699 get_db_path(hdp
, DB_FILE
, file
, sizeof (file
));
700 get_db_path(hdp
, DB_TMP
, tmp
, sizeof (tmp
));
703 * update database with actual contents of /dev
705 (void) dprintf(DBG_INFO
, "di_devlink_close: update_count = %u\n",
706 CACHE(hdp
)->update_count
);
709 * For performance reasons, synchronization of the database
710 * with /dev is turned off by default. However, applications
711 * with appropriate permissions can request a "sync" by
712 * calling di_devlink_update().
714 if (CACHE(hdp
)->update_count
== 0) {
715 CACHE(hdp
)->update_count
= 1;
716 (void) dprintf(DBG_INFO
,
717 "di_devlink_close: synchronizing DB\n");
718 (void) synchronize_db(hdp
);
722 * Resolve dangling links AFTER synchronizing DB with /dev as the
723 * synchronization process may create dangling links.
725 resolve_dangling_links(hdp
);
728 * All changes to the cache are complete. Write out the cache
729 * to the database only if it is not empty.
731 if (CACHE_EMPTY(hdp
)) {
732 (void) dprintf(DBG_INFO
, "di_devlink_close: skipping write\n");
738 if (open_db(hdp
, OPEN_RDWR
) != 0) {
744 * Keep track of array assignments. There is at least
745 * 1 element (the "NIL" element) per type.
747 for (i
= 0; i
< DB_TYPES
; i
++) {
751 (void) write_nodes(hdp
, NULL
, CACHE_ROOT(hdp
), next
);
752 (void) write_links(hdp
, NULL
, CACHE(hdp
)->dngl
, next
);
753 DB_HDR(hdp
)->update_count
= CACHE(hdp
)->update_count
;
757 if (rv
!= 0 || DB_ERR(hdp
) || rename(tmp
, file
) != 0) {
758 (void) dprintf(DBG_ERR
, "di_devlink_close: %s error: %s\n",
759 rv
? "close_db" : "DB or rename", strerror(errno
));
768 (void) dprintf(DBG_INFO
, "di_devlink_close: wrote DB(%s)\n", file
);
774 * Inits the database header.
777 init_hdr(struct di_devlink_handle
*hdp
, long page_sz
, uint32_t *count
)
781 DB_HDR(hdp
)->magic
= DB_MAGIC
;
782 DB_HDR(hdp
)->vers
= DB_VERSION
;
783 DB_HDR(hdp
)->root_idx
= DB_NIL
;
784 DB_HDR(hdp
)->dngl_idx
= DB_NIL
;
785 DB_HDR(hdp
)->page_sz
= (uint32_t)page_sz
;
787 for (i
= 0; i
< DB_TYPES
; i
++) {
788 assert(count
[i
] >= 1);
789 DB_NUM(hdp
, i
) = count
[i
];
797 struct di_devlink_handle
*hdp
,
798 struct db_node
*pdnp
,
804 const char *fcn
= "write_nodes";
806 assert(HDL_RDWR(hdp
));
808 for (; cnp
!= NULL
; cnp
= cnp
->sib
) {
810 assert(cnp
->path
!= NULL
);
812 /* parent node should only be NULL for root node */
813 if ((pdnp
== NULL
) ^ (cnp
== CACHE_ROOT(hdp
))) {
814 (void) dprintf(DBG_ERR
, "%s: invalid parent for: %s\n",
820 assert((strcmp(cnp
->path
, "/") != 0) ^
821 (cnp
== CACHE_ROOT(hdp
)));
824 if ((dnp
= set_node(hdp
, idx
)) == NULL
) {
829 dnp
->path
= write_string(hdp
, cnp
->path
, next
);
830 if (dnp
->path
== DB_NIL
) {
834 /* commit write for this node */
838 assert(DB_HDR(hdp
)->root_idx
== DB_NIL
);
839 DB_HDR(hdp
)->root_idx
= idx
;
841 dnp
->sib
= pdnp
->child
;
845 (void) dprintf(DBG_STEP
, "%s: node[%u]: %s\n", fcn
, idx
,
848 if (write_minors(hdp
, dnp
, cnp
->minor
, next
) != 0 ||
849 write_nodes(hdp
, dnp
, cnp
->child
, next
) != 0) {
854 return (cnp
? -1 : 0);
859 struct di_devlink_handle
*hdp
,
860 struct db_node
*pdnp
,
865 struct db_minor
*dmp
;
866 const char *fcn
= "write_minors";
868 assert(HDL_RDWR(hdp
));
871 (void) dprintf(DBG_ERR
, "%s: no node for minor: %s\n", fcn
,
872 cmnp
? cmnp
->name
: "<NULL>");
877 for (; cmnp
!= NULL
; cmnp
= cmnp
->sib
) {
879 assert(cmnp
->name
!= NULL
);
881 idx
= next
[DB_MINOR
];
882 if ((dmp
= set_minor(hdp
, idx
)) == NULL
) {
887 dmp
->name
= write_string(hdp
, cmnp
->name
, next
);
888 dmp
->nodetype
= write_string(hdp
, cmnp
->nodetype
, next
);
889 if (dmp
->name
== DB_NIL
|| dmp
->nodetype
== DB_NIL
) {
890 dmp
->name
= dmp
->nodetype
= DB_NIL
;
895 /* Commit writes to this minor */
898 dmp
->sib
= pdnp
->minor
;
901 (void) dprintf(DBG_STEP
, "%s: minor[%u]: %s\n", fcn
, idx
,
904 if (write_links(hdp
, dmp
, cmnp
->link
, next
) != 0) {
909 return (cmnp
? -1 : 0);
914 struct di_devlink_handle
*hdp
,
915 struct db_minor
*pdmp
,
921 const char *fcn
= "write_links";
923 assert(HDL_RDWR(hdp
));
925 /* A NULL minor if and only if the links are dangling */
926 if (clp
!= NULL
&& ((pdmp
== NULL
) ^ (clp
== CACHE(hdp
)->dngl
))) {
927 (void) dprintf(DBG_ERR
, "%s: invalid minor for link\n", fcn
);
932 for (; clp
!= NULL
; clp
= clp
->sib
) {
934 assert(clp
->path
!= NULL
);
936 if ((pdmp
== NULL
) ^ (clp
->minor
== NULL
)) {
937 (void) dprintf(DBG_ERR
, "%s: invalid minor for link"
938 "(%s)\n", fcn
, clp
->path
);
944 if ((dlp
= set_link(hdp
, idx
)) == NULL
) {
949 dlp
->path
= write_string(hdp
, clp
->path
, next
);
950 dlp
->content
= write_string(hdp
, clp
->content
, next
);
951 if (dlp
->path
== DB_NIL
|| dlp
->content
== DB_NIL
) {
952 dlp
->path
= dlp
->content
= DB_NIL
;
957 dlp
->attr
= clp
->attr
;
959 /* Commit writes to this link */
963 dlp
->sib
= pdmp
->link
;
966 dlp
->sib
= DB_HDR(hdp
)->dngl_idx
;
967 DB_HDR(hdp
)->dngl_idx
= idx
;
970 (void) dprintf(DBG_STEP
, "%s: link[%u]: %s%s\n", fcn
, idx
,
971 clp
->path
, pdmp
== NULL
? "(DANGLING)" : "");
974 return (clp
? -1 : 0);
979 write_string(struct di_devlink_handle
*hdp
, const char *str
, uint32_t *next
)
984 assert(HDL_RDWR(hdp
));
987 (void) dprintf(DBG_ERR
, "write_string: NULL argument\n");
992 if (!VALID_STR(hdp
, idx
, str
)) {
993 (void) dprintf(DBG_ERR
, "write_string: invalid index[%u],"
994 " string(%s)\n", idx
, str
);
998 if ((dstr
= set_string(hdp
, idx
)) == NULL
) {
1002 (void) strcpy(dstr
, str
);
1004 next
[DB_STR
] += strlen(dstr
) + 1;
1010 close_db(struct di_devlink_handle
*hdp
)
1015 if (!DB_OPEN(hdp
)) {
1017 assert(DB(hdp
)->db_fd
== -1);
1018 assert(DB(hdp
)->flags
== 0);
1019 for (i
= 0; i
< DB_TYPES
; i
++) {
1020 assert(DB_SEG(hdp
, i
) == NULL
);
1021 assert(DB_SEG_PROT(hdp
, i
) == 0);
1027 /* Unmap header after unmapping all other mapped segments */
1028 for (i
= 0; i
< DB_TYPES
; i
++) {
1029 if (DB_SEG(hdp
, i
)) {
1030 sz
= seg_size(hdp
, i
);
1032 rv
+= msync(DB_SEG(hdp
, i
), sz
, MS_SYNC
);
1033 (void) munmap(DB_SEG(hdp
, i
), sz
);
1034 DB_SEG(hdp
, i
) = NULL
;
1035 DB_SEG_PROT(hdp
, i
) = 0;
1040 rv
+= msync((caddr_t
)DB_HDR(hdp
), HDR_LEN
, MS_SYNC
);
1041 (void) munmap((caddr_t
)DB_HDR(hdp
), HDR_LEN
);
1042 DB(hdp
)->hdr
= NULL
;
1044 (void) close(DB(hdp
)->db_fd
);
1045 DB(hdp
)->db_fd
= -1;
1048 return (rv
? -1 : 0);
1053 cache_free(struct di_devlink_handle
*hdp
)
1057 subtree_free(hdp
, &(CACHE_ROOT(hdp
)));
1058 assert(CACHE_LAST(hdp
) == NULL
);
1061 * Don't bother removing links from hash table chains,
1062 * as we are freeing the hash table itself.
1064 while (CACHE(hdp
)->dngl
!= NULL
) {
1065 clp
= CACHE(hdp
)->dngl
;
1066 CACHE(hdp
)->dngl
= clp
->sib
;
1067 assert(clp
->minor
== NULL
);
1071 assert((CACHE(hdp
)->hash
== NULL
) ^ (CACHE(hdp
)->hash_sz
!= 0));
1073 free(CACHE(hdp
)->hash
);
1074 CACHE(hdp
)->hash
= NULL
;
1075 CACHE(hdp
)->hash_sz
= 0;
1079 handle_free(struct di_devlink_handle
**pp
)
1081 struct di_devlink_handle
*hdp
= *pp
;
1088 (void) close_db(hdp
);
1093 assert(hdp
->lock_fd
== -1);
1101 * Frees the tree rooted at a node. Siblings of the subtree root
1102 * have to be handled by the caller.
1105 subtree_free(struct di_devlink_handle
*hdp
, cache_node_t
**pp
)
1109 cache_minor_t
*cmnp
;
1111 if (pp
== NULL
|| *pp
== NULL
)
1114 while ((*pp
)->child
!= NULL
) {
1116 (*pp
)->child
= np
->sib
;
1117 subtree_free(hdp
, &np
);
1120 while ((*pp
)->minor
!= NULL
) {
1121 cmnp
= (*pp
)->minor
;
1122 (*pp
)->minor
= cmnp
->sib
;
1124 while (cmnp
->link
!= NULL
) {
1126 cmnp
->link
= clp
->sib
;
1127 rm_link_from_hash(hdp
, clp
);
1130 minor_free(hdp
, &cmnp
);
1137 rm_link_from_hash(struct di_devlink_handle
*hdp
, cache_link_t
*clp
)
1145 if (clp
->path
== NULL
)
1148 hval
= hashfn(hdp
, clp
->path
);
1149 pp
= &(CACHE_HASH(hdp
, hval
));
1150 for (; *pp
!= NULL
; pp
= &(*pp
)->hash
) {
1158 dprintf(DBG_ERR
, "rm_link_from_hash: link(%s) not found\n", clp
->path
);
1161 static cache_link_t
*
1162 link_hash(di_devlink_handle_t hdp
, const char *link
, uint_t flags
)
1165 cache_link_t
**pp
, *clp
;
1170 hval
= hashfn(hdp
, link
);
1171 pp
= &(CACHE_HASH(hdp
, hval
));
1172 for (; (clp
= *pp
) != NULL
; pp
= &clp
->hash
) {
1173 if (strcmp(clp
->path
, link
) == 0) {
1181 if ((flags
& UNLINK_FROM_HASH
) == UNLINK_FROM_HASH
) {
1189 static cache_minor_t
*
1190 link2minor(struct di_devlink_handle
*hdp
, cache_link_t
*clp
)
1193 const char *minor_path
;
1194 char *cp
, buf
[PATH_MAX
], link
[PATH_MAX
];
1195 char abspath
[PATH_MAX
];
1198 if (TYPE_PRI(attr2type(clp
->attr
))) {
1200 * For primary link, content should point to a /devices node.
1202 if (!is_minor_node(clp
->content
, &minor_path
)) {
1206 return (lookup_minor(hdp
, minor_path
, NULL
,
1207 TYPE_CACHE
|CREATE_FLAG
));
1212 * If secondary, the primary link is derived from the secondary
1213 * link contents. Secondary link contents can have two formats:
1214 * audio -> /dev/sound/0
1219 if (strncmp(clp
->content
, DEV
"/", strlen(DEV
"/")) == 0) {
1220 cp
= &clp
->content
[strlen(DEV
"/")];
1221 } else if (clp
->content
[0] != '/') {
1222 if ((cp
= strrchr(clp
->path
, '/')) != NULL
) {
1223 char savechar
= *(cp
+ 1);
1225 (void) snprintf(buf
, sizeof (buf
), "%s", clp
->path
);
1226 *(cp
+ 1) = savechar
;
1228 (void) strlcat(buf
, clp
->content
, sizeof (buf
));
1235 * Lookup the primary link if possible and find its minor.
1237 if ((plp
= link_hash(hdp
, cp
, 0)) != NULL
&& plp
->minor
!= NULL
) {
1238 return (plp
->minor
);
1241 /* realpath() used only as a last resort because it is expensive */
1243 (void) snprintf(link
, sizeof (link
), "%s/%s", hdp
->dev_dir
, clp
->path
);
1247 assert(sizeof (buf
) >= PATH_MAX
);
1251 * A realpath attempt to lookup a dangling link can invoke implicit
1252 * reconfig so verify there's an actual device behind the link first.
1254 if (lstat(link
, &st
) == -1)
1256 if (S_ISLNK(st
.st_mode
)) {
1257 if (s_readlink(link
, buf
, sizeof (buf
)) < 0)
1259 if (buf
[0] != '/') {
1261 size_t n
= sizeof (abspath
);
1262 if (strlcpy(abspath
, link
, n
) >= n
)
1264 p
= strrchr(abspath
, '/') + 1;
1266 n
= sizeof (abspath
) - strlen(p
);
1267 if (strlcpy(p
, buf
, n
) >= n
)
1270 if (strlcpy(abspath
, buf
, sizeof (abspath
)) >=
1274 if (!device_exists(abspath
))
1278 if (s_realpath(link
, buf
) == NULL
|| !is_minor_node(buf
, &minor_path
)) {
1281 return (lookup_minor(hdp
, minor_path
, NULL
, TYPE_CACHE
|CREATE_FLAG
));
1286 resolve_dangling_links(struct di_devlink_handle
*hdp
)
1288 cache_minor_t
*cmnp
;
1289 cache_link_t
*clp
, **pp
;
1291 for (pp
= &(CACHE(hdp
)->dngl
); *pp
!= NULL
; ) {
1293 if ((cmnp
= link2minor(hdp
, clp
)) != NULL
) {
1295 clp
->sib
= cmnp
->link
;
1297 assert(clp
->minor
== NULL
);
1300 dprintf(DBG_INFO
, "resolve_dangling_links: link(%s):"
1301 " unresolved\n", clp
->path
);
1309 * The elements are assumed to be detached from the cache tree.
1312 node_free(cache_node_t
**pp
)
1314 cache_node_t
*cnp
= *pp
;
1326 minor_free(struct di_devlink_handle
*hdp
, cache_minor_t
**pp
)
1328 cache_minor_t
*cmnp
= *pp
;
1335 if (CACHE_LAST(hdp
) == cmnp
) {
1336 dprintf(DBG_STEP
, "minor_free: last_minor(%s)\n", cmnp
->name
);
1337 CACHE_LAST(hdp
) = NULL
;
1341 free(cmnp
->nodetype
);
1346 link_free(cache_link_t
**pp
)
1348 cache_link_t
*clp
= *pp
;
1361 * Returns the ':' preceding the minor name
1364 minor_colon(const char *path
)
1368 if ((cp
= strrchr(path
, '/')) == NULL
) {
1372 return (strchr(cp
, ':'));
1377 struct di_devlink_handle
*hdp
,
1378 const char *minor_path
,
1379 const char *nodetype
,
1384 char pdup
[PATH_MAX
];
1385 const char *fcn
= "lookup_minor";
1387 if (minor_path
== NULL
) {
1392 (void) snprintf(pdup
, sizeof (pdup
), "%s", minor_path
);
1394 if ((colon
= minor_colon(pdup
)) == NULL
) {
1395 (void) dprintf(DBG_ERR
, "%s: invalid minor path(%s)\n", fcn
,
1402 if ((vp
= get_last_minor(hdp
, pdup
, colon
+ 1, flags
)) != NULL
) {
1406 if ((vp
= lookup_node(hdp
, pdup
, flags
)) == NULL
) {
1407 (void) dprintf(DBG_ERR
, "%s: node(%s) not found\n", fcn
, pdup
);
1412 if (LOOKUP_CACHE(flags
)) {
1415 pp
= &((cache_node_t
*)vp
)->minor
;
1416 for (; *pp
!= NULL
; pp
= &(*pp
)->sib
) {
1417 if (strcmp((*pp
)->name
, colon
+ 1) == 0)
1421 if (*pp
== NULL
&& CREATE_ELEM(flags
)) {
1422 *pp
= minor_insert(hdp
, vp
, colon
+ 1, nodetype
, pp
);
1424 set_last_minor(hdp
, *pp
, flags
);
1430 struct db_minor
*dmp
;
1432 nidx
= (((struct db_node
*)vp
)->minor
);
1433 for (; dmp
= get_minor(hdp
, nidx
); nidx
= dmp
->sib
) {
1434 cp
= get_string(hdp
, dmp
->name
);
1435 if (cp
&& strcmp(cp
, colon
+ 1) == 0)
1443 lookup_node(struct di_devlink_handle
*hdp
, char *path
, const int flags
)
1445 struct tnode tnd
= {NULL
};
1447 if (tnd
.node
= get_last_node(hdp
, path
, flags
))
1453 if (walk_tree(path
, &tnd
, visit_node
) != 0)
1460 * last_minor is used for nodes of TYPE_CACHE only.
1463 get_last_node(struct di_devlink_handle
*hdp
, const char *path
, int flags
)
1468 if (getenv(SKIP_LAST_CACHE
)) {
1469 (void) dprintf(DBG_INFO
, "get_last_node: SKIPPING \"last\" "
1475 if (!LOOKUP_CACHE(flags
) || CACHE_LAST(hdp
) == NULL
||
1476 CACHE_LAST(hdp
)->node
== NULL
) {
1480 cnp
= CACHE_LAST(hdp
)->node
;
1481 if (strcmp(cnp
->path
, path
) == 0) {
1486 if (cnp
&& strcmp(cnp
->path
, path
) == 0) {
1495 struct di_devlink_handle
*hdp
,
1496 const char *devfs_path
,
1497 const char *minor_name
,
1500 cache_minor_t
*cmnp
;
1503 if (getenv(SKIP_LAST_CACHE
)) {
1504 (void) dprintf(DBG_INFO
, "get_last_minor: SKIPPING \"last\" "
1510 if (!LOOKUP_CACHE(flags
) || CACHE_LAST(hdp
) == NULL
) {
1514 cmnp
= CACHE_LAST(hdp
);
1515 if (strcmp(cmnp
->name
, minor_name
) == 0 && cmnp
->node
&&
1516 strcmp(cmnp
->node
->path
, devfs_path
) == 0) {
1521 if (cmnp
&& strcmp(cmnp
->name
, minor_name
) == 0 && cmnp
->node
&&
1522 strcmp(cmnp
->node
->path
, devfs_path
) == 0) {
1523 set_last_minor(hdp
, cmnp
, TYPE_CACHE
);
1531 set_last_minor(struct di_devlink_handle
*hdp
, cache_minor_t
*cmnp
, int flags
)
1534 if (getenv(SKIP_LAST_CACHE
)) {
1535 (void) dprintf(DBG_INFO
, "set_last_minor: SKIPPING \"last\" "
1541 if (LOOKUP_CACHE(flags
) && cmnp
) {
1542 CACHE_LAST(hdp
) = cmnp
;
1548 * Returns 0 if normal return or -1 otherwise.
1554 int (*node_callback
)(const char *path
, void *arg
))
1556 char *slash
, buf
[PATH_MAX
];
1558 if (cur
== NULL
|| cur
[0] != '/' || strlen(cur
) > sizeof (buf
) - 1) {
1563 (void) strcpy(buf
, "/");
1567 if (node_callback(buf
, arg
) != DI_WALK_CONTINUE
)
1577 * There is a next component(s). Append a "/" separator for all
1578 * but the first (root) component.
1580 if (buf
[1] != '\0') {
1581 (void) strlcat(buf
, "/", sizeof (buf
));
1584 if (slash
= strchr(cur
, '/')) {
1586 (void) strlcat(buf
, cur
, sizeof (buf
));
1590 (void) strlcat(buf
, cur
, sizeof (buf
));
1601 visit_node(const char *path
, void *arg
)
1603 struct tnode
*tnp
= arg
;
1605 if (LOOKUP_CACHE(tnp
->flags
)) {
1607 cache_node_t
*cnp
= tnp
->node
;
1609 cnp
= (cnp
) ? cnp
->child
: CACHE_ROOT(tnp
->handle
);
1611 for (; cnp
!= NULL
; cnp
= cnp
->sib
) {
1612 if (strcmp(cnp
->path
, path
) == 0)
1615 if (cnp
== NULL
&& CREATE_ELEM(tnp
->flags
)) {
1616 cnp
= node_insert(tnp
->handle
, tnp
->node
, path
,
1622 struct db_node
*dnp
= tnp
->node
;
1624 dnp
= (dnp
) ? get_node(tnp
->handle
, dnp
->child
)
1625 : get_node(tnp
->handle
, DB_HDR(tnp
->handle
)->root_idx
);
1627 for (; dnp
!= NULL
; dnp
= get_node(tnp
->handle
, dnp
->sib
)) {
1628 cp
= get_string(tnp
->handle
, dnp
->path
);
1629 if (cp
&& strcmp(cp
, path
) == 0) {
1637 * Terminate walk if node is not found for a path component.
1639 return (tnp
->node
? DI_WALK_CONTINUE
: DI_WALK_TERMINATE
);
1643 minor_delete(di_devlink_handle_t hdp
, cache_minor_t
*cmnp
)
1646 cache_minor_t
**mpp
;
1647 const char *fcn
= "minor_delete";
1649 (void) dprintf(DBG_STEP
, "%s: removing minor: %s\n", fcn
, cmnp
->name
);
1651 /* detach minor from node */
1652 if (cmnp
->node
!= NULL
) {
1653 mpp
= &cmnp
->node
->minor
;
1654 for (; *mpp
!= NULL
; mpp
= &(*mpp
)->sib
) {
1660 (void) dprintf(DBG_ERR
, "%s: dangling minor: %s\n",
1666 (void) dprintf(DBG_ERR
, "%s: orphan minor(%s)\n", fcn
,
1670 delete_unused_nodes(hdp
, cmnp
->node
);
1675 /* Move all remaining links to dangling list */
1676 for (lpp
= &cmnp
->link
; *lpp
!= NULL
; lpp
= &(*lpp
)->sib
) {
1677 (*lpp
)->minor
= NULL
;
1679 *lpp
= CACHE(hdp
)->dngl
;
1680 CACHE(hdp
)->dngl
= cmnp
->link
;
1683 minor_free(hdp
, &cmnp
);
1687 delete_unused_nodes(di_devlink_handle_t hdp
, cache_node_t
*cnp
)
1690 const char *fcn
= "delete_unused_nodes";
1695 if (cnp
->minor
!= NULL
|| cnp
->child
!= NULL
)
1698 (void) dprintf(DBG_INFO
, "%s: removing unused node: %s\n", fcn
,
1701 /* Unlink node from tree */
1702 if (cnp
->parent
!= NULL
) {
1703 npp
= &cnp
->parent
->child
;
1704 for (; *npp
!= NULL
; npp
= &(*npp
)->sib
) {
1710 (void) dprintf(DBG_ERR
, "%s: dangling node: %s\n", fcn
,
1715 } else if (cnp
== CACHE_ROOT(hdp
)) {
1716 CACHE_ROOT(hdp
) = NULL
;
1718 (void) dprintf(DBG_ERR
, "%s: orphan node (%s)\n", fcn
,
1722 delete_unused_nodes(hdp
, cnp
->parent
);
1724 cnp
->parent
= cnp
->sib
= NULL
;
1730 rm_link(di_devlink_handle_t hdp
, const char *link
)
1733 const char *fcn
= "rm_link";
1735 if (hdp
== NULL
|| DB_ERR(hdp
) || link
== NULL
|| link
[0] == '/' ||
1736 (!HDL_RDWR(hdp
) && !HDL_RDONLY(hdp
))) {
1737 dprintf(DBG_ERR
, "%s: %s: invalid args\n",
1738 fcn
, link
? link
: "<NULL>");
1743 dprintf(DBG_STEP
, "%s: link(%s)\n", fcn
, link
);
1745 if ((clp
= link_hash(hdp
, link
, UNLINK_FROM_HASH
)) == NULL
) {
1749 link_delete(hdp
, clp
);
1755 di_devlink_rm_link(di_devlink_handle_t hdp
, const char *link
)
1757 if (hdp
== NULL
|| !HDL_RDWR(hdp
)) {
1762 return (rm_link(hdp
, link
));
1766 link_delete(di_devlink_handle_t hdp
, cache_link_t
*clp
)
1769 const char *fcn
= "link_delete";
1771 (void) dprintf(DBG_STEP
, "%s: removing link: %s\n", fcn
, clp
->path
);
1773 if (clp
->minor
== NULL
)
1774 pp
= &(CACHE(hdp
)->dngl
);
1776 pp
= &clp
->minor
->link
;
1778 for (; *pp
!= NULL
; pp
= &(*pp
)->sib
) {
1784 (void) dprintf(DBG_ERR
, "%s: link(%s) not on list\n",
1790 delete_unused_minor(hdp
, clp
->minor
);
1798 delete_unused_minor(di_devlink_handle_t hdp
, cache_minor_t
*cmnp
)
1803 if (cmnp
->link
!= NULL
)
1806 dprintf(DBG_STEP
, "delete_unused_minor: removing minor(%s)\n",
1809 minor_delete(hdp
, cmnp
);
1813 di_devlink_add_link(
1814 di_devlink_handle_t hdp
,
1816 const char *content
,
1819 return (add_link(hdp
, link
, content
, flags
) != NULL
? 0 : -1);
1822 static cache_link_t
*
1824 struct di_devlink_handle
*hdp
,
1826 const char *content
,
1831 cache_minor_t
*cmnp
;
1832 const char *fcn
= "add_link";
1834 if (hdp
== NULL
|| DB_ERR(hdp
) || link
== NULL
||
1835 link
[0] == '/' || content
== NULL
|| !link_flag(flags
) ||
1836 (!HDL_RDWR(hdp
) && !HDL_RDONLY(hdp
))) {
1837 dprintf(DBG_ERR
, "%s: %s: invalid args\n",
1838 fcn
, link
? link
: "<NULL>");
1843 if ((clp
= link_hash(hdp
, link
, 0)) != NULL
) {
1844 if (link_cmp(clp
, content
, LINK_TYPE(flags
)) != 0) {
1845 (void) rm_link(hdp
, link
);
1851 if (TYPE_PRI(flags
)) {
1852 const char *minor_path
= NULL
;
1854 if (!is_minor_node(content
, &minor_path
)) {
1855 (void) dprintf(DBG_ERR
, "%s: invalid content(%s)"
1856 " for primary link\n", fcn
, content
);
1860 if ((cmnp
= lookup_minor(hdp
, minor_path
, NULL
,
1861 TYPE_CACHE
|CREATE_FLAG
)) == NULL
) {
1867 * Defer resolving a secondary link to a minor until the
1868 * database is closed. This ensures that the primary link
1869 * (required for a successful resolve) has also been created.
1875 return (link_insert(hdp
, cmnp
, link
, content
, attr
));
1879 * Returns 0 on match or 1 otherwise.
1882 link_cmp(cache_link_t
*clp
, const char *content
, int type
)
1884 if (strcmp(clp
->content
, content
) != 0)
1887 if (attr2type(clp
->attr
) != type
)
1894 di_devlink_update(di_devlink_handle_t hdp
)
1896 if (hdp
== NULL
|| !HDL_RDWR(hdp
) || DB_ERR(hdp
)) {
1902 * Reset the counter to schedule a synchronization with /dev on the next
1903 * di_devlink_close().
1905 CACHE(hdp
)->update_count
= 0;
1911 synchronize_db(di_devlink_handle_t hdp
)
1915 char pdup
[PATH_MAX
];
1916 recurse_t rec
= {NULL
};
1917 const char *fcn
= "synchronize_db";
1920 rec
.fcn
= cache_dev_link
;
1923 * Walk through $ROOT/dev, reading every link and marking the
1924 * corresponding cached version as valid(adding new links as needed).
1925 * Then walk through the cache and remove all unmarked links.
1927 if (recurse_dev(hdp
, &rec
) != 0) {
1931 for (hval
= 0; hval
< CACHE(hdp
)->hash_sz
; hval
++) {
1932 for (clp
= CACHE_HASH(hdp
, hval
); clp
!= NULL
; ) {
1933 if (GET_VALID_ATTR(clp
->attr
)) {
1934 CLR_VALID_ATTR(clp
->attr
);
1940 * The link is stale, so remove it. Since the link
1941 * will be destroyed, use a copy of the link path to
1942 * invoke the remove function.
1944 (void) snprintf(pdup
, sizeof (pdup
), "%s", clp
->path
);
1946 (void) dprintf(DBG_STEP
, "%s: removing invalid link:"
1947 " %s\n", fcn
, pdup
);
1948 (void) di_devlink_rm_link(hdp
, pdup
);
1952 (void) dprintf(DBG_STEP
, "%s: update completed\n", fcn
);
1957 static di_devlink_handle_t
1958 di_devlink_init_impl(const char *root
, const char *name
, uint_t flags
)
1962 if ((flags
!= 0 && flags
!= DI_MAKE_LINK
) ||
1963 (flags
== 0 && name
!= NULL
)) {
1968 if ((flags
== DI_MAKE_LINK
) &&
1969 (err
= devlink_create(root
, name
, DCA_DEVLINK_CACHE
))) {
1974 (void) dprintf(DBG_INFO
, "devlink_init_impl: success\n");
1976 return (devlink_snapshot(root
));
1980 di_devlink_init(const char *name
, uint_t flags
)
1982 return (di_devlink_init_impl("/", name
, flags
));
1986 di_devlink_init_root(const char *root
, const char *name
, uint_t flags
)
1988 return (di_devlink_init_impl(root
, name
, flags
));
1991 static di_devlink_handle_t
1992 devlink_snapshot(const char *root_dir
)
1994 struct di_devlink_handle
*hdp
;
1996 static int retried
= 0;
1998 if ((hdp
= handle_alloc(root_dir
, OPEN_RDONLY
)) == NULL
) {
2003 * We don't need to lock. If a consumer wants the very latest db
2004 * then it must perform a di_devlink_init with the DI_MAKE_LINK
2005 * flag to force a sync with devfsadm first. Otherwise, the
2006 * current database file is opened and mmaped on demand: the rename
2007 * associated with a db update does not change the contents
2008 * of files already opened.
2010 again
: err
= open_db(hdp
, OPEN_RDONLY
);
2013 * If we failed to open DB the most likely cause is that DB file did
2014 * not exist. If we have not done a retry, signal devfsadmd to
2015 * recreate the DB file and retry. If we fail to open the DB after
2016 * retry, we will walk /dev in di_devlink_walk.
2018 if (err
&& (retried
== 0)) {
2020 (void) devlink_create(root_dir
, NULL
, DCA_DEVLINK_SYNC
);
2027 di_devlink_fini(di_devlink_handle_t
*pp
)
2029 if (pp
== NULL
|| *pp
== NULL
|| !HDL_RDONLY(*pp
)) {
2034 /* Freeing the handle also closes the DB */
2042 di_devlink_handle_t hdp
,
2044 const char *minor_path
,
2047 int (*devlink_callback
)(di_devlink_t
, void *))
2051 link_desc_t linkd
= {NULL
};
2053 if (hdp
== NULL
|| !HDL_RDONLY(hdp
)) {
2058 linkd
.minor_path
= minor_path
;
2059 linkd
.flags
= flags
;
2061 linkd
.fcn
= devlink_callback
;
2064 if (regcomp(®
, re
, REG_EXTENDED
) != 0)
2069 if (check_args(&linkd
)) {
2076 rv
= walk_db(hdp
, &linkd
);
2078 rv
= walk_dev(hdp
, &linkd
);
2086 return (rv
? -1 : 0);
2090 link_flag(uint_t flags
)
2092 if (flags
!= 0 && flags
!= DI_PRIMARY_LINK
&&
2093 flags
!= DI_SECONDARY_LINK
) {
2101 * Currently allowed flags are:
2106 check_args(link_desc_t
*linkp
)
2108 if (linkp
->fcn
== NULL
)
2111 if (!link_flag(linkp
->flags
)) {
2116 * Minor path can be NULL. In that case, all links will be
2119 if (linkp
->minor_path
) {
2120 if (linkp
->minor_path
[0] != '/' ||
2121 minor_colon(linkp
->minor_path
) == NULL
) {
2131 * Walk all links in database if no minor path is specified.
2134 walk_db(struct di_devlink_handle
*hdp
, link_desc_t
*linkp
)
2136 assert(DB_OPEN(hdp
));
2138 if (linkp
->minor_path
== NULL
) {
2139 return (walk_all_links(hdp
, linkp
));
2141 return (walk_matching_links(hdp
, linkp
));
2146 cache_dev(struct di_devlink_handle
*hdp
)
2149 recurse_t rec
= {NULL
};
2152 assert(HDL_RDONLY(hdp
));
2154 if (hdp
== NULL
|| !HDL_RDONLY(hdp
)) {
2155 dprintf(DBG_ERR
, "cache_dev: invalid arg\n");
2161 CACHE(hdp
)->hash
= calloc(sz
, sizeof (cache_link_t
*));
2162 if (CACHE(hdp
)->hash
== NULL
) {
2165 CACHE(hdp
)->hash_sz
= sz
;
2168 rec
.fcn
= cache_dev_link
;
2170 return (recurse_dev(hdp
, &rec
));
2174 walk_dev(struct di_devlink_handle
*hdp
, link_desc_t
*linkp
)
2176 assert(hdp
&& linkp
);
2177 assert(!DB_OPEN(hdp
));
2178 assert(HDL_RDONLY(hdp
));
2180 if (hdp
== NULL
|| !HDL_RDONLY(hdp
) || DB_OPEN(hdp
)) {
2181 dprintf(DBG_ERR
, "walk_dev: invalid args\n");
2185 if (CACHE_EMPTY(hdp
) && cache_dev(hdp
) != 0) {
2186 dprintf(DBG_ERR
, "walk_dev: /dev caching failed\n");
2190 if (linkp
->minor_path
)
2191 walk_cache_minor(hdp
, linkp
->minor_path
, linkp
);
2193 walk_all_cache(hdp
, linkp
);
2195 return (linkp
->retval
);
2200 cache_dev_link(struct di_devlink_handle
*hdp
, void *data
, const char *link
)
2204 char content
[PATH_MAX
];
2206 assert(HDL_RDWR(hdp
) || HDL_RDONLY(hdp
));
2208 if (s_readlink(link
, content
, sizeof (content
)) < 0) {
2209 return (DI_WALK_CONTINUE
);
2212 if (is_minor_node(content
, NULL
)) {
2213 flags
= DI_PRIMARY_LINK
;
2215 flags
= DI_SECONDARY_LINK
;
2218 assert(strncmp(link
, hdp
->dev_dir
, strlen(hdp
->dev_dir
)) == 0);
2221 * Store only the part after <root-dir>/dev/
2223 link
+= strlen(hdp
->dev_dir
) + 1;
2225 if ((clp
= add_link(hdp
, link
, content
, flags
)) != NULL
) {
2226 SET_VALID_ATTR(clp
->attr
);
2229 return (DI_WALK_CONTINUE
);
2234 walk_all_links(struct di_devlink_handle
*hdp
, link_desc_t
*linkp
)
2236 struct db_link
*dlp
;
2237 uint32_t nidx
, eidx
;
2239 assert(DB_NUM(hdp
, DB_LINK
) >= 1);
2241 eidx
= DB_NUM(hdp
, DB_LINK
);
2243 /* Skip the "NIL" (index == 0) link. */
2244 for (nidx
= 1; nidx
< eidx
; nidx
++) {
2246 * Declare this local to the block with zero
2247 * initializer so that it gets rezeroed
2248 * for each iteration.
2250 struct di_devlink vlink
= {NULL
};
2252 if ((dlp
= get_link(hdp
, nidx
)) == NULL
)
2255 vlink
.rel_path
= get_string(hdp
, dlp
->path
);
2256 vlink
.content
= get_string(hdp
, dlp
->content
);
2257 vlink
.type
= attr2type(dlp
->attr
);
2259 if (visit_link(hdp
, linkp
, &vlink
) != DI_WALK_CONTINUE
) {
2264 return (linkp
->retval
);
2268 walk_matching_links(struct di_devlink_handle
*hdp
, link_desc_t
*linkp
)
2271 struct db_link
*dlp
;
2272 struct db_minor
*dmp
;
2274 assert(linkp
->minor_path
!= NULL
);
2276 dmp
= lookup_minor(hdp
, linkp
->minor_path
, NULL
, TYPE_DB
);
2279 * If a minor matching the path exists, walk that minor's devlinks list.
2280 * Then walk the dangling devlinks list. Non-matching devlinks will be
2281 * filtered out in visit_link.
2284 nidx
= dmp
? dmp
->link
: DB_HDR(hdp
)->dngl_idx
;
2285 for (; dlp
= get_link(hdp
, nidx
); nidx
= dlp
->sib
) {
2286 struct di_devlink vlink
= {NULL
};
2288 vlink
.rel_path
= get_string(hdp
, dlp
->path
);
2289 vlink
.content
= get_string(hdp
, dlp
->content
);
2290 vlink
.type
= attr2type(dlp
->attr
);
2292 if (visit_link(hdp
, linkp
, &vlink
) != DI_WALK_CONTINUE
)
2303 return (linkp
->retval
);
2308 struct di_devlink_handle
*hdp
,
2310 struct di_devlink
*vlp
)
2313 const char *minor_path
= NULL
;
2314 char abs_path
[PATH_MAX
], cont
[PATH_MAX
];
2317 * It is legal for the link's content and type to be unknown.
2318 * but one of absolute or relative path must be set.
2320 if (vlp
->rel_path
== NULL
&& vlp
->abs_path
== NULL
) {
2321 (void) dprintf(DBG_ERR
, "visit_link: invalid arguments\n");
2322 return (DI_WALK_CONTINUE
);
2325 if (vlp
->rel_path
== NULL
) {
2326 vlp
->rel_path
= (char *)rel_path(hdp
, vlp
->abs_path
);
2327 if (vlp
->rel_path
== NULL
|| vlp
->rel_path
[0] == '\0')
2328 return (DI_WALK_CONTINUE
);
2332 if (regexec(linkp
->regp
, vlp
->rel_path
, 0, NULL
, 0) != 0)
2333 return (DI_WALK_CONTINUE
);
2336 if (vlp
->abs_path
== NULL
) {
2337 assert(vlp
->rel_path
[0] != '/');
2338 (void) snprintf(abs_path
, sizeof (abs_path
), "%s/%s",
2339 hdp
->dev_dir
, vlp
->rel_path
);
2340 vlp
->abs_path
= abs_path
;
2343 if (vlp
->content
== NULL
) {
2344 if (s_readlink(vlp
->abs_path
, cont
, sizeof (cont
)) < 0) {
2345 return (DI_WALK_CONTINUE
);
2347 vlp
->content
= cont
;
2351 if (vlp
->type
== 0) {
2352 if (is_minor_node(vlp
->content
, &minor_path
)) {
2353 vlp
->type
= DI_PRIMARY_LINK
;
2355 vlp
->type
= DI_SECONDARY_LINK
;
2360 * Filter based on minor path
2362 if (linkp
->minor_path
) {
2368 if (vlp
->type
== DI_SECONDARY_LINK
) {
2372 assert(sizeof (tmp
) >= PATH_MAX
);
2374 if (s_realpath(vlp
->abs_path
, tmp
) == NULL
)
2375 return (DI_WALK_CONTINUE
);
2377 if (!is_minor_node(tmp
, &minor_path
))
2378 return (DI_WALK_CONTINUE
);
2380 } else if (minor_path
== NULL
) {
2381 if (!is_minor_node(vlp
->content
, &minor_path
))
2382 return (DI_WALK_CONTINUE
);
2385 assert(minor_path
!= NULL
);
2387 if (strcmp(linkp
->minor_path
, minor_path
) != 0)
2388 return (DI_WALK_CONTINUE
);
2392 * Filter based on link type
2394 if (!TYPE_NONE(linkp
->flags
) && LINK_TYPE(linkp
->flags
) != vlp
->type
) {
2395 return (DI_WALK_CONTINUE
);
2398 if (lstat(vlp
->abs_path
, &sbuf
) < 0) {
2399 dprintf(DBG_ERR
, "visit_link: %s: lstat failed: %s\n",
2400 vlp
->abs_path
, strerror(errno
));
2401 return (DI_WALK_CONTINUE
);
2404 return (linkp
->fcn(vlp
, linkp
->arg
));
2408 devlink_valid(di_devlink_t devlink
)
2410 if (devlink
== NULL
|| devlink
->rel_path
== NULL
||
2411 devlink
->abs_path
== NULL
|| devlink
->content
== NULL
||
2412 TYPE_NONE(devlink
->type
)) {
2420 di_devlink_path(di_devlink_t devlink
)
2422 if (!devlink_valid(devlink
)) {
2427 return (devlink
->abs_path
);
2431 di_devlink_content(di_devlink_t devlink
)
2433 if (!devlink_valid(devlink
)) {
2438 return (devlink
->content
);
2442 di_devlink_type(di_devlink_t devlink
)
2444 if (!devlink_valid(devlink
)) {
2449 return (devlink
->type
);
2453 di_devlink_dup(di_devlink_t devlink
)
2455 struct di_devlink
*duplink
;
2457 if (!devlink_valid(devlink
)) {
2462 if ((duplink
= calloc(1, sizeof (struct di_devlink
))) == NULL
) {
2466 duplink
->rel_path
= strdup(devlink
->rel_path
);
2467 duplink
->abs_path
= strdup(devlink
->abs_path
);
2468 duplink
->content
= strdup(devlink
->content
);
2469 duplink
->type
= devlink
->type
;
2471 if (!devlink_valid(duplink
)) {
2472 (void) di_devlink_free(duplink
);
2481 di_devlink_free(di_devlink_t devlink
)
2483 if (devlink
== NULL
) {
2488 free(devlink
->rel_path
);
2489 free(devlink
->abs_path
);
2490 free(devlink
->content
);
2497 * Obtain path relative to dev_dir
2500 rel_path(struct di_devlink_handle
*hdp
, const char *path
)
2502 const size_t len
= strlen(hdp
->dev_dir
);
2504 if (strncmp(path
, hdp
->dev_dir
, len
) != 0)
2507 if (path
[len
] == '\0')
2508 return (&path
[len
]);
2510 if (path
[len
] != '/')
2513 return (&path
[len
+1]);
2517 recurse_dev(struct di_devlink_handle
*hdp
, recurse_t
*rp
)
2521 (void) do_recurse(hdp
->dev_dir
, hdp
, rp
, &ret
);
2529 struct di_devlink_handle
*hdp
,
2536 char cur
[PATH_MAX
], *cp
;
2537 int i
, rv
= DI_WALK_CONTINUE
;
2538 finddevhdl_t handle
;
2542 if ((rel
= rel_path(hdp
, dir
)) == NULL
)
2543 return (DI_WALK_CONTINUE
);
2546 * Skip directories we are not interested in.
2548 for (i
= 0; i
< N_SKIP_DIRS
; i
++) {
2549 if (strcmp(rel
, skip_dirs
[i
]) == 0) {
2550 (void) dprintf(DBG_STEP
, "do_recurse: skipping %s\n",
2552 return (DI_WALK_CONTINUE
);
2556 (void) dprintf(DBG_STEP
, "do_recurse: dir = %s\n", dir
);
2558 if (finddev_readdir(dir
, &handle
) != 0)
2559 return (DI_WALK_CONTINUE
);
2561 (void) snprintf(cur
, sizeof (cur
), "%s/", dir
);
2564 len
= sizeof (cur
) - len
;
2567 if ((d_name
= (char *)finddev_next(handle
)) == NULL
)
2570 if (strlcpy(cp
, d_name
, len
) >= len
)
2574 * Skip files we are not interested in.
2576 for (i
= 0; i
< N_SKIP_FILES
; i
++) {
2578 rel
= rel_path(hdp
, cur
);
2579 if (rel
== NULL
|| strcmp(rel
, skip_files
[i
]) == 0) {
2580 (void) dprintf(DBG_STEP
,
2581 "do_recurse: skipping %s\n", cur
);
2586 if (lstat(cur
, &sbuf
) == 0) {
2587 if (S_ISDIR(sbuf
.st_mode
)) {
2588 rv
= do_recurse(cur
, hdp
, rp
, retp
);
2589 } else if (S_ISLNK(sbuf
.st_mode
)) {
2590 rv
= rp
->fcn(hdp
, rp
->data
, cur
);
2592 (void) dprintf(DBG_STEP
,
2593 "do_recurse: Skipping entry: %s\n", cur
);
2596 (void) dprintf(DBG_ERR
, "do_recurse: cur(%s): lstat"
2597 " failed: %s\n", cur
, strerror(errno
));
2603 if (rv
!= DI_WALK_CONTINUE
)
2607 finddev_close(handle
);
2614 check_attr(uint32_t attr
)
2616 switch (attr
& A_LINK_TYPES
) {
2621 dprintf(DBG_ERR
, "check_attr: incorrect attr(%u)\n",
2628 attr2type(uint32_t attr
)
2630 switch (attr
& A_LINK_TYPES
) {
2632 return (DI_PRIMARY_LINK
);
2634 return (DI_SECONDARY_LINK
);
2636 dprintf(DBG_ERR
, "attr2type: incorrect attr(%u)\n",
2642 /* Allocate new node and link it in */
2643 static cache_node_t
*
2645 struct di_devlink_handle
*hdp
,
2658 if ((cnp
= calloc(1, sizeof (cache_node_t
))) == NULL
) {
2663 if ((cnp
->path
= strdup(path
)) == NULL
) {
2672 assert(strcmp(path
, "/") == 0);
2673 assert(CACHE(hdp
)->root
== NULL
);
2674 CACHE(hdp
)->root
= cnp
;
2675 } else if (insert
== INSERT_HEAD
) {
2676 cnp
->sib
= pcnp
->child
;
2678 } else if (CACHE_LAST(hdp
) && CACHE_LAST(hdp
)->node
&&
2679 CACHE_LAST(hdp
)->node
->parent
== pcnp
&&
2680 CACHE_LAST(hdp
)->node
->sib
== NULL
) {
2682 CACHE_LAST(hdp
)->node
->sib
= cnp
;
2687 for (pp
= &pcnp
->child
; *pp
!= NULL
; pp
= &(*pp
)->sib
)
2696 * Allocate a new minor and link it in either at the tail or head
2697 * of the minor list depending on the value of "prev".
2699 static cache_minor_t
*
2701 struct di_devlink_handle
*hdp
,
2704 const char *nodetype
,
2705 cache_minor_t
**prev
)
2707 cache_minor_t
*cmnp
;
2709 if (pcnp
== NULL
|| name
== NULL
) {
2716 * Some pseudo drivers don't specify nodetype. Assume pseudo if
2717 * nodetype is not specified.
2719 if (nodetype
== NULL
)
2720 nodetype
= DDI_PSEUDO
;
2722 if ((cmnp
= calloc(1, sizeof (cache_minor_t
))) == NULL
) {
2727 cmnp
->name
= strdup(name
);
2728 cmnp
->nodetype
= strdup(nodetype
);
2729 if (cmnp
->name
== NULL
|| cmnp
->nodetype
== NULL
) {
2732 free(cmnp
->nodetype
);
2739 /* Add to node's minor list */
2741 cmnp
->sib
= pcnp
->minor
;
2744 assert(*prev
== NULL
);
2751 static cache_link_t
*
2753 struct di_devlink_handle
*hdp
,
2754 cache_minor_t
*cmnp
,
2756 const char *content
,
2761 if (path
== NULL
|| content
== NULL
|| !check_attr(attr
)) {
2767 if ((clp
= calloc(1, sizeof (cache_link_t
))) == NULL
) {
2772 clp
->path
= strdup(path
);
2773 clp
->content
= strdup(content
);
2774 if (clp
->path
== NULL
|| clp
->content
== NULL
) {
2781 hash_insert(hdp
, clp
);
2784 /* Add to minor's link list */
2786 clp
->sib
= cmnp
->link
;
2789 clp
->sib
= CACHE(hdp
)->dngl
;
2790 CACHE(hdp
)->dngl
= clp
;
2797 hash_insert(struct di_devlink_handle
*hdp
, cache_link_t
*clp
)
2801 hval
= hashfn(hdp
, clp
->path
);
2802 clp
->hash
= CACHE_HASH(hdp
, hval
);
2803 CACHE_HASH(hdp
, hval
) = clp
;
2807 static struct db_node
*
2808 get_node(struct di_devlink_handle
*hdp
, uint32_t idx
)
2810 return (map_seg(hdp
, idx
, PROT_READ
, DB_NODE
));
2813 static struct db_node
*
2814 set_node(struct di_devlink_handle
*hdp
, uint32_t idx
)
2816 return (map_seg(hdp
, idx
, PROT_READ
| PROT_WRITE
, DB_NODE
));
2819 static struct db_minor
*
2820 get_minor(struct di_devlink_handle
*hdp
, uint32_t idx
)
2822 return (map_seg(hdp
, idx
, PROT_READ
, DB_MINOR
));
2825 static struct db_minor
*
2826 set_minor(struct di_devlink_handle
*hdp
, uint32_t idx
)
2828 return (map_seg(hdp
, idx
, PROT_READ
| PROT_WRITE
, DB_MINOR
));
2831 static struct db_link
*
2832 get_link(struct di_devlink_handle
*hdp
, uint32_t idx
)
2834 return (map_seg(hdp
, idx
, PROT_READ
, DB_LINK
));
2837 static struct db_link
*
2838 set_link(struct di_devlink_handle
*hdp
, uint32_t idx
)
2840 return (map_seg(hdp
, idx
, PROT_READ
| PROT_WRITE
, DB_LINK
));
2844 get_string(struct di_devlink_handle
*hdp
, uint32_t idx
)
2846 return (map_seg(hdp
, idx
, PROT_READ
, DB_STR
));
2850 set_string(struct di_devlink_handle
*hdp
, uint32_t idx
)
2852 return (map_seg(hdp
, idx
, PROT_READ
| PROT_WRITE
, DB_STR
));
2857 * Returns the element corresponding to idx. If the portion of file involved
2858 * is not yet mapped, does an mmap() as well. Existing mappings are not changed.
2862 struct di_devlink_handle
*hdp
,
2872 if (idx
== DB_NIL
) {
2876 if (!VALID_INDEX(hdp
, seg
, idx
)) {
2877 (void) dprintf(DBG_ERR
, "map_seg: seg(%d): invalid idx(%u)\n",
2883 * If the seg is already mapped in, use it if the access type is
2886 if (DB_SEG(hdp
, seg
) != NULL
) {
2887 if (DB_SEG_PROT(hdp
, seg
) != prot
) {
2888 (void) dprintf(DBG_ERR
, "map_seg: illegal access: "
2889 "seg[%d]: idx=%u, seg_prot=%d, access=%d\n",
2890 seg
, idx
, DB_SEG_PROT(hdp
, seg
), prot
);
2893 return (DB_SEG(hdp
, seg
) + idx
* elem_sizes
[seg
]);
2897 * Segment is not mapped. Mmap() the segment.
2899 off
= seg_size(hdp
, DB_HEADER
);
2900 for (s
= 0; s
< seg
; s
++) {
2901 off
+= seg_size(hdp
, s
);
2903 slen
= seg_size(hdp
, seg
);
2905 addr
= mmap(NULL
, slen
, prot
, MAP_SHARED
, DB(hdp
)->db_fd
, off
);
2906 if (addr
== MAP_FAILED
) {
2907 (void) dprintf(DBG_ERR
, "map_seg: seg[%d]: mmap failed: %s\n",
2908 seg
, strerror(errno
));
2909 (void) dprintf(DBG_ERR
, "map_seg: args: len=%lu, prot=%d,"
2910 " fd=%d, off=%ld\n", (ulong_t
)slen
, prot
, DB(hdp
)->db_fd
,
2915 DB_SEG(hdp
, seg
) = addr
;
2916 DB_SEG_PROT(hdp
, seg
) = prot
;
2918 (void) dprintf(DBG_STEP
, "map_seg: seg[%d]: len=%lu, prot=%d, fd=%d, "
2919 "off=%ld, seg_base=%p\n", seg
, (ulong_t
)slen
, prot
, DB(hdp
)->db_fd
,
2922 return (DB_SEG(hdp
, seg
) + idx
* elem_sizes
[seg
]);
2926 * Computes the size of a segment rounded up to the nearest page boundary.
2929 seg_size(struct di_devlink_handle
*hdp
, int seg
)
2933 assert(DB_HDR(hdp
)->page_sz
);
2935 if (seg
== DB_HEADER
) {
2938 assert(DB_NUM(hdp
, seg
) >= 1);
2939 sz
= DB_NUM(hdp
, seg
) * elem_sizes
[seg
];
2942 sz
= (sz
/ DB_HDR(hdp
)->page_sz
) + 1;
2944 sz
*= DB_HDR(hdp
)->page_sz
;
2950 size_db(struct di_devlink_handle
*hdp
, long page_sz
, uint32_t *count
)
2956 assert(page_sz
> 0);
2958 /* Take "NIL" element into account */
2959 for (i
= 0; i
< DB_TYPES
; i
++) {
2963 count_node(CACHE(hdp
)->root
, count
);
2965 for (clp
= CACHE(hdp
)->dngl
; clp
!= NULL
; clp
= clp
->sib
) {
2966 count_link(clp
, count
);
2969 sz
= ((HDR_LEN
/ page_sz
) + 1) * page_sz
;
2970 for (i
= 0; i
< DB_TYPES
; i
++) {
2971 assert(count
[i
] >= 1);
2972 sz
+= (((count
[i
] * elem_sizes
[i
]) / page_sz
) + 1) * page_sz
;
2973 (void) dprintf(DBG_INFO
, "N[%u]=%u\n", i
, count
[i
]);
2975 (void) dprintf(DBG_INFO
, "DB size=%lu\n", (ulong_t
)sz
);
2982 count_node(cache_node_t
*cnp
, uint32_t *count
)
2984 cache_minor_t
*cmnp
;
2990 count_string(cnp
->path
, count
);
2992 for (cmnp
= cnp
->minor
; cmnp
!= NULL
; cmnp
= cmnp
->sib
) {
2993 count_minor(cmnp
, count
);
2996 for (cnp
= cnp
->child
; cnp
!= NULL
; cnp
= cnp
->sib
) {
2997 count_node(cnp
, count
);
3003 count_minor(cache_minor_t
*cmnp
, uint32_t *count
)
3011 count_string(cmnp
->name
, count
);
3012 count_string(cmnp
->nodetype
, count
);
3014 for (clp
= cmnp
->link
; clp
!= NULL
; clp
= clp
->sib
) {
3015 count_link(clp
, count
);
3020 count_link(cache_link_t
*clp
, uint32_t *count
)
3026 count_string(clp
->path
, count
);
3027 count_string(clp
->content
, count
);
3032 count_string(const char *str
, uint32_t *count
)
3035 (void) dprintf(DBG_ERR
, "count_string: NULL argument\n");
3039 count
[DB_STR
] += strlen(str
) + 1;
3043 hashfn(struct di_devlink_handle
*hdp
, const char *str
)
3052 assert(CACHE(hdp
)->hash_sz
>= MIN_HASH_SIZE
);
3054 for (cp
= str
; *cp
!= '\0'; cp
++) {
3058 return (hval
% CACHE(hdp
)->hash_sz
);
3064 * If the handle is IS_RDWR then we lock as writer to "update" database,
3065 * if IS_RDONLY then we lock as reader to "snapshot" database. The
3066 * implementation uses advisory file locking.
3068 * This function returns:
3069 * == 1 success and grabbed the lock file, we can open the DB.
3070 * == 0 success but did not lock the lock file, reader must walk
3071 * the /dev directory.
3075 enter_db_lock(struct di_devlink_handle
*hdp
, const char *root_dir
)
3079 char lockfile
[PATH_MAX
];
3081 int writer
= HDL_RDWR(hdp
);
3082 static int did_sync
= 0;
3085 assert(hdp
->lock_fd
< 0);
3087 get_db_path(hdp
, DB_LOCK
, lockfile
, sizeof (lockfile
));
3089 dprintf(DBG_LCK
, "enter_db_lock: %s BEGIN\n",
3090 writer
? "update" : "snapshot");
3092 /* Record locks are per-process. Protect against multiple threads. */
3093 (void) mutex_lock(&update_mutex
);
3095 again
: if ((fd
= open(lockfile
,
3096 (writer
? (O_RDWR
|O_CREAT
) : O_RDONLY
), DB_LOCK_PERMS
)) < 0) {
3098 * Typically the lock file and the database go hand in hand.
3099 * If we find that the lock file does not exist (for some
3100 * unknown reason) and we are the reader then we return
3101 * success (after triggering devfsadm to create the file and
3102 * a retry) so that we can still provide service via slow
3103 * /dev walk. If we get a failure as a writer we want the
3104 * error to manifests itself.
3106 if ((errno
== ENOENT
) && !writer
) {
3107 /* If reader, signal once to get files created */
3108 if (did_sync
== 0) {
3110 dprintf(DBG_LCK
, "enter_db_lock: %s OSYNC\n",
3111 writer
? "update" : "snapshot");
3113 /* signal to get files created */
3114 (void) devlink_create(root_dir
, NULL
,
3118 dprintf(DBG_LCK
, "enter_db_lock: %s OPENFAILD %s: "
3119 "WALK\n", writer
? "update" : "snapshot",
3121 (void) mutex_unlock(&update_mutex
);
3122 return (0); /* success, but not locked */
3124 dprintf(DBG_LCK
, "enter_db_lock: %s OPENFAILD %s\n",
3125 writer
? "update" : "snapshot", strerror(errno
));
3126 (void) mutex_unlock(&update_mutex
);
3127 return (-1); /* failed */
3131 lock
.l_type
= writer
? F_WRLCK
: F_RDLCK
;
3132 lock
.l_whence
= SEEK_SET
;
3136 /* Enter the lock. */
3137 for (eintrs
= 0; eintrs
< MAX_LOCK_RETRY
; eintrs
++) {
3138 rv
= fcntl(fd
, F_SETLKW
, &lock
);
3139 if ((rv
!= -1) || (errno
!= EINTR
))
3145 dprintf(DBG_LCK
, "enter_db_lock: %s LOCKED\n",
3146 writer
? "update" : "snapshot");
3147 return (1); /* success, locked */
3151 dprintf(DBG_ERR
, "enter_db_lock: %s FAILED: %s: WALK\n",
3152 writer
? "update" : "snapshot", strerror(errno
));
3153 (void) mutex_unlock(&update_mutex
);
3158 * Close and re-open lock file every time so that it is recreated if deleted.
3161 exit_db_lock(struct di_devlink_handle
*hdp
)
3163 struct flock unlock
;
3164 int writer
= HDL_RDWR(hdp
);
3166 if (hdp
->lock_fd
< 0) {
3170 unlock
.l_type
= F_UNLCK
;
3171 unlock
.l_whence
= SEEK_SET
;
3175 dprintf(DBG_LCK
, "exit_db_lock : %s UNLOCKED\n",
3176 writer
? "update" : "snapshot");
3177 if (fcntl(hdp
->lock_fd
, F_SETLK
, &unlock
) == -1) {
3178 dprintf(DBG_ERR
, "exit_db_lock : %s failed: %s\n",
3179 writer
? "update" : "snapshot", strerror(errno
));
3182 (void) close(hdp
->lock_fd
);
3186 (void) mutex_unlock(&update_mutex
);
3190 * returns 1 if contents is a minor node in /devices.
3191 * If mn_root is not NULL, mn_root is set to:
3192 * if contents is a /dev node, mn_root = contents
3194 * if contents is a /devices node, mn_root set to the '/'
3195 * following /devices.
3198 is_minor_node(const char *contents
, const char **mn_root
)
3202 prefix
= "../devices/";
3204 if ((ptr
= strstr(contents
, prefix
)) != NULL
) {
3206 /* mn_root should point to the / following /devices */
3207 if (mn_root
!= NULL
) {
3208 *mn_root
= ptr
+= strlen(prefix
) - 1;
3213 prefix
= "/devices/";
3215 if (strncmp(contents
, prefix
, strlen(prefix
)) == 0) {
3217 /* mn_root should point to the / following /devices/ */
3218 if (mn_root
!= NULL
) {
3219 *mn_root
= contents
+ strlen(prefix
) - 1;
3224 if (mn_root
!= NULL
) {
3225 *mn_root
= contents
;
3231 s_readlink(const char *link
, char *buf
, size_t blen
)
3235 if ((rv
= readlink(link
, buf
, blen
)) == -1)
3238 if (rv
>= blen
&& buf
[blen
- 1] != '\0') {
3239 errno
= ENAMETOOLONG
;
3241 } else if (rv
< blen
) {
3247 dprintf(DBG_ERR
, "s_readlink: %s: failed: %s\n",
3248 link
, strerror(errno
));
3253 * Synchronous link creation interface routines
3254 * The scope of the operation is determined by the "name" arg.
3255 * "name" can be NULL, a driver name or a devfs pathname (without /devices)
3260 * NULL => All devlinks in system
3261 * <driver> => devlinks for named driver
3262 * /pci@1 => devlinks for subtree rooted at pci@1
3263 * /pseudo/foo@0:X => devlinks for minor X
3265 * devlink_create() returns 0 on success or an errno value on failure
3268 #define MAX_DAEMON_ATTEMPTS 2
3271 devlink_create(const char *root
, const char *name
, int dca_devlink_flag
)
3280 * Convert name into arg for door_call
3282 if (dca_init(name
, &dca
, dca_devlink_flag
) != 0)
3286 * Attempt to use the daemon first
3290 install
= daemon_call(root
, &dca
);
3292 dprintf(DBG_INFO
, "daemon_call() retval=%d\n", dca
.dca_error
);
3295 * Retry only if door server isn't running
3297 if (dca
.dca_error
!= ENOENT
&& dca
.dca_error
!= EBADF
) {
3298 return (dca
.dca_error
);
3304 * To improve performance defer this check until the first
3305 * failure. Safe to defer as door server checks perms.
3310 * Daemon may not be running. Try to start it.
3312 } while ((++i
< MAX_DAEMON_ATTEMPTS
) &&
3313 start_daemon(root
, install
) == 0);
3315 dprintf(DBG_INFO
, "devlink_create: can't start daemon\n");
3317 assert(dca
.dca_error
== 0);
3320 * If the daemon cannot be started execute the devfsadm command.
3322 exec_cmd(root
, &dca
);
3324 return (dca
.dca_error
);
3328 * The "name" member of "struct dca" contains data in the following order
3329 * root'\0'minor'\0'driver'\0'
3330 * The root component is always present at offset 0 in the "name" field.
3331 * The driver and minor are optional. If present they have a non-zero
3332 * offset in the "name" member.
3335 dca_init(const char *name
, struct dca_off
*dcp
, int dca_flags
)
3341 dcp
->dca_driver
= 0;
3343 dcp
->dca_flags
= dca_flags
;
3344 dcp
->dca_name
[0] = '\0';
3346 name
= name
? name
: "/";
3349 * Check if name is a driver name
3352 (void) snprintf(dcp
->dca_name
, sizeof (dcp
->dca_name
),
3355 *(dcp
->dca_name
+ 1) = '\0';
3356 dcp
->dca_driver
= 2;
3360 (void) snprintf(dcp
->dca_name
, sizeof (dcp
->dca_name
), "%s", name
);
3363 * "/devices" not allowed in devfs pathname
3365 if (is_minor_node(name
, NULL
))
3369 if (cp
= strrchr(dcp
->dca_name
, ':')) {
3371 dcp
->dca_minor
= cp
- dcp
->dca_name
;
3378 #define DAEMON_STARTUP_TIME 1 /* 1 second. This may need to be adjusted */
3379 #define DEVNAME_CHECK_FILE "/etc/devname_check_RDONLY"
3382 daemon_call(const char *root
, struct dca_off
*dcp
)
3386 sigset_t oset
, nset
;
3387 char synch_door
[PATH_MAX
];
3395 * If root is readonly, there are two possibilities:
3396 * - we are in some sort of install scenario
3397 * - we are early in boot
3398 * If the latter we don't want daemon_call() to succeed.
3399 * else we want to use /tmp/etc/dev
3401 * Both of these requrements are fulfilled if we check for
3402 * for a root owned door file in /tmp/etc/dev. If we are
3403 * early in boot, the door file won't exist, so this call
3406 * If we are in install, the door file will be present.
3408 * If root is read-only, try only once, since libdevinfo
3409 * isn't capable of starting devfsadmd correctly in that
3412 * Don't use statvfs() to check for readonly roots since it
3413 * doesn't always report the truth.
3417 if ((rofd
= open(DEVNAME_CHECK_FILE
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0644))
3418 == -1 && errno
== EROFS
) {
3424 (void) unlink(DEVNAME_CHECK_FILE
);
3426 prefix
= (char *)root
;
3429 if (rdonly
&& stat(DEVNAME_CHECK_FILE
, &sb
) != -1)
3432 (void) snprintf(synch_door
, sizeof (synch_door
),
3433 "%s/etc/dev/%s", prefix
, DEVFSADM_SYNCH_DOOR
);
3436 * Return ENOTSUP to prevent retries if root is readonly
3438 if (stat(synch_door
, &sb
) == -1 || sb
.st_uid
!= 0) {
3440 dcp
->dca_error
= ENOTSUP
;
3442 dcp
->dca_error
= ENOENT
;
3443 dprintf(DBG_ERR
, "stat failed: %s: no file or not root owned\n",
3448 if ((fd
= open(synch_door
, O_RDONLY
)) == -1) {
3449 dcp
->dca_error
= errno
;
3450 dprintf(DBG_ERR
, "open of %s failed: %s\n",
3451 synch_door
, strerror(errno
));
3455 arg
.data_ptr
= (char *)dcp
;
3456 arg
.data_size
= sizeof (*dcp
);
3457 arg
.desc_ptr
= NULL
;
3459 arg
.rbuf
= (char *)dcp
;
3460 arg
.rsize
= sizeof (*dcp
);
3463 * Block signals to this thread until door call
3466 (void) sigfillset(&nset
);
3467 (void) sigemptyset(&oset
);
3468 (void) sigprocmask(SIG_SETMASK
, &nset
, &oset
);
3469 if (door_call(fd
, &arg
)) {
3471 dcp
->dca_error
= errno
;
3473 (void) sigprocmask(SIG_SETMASK
, &oset
, NULL
);
3480 assert(arg
.data_ptr
);
3483 dcp
->dca_error
= ((struct dca_off
*)arg
.data_ptr
)->dca_error
;
3486 * The doors interface may return data in a different buffer
3487 * If that happens, deallocate buffer via munmap()
3489 if (arg
.rbuf
!= (char *)dcp
)
3490 (void) munmap(arg
.rbuf
, arg
.rsize
);
3495 #define DEVFSADM_PATH "/usr/sbin/devfsadm"
3496 #define DEVFSADM "devfsadm"
3498 #define DEVFSADMD_PATH "/usr/lib/devfsadm/devfsadmd"
3499 #define DEVFSADM_DAEMON "devfsadmd"
3502 start_daemon(const char *root
, int install
)
3507 argv
[i
++] = DEVFSADM_DAEMON
;
3512 argv
[i
++] = "/tmp/root/etc/path_to_inst";
3513 } else if (strcmp(root
, "/")) {
3515 argv
[i
++] = (char *)root
;
3519 rv
= do_exec(DEVFSADMD_PATH
, argv
);
3521 (void) sleep(DAEMON_STARTUP_TIME
);
3527 exec_cmd(const char *root
, struct dca_off
*dcp
)
3533 argv
[i
++] = DEVFSADM
;
3536 * Load drivers only if -i is specified
3538 if (dcp
->dca_driver
) {
3540 argv
[i
++] = &dcp
->dca_name
[dcp
->dca_driver
];
3545 if (root
!= NULL
&& strcmp(root
, "/") != 0) {
3547 argv
[i
++] = (char *)root
;
3552 if (do_exec(DEVFSADM_PATH
, argv
))
3553 dcp
->dca_error
= errno
;
3557 do_exec(const char *path
, char *const argv
[])
3563 dprintf(DBG_INFO
, "Executing %s\n\tArgument list:", path
);
3564 for (i
= 0; argv
[i
] != NULL
; i
++) {
3565 dprintf(DBG_INFO
, " %s", argv
[i
]);
3567 dprintf(DBG_INFO
, "\n");
3570 if ((cpid
= fork1()) == -1) {
3571 dprintf(DBG_ERR
, "fork1 failed: %s\n", strerror(errno
));
3575 if (cpid
== 0) { /* child process */
3578 if ((fd
= open("/dev/null", O_RDWR
)) >= 0) {
3579 (void) dup2(fd
, fileno(stdout
));
3580 (void) dup2(fd
, fileno(stderr
));
3583 (void) execv(path
, argv
);
3585 dprintf(DBG_ERR
, "open of /dev/null failed: %s\n",
3592 /* Parent process */
3593 if (waitpid(cpid
, &i
, 0) == cpid
) {
3595 if (WEXITSTATUS(i
) == 0) {
3597 "do_exec: child exited normally\n");
3603 * The child was interrupted by a signal
3607 dprintf(DBG_ERR
, "child terminated abnormally: %s\n",
3610 dprintf(DBG_ERR
, "waitpid failed: %s\n", strerror(errno
));
3617 walk_cache_links(di_devlink_handle_t hdp
, cache_link_t
*clp
, link_desc_t
*linkp
)
3621 assert(HDL_RDWR(hdp
) || HDL_RDONLY(hdp
));
3623 dprintf(DBG_INFO
, "walk_cache_links: initial link: %s\n",
3624 clp
? clp
->path
: "<NULL>");
3627 * First search the links under the specified minor. On the
3628 * 2nd pass, search the dangling list - secondary links may
3629 * exist on this list since they are not resolved during the
3632 for (i
= 0; i
< 2; i
++) {
3633 for (; clp
!= NULL
; clp
= clp
->sib
) {
3634 struct di_devlink vlink
= {NULL
};
3636 assert(clp
->path
[0] != '/');
3638 vlink
.rel_path
= clp
->path
;
3639 vlink
.content
= clp
->content
;
3640 vlink
.type
= attr2type(clp
->attr
);
3642 if (visit_link(hdp
, linkp
, &vlink
)
3643 != DI_WALK_CONTINUE
) {
3644 dprintf(DBG_INFO
, "walk_cache_links: "
3645 "terminating at link: %s\n", clp
->path
);
3650 clp
= CACHE(hdp
)->dngl
;
3655 /* If i < 2, we terminated the walk prematurely */
3656 return (i
< 2 ? DI_WALK_TERMINATE
: DI_WALK_CONTINUE
);
3660 walk_all_cache(di_devlink_handle_t hdp
, link_desc_t
*linkp
)
3665 dprintf(DBG_INFO
, "walk_all_cache: entered\n");
3667 for (i
= 0; i
< CACHE(hdp
)->hash_sz
; i
++) {
3668 clp
= CACHE_HASH(hdp
, i
);
3669 for (; clp
; clp
= clp
->hash
) {
3670 struct di_devlink vlink
= {NULL
};
3672 assert(clp
->path
[0] != '/');
3674 vlink
.rel_path
= clp
->path
;
3675 vlink
.content
= clp
->content
;
3676 vlink
.type
= attr2type(clp
->attr
);
3677 if (visit_link(hdp
, linkp
, &vlink
) !=
3679 dprintf(DBG_INFO
, "walk_all_cache: terminating "
3680 "walk at link: %s\n", clp
->path
);
3688 walk_cache_minor(di_devlink_handle_t hdp
, const char *mpath
, link_desc_t
*linkp
)
3690 cache_minor_t
*cmnp
;
3694 if ((cmnp
= lookup_minor(hdp
, mpath
, NULL
, TYPE_CACHE
)) != NULL
) {
3695 (void) walk_cache_links(hdp
, cmnp
->link
, linkp
);
3697 dprintf(DBG_ERR
, "lookup minor failed: %s\n", mpath
);
3702 walk_cache_node(di_devlink_handle_t hdp
, const char *path
, link_desc_t
*linkp
)
3704 cache_minor_t
*cmnp
;
3709 if ((cnp
= lookup_node(hdp
, (char *)path
, TYPE_CACHE
)) == NULL
) {
3710 dprintf(DBG_ERR
, "lookup node failed: %s\n", path
);
3714 for (cmnp
= cnp
->minor
; cmnp
!= NULL
; cmnp
= cmnp
->sib
) {
3715 if (walk_cache_links(hdp
, cmnp
->link
, linkp
)
3716 == DI_WALK_TERMINATE
)
3724 * Walk cached links corresponding to the given path.
3726 * path path to a node or minor node.
3728 * flags specifies the type of devlinks to be selected.
3729 * If DI_PRIMARY_LINK is used, only primary links are selected.
3730 * If DI_SECONDARY_LINK is specified, only secondary links
3732 * If neither flag is specified, all devlinks are selected.
3734 * re An extended regular expression in regex(5) format which
3735 * selects the /dev links to be returned. The regular
3736 * expression should use link pathnames relative to
3737 * /dev. i.e. without the leading "/dev/" prefix.
3738 * A NULL value matches all devlinks.
3741 di_devlink_cache_walk(di_devlink_handle_t hdp
,
3746 int (*devlink_callback
)(di_devlink_t
, void *))
3749 link_desc_t linkd
= {NULL
};
3751 if (hdp
== NULL
|| path
== NULL
|| !link_flag(flags
) ||
3752 !HDL_RDWR(hdp
) || devlink_callback
== NULL
) {
3757 linkd
.flags
= flags
;
3759 linkd
.fcn
= devlink_callback
;
3762 if (regcomp(®
, re
, REG_EXTENDED
) != 0)
3767 if (minor_colon(path
) == NULL
) {
3768 walk_cache_node(hdp
, path
, &linkd
);
3770 walk_cache_minor(hdp
, path
, &linkd
);
3779 #define DEBUG_ENV_VAR "_DEVLINK_DEBUG"
3780 static int _devlink_debug
= -1;
3783 * debug level is initialized to -1.
3784 * On first call into this routine, debug level is set.
3785 * If debug level is zero, debugging msgs are disabled.
3788 debug_print(debug_level_t msglevel
, const char *fmt
, va_list ap
)
3794 * We shouldn't be here if debug is disabled
3796 assert(_devlink_debug
!= 0);
3799 * Set debug level on first call into this routine
3801 if (_devlink_debug
< 0) {
3802 if ((cp
= getenv(DEBUG_ENV_VAR
)) == NULL
) {
3809 _devlink_debug
= strtol(cp
, NULL
, 10);
3810 if (errno
!= 0 || _devlink_debug
< 0) {
3817 if (!_devlink_debug
)
3821 /* debug msgs are enabled */
3822 assert(_devlink_debug
> 0);
3824 if (_devlink_debug
< msglevel
)
3826 if ((_devlink_debug
== DBG_LCK
) && (msglevel
!= _devlink_debug
))
3829 /* Print a distinctive label for error msgs */
3830 if (msglevel
== DBG_ERR
) {
3831 (void) fprintf(stderr
, "[ERROR]: ");
3834 (void) vfprintf(stderr
, fmt
, ap
);
3835 (void) fflush(stderr
);
3841 dprintf(debug_level_t msglevel
, const char *fmt
, ...)
3845 assert(msglevel
> 0);
3846 if (!_devlink_debug
)
3850 debug_print(msglevel
, fmt
, ap
);