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