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