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, *result; 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 entp = malloc(sizeof (struct dirent) + PATH_MAX + 1); 2431 if (entp == NULL) { 2432 SET_DB_ERR(hdp); 2433 (void) closedir(dp); 2434 *retp = -1; 2435 return (DI_WALK_TERMINATE); 2436 } 2437 2438 (void) snprintf(cur, sizeof (cur), "%s/", dir); 2439 len = strlen(cur); 2440 cp = cur + len; 2441 len = sizeof (cur) - len; 2442 2443 while (readdir_r(dp, entp, &result) == 0) { 2444 2445 if (result == NULL) 2446 break; 2447 2448 if (strcmp(entp->d_name, ".") == 0 || 2449 strcmp(entp->d_name, "..") == 0) { 2450 continue; 2451 } 2452 2453 (void) snprintf(cp, len, "%s", entp->d_name); 2454 2455 /* 2456 * Skip files we are not interested in. 2457 */ 2458 for (i = 0; i < N_SKIP_FILES; i++) { 2459 2460 rel = rel_path(hdp, cur); 2461 if (rel == NULL || strcmp(rel, skip_files[i]) == 0) { 2462 (void) dprintf(DBG_STEP, 2463 "do_recurse: skipping %s\n", cur); 2464 goto next_entry; 2465 } 2466 } 2467 2468 if (lstat(cur, &sbuf) == 0) { 2469 if (S_ISDIR(sbuf.st_mode)) { 2470 rv = do_recurse(cur, hdp, rp, retp); 2471 } else if (S_ISLNK(sbuf.st_mode)) { 2472 rv = rp->fcn(hdp, rp->data, cur); 2473 } else { 2474 (void) dprintf(DBG_STEP, 2475 "do_recurse: Skipping entry: %s\n", cur); 2476 } 2477 } else { 2478 (void) dprintf(DBG_ERR, "do_recurse: cur(%s): lstat" 2479 " failed: %s\n", cur, strerror(errno)); 2480 } 2481 2482 next_entry: 2483 *cp = '\0'; 2484 2485 if (rv != DI_WALK_CONTINUE) 2486 break; 2487 } 2488 2489 free(entp); 2490 (void) closedir(dp); 2491 2492 return (rv); 2493 } 2494 2495 2496 static int 2497 check_attr(uint32_t attr) 2498 { 2499 switch (attr & A_LINK_TYPES) { 2500 case A_PRIMARY: 2501 case A_SECONDARY: 2502 return (1); 2503 default: 2504 dprintf(DBG_ERR, "check_attr: incorrect attr(%u)\n", 2505 attr); 2506 return (0); 2507 } 2508 } 2509 2510 static int 2511 attr2type(uint32_t attr) 2512 { 2513 switch (attr & A_LINK_TYPES) { 2514 case A_PRIMARY: 2515 return (DI_PRIMARY_LINK); 2516 case A_SECONDARY: 2517 return (DI_SECONDARY_LINK); 2518 default: 2519 dprintf(DBG_ERR, "attr2type: incorrect attr(%u)\n", 2520 attr); 2521 return (0); 2522 } 2523 } 2524 2525 /* Allocate new node and link it in */ 2526 static cache_node_t * 2527 node_insert( 2528 struct di_devlink_handle *hdp, 2529 cache_node_t *pcnp, 2530 const char *path, 2531 int insert) 2532 { 2533 cache_node_t *cnp; 2534 2535 if (path == NULL) { 2536 errno = EINVAL; 2537 SET_DB_ERR(hdp); 2538 return (NULL); 2539 } 2540 2541 if ((cnp = calloc(1, sizeof (cache_node_t))) == NULL) { 2542 SET_DB_ERR(hdp); 2543 return (NULL); 2544 } 2545 2546 if ((cnp->path = strdup(path)) == NULL) { 2547 SET_DB_ERR(hdp); 2548 free(cnp); 2549 return (NULL); 2550 } 2551 2552 cnp->parent = pcnp; 2553 2554 if (pcnp == NULL) { 2555 assert(strcmp(path, "/") == 0); 2556 assert(CACHE(hdp)->root == NULL); 2557 CACHE(hdp)->root = cnp; 2558 } else if (insert == INSERT_HEAD) { 2559 cnp->sib = pcnp->child; 2560 pcnp->child = cnp; 2561 } else if (CACHE_LAST(hdp) && CACHE_LAST(hdp)->node && 2562 CACHE_LAST(hdp)->node->parent == pcnp && 2563 CACHE_LAST(hdp)->node->sib == NULL) { 2564 2565 CACHE_LAST(hdp)->node->sib = cnp; 2566 2567 } else { 2568 cache_node_t **pp; 2569 2570 for (pp = &pcnp->child; *pp != NULL; pp = &(*pp)->sib) 2571 ; 2572 *pp = cnp; 2573 } 2574 2575 return (cnp); 2576 } 2577 2578 /* 2579 * Allocate a new minor and link it in either at the tail or head 2580 * of the minor list depending on the value of "prev". 2581 */ 2582 static cache_minor_t * 2583 minor_insert( 2584 struct di_devlink_handle *hdp, 2585 cache_node_t *pcnp, 2586 const char *name, 2587 const char *nodetype, 2588 cache_minor_t **prev) 2589 { 2590 cache_minor_t *cmnp; 2591 2592 if (pcnp == NULL || name == NULL) { 2593 errno = EINVAL; 2594 SET_DB_ERR(hdp); 2595 return (NULL); 2596 } 2597 2598 /* 2599 * Some pseudo drivers don't specify nodetype. Assume pseudo if 2600 * nodetype is not specified. 2601 */ 2602 if (nodetype == NULL) 2603 nodetype = DDI_PSEUDO; 2604 2605 if ((cmnp = calloc(1, sizeof (cache_minor_t))) == NULL) { 2606 SET_DB_ERR(hdp); 2607 return (NULL); 2608 } 2609 2610 cmnp->name = strdup(name); 2611 cmnp->nodetype = strdup(nodetype); 2612 if (cmnp->name == NULL || cmnp->nodetype == NULL) { 2613 SET_DB_ERR(hdp); 2614 free(cmnp->name); 2615 free(cmnp->nodetype); 2616 free(cmnp); 2617 return (NULL); 2618 } 2619 2620 cmnp->node = pcnp; 2621 2622 /* Add to node's minor list */ 2623 if (prev == NULL) { 2624 cmnp->sib = pcnp->minor; 2625 pcnp->minor = cmnp; 2626 } else { 2627 assert(*prev == NULL); 2628 *prev = cmnp; 2629 } 2630 2631 return (cmnp); 2632 } 2633 2634 static cache_link_t * 2635 link_insert( 2636 struct di_devlink_handle *hdp, 2637 cache_minor_t *cmnp, 2638 const char *path, 2639 const char *content, 2640 uint32_t attr) 2641 { 2642 cache_link_t *clp; 2643 2644 if (path == NULL || content == NULL || !check_attr(attr)) { 2645 errno = EINVAL; 2646 SET_DB_ERR(hdp); 2647 return (NULL); 2648 } 2649 2650 if ((clp = calloc(1, sizeof (cache_link_t))) == NULL) { 2651 SET_DB_ERR(hdp); 2652 return (NULL); 2653 } 2654 2655 clp->path = strdup(path); 2656 clp->content = strdup(content); 2657 if (clp->path == NULL || clp->content == NULL) { 2658 SET_DB_ERR(hdp); 2659 link_free(&clp); 2660 return (NULL); 2661 } 2662 2663 clp->attr = attr; 2664 hash_insert(hdp, clp); 2665 clp->minor = cmnp; 2666 2667 /* Add to minor's link list */ 2668 if (cmnp != NULL) { 2669 clp->sib = cmnp->link; 2670 cmnp->link = clp; 2671 } else { 2672 clp->sib = CACHE(hdp)->dngl; 2673 CACHE(hdp)->dngl = clp; 2674 } 2675 2676 return (clp); 2677 } 2678 2679 static void 2680 hash_insert(struct di_devlink_handle *hdp, cache_link_t *clp) 2681 { 2682 uint_t hval; 2683 2684 hval = hashfn(hdp, clp->path); 2685 clp->hash = CACHE_HASH(hdp, hval); 2686 CACHE_HASH(hdp, hval) = clp; 2687 } 2688 2689 2690 static struct db_node * 2691 get_node(struct di_devlink_handle *hdp, uint32_t idx) 2692 { 2693 return (map_seg(hdp, idx, PROT_READ, DB_NODE)); 2694 } 2695 2696 static struct db_node * 2697 set_node(struct di_devlink_handle *hdp, uint32_t idx) 2698 { 2699 return (map_seg(hdp, idx, PROT_READ | PROT_WRITE, DB_NODE)); 2700 } 2701 2702 static struct db_minor * 2703 get_minor(struct di_devlink_handle *hdp, uint32_t idx) 2704 { 2705 return (map_seg(hdp, idx, PROT_READ, DB_MINOR)); 2706 } 2707 2708 static struct db_minor * 2709 set_minor(struct di_devlink_handle *hdp, uint32_t idx) 2710 { 2711 return (map_seg(hdp, idx, PROT_READ | PROT_WRITE, DB_MINOR)); 2712 } 2713 2714 static struct db_link * 2715 get_link(struct di_devlink_handle *hdp, uint32_t idx) 2716 { 2717 return (map_seg(hdp, idx, PROT_READ, DB_LINK)); 2718 } 2719 2720 static struct db_link * 2721 set_link(struct di_devlink_handle *hdp, uint32_t idx) 2722 { 2723 return (map_seg(hdp, idx, PROT_READ | PROT_WRITE, DB_LINK)); 2724 } 2725 2726 static char * 2727 get_string(struct di_devlink_handle *hdp, uint32_t idx) 2728 { 2729 return (map_seg(hdp, idx, PROT_READ, DB_STR)); 2730 } 2731 2732 static char * 2733 set_string(struct di_devlink_handle *hdp, uint32_t idx) 2734 { 2735 return (map_seg(hdp, idx, PROT_READ | PROT_WRITE, DB_STR)); 2736 } 2737 2738 2739 /* 2740 * Returns the element corresponding to idx. If the portion of file involved 2741 * is not yet mapped, does an mmap() as well. Existing mappings are not changed. 2742 */ 2743 static void * 2744 map_seg( 2745 struct di_devlink_handle *hdp, 2746 uint32_t idx, 2747 int prot, 2748 db_seg_t seg) 2749 { 2750 int s; 2751 off_t off; 2752 size_t slen; 2753 caddr_t addr; 2754 2755 if (idx == DB_NIL) { 2756 return (NULL); 2757 } 2758 2759 if (!VALID_INDEX(hdp, seg, idx)) { 2760 (void) dprintf(DBG_ERR, "map_seg: seg(%d): invalid idx(%u)\n", 2761 seg, idx); 2762 return (NULL); 2763 } 2764 2765 /* 2766 * If the seg is already mapped in, use it if the access type is 2767 * valid. 2768 */ 2769 if (DB_SEG(hdp, seg) != NULL) { 2770 if (DB_SEG_PROT(hdp, seg) != prot) { 2771 (void) dprintf(DBG_ERR, "map_seg: illegal access: " 2772 "seg[%d]: idx=%u, seg_prot=%d, access=%d\n", 2773 seg, idx, DB_SEG_PROT(hdp, seg), prot); 2774 return (NULL); 2775 } 2776 return (DB_SEG(hdp, seg) + idx * elem_sizes[seg]); 2777 } 2778 2779 /* 2780 * Segment is not mapped. Mmap() the segment. 2781 */ 2782 off = seg_size(hdp, DB_HEADER); 2783 for (s = 0; s < seg; s++) { 2784 off += seg_size(hdp, s); 2785 } 2786 slen = seg_size(hdp, seg); 2787 2788 addr = mmap(0, slen, prot, MAP_SHARED, DB(hdp)->db_fd, off); 2789 if (addr == MAP_FAILED) { 2790 (void) dprintf(DBG_ERR, "map_seg: seg[%d]: mmap failed: %s\n", 2791 seg, strerror(errno)); 2792 (void) dprintf(DBG_ERR, "map_seg: args: len=%lu, prot=%d," 2793 " fd=%d, off=%ld\n", (ulong_t)slen, prot, DB(hdp)->db_fd, 2794 off); 2795 return (NULL); 2796 } 2797 2798 DB_SEG(hdp, seg) = addr; 2799 DB_SEG_PROT(hdp, seg) = prot; 2800 2801 (void) dprintf(DBG_STEP, "map_seg: seg[%d]: len=%lu, prot=%d, fd=%d, " 2802 "off=%ld, seg_base=%p\n", seg, (ulong_t)slen, prot, DB(hdp)->db_fd, 2803 off, (void *)addr); 2804 2805 return (DB_SEG(hdp, seg) + idx * elem_sizes[seg]); 2806 } 2807 2808 /* 2809 * Computes the size of a segment rounded up to the nearest page boundary. 2810 */ 2811 static size_t 2812 seg_size(struct di_devlink_handle *hdp, int seg) 2813 { 2814 size_t sz; 2815 2816 assert(DB_HDR(hdp)->page_sz); 2817 2818 if (seg == DB_HEADER) { 2819 sz = HDR_LEN; 2820 } else { 2821 assert(DB_NUM(hdp, seg) >= 1); 2822 sz = DB_NUM(hdp, seg) * elem_sizes[seg]; 2823 } 2824 2825 sz = (sz / DB_HDR(hdp)->page_sz) + 1; 2826 2827 sz *= DB_HDR(hdp)->page_sz; 2828 2829 return (sz); 2830 } 2831 2832 static size_t 2833 size_db(struct di_devlink_handle *hdp, long page_sz, uint32_t *count) 2834 { 2835 int i; 2836 size_t sz; 2837 cache_link_t *clp; 2838 2839 assert(page_sz > 0); 2840 2841 /* Take "NIL" element into account */ 2842 for (i = 0; i < DB_TYPES; i++) { 2843 count[i] = 1; 2844 } 2845 2846 count_node(CACHE(hdp)->root, count); 2847 2848 for (clp = CACHE(hdp)->dngl; clp != NULL; clp = clp->sib) { 2849 count_link(clp, count); 2850 } 2851 2852 sz = ((HDR_LEN / page_sz) + 1) * page_sz; 2853 for (i = 0; i < DB_TYPES; i++) { 2854 assert(count[i] >= 1); 2855 sz += (((count[i] * elem_sizes[i]) / page_sz) + 1) * page_sz; 2856 (void) dprintf(DBG_INFO, "N[%u]=%u\n", i, count[i]); 2857 } 2858 (void) dprintf(DBG_INFO, "DB size=%lu\n", (ulong_t)sz); 2859 2860 return (sz); 2861 } 2862 2863 2864 static void 2865 count_node(cache_node_t *cnp, uint32_t *count) 2866 { 2867 cache_minor_t *cmnp; 2868 2869 if (cnp == NULL) 2870 return; 2871 2872 count[DB_NODE]++; 2873 count_string(cnp->path, count); 2874 2875 for (cmnp = cnp->minor; cmnp != NULL; cmnp = cmnp->sib) { 2876 count_minor(cmnp, count); 2877 } 2878 2879 for (cnp = cnp->child; cnp != NULL; cnp = cnp->sib) { 2880 count_node(cnp, count); 2881 } 2882 2883 } 2884 2885 static void 2886 count_minor(cache_minor_t *cmnp, uint32_t *count) 2887 { 2888 cache_link_t *clp; 2889 2890 if (cmnp == NULL) 2891 return; 2892 2893 count[DB_MINOR]++; 2894 count_string(cmnp->name, count); 2895 count_string(cmnp->nodetype, count); 2896 2897 for (clp = cmnp->link; clp != NULL; clp = clp->sib) { 2898 count_link(clp, count); 2899 } 2900 } 2901 2902 static void 2903 count_link(cache_link_t *clp, uint32_t *count) 2904 { 2905 if (clp == NULL) 2906 return; 2907 2908 count[DB_LINK]++; 2909 count_string(clp->path, count); 2910 count_string(clp->content, count); 2911 } 2912 2913 2914 static void 2915 count_string(const char *str, uint32_t *count) 2916 { 2917 if (str == NULL) { 2918 (void) dprintf(DBG_ERR, "count_string: NULL argument\n"); 2919 return; 2920 } 2921 2922 count[DB_STR] += strlen(str) + 1; 2923 } 2924 2925 static uint_t 2926 hashfn(struct di_devlink_handle *hdp, const char *str) 2927 { 2928 const char *cp; 2929 ulong_t hval = 0; 2930 2931 if (str == NULL) { 2932 return (0); 2933 } 2934 2935 assert(CACHE(hdp)->hash_sz >= MIN_HASH_SIZE); 2936 2937 for (cp = str; *cp != '\0'; cp++) { 2938 hval += *cp; 2939 } 2940 2941 return (hval % CACHE(hdp)->hash_sz); 2942 } 2943 2944 static int 2945 enter_update_lock(struct di_devlink_handle *hdp) 2946 { 2947 int i, fd, rv; 2948 struct flock lock; 2949 char lockfile[PATH_MAX]; 2950 2951 assert(hdp->lock_fd < 0); 2952 2953 get_db_path(hdp, DB_LOCK, lockfile, sizeof (lockfile)); 2954 2955 /* 2956 * Record locks are per-process. Protect against multiple threads. 2957 */ 2958 (void) mutex_lock(&update_mutex); 2959 2960 if ((fd = open(lockfile, O_RDWR|O_CREAT, DB_LOCK_PERMS)) < 0) { 2961 goto error; 2962 } 2963 2964 lock.l_type = F_WRLCK; 2965 lock.l_whence = SEEK_SET; 2966 lock.l_start = 0; 2967 lock.l_len = 0; 2968 2969 i = 1; 2970 while ((rv = fcntl(fd, F_SETLKW, &lock)) == -1 && errno == EINTR) { 2971 if (i < MAX_LOCK_RETRY) { 2972 i++; 2973 } else { 2974 break; 2975 } 2976 } 2977 2978 if (rv == 0) { 2979 hdp->lock_fd = fd; 2980 return (0); 2981 } else { 2982 (void) close(fd); 2983 } 2984 2985 error: 2986 (void) mutex_unlock(&update_mutex); 2987 2988 dprintf(DBG_ERR, "lockfile(%s): lock failed: %s\n", lockfile, 2989 strerror(errno)); 2990 return (-1); 2991 } 2992 2993 /* 2994 * Close and re-open lock file every time so that it is recreated if deleted. 2995 */ 2996 static void 2997 exit_update_lock(struct di_devlink_handle *hdp) 2998 { 2999 struct flock unlock; 3000 3001 if (hdp->lock_fd < 0) { 3002 return; 3003 } 3004 3005 unlock.l_type = F_UNLCK; 3006 unlock.l_whence = SEEK_SET; 3007 unlock.l_start = 0; 3008 unlock.l_len = 0; 3009 3010 if (fcntl(hdp->lock_fd, F_SETLK, &unlock) == -1) { 3011 dprintf(DBG_ERR, "update lockfile: unlock failed: %s\n", 3012 strerror(errno)); 3013 } 3014 3015 (void) close(hdp->lock_fd); 3016 3017 hdp->lock_fd = -1; 3018 3019 (void) mutex_unlock(&update_mutex); 3020 } 3021 3022 /* 3023 * returns 1 if contents is a minor node in /devices. 3024 * If mn_root is not NULL, mn_root is set to: 3025 * if contents is a /dev node, mn_root = contents 3026 * OR 3027 * if contents is a /devices node, mn_root set to the '/' 3028 * following /devices. 3029 */ 3030 int 3031 is_minor_node(const char *contents, const char **mn_root) 3032 { 3033 char *ptr, *prefix; 3034 3035 prefix = "../devices/"; 3036 3037 if ((ptr = strstr(contents, prefix)) != NULL) { 3038 3039 /* mn_root should point to the / following /devices */ 3040 if (mn_root != NULL) { 3041 *mn_root = ptr += strlen(prefix) - 1; 3042 } 3043 return (1); 3044 } 3045 3046 prefix = "/devices/"; 3047 3048 if (strncmp(contents, prefix, strlen(prefix)) == 0) { 3049 3050 /* mn_root should point to the / following /devices/ */ 3051 if (mn_root != NULL) { 3052 *mn_root = contents + strlen(prefix) - 1; 3053 } 3054 return (1); 3055 } 3056 3057 if (mn_root != NULL) { 3058 *mn_root = contents; 3059 } 3060 return (0); 3061 } 3062 3063 static int 3064 s_readlink(const char *link, char *buf, size_t blen) 3065 { 3066 int rv; 3067 3068 if ((rv = readlink(link, buf, blen)) == -1) 3069 goto bad; 3070 3071 if (rv >= blen && buf[blen - 1] != '\0') { 3072 errno = ENAMETOOLONG; 3073 goto bad; 3074 } else if (rv < blen) { 3075 buf[rv] = '\0'; 3076 } 3077 3078 return (0); 3079 bad: 3080 dprintf(DBG_ERR, "s_readlink: %s: failed: %s\n", 3081 link, strerror(errno)); 3082 return (-1); 3083 } 3084 3085 /* 3086 * Synchronous link creation interface routines 3087 * The scope of the operation is determined by the "name" arg. 3088 * "name" can be NULL, a driver name or a devfs pathname (without /devices) 3089 * 3090 * "name" creates 3091 * ====== ======= 3092 * 3093 * NULL => All devlinks in system 3094 * <driver> => devlinks for named driver 3095 * /pci@1 => devlinks for subtree rooted at pci@1 3096 * /pseudo/foo@0:X => devlinks for minor X 3097 * 3098 * devlink_create() returns 0 on success or an errno value on failure 3099 */ 3100 3101 #define MAX_DAEMON_ATTEMPTS 2 3102 3103 static int 3104 devlink_create(const char *root, const char *name) 3105 { 3106 int i; 3107 struct dca_off dca; 3108 3109 assert(root); 3110 3111 /* 3112 * Convert name into arg for door_call 3113 */ 3114 if (dca_init(name, &dca) != 0) 3115 return (EINVAL); 3116 3117 /* 3118 * Attempt to use the daemon first 3119 */ 3120 i = 0; 3121 do { 3122 daemon_call(root, &dca); 3123 3124 dprintf(DBG_INFO, "daemon_call() retval=%d\n", dca.dca_error); 3125 3126 /* 3127 * Retry only if door server isn't running 3128 */ 3129 if (dca.dca_error != ENOENT && dca.dca_error != EBADF) { 3130 return (dca.dca_error); 3131 } 3132 3133 dca.dca_error = 0; 3134 3135 /* 3136 * To improve performance defer this check until the first 3137 * failure. Safe to defer as door server checks perms. 3138 */ 3139 if (geteuid() != 0) 3140 return (EPERM); 3141 /* 3142 * Daemon may not be running. Try to start it. 3143 */ 3144 } while ((++i < MAX_DAEMON_ATTEMPTS) && start_daemon(root) == 0); 3145 3146 dprintf(DBG_INFO, "devlink_create: can't start daemon\n"); 3147 3148 assert(dca.dca_error == 0); 3149 3150 /* 3151 * If the daemon cannot be started execute the devfsadm command. 3152 */ 3153 exec_cmd(root, &dca); 3154 3155 return (dca.dca_error); 3156 } 3157 3158 /* 3159 * The "name" member of "struct dca" contains data in the following order 3160 * root'\0'minor'\0'driver'\0' 3161 * The root component is always present at offset 0 in the "name" field. 3162 * The driver and minor are optional. If present they have a non-zero 3163 * offset in the "name" member. 3164 */ 3165 static int 3166 dca_init(const char *name, struct dca_off *dcp) 3167 { 3168 char *cp; 3169 3170 dcp->dca_root = 0; 3171 dcp->dca_minor = 0; 3172 dcp->dca_driver = 0; 3173 dcp->dca_error = 0; 3174 dcp->dca_flags = 0; 3175 dcp->dca_name[0] = '\0'; 3176 3177 name = name ? name : "/"; 3178 3179 /* 3180 * Check if name is a driver name 3181 */ 3182 if (*name != '/') { 3183 (void) snprintf(dcp->dca_name, sizeof (dcp->dca_name), 3184 "/ %s", name); 3185 dcp->dca_root = 0; 3186 *(dcp->dca_name + 1) = '\0'; 3187 dcp->dca_driver = 2; 3188 return (0); 3189 } 3190 3191 (void) snprintf(dcp->dca_name, sizeof (dcp->dca_name), "%s", name); 3192 3193 /* 3194 * "/devices" not allowed in devfs pathname 3195 */ 3196 if (is_minor_node(name, NULL)) 3197 return (-1); 3198 3199 dcp->dca_root = 0; 3200 if (cp = strrchr(dcp->dca_name, ':')) { 3201 *cp++ = '\0'; 3202 dcp->dca_minor = cp - dcp->dca_name; 3203 } 3204 3205 return (0); 3206 } 3207 3208 3209 #define DAEMON_STARTUP_TIME 1 /* 1 second. This may need to be adjusted */ 3210 3211 static void 3212 daemon_call(const char *root, struct dca_off *dcp) 3213 { 3214 door_arg_t arg; 3215 int fd, door_error; 3216 sigset_t oset, nset; 3217 char synch_door[PATH_MAX]; 3218 3219 (void) snprintf(synch_door, sizeof (synch_door), 3220 "%s/dev/%s", root, DEVFSADM_SYNCH_DOOR); 3221 3222 if ((fd = open(synch_door, O_RDONLY)) == -1) { 3223 dcp->dca_error = errno; 3224 dprintf(DBG_ERR, "open of %s failed: %s\n", 3225 synch_door, strerror(errno)); 3226 return; 3227 } 3228 3229 arg.data_ptr = (char *)dcp; 3230 arg.data_size = sizeof (*dcp); 3231 arg.desc_ptr = NULL; 3232 arg.desc_num = 0; 3233 arg.rbuf = (char *)dcp; 3234 arg.rsize = sizeof (*dcp); 3235 3236 /* 3237 * Block signals to this thread until door call 3238 * completes. 3239 */ 3240 (void) sigfillset(&nset); 3241 (void) sigemptyset(&oset); 3242 (void) sigprocmask(SIG_SETMASK, &nset, &oset); 3243 if (door_call(fd, &arg)) { 3244 door_error = 1; 3245 dcp->dca_error = errno; 3246 } 3247 (void) sigprocmask(SIG_SETMASK, &oset, NULL); 3248 3249 (void) close(fd); 3250 3251 if (door_error) 3252 return; 3253 3254 assert(arg.data_ptr); 3255 3256 /*LINTED*/ 3257 dcp->dca_error = ((struct dca_off *)arg.data_ptr)->dca_error; 3258 3259 /* 3260 * The doors interface may return data in a different buffer 3261 * If that happens, deallocate buffer via munmap() 3262 */ 3263 if (arg.rbuf != (char *)dcp) 3264 (void) munmap(arg.rbuf, arg.rsize); 3265 } 3266 3267 #define DEVFSADM_PATH "/usr/sbin/devfsadm" 3268 #define DEVFSADM "devfsadm" 3269 3270 #define DEVFSADMD_PATH "/usr/lib/devfsadm/devfsadmd" 3271 #define DEVFSADM_DAEMON "devfsadmd" 3272 3273 static int 3274 start_daemon(const char *root) 3275 { 3276 int rv, i = 0; 3277 char *argv[20]; 3278 3279 argv[i++] = DEVFSADM_DAEMON; 3280 if (strcmp(root, "/")) { 3281 argv[i++] = "-r"; 3282 argv[i++] = (char *)root; 3283 } 3284 argv[i++] = NULL; 3285 3286 rv = do_exec(DEVFSADMD_PATH, argv); 3287 3288 (void) sleep(DAEMON_STARTUP_TIME); 3289 3290 return (rv); 3291 } 3292 3293 static void 3294 exec_cmd(const char *root, struct dca_off *dcp) 3295 { 3296 int i; 3297 char *argv[20]; 3298 3299 i = 0; 3300 argv[i++] = DEVFSADM; 3301 3302 /* 3303 * Load drivers only if -i is specified 3304 */ 3305 if (dcp->dca_driver) { 3306 argv[i++] = "-i"; 3307 argv[i++] = &dcp->dca_name[dcp->dca_driver]; 3308 } else { 3309 argv[i++] = "-n"; 3310 } 3311 3312 if (root != NULL && strcmp(root, "/") != 0) { 3313 argv[i++] = "-r"; 3314 argv[i++] = (char *)root; 3315 } 3316 3317 argv[i] = NULL; 3318 3319 if (do_exec(DEVFSADM_PATH, argv)) 3320 dcp->dca_error = errno; 3321 } 3322 3323 static int 3324 do_exec(const char *path, char *const argv[]) 3325 { 3326 int i; 3327 pid_t cpid; 3328 3329 #ifdef DEBUG 3330 dprintf(DBG_INFO, "Executing %s\n\tArgument list:", path); 3331 for (i = 0; argv[i] != NULL; i++) { 3332 dprintf(DBG_INFO, " %s", argv[i]); 3333 } 3334 dprintf(DBG_INFO, "\n"); 3335 #endif 3336 3337 if ((cpid = fork1()) == -1) { 3338 dprintf(DBG_ERR, "fork1 failed: %s\n", strerror(errno)); 3339 return (-1); 3340 } 3341 3342 if (cpid == 0) { /* child process */ 3343 int fd; 3344 3345 if ((fd = open("/dev/null", O_RDWR)) >= 0) { 3346 (void) dup2(fd, fileno(stdout)); 3347 (void) dup2(fd, fileno(stderr)); 3348 (void) close(fd); 3349 3350 (void) execv(path, argv); 3351 } else { 3352 dprintf(DBG_ERR, "open of /dev/null failed: %s\n", 3353 strerror(errno)); 3354 } 3355 3356 _exit(-1); 3357 } 3358 3359 /* Parent process */ 3360 if (waitpid(cpid, &i, 0) == cpid) { 3361 if (WIFEXITED(i)) { 3362 if (WEXITSTATUS(i) == 0) { 3363 dprintf(DBG_STEP, 3364 "do_exec: child exited normally\n"); 3365 return (0); 3366 } else 3367 errno = EINVAL; 3368 } else { 3369 /* 3370 * The child was interrupted by a signal 3371 */ 3372 errno = EINTR; 3373 } 3374 dprintf(DBG_ERR, "child terminated abnormally: %s\n", 3375 strerror(errno)); 3376 } else { 3377 dprintf(DBG_ERR, "waitpid failed: %s\n", strerror(errno)); 3378 } 3379 3380 return (-1); 3381 } 3382 3383 static int 3384 walk_cache_links(di_devlink_handle_t hdp, cache_link_t *clp, link_desc_t *linkp) 3385 { 3386 int i; 3387 3388 assert(HDL_RDWR(hdp) || HDL_RDONLY(hdp)); 3389 3390 dprintf(DBG_INFO, "walk_cache_links: initial link: %s\n", 3391 clp ? clp->path : "<NULL>"); 3392 3393 /* 3394 * First search the links under the specified minor. On the 3395 * 2nd pass, search the dangling list - secondary links may 3396 * exist on this list since they are not resolved during the 3397 * /dev walk. 3398 */ 3399 for (i = 0; i < 2; i++) { 3400 for (; clp != NULL; clp = clp->sib) { 3401 struct di_devlink vlink = {NULL}; 3402 3403 assert(clp->path[0] != '/'); 3404 3405 vlink.rel_path = clp->path; 3406 vlink.content = clp->content; 3407 vlink.type = attr2type(clp->attr); 3408 3409 if (visit_link(hdp, linkp, &vlink) 3410 != DI_WALK_CONTINUE) { 3411 dprintf(DBG_INFO, "walk_cache_links: " 3412 "terminating at link: %s\n", clp->path); 3413 goto out; 3414 } 3415 } 3416 3417 clp = CACHE(hdp)->dngl; 3418 } 3419 3420 out: 3421 3422 /* If i < 2, we terminated the walk prematurely */ 3423 return (i < 2 ? DI_WALK_TERMINATE : DI_WALK_CONTINUE); 3424 } 3425 3426 static void 3427 walk_all_cache(di_devlink_handle_t hdp, link_desc_t *linkp) 3428 { 3429 int i; 3430 cache_link_t *clp; 3431 3432 dprintf(DBG_INFO, "walk_all_cache: entered\n"); 3433 3434 for (i = 0; i < CACHE(hdp)->hash_sz; i++) { 3435 clp = CACHE_HASH(hdp, i); 3436 for (; clp; clp = clp->hash) { 3437 struct di_devlink vlink = {NULL}; 3438 3439 assert(clp->path[0] != '/'); 3440 3441 vlink.rel_path = clp->path; 3442 vlink.content = clp->content; 3443 vlink.type = attr2type(clp->attr); 3444 if (visit_link(hdp, linkp, &vlink) != 3445 DI_WALK_CONTINUE) { 3446 dprintf(DBG_INFO, "walk_all_cache: terminating " 3447 "walk at link: %s\n", clp->path); 3448 return; 3449 } 3450 } 3451 } 3452 } 3453 3454 static void 3455 walk_cache_minor(di_devlink_handle_t hdp, const char *mpath, link_desc_t *linkp) 3456 { 3457 cache_minor_t *cmnp; 3458 3459 assert(mpath); 3460 3461 if ((cmnp = lookup_minor(hdp, mpath, NULL, TYPE_CACHE)) != NULL) { 3462 (void) walk_cache_links(hdp, cmnp->link, linkp); 3463 } else { 3464 dprintf(DBG_ERR, "lookup minor failed: %s\n", mpath); 3465 } 3466 } 3467 3468 static void 3469 walk_cache_node(di_devlink_handle_t hdp, const char *path, link_desc_t *linkp) 3470 { 3471 cache_minor_t *cmnp; 3472 cache_node_t *cnp; 3473 3474 assert(path); 3475 3476 if ((cnp = lookup_node(hdp, (char *)path, TYPE_CACHE)) == NULL) { 3477 dprintf(DBG_ERR, "lookup node failed: %s\n", path); 3478 return; 3479 } 3480 3481 for (cmnp = cnp->minor; cmnp != NULL; cmnp = cmnp->sib) { 3482 if (walk_cache_links(hdp, cmnp->link, linkp) 3483 == DI_WALK_TERMINATE) 3484 break; 3485 } 3486 } 3487 3488 /* 3489 * Private function 3490 * 3491 * Walk cached links corresponding to the given path. 3492 * 3493 * path path to a node or minor node. 3494 * 3495 * flags specifies the type of devlinks to be selected. 3496 * If DI_PRIMARY_LINK is used, only primary links are selected. 3497 * If DI_SECONDARY_LINK is specified, only secondary links 3498 * are selected. 3499 * If neither flag is specified, all devlinks are selected. 3500 * 3501 * re An extended regular expression in regex(5) format which 3502 * selects the /dev links to be returned. The regular 3503 * expression should use link pathnames relative to 3504 * /dev. i.e. without the leading "/dev/" prefix. 3505 * A NULL value matches all devlinks. 3506 */ 3507 int 3508 di_devlink_cache_walk(di_devlink_handle_t hdp, 3509 const char *re, 3510 const char *path, 3511 uint_t flags, 3512 void *arg, 3513 int (*devlink_callback)(di_devlink_t, void *)) 3514 { 3515 regex_t reg; 3516 link_desc_t linkd = {NULL}; 3517 3518 if (hdp == NULL || path == NULL || !link_flag(flags) || 3519 !HDL_RDWR(hdp) || devlink_callback == NULL) { 3520 errno = EINVAL; 3521 return (-1); 3522 } 3523 3524 linkd.flags = flags; 3525 linkd.arg = arg; 3526 linkd.fcn = devlink_callback; 3527 3528 if (re) { 3529 if (regcomp(®, re, REG_EXTENDED) != 0) 3530 return (-1); 3531 linkd.regp = ® 3532 } 3533 3534 if (minor_colon(path) == NULL) { 3535 walk_cache_node(hdp, path, &linkd); 3536 } else { 3537 walk_cache_minor(hdp, path, &linkd); 3538 } 3539 3540 if (re) 3541 regfree(®); 3542 3543 return (0); 3544 } 3545 3546 #define DEBUG_ENV_VAR "_DEVLINK_DEBUG" 3547 static int _devlink_debug = -1; 3548 3549 /* 3550 * debug level is initialized to -1. 3551 * On first call into this routine, debug level is set. 3552 * If debug level is zero, debugging msgs are disabled. 3553 */ 3554 static void 3555 debug_print(debug_level_t msglevel, const char *fmt, va_list ap) 3556 { 3557 char *cp; 3558 int save; 3559 3560 /* 3561 * We shouldn't be here if debug is disabled 3562 */ 3563 assert(_devlink_debug != 0); 3564 3565 /* 3566 * Set debug level on first call into this routine 3567 */ 3568 if (_devlink_debug < 0) { 3569 if ((cp = getenv(DEBUG_ENV_VAR)) == NULL) { 3570 _devlink_debug = 0; 3571 return; 3572 } 3573 3574 save = errno; 3575 errno = 0; 3576 _devlink_debug = strtol(cp, NULL, 10); 3577 if (errno != 0 || _devlink_debug < 0) { 3578 _devlink_debug = 0; 3579 errno = save; 3580 return; 3581 } 3582 errno = save; 3583 3584 if (!_devlink_debug) 3585 return; 3586 } 3587 3588 /* debug msgs are enabled */ 3589 assert(_devlink_debug > 0); 3590 3591 if (_devlink_debug < msglevel) 3592 return; 3593 3594 3595 /* Print a distinctive label for error msgs */ 3596 if (msglevel == DBG_ERR) { 3597 (void) fprintf(stderr, "[ERROR]: "); 3598 } 3599 3600 (void) vfprintf(stderr, fmt, ap); 3601 } 3602 3603 /* ARGSUSED */ 3604 /* PRINTFLIKE2 */ 3605 void 3606 dprintf(debug_level_t msglevel, const char *fmt, ...) 3607 { 3608 va_list ap; 3609 3610 assert(msglevel > 0); 3611 3612 if (!_devlink_debug) 3613 return; 3614 3615 va_start(ap, fmt); 3616 debug_print(msglevel, fmt, ap); 3617 va_end(ap); 3618 } 3619