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 */ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <libelf.h> 29 #include <sys/types.h> 30 #include <sys/stat.h> 31 #include <sys/buf.h> 32 #include <wait.h> 33 #include <unistd.h> 34 #include <libintl.h> 35 #include <sys/modctl.h> 36 #include <sys/systeminfo.h> 37 #include <string.h> 38 #include <limits.h> 39 #include <locale.h> 40 #include <ftw.h> 41 #include <sys/sunddi.h> 42 #include <libdevinfo.h> 43 #include <sys/sysmacros.h> 44 #include <fcntl.h> 45 #include "addrem.h" 46 #include "errmsg.h" 47 #include "plcysubr.h" 48 49 /* 50 * globals needed for libdevinfo - there is no way to pass 51 * private data to the find routine. 52 */ 53 struct dev_list { 54 int clone; 55 char *dev_name; 56 char *driver_name; 57 struct dev_list *next; 58 }; 59 60 static char *kelf_desc = NULL; 61 static int kelf_type = ELFCLASSNONE; 62 63 static char *new_drv; 64 static struct dev_list *conflict_lst = NULL; 65 66 static int module_not_found(char *, char *, int, char **, int *); 67 static void usage(); 68 static int update_minor_perm(char *, char *); 69 static int devfs_update_minor_perm(char *, char *); 70 static int update_driver_classes(char *, char *); 71 static int drv_name_conflict(di_node_t); 72 static int devfs_node(di_node_t node, void *arg); 73 static int drv_name_match(char *, int, char *, char *); 74 static void print_drv_conflict_info(int); 75 static void check_dev_dir(int); 76 static int dev_node(const char *, const struct stat *, int, struct FTW *); 77 static void free_conflict_list(struct dev_list *); 78 static int clone(di_node_t node); 79 static int elf_type(char *, char **, int *); 80 static int correct_location(char *, char **, int *); 81 static int isaspec_drvmod_discovery(); 82 static void remove_slashes(char *); 83 static int update_extra_privs(char *, char *privlist); 84 static int ignore_root_basedir(); 85 86 int 87 main(int argc, char *argv[]) 88 { 89 int opt; 90 major_t major_num; 91 char driver_name[FILENAME_MAX + 1]; 92 int driver_name_size = sizeof (driver_name); 93 char path_driver_name[MAXPATHLEN]; 94 int path_driver_name_size = sizeof (path_driver_name); 95 char *perms = NULL; 96 char *aliases = NULL; 97 char *classes = NULL; 98 char *policy = NULL; 99 char *priv = NULL; 100 int noload_flag = 0; 101 int verbose_flag = 0; 102 int force_flag = 0; 103 int i_flag = 0; 104 int c_flag = 0; 105 int m_flag = 0; 106 int cleanup_flag = 0; 107 int server = 0; 108 char *basedir = NULL; 109 int is_unique; 110 char *slash; 111 int conflict; 112 di_node_t root_node; /* for device tree snapshot */ 113 char *drvelf_desc = NULL; 114 int drvelf_type = ELFCLASSNONE; 115 116 moddir = NULL; 117 118 (void) setlocale(LC_ALL, ""); 119 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 120 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 121 #endif 122 (void) textdomain(TEXT_DOMAIN); 123 124 /* must be run by root */ 125 126 if (geteuid() != 0) { 127 (void) fprintf(stderr, gettext(ERR_NOT_ROOT)); 128 exit(1); 129 } 130 131 while ((opt = getopt(argc, argv, "vfm:ni:b:c:p:P:")) != EOF) { 132 switch (opt) { 133 case 'm' : 134 m_flag = 1; 135 perms = optarg; 136 break; 137 case 'f': 138 force_flag++; 139 break; 140 case 'v': 141 verbose_flag++; 142 break; 143 case 'n': 144 noload_flag++; 145 break; 146 case 'i' : 147 i_flag = 1; 148 aliases = optarg; 149 if (check_space_within_quote(aliases) == ERROR) { 150 (void) fprintf(stderr, gettext(ERR_NO_SPACE), 151 aliases); 152 exit(1); 153 } 154 break; 155 case 'b' : 156 server = 1; 157 basedir = optarg; 158 if (strcmp(basedir, "/") == 0 && 159 ignore_root_basedir()) { 160 server = 0; 161 basedir = NULL; 162 } 163 break; 164 case 'c': 165 c_flag = 1; 166 classes = optarg; 167 break; 168 case 'p': 169 policy = optarg; 170 break; 171 case 'P': 172 priv = optarg; 173 break; 174 case '?' : 175 default: 176 usage(); 177 exit(1); 178 } 179 } 180 181 182 if (argv[optind] != NULL) { 183 if (strlcpy(driver_name, argv[optind], driver_name_size) >= 184 driver_name_size) { 185 (void) fprintf(stderr, gettext(ERR_DRVNAME_TOO_LONG), 186 driver_name_size, argv[optind]); 187 exit(1); 188 } 189 190 /* 191 * check for extra args 192 */ 193 if ((optind + 1) != argc) { 194 usage(); 195 exit(1); 196 } 197 198 } else { 199 usage(); 200 exit(1); 201 } 202 203 /* 204 * Fail if add_drv was invoked with a pathname prepended to the 205 * driver_name argument. 206 * 207 * Check driver_name for any '/'s. If found, we assume that caller 208 * is trying to specify a pathname. 209 */ 210 211 slash = strchr(driver_name, '/'); 212 if (slash) { 213 remove_slashes(driver_name); 214 215 /* extract module name out of path */ 216 slash = strrchr(driver_name, '/'); 217 218 if (slash != NULL) { 219 (void) fprintf(stderr, gettext(ERR_PATH_SPEC), 220 driver_name); 221 (void) fprintf(stderr, gettext(ERR_INSTALL_FAIL), 222 ++slash); 223 exit(1); 224 } 225 } 226 new_drv = driver_name; 227 228 /* set up add_drv filenames */ 229 if ((build_filenames(basedir)) == ERROR) { 230 exit(1); 231 } 232 233 /* must be only running version of add_drv/rem_drv */ 234 enter_lock(); 235 236 if ((check_perms_aliases(m_flag, i_flag)) == ERROR) 237 err_exit(); 238 239 if ((check_name_to_major(R_OK | W_OK)) == ERROR) 240 err_exit(); 241 242 /* 243 * check validity of options 244 */ 245 if (m_flag) { 246 if ((check_perm_opts(perms)) == ERROR) { 247 usage(); 248 err_exit(); 249 } 250 } 251 252 if (i_flag) { 253 if (aliases != NULL) 254 if ((aliases_unique(aliases)) == ERROR) 255 err_exit(); 256 } 257 258 /* update kernel unless -b or -n */ 259 if (noload_flag == 0 && server == 0 && 260 priv != NULL && check_priv_entry(priv, 1) != 0) 261 err_exit(); 262 263 if (policy != NULL && 264 (policy = check_plcy_entry(policy, driver_name, B_FALSE)) == NULL) { 265 err_exit(); 266 } 267 268 if ((unique_driver_name(driver_name, name_to_major, 269 &is_unique)) == ERROR) 270 err_exit(); 271 272 if (is_unique == NOT_UNIQUE) { 273 (void) fprintf(stderr, gettext(ERR_NOT_UNIQUE), driver_name); 274 err_exit(); 275 } 276 277 if (noload_flag == 0 && server == 0) { 278 if (elf_type("/dev/ksyms", &kelf_desc, &kelf_type) == ERROR) { 279 (void) fprintf(stderr, gettext(ERR_KERNEL_ISA)); 280 err_exit(); 281 } 282 283 if (module_not_found(driver_name, path_driver_name, 284 path_driver_name_size, &drvelf_desc, &drvelf_type) == 285 ERROR) { 286 (void) fprintf(stderr, gettext(ERR_NOMOD), driver_name); 287 err_exit(); 288 } 289 290 /* 291 * If the driver location is incorrect but the kernel and driver 292 * are of the same ISA, suggest a fix. If the driver location 293 * is incorrect and the ISA's mismatch, notify the user that 294 * this driver can not be loaded on this kernel. In both cases, 295 * do not attempt to load the driver module. 296 */ 297 298 if (correct_location(path_driver_name, &drvelf_desc, 299 (&drvelf_type)) == ERROR) { 300 noload_flag = 1; 301 if (kelf_type == drvelf_type) { 302 (void) fprintf(stderr, 303 gettext(ERR_SOL_LOCATION), driver_name, 304 driver_name); 305 } else { 306 (void) fprintf(stderr, 307 gettext(ERR_NOT_LOADABLE), 308 drvelf_desc, driver_name, kelf_desc); 309 } 310 311 /* 312 * The driver location is correct. Verify that the kernel ISA 313 * and driver ISA match. If they do not match, produce an error 314 * message and do not attempt to load the module. 315 */ 316 317 } else if (kelf_type != drvelf_type) { 318 noload_flag = 1; 319 (void) fprintf(stderr, gettext(ERR_ISA_MISMATCH), 320 kelf_desc, driver_name, drvelf_desc); 321 (void) fprintf(stderr, gettext(ERR_NOT_LOADABLE), 322 drvelf_desc, driver_name, kelf_desc); 323 } 324 325 326 /* 327 * Check for a more specific driver conflict - see 328 * PSARC/1995/239 329 * Note that drv_name_conflict() can return -1 for error 330 * or 1 for a conflict. Since the default is to fail unless 331 * the -f flag is specified, we don't bother to differentiate. 332 */ 333 if ((root_node = di_init("/", DINFOSUBTREE | DINFOMINOR)) 334 == DI_NODE_NIL) { 335 (void) fprintf(stderr, gettext(ERR_DEVTREE)); 336 conflict = -1; 337 } else { 338 conflict = drv_name_conflict(root_node); 339 di_fini(root_node); 340 } 341 342 if (conflict) { 343 /* 344 * if the force flag is not set, we fail here 345 */ 346 if (!force_flag) { 347 (void) fprintf(stderr, 348 gettext(ERR_INSTALL_FAIL), driver_name); 349 (void) fprintf(stderr, "Device managed by " 350 "another driver.\n"); 351 if (verbose_flag) 352 print_drv_conflict_info(force_flag); 353 err_exit(); 354 } 355 /* 356 * The force flag was specified so we print warnings 357 * and install the driver anyways 358 */ 359 if (verbose_flag) 360 print_drv_conflict_info(force_flag); 361 free_conflict_list(conflict_lst); 362 } 363 } 364 365 if ((update_name_to_major(driver_name, &major_num, server)) == ERROR) { 366 err_exit(); 367 } 368 369 cleanup_flag |= CLEAN_NAM_MAJ; 370 371 372 if (m_flag) { 373 cleanup_flag |= CLEAN_MINOR_PERM; 374 if (update_minor_perm(driver_name, perms) == ERROR) { 375 remove_entry(cleanup_flag, driver_name); 376 err_exit(); 377 } 378 } 379 380 if (i_flag) { 381 cleanup_flag |= CLEAN_DRV_ALIAS; 382 if (update_driver_aliases(driver_name, aliases) == ERROR) { 383 remove_entry(cleanup_flag, driver_name); 384 err_exit(); 385 386 } 387 } 388 389 if (c_flag) { 390 cleanup_flag |= CLEAN_DRV_CLASSES; 391 if (update_driver_classes(driver_name, classes) == ERROR) { 392 remove_entry(cleanup_flag, driver_name); 393 err_exit(); 394 395 } 396 } 397 398 if (priv != NULL) { 399 cleanup_flag |= CLEAN_DRV_PRIV; 400 if (update_extra_privs(driver_name, priv) == ERROR) { 401 remove_entry(cleanup_flag, driver_name); 402 err_exit(); 403 } 404 } 405 406 if (policy != NULL) { 407 cleanup_flag |= CLEAN_DEV_POLICY; 408 if (update_device_policy(device_policy, policy, B_FALSE) 409 == ERROR) { 410 remove_entry(cleanup_flag, driver_name); 411 err_exit(); 412 } 413 } 414 415 if (noload_flag || server) { 416 (void) fprintf(stderr, gettext(BOOT_CLIENT)); 417 } else { 418 /* 419 * paranoia - if we crash whilst configuring the driver 420 * this might avert possible file corruption. 421 */ 422 sync(); 423 424 if (config_driver(driver_name, major_num, aliases, classes, 425 cleanup_flag, verbose_flag) == ERROR) { 426 err_exit(); 427 } 428 if (m_flag) { 429 if (devfs_update_minor_perm(basedir, 430 driver_name) == ERROR) { 431 err_exit(); 432 } 433 } 434 if (!noload_flag) 435 load_driver(driver_name, verbose_flag); 436 else 437 (void) fprintf(stderr, gettext(ERR_CONFIG_NOLOAD), 438 driver_name); 439 } 440 441 if (create_reconfig(basedir) == ERROR) 442 (void) fprintf(stderr, gettext(ERR_CREATE_RECONFIG)); 443 444 cleanup_moddir(); 445 exit_unlock(); 446 447 if (verbose_flag) { 448 (void) fprintf(stderr, gettext(DRIVER_INSTALLED), driver_name); 449 } 450 451 return (NOERR); 452 } 453 454 /* 455 * Searches for the driver module along the module path (returned 456 * from modctl) and returns a string (in drv_path) representing the path 457 * where drv_name was found. ERROR is returned if function is unable 458 * to locate drv_name. 459 */ 460 int 461 module_not_found(char *drv_name, char *drv_path, int drv_path_size, 462 char **drvelf_desc, int *drvelf_type_ptr) 463 { 464 struct stat buf; 465 char data [MAXMODPATHS]; 466 char pathsave [MAXMODPATHS]; 467 char *next = data; 468 struct drvmod_dir *curdir = NULL; 469 char foundpath[MAXPATHLEN]; 470 471 if (modctl(MODGETPATH, NULL, data) != 0) { 472 (void) fprintf(stderr, gettext(ERR_MODPATH)); 473 return (ERROR); 474 } 475 (void) strcpy(pathsave, data); 476 next = strtok(data, MOD_SEP); 477 478 if (isaspec_drvmod_discovery() == ERROR) 479 err_exit(); 480 481 curdir = moddir; 482 while (curdir != NULL) { 483 while (next != NULL) { 484 (void) snprintf(foundpath, sizeof (foundpath), 485 "%s/drv/%s/%s", next, curdir->direc, drv_name); 486 if ((stat(foundpath, &buf) == 0) && 487 ((buf.st_mode & S_IFMT) == S_IFREG)) { 488 if (elf_type(foundpath, drvelf_desc, 489 drvelf_type_ptr) == ERROR) { 490 (void) fprintf(stderr, 491 gettext(ERR_INSTALL_FAIL), 492 drv_name); 493 err_exit(); 494 } 495 remove_slashes(foundpath); 496 497 if (strlcpy(drv_path, foundpath, drv_path_size) 498 >= drv_path_size) { 499 return (ERROR); 500 } 501 502 return (NOERR); 503 } 504 next = strtok((char *)NULL, MOD_SEP); 505 } 506 (void) strcpy(data, pathsave); 507 next = strtok(data, MOD_SEP); 508 curdir = curdir->next; 509 } 510 511 return (ERROR); 512 } 513 514 static void 515 usage() 516 { 517 (void) fprintf(stderr, gettext(USAGE)); 518 } 519 520 static int 521 update_driver_classes( 522 char *driver_name, 523 char *classes) 524 { 525 /* make call to update the classes file */ 526 return (append_to_file(driver_name, classes, driver_classes, 527 ' ', "\t", 0)); 528 } 529 530 static int 531 update_minor_perm( 532 char *driver_name, 533 char *perm_list) 534 { 535 return (append_to_file(driver_name, perm_list, minor_perm, 536 ',', ":", 0)); 537 } 538 539 540 /* 541 * Complete the minor perm update by communicating the minor perm 542 * data to the kernel. This information is used by devfs to ensure 543 * that devices always have the correct permissions when attached. 544 * The minor perm file must be updated and the driver configured 545 * in the system for this step to complete correctly. 546 */ 547 static int 548 devfs_update_minor_perm( 549 char *basedir, 550 char *driver_name) 551 { 552 int rval = 0; 553 554 if (basedir == NULL || (strcmp(basedir, "/") == 0)) { 555 if (devfs_add_minor_perm(driver_name, 556 log_minorperm_error) != 0) { 557 (void) fprintf(stderr, 558 gettext(ERR_UPDATE_PERM), driver_name); 559 } 560 } 561 return (rval); 562 } 563 564 static int 565 update_extra_privs( 566 char *driver_name, 567 char *privlist) 568 { 569 return (append_to_file(driver_name, privlist, extra_privs, 570 ',', ":", 0)); 571 } 572 573 /* 574 * Check to see if the driver we are adding is a more specific 575 * driver for a device already attached to a less specific driver. 576 * In other words, see if this driver comes earlier on the compatible 577 * list of a device already attached to another driver. 578 * If so, the new node will not be created (since the device is 579 * already attached) but when the system reboots, it will attach to 580 * the new driver but not have a node - we need to warn the user 581 * if this is the case. 582 */ 583 static int 584 drv_name_conflict(di_node_t root_node) 585 { 586 /* 587 * walk the device tree checking each node 588 */ 589 if (di_walk_node(root_node, DI_WALK_SIBFIRST, NULL, devfs_node) == -1) { 590 free_conflict_list(conflict_lst); 591 conflict_lst = (struct dev_list *)NULL; 592 (void) fprintf(stderr, gettext(ERR_DEVTREE)); 593 return (-1); 594 } 595 596 if (conflict_lst == NULL) 597 /* no conflicts found */ 598 return (0); 599 else 600 /* conflicts! */ 601 return (1); 602 } 603 604 /* 605 * called via di_walk_node(). 606 * called for each node in the device tree. We skip nodes that: 607 * 1. are not hw nodes (since they cannot have generic names) 608 * 2. that do not have a compatible property 609 * 3. whose node name = binding name. 610 * 4. nexus nodes - the name of a generic nexus node would 611 * not be affected by a driver change. 612 * Otherwise, we parse the compatible property, if we find a 613 * match with the new driver before we find a match with the 614 * current driver, then we have a conflict and we save the 615 * node away. 616 */ 617 /*ARGSUSED*/ 618 static int 619 devfs_node(di_node_t node, void *arg) 620 { 621 char *binding_name, *node_name, *compat_names, *devfsnm; 622 struct dev_list *new_entry; 623 char strbuf[MAXPATHLEN]; 624 int n_names; 625 626 /* 627 * if there is no compatible property, we don't 628 * have to worry about any conflicts. 629 */ 630 if ((n_names = di_compatible_names(node, &compat_names)) <= 0) 631 return (DI_WALK_CONTINUE); 632 633 /* 634 * if the binding name and the node name match, then 635 * either no driver existed that could be bound to this node, 636 * or the driver name is the same as the node name. 637 */ 638 binding_name = di_binding_name(node); 639 node_name = di_node_name(node); 640 if ((binding_name == NULL) || (strcmp(node_name, binding_name) == 0)) 641 return (DI_WALK_CONTINUE); 642 643 /* 644 * we can skip nexus drivers since they do not 645 * have major/minor number info encoded in their 646 * /devices name and therefore won't change. 647 */ 648 if (di_driver_ops(node) & DI_BUS_OPS) 649 return (DI_WALK_CONTINUE); 650 651 /* 652 * check for conflicts 653 * If we do find that the new driver is a more specific driver 654 * than the driver already attached to the device, we'll save 655 * away the node name for processing later. 656 */ 657 if (drv_name_match(compat_names, n_names, binding_name, new_drv)) { 658 devfsnm = di_devfs_path(node); 659 (void) snprintf(strbuf, sizeof (strbuf), 660 "%s%s", DEVFS_ROOT, devfsnm); 661 di_devfs_path_free(devfsnm); 662 new_entry = (struct dev_list *)calloc(1, 663 sizeof (struct dev_list)); 664 if (new_entry == (struct dev_list *)NULL) { 665 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 666 err_exit(); 667 } 668 /* save the /devices name */ 669 if ((new_entry->dev_name = strdup(strbuf)) == NULL) { 670 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 671 free(new_entry); 672 err_exit(); 673 } 674 /* save the driver name */ 675 if ((new_entry->driver_name = strdup(di_driver_name(node))) 676 == NULL) { 677 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 678 free(new_entry->dev_name); 679 free(new_entry); 680 err_exit(); 681 } 682 /* check to see if this is a clone device */ 683 if (clone(node)) 684 new_entry->clone = 1; 685 686 /* add it to the list */ 687 new_entry->next = conflict_lst; 688 conflict_lst = new_entry; 689 } 690 691 return (DI_WALK_CONTINUE); 692 } 693 694 static int 695 clone(di_node_t node) 696 { 697 di_minor_t minor = DI_MINOR_NIL; 698 699 while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) { 700 if (di_minor_type(minor) == DDM_ALIAS) 701 return (1); 702 } 703 return (0); 704 } 705 /* 706 * check to see if the new_name shows up on the compat list before 707 * the cur_name (driver currently attached to the device). 708 */ 709 static int 710 drv_name_match(char *compat_names, int n_names, char *cur_name, char *new_name) 711 { 712 int i, ret = 0; 713 714 if (strcmp(cur_name, new_name) == 0) 715 return (0); 716 717 /* parse the coompatible list */ 718 for (i = 0; i < n_names; i++) { 719 if (strcmp(compat_names, new_name) == 0) { 720 ret = 1; 721 break; 722 } 723 if (strcmp(compat_names, cur_name) == 0) { 724 break; 725 } 726 compat_names += strlen(compat_names) + 1; 727 } 728 return (ret); 729 } 730 731 /* 732 * A more specific driver is being added for a device already attached 733 * to a less specific driver. Print out a general warning and if 734 * the force flag was passed in, give the user a hint as to what 735 * nodes may be affected in /devices and /dev 736 */ 737 static void 738 print_drv_conflict_info(int force) 739 { 740 struct dev_list *ptr; 741 742 if (conflict_lst == NULL) 743 return; 744 if (force) { 745 (void) fprintf(stderr, 746 "\nA reconfiguration boot must be performed to " 747 "complete the\n"); 748 (void) fprintf(stderr, "installation of this driver.\n"); 749 } 750 751 if (force) { 752 (void) fprintf(stderr, 753 "\nThe following entries in /devices will be " 754 "affected:\n\n"); 755 } else { 756 (void) fprintf(stderr, 757 "\nDriver installation failed because the following\n"); 758 (void) fprintf(stderr, 759 "entries in /devices would be affected:\n\n"); 760 } 761 762 ptr = conflict_lst; 763 while (ptr != NULL) { 764 (void) fprintf(stderr, "\t%s", ptr->dev_name); 765 if (ptr->clone) 766 (void) fprintf(stderr, " (clone device)\n"); 767 else 768 (void) fprintf(stderr, "[:*]\n"); 769 (void) fprintf(stderr, "\t(Device currently managed by driver " 770 "\"%s\")\n\n", ptr->driver_name); 771 ptr = ptr->next; 772 } 773 check_dev_dir(force); 774 } 775 776 /* 777 * use nftw to walk through /dev looking for links that match 778 * an entry in the conflict list. 779 */ 780 static void 781 check_dev_dir(int force) 782 { 783 int walk_flags = FTW_PHYS | FTW_MOUNT; 784 int ft_depth = 15; 785 786 if (force) { 787 (void) fprintf(stderr, "\nThe following entries in /dev will " 788 "be affected:\n\n"); 789 } else { 790 (void) fprintf(stderr, "\nThe following entries in /dev would " 791 "be affected:\n\n"); 792 } 793 794 (void) nftw("/dev", dev_node, ft_depth, walk_flags); 795 796 (void) fprintf(stderr, "\n"); 797 } 798 799 /* 800 * checks a /dev link to see if it matches any of the conlficting 801 * /devices nodes in conflict_lst. 802 */ 803 /*ARGSUSED1*/ 804 static int 805 dev_node(const char *node, const struct stat *node_stat, int flags, 806 struct FTW *ftw_info) 807 { 808 char linkbuf[MAXPATHLEN]; 809 struct dev_list *ptr; 810 811 if (readlink(node, linkbuf, MAXPATHLEN) == -1) 812 return (0); 813 814 ptr = conflict_lst; 815 816 while (ptr != NULL) { 817 if (strstr(linkbuf, ptr->dev_name) != NULL) 818 (void) fprintf(stderr, "\t%s\n", node); 819 ptr = ptr->next; 820 } 821 return (0); 822 } 823 824 825 static void 826 free_conflict_list(struct dev_list *list) 827 { 828 struct dev_list *save; 829 830 /* free up any dev_list structs we allocated. */ 831 while (list != NULL) { 832 save = list; 833 list = list->next; 834 free(save->dev_name); 835 free(save); 836 } 837 } 838 839 int 840 elf_type(char *file, char **elfdesc, int *elf_type_ptr) 841 { 842 int fd; 843 Elf *elf; 844 char *ident; 845 846 if ((fd = open(file, O_RDONLY)) < 0) { 847 (void) fprintf(stderr, gettext(ERR_CANNOT_OPEN), file, 848 strerror(errno)); 849 return (ERROR); 850 } 851 if (elf_version(EV_CURRENT) == EV_NONE) { 852 (void) fprintf(stderr, gettext(ERR_ELF_VERSION), 853 elf_errmsg(-1)); 854 (void) close(fd); 855 return (ERROR); 856 } 857 elf = elf_begin(fd, ELF_C_READ, NULL); 858 if (elf_kind(elf) != ELF_K_ELF) { 859 (void) fprintf(stderr, gettext(ERR_ELF_KIND), file); 860 (void) elf_end(elf); 861 (void) close(fd); 862 return (ERROR); 863 } 864 ident = elf_getident(elf, 0); 865 if (ident[EI_CLASS] == ELFCLASS32) { 866 *elfdesc = "32"; 867 *elf_type_ptr = ELFCLASS32; 868 } else if (ident[EI_CLASS] == ELFCLASS64) { 869 *elfdesc = "64"; 870 *elf_type_ptr = ELFCLASS64; 871 } else { 872 *elfdesc = "none"; 873 *elf_type_ptr = ELFCLASSNONE; 874 } 875 (void) elf_end(elf); 876 (void) close(fd); 877 return (NOERR); 878 } 879 880 int 881 correct_location(char *drv_path, char **drvelf_desc, int *drvelf_type_ptr) 882 { 883 884 char copy_drv_path[MAXPATHLEN]; 885 char *token = copy_drv_path; 886 887 (void) strcpy(copy_drv_path, drv_path); 888 889 if (elf_type(drv_path, drvelf_desc, drvelf_type_ptr) == ERROR) { 890 err_exit(); 891 } 892 token = strtok(copy_drv_path, DIR_SEP); 893 while (token != NULL) { 894 if (strcmp("drv", token) == 0) { 895 token = strtok((char *)NULL, DIR_SEP); 896 if (strcmp(DRVDIR64, token) == 0) { 897 if (*drvelf_type_ptr == ELFCLASS64) 898 return (NOERR); 899 (void) fprintf(stderr, gettext(ERR_LOCATION), 900 *drvelf_desc, drv_path); 901 return (ERROR); 902 } else { 903 if (*drvelf_type_ptr == ELFCLASS32) 904 return (NOERR); 905 (void) fprintf(stderr, gettext(ERR_LOCATION), 906 *drvelf_desc, drv_path); 907 return (ERROR); 908 } 909 } else { 910 token = strtok((char *)NULL, DIR_SEP); 911 } 912 } 913 return (ERROR); 914 } 915 916 /* 917 * Creates a two-element linked list of isa-specific subdirectories to 918 * search for each driver, which is is used by the function 919 * module_not_found() to convert the isa-independent modpath into an 920 * isa-specific path . The list is ordered depending on the machine 921 * architecture and instruction set architecture, corresponding to the 922 * order in which module_not_found() will search for the driver. This 923 * routine relies on an architecture not having more than two 924 * sub-architectures (e.g., sparc/sparcv9 or i386/amd64). 925 */ 926 int 927 isaspec_drvmod_discovery() 928 { 929 char arch[SYS_NMLN]; 930 931 moddir = (struct drvmod_dir *)calloc(1, sizeof (struct drvmod_dir)); 932 if (moddir == NULL) { 933 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 934 return (ERROR); 935 } 936 937 if (sysinfo(SI_ARCHITECTURE, arch, sizeof (arch)) == -1) { 938 (void) fprintf(stderr, gettext(ERR_SYSINFO_ARCH)); 939 return (ERROR); 940 } 941 942 if (strcmp(arch, "sparc") == 0 || strcmp(arch, "i386") == 0) { 943 moddir->next = (struct drvmod_dir *) 944 calloc(1, sizeof (struct drvmod_dir)); 945 if (moddir->next == NULL) { 946 (void) fprintf(stderr, gettext(ERR_NO_MEM)); 947 return (ERROR); 948 } 949 if (kelf_type == ELFCLASS64) { 950 (void) strcpy(moddir->direc, DRVDIR64); 951 (void) strcpy(moddir->next->direc, ""); 952 } else { 953 (void) strcpy(moddir->direc, ""); 954 (void) strcpy(moddir->next->direc, DRVDIR64); 955 } 956 moddir->next->next = NULL; 957 return (NOERR); 958 } else { 959 (void) fprintf(stderr, gettext(ERR_ARCH_NOT_SUPPORTED), arch); 960 return (ERROR); 961 } 962 } 963 964 void 965 remove_slashes(char *path) 966 { 967 char *slash = path; 968 char *remain_str; 969 int pathlen; 970 971 while ((slash = strchr(slash, '/')) != NULL) { 972 remain_str = ++slash; 973 while (*remain_str == '/') 974 ++remain_str; 975 if (slash != remain_str) 976 (void) strcpy(slash, remain_str); 977 } 978 979 pathlen = strlen(path); 980 if ((pathlen > 1) && path[pathlen - 1] == '/') 981 path[pathlen - 1] = '\0'; 982 } 983 984 /* 985 * This is for ITU floppies to add packages to the miniroot 986 */ 987 static int 988 ignore_root_basedir(void) 989 { 990 struct stat statbuf; 991 992 return (stat("/ADD_DRV_IGNORE_ROOT_BASEDIR", &statbuf) == 0); 993 } 994