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