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