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