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