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