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