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