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