17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5f4da9be0Scth * Common Development and Distribution License (the "License"). 6f4da9be0Scth * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 227e485317SJerry Gilliam * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <stdio.h> 277c478bd9Sstevel@tonic-gate #include <stdlib.h> 287c478bd9Sstevel@tonic-gate #include <libelf.h> 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/stat.h> 317c478bd9Sstevel@tonic-gate #include <sys/buf.h> 327c478bd9Sstevel@tonic-gate #include <wait.h> 337c478bd9Sstevel@tonic-gate #include <unistd.h> 347c478bd9Sstevel@tonic-gate #include <libintl.h> 357c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 367c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h> 377c478bd9Sstevel@tonic-gate #include <string.h> 387c478bd9Sstevel@tonic-gate #include <limits.h> 397c478bd9Sstevel@tonic-gate #include <locale.h> 407c478bd9Sstevel@tonic-gate #include <ftw.h> 417c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 427c478bd9Sstevel@tonic-gate #include <libdevinfo.h> 437c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 447c478bd9Sstevel@tonic-gate #include <fcntl.h> 4517e9b2b7SDhanaraj M #include <zone.h> 467c478bd9Sstevel@tonic-gate #include "addrem.h" 477c478bd9Sstevel@tonic-gate #include "errmsg.h" 487c478bd9Sstevel@tonic-gate #include "plcysubr.h" 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate /* 517c478bd9Sstevel@tonic-gate * globals needed for libdevinfo - there is no way to pass 527c478bd9Sstevel@tonic-gate * private data to the find routine. 537c478bd9Sstevel@tonic-gate */ 547c478bd9Sstevel@tonic-gate struct dev_list { 557c478bd9Sstevel@tonic-gate int clone; 567c478bd9Sstevel@tonic-gate char *dev_name; 577c478bd9Sstevel@tonic-gate char *driver_name; 587c478bd9Sstevel@tonic-gate struct dev_list *next; 597c478bd9Sstevel@tonic-gate }; 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate static char *kelf_desc = NULL; 627c478bd9Sstevel@tonic-gate static int kelf_type = ELFCLASSNONE; 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate static char *new_drv; 657c478bd9Sstevel@tonic-gate static struct dev_list *conflict_lst = NULL; 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate static int module_not_found(char *, char *, int, char **, int *); 687c478bd9Sstevel@tonic-gate static void usage(); 697c478bd9Sstevel@tonic-gate static int update_minor_perm(char *, char *); 702e107de7SJerry Gilliam static int devfs_update_minor_perm(char *, char *); 717c478bd9Sstevel@tonic-gate static int update_driver_classes(char *, char *); 727c478bd9Sstevel@tonic-gate static int drv_name_conflict(di_node_t); 737c478bd9Sstevel@tonic-gate static int devfs_node(di_node_t node, void *arg); 747c478bd9Sstevel@tonic-gate static int drv_name_match(char *, int, char *, char *); 757c478bd9Sstevel@tonic-gate static void print_drv_conflict_info(int); 767c478bd9Sstevel@tonic-gate static void check_dev_dir(int); 777c478bd9Sstevel@tonic-gate static int dev_node(const char *, const struct stat *, int, struct FTW *); 787c478bd9Sstevel@tonic-gate static void free_conflict_list(struct dev_list *); 797c478bd9Sstevel@tonic-gate static int clone(di_node_t node); 807c478bd9Sstevel@tonic-gate static int elf_type(char *, char **, int *); 817c478bd9Sstevel@tonic-gate static int correct_location(char *, char **, int *); 827c478bd9Sstevel@tonic-gate static int isaspec_drvmod_discovery(); 837c478bd9Sstevel@tonic-gate static void remove_slashes(char *); 847c478bd9Sstevel@tonic-gate static int update_extra_privs(char *, char *privlist); 857c478bd9Sstevel@tonic-gate static int ignore_root_basedir(); 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate int 887c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 897c478bd9Sstevel@tonic-gate { 907c478bd9Sstevel@tonic-gate int opt; 917c478bd9Sstevel@tonic-gate major_t major_num; 927c478bd9Sstevel@tonic-gate char driver_name[FILENAME_MAX + 1]; 937c478bd9Sstevel@tonic-gate int driver_name_size = sizeof (driver_name); 947c478bd9Sstevel@tonic-gate char path_driver_name[MAXPATHLEN]; 957c478bd9Sstevel@tonic-gate int path_driver_name_size = sizeof (path_driver_name); 967c478bd9Sstevel@tonic-gate char *perms = NULL; 977c478bd9Sstevel@tonic-gate char *aliases = NULL; 987c478bd9Sstevel@tonic-gate char *classes = NULL; 997c478bd9Sstevel@tonic-gate char *policy = NULL; 1007c478bd9Sstevel@tonic-gate char *priv = NULL; 1017c478bd9Sstevel@tonic-gate int noload_flag = 0; 1027c478bd9Sstevel@tonic-gate int verbose_flag = 0; 1037c478bd9Sstevel@tonic-gate int force_flag = 0; 104*c9cc1492SJerry Gilliam int update_only = 0; 1057c478bd9Sstevel@tonic-gate int i_flag = 0; 1067c478bd9Sstevel@tonic-gate int c_flag = 0; 1077c478bd9Sstevel@tonic-gate int m_flag = 0; 1087c478bd9Sstevel@tonic-gate int cleanup_flag = 0; 1097c478bd9Sstevel@tonic-gate int server = 0; 1107c478bd9Sstevel@tonic-gate char *basedir = NULL; 1117c478bd9Sstevel@tonic-gate int is_unique; 1127c478bd9Sstevel@tonic-gate char *slash; 1137c478bd9Sstevel@tonic-gate int conflict; 1147c478bd9Sstevel@tonic-gate di_node_t root_node; /* for device tree snapshot */ 1157c478bd9Sstevel@tonic-gate char *drvelf_desc = NULL; 1167c478bd9Sstevel@tonic-gate int drvelf_type = ELFCLASSNONE; 117*c9cc1492SJerry Gilliam int config_flags; 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate moddir = NULL; 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1227c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 1237c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 1247c478bd9Sstevel@tonic-gate #endif 1257c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate /* must be run by root */ 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate if (geteuid() != 0) { 1307c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NOT_ROOT)); 1317c478bd9Sstevel@tonic-gate exit(1); 1327c478bd9Sstevel@tonic-gate } 1337c478bd9Sstevel@tonic-gate 134*c9cc1492SJerry Gilliam while ((opt = getopt(argc, argv, "vfm:ni:b:c:p:P:u")) != EOF) { 1357c478bd9Sstevel@tonic-gate switch (opt) { 1367c478bd9Sstevel@tonic-gate case 'm' : 1377c478bd9Sstevel@tonic-gate m_flag = 1; 1387c478bd9Sstevel@tonic-gate perms = optarg; 1397c478bd9Sstevel@tonic-gate break; 1407c478bd9Sstevel@tonic-gate case 'f': 1417c478bd9Sstevel@tonic-gate force_flag++; 1427c478bd9Sstevel@tonic-gate break; 1437c478bd9Sstevel@tonic-gate case 'v': 1447c478bd9Sstevel@tonic-gate verbose_flag++; 1457c478bd9Sstevel@tonic-gate break; 1467c478bd9Sstevel@tonic-gate case 'n': 1477c478bd9Sstevel@tonic-gate noload_flag++; 1487c478bd9Sstevel@tonic-gate break; 1497c478bd9Sstevel@tonic-gate case 'i' : 1507c478bd9Sstevel@tonic-gate i_flag = 1; 1517c478bd9Sstevel@tonic-gate aliases = optarg; 1527c478bd9Sstevel@tonic-gate if (check_space_within_quote(aliases) == ERROR) { 1537c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_SPACE), 1547c478bd9Sstevel@tonic-gate aliases); 1557c478bd9Sstevel@tonic-gate exit(1); 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate break; 1587c478bd9Sstevel@tonic-gate case 'b' : 1597c478bd9Sstevel@tonic-gate server = 1; 1607c478bd9Sstevel@tonic-gate basedir = optarg; 1617c478bd9Sstevel@tonic-gate if (strcmp(basedir, "/") == 0 && 1627c478bd9Sstevel@tonic-gate ignore_root_basedir()) { 1637c478bd9Sstevel@tonic-gate server = 0; 1647c478bd9Sstevel@tonic-gate basedir = NULL; 1657c478bd9Sstevel@tonic-gate } 1667c478bd9Sstevel@tonic-gate break; 1677c478bd9Sstevel@tonic-gate case 'c': 1687c478bd9Sstevel@tonic-gate c_flag = 1; 1697c478bd9Sstevel@tonic-gate classes = optarg; 1707c478bd9Sstevel@tonic-gate break; 1717c478bd9Sstevel@tonic-gate case 'p': 1727c478bd9Sstevel@tonic-gate policy = optarg; 1737c478bd9Sstevel@tonic-gate break; 1747c478bd9Sstevel@tonic-gate case 'P': 1757c478bd9Sstevel@tonic-gate priv = optarg; 1767c478bd9Sstevel@tonic-gate break; 177*c9cc1492SJerry Gilliam case 'u': 178*c9cc1492SJerry Gilliam /* 179*c9cc1492SJerry Gilliam * Update binding files and kernel but 180*c9cc1492SJerry Gilliam * do not load or configure devices. 181*c9cc1492SJerry Gilliam */ 182*c9cc1492SJerry Gilliam update_only = 1; 183*c9cc1492SJerry Gilliam break; 1847c478bd9Sstevel@tonic-gate case '?' : 1857c478bd9Sstevel@tonic-gate default: 1867c478bd9Sstevel@tonic-gate usage(); 1877c478bd9Sstevel@tonic-gate exit(1); 1887c478bd9Sstevel@tonic-gate } 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate if (argv[optind] != NULL) { 1937c478bd9Sstevel@tonic-gate if (strlcpy(driver_name, argv[optind], driver_name_size) >= 1947c478bd9Sstevel@tonic-gate driver_name_size) { 1957c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_DRVNAME_TOO_LONG), 1967c478bd9Sstevel@tonic-gate driver_name_size, argv[optind]); 1977c478bd9Sstevel@tonic-gate exit(1); 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate /* 2017c478bd9Sstevel@tonic-gate * check for extra args 2027c478bd9Sstevel@tonic-gate */ 2037c478bd9Sstevel@tonic-gate if ((optind + 1) != argc) { 2047c478bd9Sstevel@tonic-gate usage(); 2057c478bd9Sstevel@tonic-gate exit(1); 2067c478bd9Sstevel@tonic-gate } 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate } else { 2097c478bd9Sstevel@tonic-gate usage(); 2107c478bd9Sstevel@tonic-gate exit(1); 2117c478bd9Sstevel@tonic-gate } 2127c478bd9Sstevel@tonic-gate 21317e9b2b7SDhanaraj M if (getzoneid() != GLOBAL_ZONEID) { 21417e9b2b7SDhanaraj M (void) fprintf(stderr, gettext(ERR_NOT_GLOBAL_ZONE)); 21517e9b2b7SDhanaraj M exit(1); 21617e9b2b7SDhanaraj M } 21717e9b2b7SDhanaraj M 2187c478bd9Sstevel@tonic-gate /* 2197c478bd9Sstevel@tonic-gate * Fail if add_drv was invoked with a pathname prepended to the 2207c478bd9Sstevel@tonic-gate * driver_name argument. 2217c478bd9Sstevel@tonic-gate * 2227c478bd9Sstevel@tonic-gate * Check driver_name for any '/'s. If found, we assume that caller 2237c478bd9Sstevel@tonic-gate * is trying to specify a pathname. 2247c478bd9Sstevel@tonic-gate */ 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate slash = strchr(driver_name, '/'); 2277c478bd9Sstevel@tonic-gate if (slash) { 2287c478bd9Sstevel@tonic-gate remove_slashes(driver_name); 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate /* extract module name out of path */ 2317c478bd9Sstevel@tonic-gate slash = strrchr(driver_name, '/'); 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate if (slash != NULL) { 2347c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_PATH_SPEC), 2357c478bd9Sstevel@tonic-gate driver_name); 2367c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_INSTALL_FAIL), 2377c478bd9Sstevel@tonic-gate ++slash); 2387c478bd9Sstevel@tonic-gate exit(1); 2397c478bd9Sstevel@tonic-gate } 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate new_drv = driver_name; 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate /* set up add_drv filenames */ 2447c478bd9Sstevel@tonic-gate if ((build_filenames(basedir)) == ERROR) { 2457c478bd9Sstevel@tonic-gate exit(1); 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate /* must be only running version of add_drv/rem_drv */ 2497c478bd9Sstevel@tonic-gate enter_lock(); 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate if ((check_perms_aliases(m_flag, i_flag)) == ERROR) 2527c478bd9Sstevel@tonic-gate err_exit(); 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate if ((check_name_to_major(R_OK | W_OK)) == ERROR) 2557c478bd9Sstevel@tonic-gate err_exit(); 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate /* 2587c478bd9Sstevel@tonic-gate * check validity of options 2597c478bd9Sstevel@tonic-gate */ 2607c478bd9Sstevel@tonic-gate if (m_flag) { 2617c478bd9Sstevel@tonic-gate if ((check_perm_opts(perms)) == ERROR) { 2627c478bd9Sstevel@tonic-gate usage(); 2637c478bd9Sstevel@tonic-gate err_exit(); 2647c478bd9Sstevel@tonic-gate } 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate if (i_flag) { 2687c478bd9Sstevel@tonic-gate if (aliases != NULL) 2697c478bd9Sstevel@tonic-gate if ((aliases_unique(aliases)) == ERROR) 2707c478bd9Sstevel@tonic-gate err_exit(); 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate 273*c9cc1492SJerry Gilliam /* -u and -n/-b are mutually exclusive */ 274*c9cc1492SJerry Gilliam if (update_only && (noload_flag || server)) { 275*c9cc1492SJerry Gilliam usage(); 276*c9cc1492SJerry Gilliam err_exit(); 277*c9cc1492SJerry Gilliam } 278*c9cc1492SJerry Gilliam 2797e485317SJerry Gilliam /* update kernel unless -b or -n */ 2807e485317SJerry Gilliam if (noload_flag == 0 && server == 0 && 2817e485317SJerry Gilliam priv != NULL && check_priv_entry(priv, 1) != 0) 2827c478bd9Sstevel@tonic-gate err_exit(); 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate if (policy != NULL && 2857c478bd9Sstevel@tonic-gate (policy = check_plcy_entry(policy, driver_name, B_FALSE)) == NULL) { 2867c478bd9Sstevel@tonic-gate err_exit(); 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate if ((unique_driver_name(driver_name, name_to_major, 2907c478bd9Sstevel@tonic-gate &is_unique)) == ERROR) 2917c478bd9Sstevel@tonic-gate err_exit(); 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate if (is_unique == NOT_UNIQUE) { 2947c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NOT_UNIQUE), driver_name); 2957c478bd9Sstevel@tonic-gate err_exit(); 2967c478bd9Sstevel@tonic-gate } 2977c478bd9Sstevel@tonic-gate 2987e485317SJerry Gilliam if (noload_flag == 0 && server == 0) { 2997c478bd9Sstevel@tonic-gate if (elf_type("/dev/ksyms", &kelf_desc, &kelf_type) == ERROR) { 3007c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_KERNEL_ISA)); 3017c478bd9Sstevel@tonic-gate err_exit(); 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate if (module_not_found(driver_name, path_driver_name, 3057c478bd9Sstevel@tonic-gate path_driver_name_size, &drvelf_desc, &drvelf_type) == 3067c478bd9Sstevel@tonic-gate ERROR) { 3077c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NOMOD), driver_name); 3087c478bd9Sstevel@tonic-gate err_exit(); 3097c478bd9Sstevel@tonic-gate } 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate /* 3127c478bd9Sstevel@tonic-gate * If the driver location is incorrect but the kernel and driver 3137c478bd9Sstevel@tonic-gate * are of the same ISA, suggest a fix. If the driver location 3147c478bd9Sstevel@tonic-gate * is incorrect and the ISA's mismatch, notify the user that 3157c478bd9Sstevel@tonic-gate * this driver can not be loaded on this kernel. In both cases, 3167c478bd9Sstevel@tonic-gate * do not attempt to load the driver module. 3177c478bd9Sstevel@tonic-gate */ 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate if (correct_location(path_driver_name, &drvelf_desc, 3207c478bd9Sstevel@tonic-gate (&drvelf_type)) == ERROR) { 3217c478bd9Sstevel@tonic-gate noload_flag = 1; 3227c478bd9Sstevel@tonic-gate if (kelf_type == drvelf_type) { 3237c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3247c478bd9Sstevel@tonic-gate gettext(ERR_SOL_LOCATION), driver_name, 3257c478bd9Sstevel@tonic-gate driver_name); 3267c478bd9Sstevel@tonic-gate } else { 3277c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3287c478bd9Sstevel@tonic-gate gettext(ERR_NOT_LOADABLE), 3297c478bd9Sstevel@tonic-gate drvelf_desc, driver_name, kelf_desc); 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* 3337c478bd9Sstevel@tonic-gate * The driver location is correct. Verify that the kernel ISA 3347c478bd9Sstevel@tonic-gate * and driver ISA match. If they do not match, produce an error 3357c478bd9Sstevel@tonic-gate * message and do not attempt to load the module. 3367c478bd9Sstevel@tonic-gate */ 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate } else if (kelf_type != drvelf_type) { 3397c478bd9Sstevel@tonic-gate noload_flag = 1; 3407c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_ISA_MISMATCH), 3417c478bd9Sstevel@tonic-gate kelf_desc, driver_name, drvelf_desc); 3427c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NOT_LOADABLE), 3437c478bd9Sstevel@tonic-gate drvelf_desc, driver_name, kelf_desc); 3447c478bd9Sstevel@tonic-gate } 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate /* 3487c478bd9Sstevel@tonic-gate * Check for a more specific driver conflict - see 3497c478bd9Sstevel@tonic-gate * PSARC/1995/239 3507c478bd9Sstevel@tonic-gate * Note that drv_name_conflict() can return -1 for error 3517c478bd9Sstevel@tonic-gate * or 1 for a conflict. Since the default is to fail unless 3527c478bd9Sstevel@tonic-gate * the -f flag is specified, we don't bother to differentiate. 3537c478bd9Sstevel@tonic-gate */ 3547c478bd9Sstevel@tonic-gate if ((root_node = di_init("/", DINFOSUBTREE | DINFOMINOR)) 3557c478bd9Sstevel@tonic-gate == DI_NODE_NIL) { 3567c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_DEVTREE)); 3577c478bd9Sstevel@tonic-gate conflict = -1; 3587c478bd9Sstevel@tonic-gate } else { 3597c478bd9Sstevel@tonic-gate conflict = drv_name_conflict(root_node); 3607c478bd9Sstevel@tonic-gate di_fini(root_node); 3617c478bd9Sstevel@tonic-gate } 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate if (conflict) { 3647c478bd9Sstevel@tonic-gate /* 3657c478bd9Sstevel@tonic-gate * if the force flag is not set, we fail here 3667c478bd9Sstevel@tonic-gate */ 3677c478bd9Sstevel@tonic-gate if (!force_flag) { 3687c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3697c478bd9Sstevel@tonic-gate gettext(ERR_INSTALL_FAIL), driver_name); 3707c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Device managed by " 3717c478bd9Sstevel@tonic-gate "another driver.\n"); 3727c478bd9Sstevel@tonic-gate if (verbose_flag) 3737c478bd9Sstevel@tonic-gate print_drv_conflict_info(force_flag); 3747c478bd9Sstevel@tonic-gate err_exit(); 3757c478bd9Sstevel@tonic-gate } 3767c478bd9Sstevel@tonic-gate /* 3777c478bd9Sstevel@tonic-gate * The force flag was specified so we print warnings 3787c478bd9Sstevel@tonic-gate * and install the driver anyways 3797c478bd9Sstevel@tonic-gate */ 3807c478bd9Sstevel@tonic-gate if (verbose_flag) 3817c478bd9Sstevel@tonic-gate print_drv_conflict_info(force_flag); 3827c478bd9Sstevel@tonic-gate free_conflict_list(conflict_lst); 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate if ((update_name_to_major(driver_name, &major_num, server)) == ERROR) { 3877c478bd9Sstevel@tonic-gate err_exit(); 3887c478bd9Sstevel@tonic-gate } 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate cleanup_flag |= CLEAN_NAM_MAJ; 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate if (m_flag) { 3947c478bd9Sstevel@tonic-gate cleanup_flag |= CLEAN_MINOR_PERM; 3957c478bd9Sstevel@tonic-gate if (update_minor_perm(driver_name, perms) == ERROR) { 3967c478bd9Sstevel@tonic-gate remove_entry(cleanup_flag, driver_name); 3977c478bd9Sstevel@tonic-gate err_exit(); 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate if (i_flag) { 4027c478bd9Sstevel@tonic-gate cleanup_flag |= CLEAN_DRV_ALIAS; 4037c478bd9Sstevel@tonic-gate if (update_driver_aliases(driver_name, aliases) == ERROR) { 4047c478bd9Sstevel@tonic-gate remove_entry(cleanup_flag, driver_name); 4057c478bd9Sstevel@tonic-gate err_exit(); 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate if (c_flag) { 4117c478bd9Sstevel@tonic-gate cleanup_flag |= CLEAN_DRV_CLASSES; 4127c478bd9Sstevel@tonic-gate if (update_driver_classes(driver_name, classes) == ERROR) { 4137c478bd9Sstevel@tonic-gate remove_entry(cleanup_flag, driver_name); 4147c478bd9Sstevel@tonic-gate err_exit(); 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate } 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate if (priv != NULL) { 4207c478bd9Sstevel@tonic-gate cleanup_flag |= CLEAN_DRV_PRIV; 4217c478bd9Sstevel@tonic-gate if (update_extra_privs(driver_name, priv) == ERROR) { 4227c478bd9Sstevel@tonic-gate remove_entry(cleanup_flag, driver_name); 4237c478bd9Sstevel@tonic-gate err_exit(); 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate if (policy != NULL) { 4287c478bd9Sstevel@tonic-gate cleanup_flag |= CLEAN_DEV_POLICY; 4297c478bd9Sstevel@tonic-gate if (update_device_policy(device_policy, policy, B_FALSE) 4307c478bd9Sstevel@tonic-gate == ERROR) { 4317c478bd9Sstevel@tonic-gate remove_entry(cleanup_flag, driver_name); 4327c478bd9Sstevel@tonic-gate err_exit(); 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate } 4357c478bd9Sstevel@tonic-gate 4367e485317SJerry Gilliam if (noload_flag || server) { 4377c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(BOOT_CLIENT)); 4387c478bd9Sstevel@tonic-gate } else { 4397c478bd9Sstevel@tonic-gate /* 4407c478bd9Sstevel@tonic-gate * paranoia - if we crash whilst configuring the driver 4417c478bd9Sstevel@tonic-gate * this might avert possible file corruption. 4427c478bd9Sstevel@tonic-gate */ 4437c478bd9Sstevel@tonic-gate sync(); 4447c478bd9Sstevel@tonic-gate 445*c9cc1492SJerry Gilliam config_flags = 0; 446*c9cc1492SJerry Gilliam if (verbose_flag) 447*c9cc1492SJerry Gilliam config_flags |= CONFIG_DRV_VERBOSE; 448*c9cc1492SJerry Gilliam if (update_only) 449*c9cc1492SJerry Gilliam config_flags |= CONFIG_DRV_UPDATE_ONLY; 450*c9cc1492SJerry Gilliam 4517c478bd9Sstevel@tonic-gate if (config_driver(driver_name, major_num, aliases, classes, 452*c9cc1492SJerry Gilliam cleanup_flag, config_flags) == ERROR) { 4537c478bd9Sstevel@tonic-gate err_exit(); 4547c478bd9Sstevel@tonic-gate } 4557c478bd9Sstevel@tonic-gate if (m_flag) { 4567c478bd9Sstevel@tonic-gate if (devfs_update_minor_perm(basedir, 4572e107de7SJerry Gilliam driver_name) == ERROR) { 4587c478bd9Sstevel@tonic-gate err_exit(); 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate } 461*c9cc1492SJerry Gilliam if (update_only) { 462*c9cc1492SJerry Gilliam (void) fprintf(stderr, gettext(INFO_UPDATE_ONLY), 463*c9cc1492SJerry Gilliam driver_name); 464*c9cc1492SJerry Gilliam } else if (noload_flag) { 4657c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_CONFIG_NOLOAD), 4667c478bd9Sstevel@tonic-gate driver_name); 467*c9cc1492SJerry Gilliam } else { 468*c9cc1492SJerry Gilliam load_driver(driver_name, verbose_flag); 469*c9cc1492SJerry Gilliam } 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate if (create_reconfig(basedir) == ERROR) 4737c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_CREATE_RECONFIG)); 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate cleanup_moddir(); 4767c478bd9Sstevel@tonic-gate exit_unlock(); 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate if (verbose_flag) { 4797c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(DRIVER_INSTALLED), driver_name); 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate return (NOERR); 4837c478bd9Sstevel@tonic-gate } 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate /* 4867c478bd9Sstevel@tonic-gate * Searches for the driver module along the module path (returned 4877c478bd9Sstevel@tonic-gate * from modctl) and returns a string (in drv_path) representing the path 4887c478bd9Sstevel@tonic-gate * where drv_name was found. ERROR is returned if function is unable 4897c478bd9Sstevel@tonic-gate * to locate drv_name. 4907c478bd9Sstevel@tonic-gate */ 4917c478bd9Sstevel@tonic-gate int 4927c478bd9Sstevel@tonic-gate module_not_found(char *drv_name, char *drv_path, int drv_path_size, 4937c478bd9Sstevel@tonic-gate char **drvelf_desc, int *drvelf_type_ptr) 4947c478bd9Sstevel@tonic-gate { 4957c478bd9Sstevel@tonic-gate struct stat buf; 4967c478bd9Sstevel@tonic-gate char data [MAXMODPATHS]; 4977c478bd9Sstevel@tonic-gate char pathsave [MAXMODPATHS]; 4987c478bd9Sstevel@tonic-gate char *next = data; 4997c478bd9Sstevel@tonic-gate struct drvmod_dir *curdir = NULL; 5007c478bd9Sstevel@tonic-gate char foundpath[MAXPATHLEN]; 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate if (modctl(MODGETPATH, NULL, data) != 0) { 5037c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_MODPATH)); 5047c478bd9Sstevel@tonic-gate return (ERROR); 5057c478bd9Sstevel@tonic-gate } 5067c478bd9Sstevel@tonic-gate (void) strcpy(pathsave, data); 5077c478bd9Sstevel@tonic-gate next = strtok(data, MOD_SEP); 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate if (isaspec_drvmod_discovery() == ERROR) 5107c478bd9Sstevel@tonic-gate err_exit(); 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate curdir = moddir; 5137c478bd9Sstevel@tonic-gate while (curdir != NULL) { 5147c478bd9Sstevel@tonic-gate while (next != NULL) { 5157c478bd9Sstevel@tonic-gate (void) snprintf(foundpath, sizeof (foundpath), 5167c478bd9Sstevel@tonic-gate "%s/drv/%s/%s", next, curdir->direc, drv_name); 5177c478bd9Sstevel@tonic-gate if ((stat(foundpath, &buf) == 0) && 5187c478bd9Sstevel@tonic-gate ((buf.st_mode & S_IFMT) == S_IFREG)) { 5197c478bd9Sstevel@tonic-gate if (elf_type(foundpath, drvelf_desc, 5207c478bd9Sstevel@tonic-gate drvelf_type_ptr) == ERROR) { 5217c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 5227c478bd9Sstevel@tonic-gate gettext(ERR_INSTALL_FAIL), 5237c478bd9Sstevel@tonic-gate drv_name); 5247c478bd9Sstevel@tonic-gate err_exit(); 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate remove_slashes(foundpath); 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate if (strlcpy(drv_path, foundpath, drv_path_size) 5297c478bd9Sstevel@tonic-gate >= drv_path_size) { 5307c478bd9Sstevel@tonic-gate return (ERROR); 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate return (NOERR); 5347c478bd9Sstevel@tonic-gate } 5357c478bd9Sstevel@tonic-gate next = strtok((char *)NULL, MOD_SEP); 5367c478bd9Sstevel@tonic-gate } 5377c478bd9Sstevel@tonic-gate (void) strcpy(data, pathsave); 5387c478bd9Sstevel@tonic-gate next = strtok(data, MOD_SEP); 5397c478bd9Sstevel@tonic-gate curdir = curdir->next; 5407c478bd9Sstevel@tonic-gate } 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate return (ERROR); 5437c478bd9Sstevel@tonic-gate } 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate static void 5467c478bd9Sstevel@tonic-gate usage() 5477c478bd9Sstevel@tonic-gate { 5487c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(USAGE)); 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate static int 5527c478bd9Sstevel@tonic-gate update_driver_classes( 5537c478bd9Sstevel@tonic-gate char *driver_name, 5547c478bd9Sstevel@tonic-gate char *classes) 5557c478bd9Sstevel@tonic-gate { 5567c478bd9Sstevel@tonic-gate /* make call to update the classes file */ 5577c478bd9Sstevel@tonic-gate return (append_to_file(driver_name, classes, driver_classes, 558f4da9be0Scth ' ', "\t", 0)); 5597c478bd9Sstevel@tonic-gate } 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate static int 5627c478bd9Sstevel@tonic-gate update_minor_perm( 5637c478bd9Sstevel@tonic-gate char *driver_name, 5647c478bd9Sstevel@tonic-gate char *perm_list) 5657c478bd9Sstevel@tonic-gate { 5663c0ea289SJerry Gilliam return (append_to_minor_perm(driver_name, perm_list, minor_perm)); 5677c478bd9Sstevel@tonic-gate } 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate /* 5717c478bd9Sstevel@tonic-gate * Complete the minor perm update by communicating the minor perm 5727c478bd9Sstevel@tonic-gate * data to the kernel. This information is used by devfs to ensure 5737c478bd9Sstevel@tonic-gate * that devices always have the correct permissions when attached. 5747c478bd9Sstevel@tonic-gate * The minor perm file must be updated and the driver configured 5757c478bd9Sstevel@tonic-gate * in the system for this step to complete correctly. 5767c478bd9Sstevel@tonic-gate */ 5777c478bd9Sstevel@tonic-gate static int 5787c478bd9Sstevel@tonic-gate devfs_update_minor_perm( 5797c478bd9Sstevel@tonic-gate char *basedir, 5802e107de7SJerry Gilliam char *driver_name) 5817c478bd9Sstevel@tonic-gate { 5827c478bd9Sstevel@tonic-gate int rval = 0; 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate if (basedir == NULL || (strcmp(basedir, "/") == 0)) { 5857c478bd9Sstevel@tonic-gate if (devfs_add_minor_perm(driver_name, 5867c478bd9Sstevel@tonic-gate log_minorperm_error) != 0) { 5877c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 5887c478bd9Sstevel@tonic-gate gettext(ERR_UPDATE_PERM), driver_name); 5897c478bd9Sstevel@tonic-gate } 5907c478bd9Sstevel@tonic-gate } 5917c478bd9Sstevel@tonic-gate return (rval); 5927c478bd9Sstevel@tonic-gate } 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate static int 5957c478bd9Sstevel@tonic-gate update_extra_privs( 5967c478bd9Sstevel@tonic-gate char *driver_name, 5977c478bd9Sstevel@tonic-gate char *privlist) 5987c478bd9Sstevel@tonic-gate { 599f4da9be0Scth return (append_to_file(driver_name, privlist, extra_privs, 600f4da9be0Scth ',', ":", 0)); 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate /* 6047c478bd9Sstevel@tonic-gate * Check to see if the driver we are adding is a more specific 6057c478bd9Sstevel@tonic-gate * driver for a device already attached to a less specific driver. 6067c478bd9Sstevel@tonic-gate * In other words, see if this driver comes earlier on the compatible 6077c478bd9Sstevel@tonic-gate * list of a device already attached to another driver. 6087c478bd9Sstevel@tonic-gate * If so, the new node will not be created (since the device is 6097c478bd9Sstevel@tonic-gate * already attached) but when the system reboots, it will attach to 6107c478bd9Sstevel@tonic-gate * the new driver but not have a node - we need to warn the user 6117c478bd9Sstevel@tonic-gate * if this is the case. 6127c478bd9Sstevel@tonic-gate */ 6137c478bd9Sstevel@tonic-gate static int 6147c478bd9Sstevel@tonic-gate drv_name_conflict(di_node_t root_node) 6157c478bd9Sstevel@tonic-gate { 6167c478bd9Sstevel@tonic-gate /* 6177c478bd9Sstevel@tonic-gate * walk the device tree checking each node 6187c478bd9Sstevel@tonic-gate */ 6197c478bd9Sstevel@tonic-gate if (di_walk_node(root_node, DI_WALK_SIBFIRST, NULL, devfs_node) == -1) { 6207c478bd9Sstevel@tonic-gate free_conflict_list(conflict_lst); 6217c478bd9Sstevel@tonic-gate conflict_lst = (struct dev_list *)NULL; 6227c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_DEVTREE)); 6237c478bd9Sstevel@tonic-gate return (-1); 6247c478bd9Sstevel@tonic-gate } 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate if (conflict_lst == NULL) 6277c478bd9Sstevel@tonic-gate /* no conflicts found */ 6287c478bd9Sstevel@tonic-gate return (0); 6297c478bd9Sstevel@tonic-gate else 6307c478bd9Sstevel@tonic-gate /* conflicts! */ 6317c478bd9Sstevel@tonic-gate return (1); 6327c478bd9Sstevel@tonic-gate } 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate /* 6357c478bd9Sstevel@tonic-gate * called via di_walk_node(). 6367c478bd9Sstevel@tonic-gate * called for each node in the device tree. We skip nodes that: 6377c478bd9Sstevel@tonic-gate * 1. are not hw nodes (since they cannot have generic names) 6387c478bd9Sstevel@tonic-gate * 2. that do not have a compatible property 6397c478bd9Sstevel@tonic-gate * 3. whose node name = binding name. 6407c478bd9Sstevel@tonic-gate * 4. nexus nodes - the name of a generic nexus node would 6417c478bd9Sstevel@tonic-gate * not be affected by a driver change. 6427c478bd9Sstevel@tonic-gate * Otherwise, we parse the compatible property, if we find a 6437c478bd9Sstevel@tonic-gate * match with the new driver before we find a match with the 6447c478bd9Sstevel@tonic-gate * current driver, then we have a conflict and we save the 6457c478bd9Sstevel@tonic-gate * node away. 6467c478bd9Sstevel@tonic-gate */ 6477c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6487c478bd9Sstevel@tonic-gate static int 6497c478bd9Sstevel@tonic-gate devfs_node(di_node_t node, void *arg) 6507c478bd9Sstevel@tonic-gate { 6517c478bd9Sstevel@tonic-gate char *binding_name, *node_name, *compat_names, *devfsnm; 6527c478bd9Sstevel@tonic-gate struct dev_list *new_entry; 6537c478bd9Sstevel@tonic-gate char strbuf[MAXPATHLEN]; 6547c478bd9Sstevel@tonic-gate int n_names; 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate /* 6577c478bd9Sstevel@tonic-gate * if there is no compatible property, we don't 6587c478bd9Sstevel@tonic-gate * have to worry about any conflicts. 6597c478bd9Sstevel@tonic-gate */ 6607c478bd9Sstevel@tonic-gate if ((n_names = di_compatible_names(node, &compat_names)) <= 0) 6617c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate /* 6647c478bd9Sstevel@tonic-gate * if the binding name and the node name match, then 6657c478bd9Sstevel@tonic-gate * either no driver existed that could be bound to this node, 6667c478bd9Sstevel@tonic-gate * or the driver name is the same as the node name. 6677c478bd9Sstevel@tonic-gate */ 6687c478bd9Sstevel@tonic-gate binding_name = di_binding_name(node); 6697c478bd9Sstevel@tonic-gate node_name = di_node_name(node); 6707c478bd9Sstevel@tonic-gate if ((binding_name == NULL) || (strcmp(node_name, binding_name) == 0)) 6717c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate /* 6747c478bd9Sstevel@tonic-gate * we can skip nexus drivers since they do not 6757c478bd9Sstevel@tonic-gate * have major/minor number info encoded in their 6767c478bd9Sstevel@tonic-gate * /devices name and therefore won't change. 6777c478bd9Sstevel@tonic-gate */ 6787c478bd9Sstevel@tonic-gate if (di_driver_ops(node) & DI_BUS_OPS) 6797c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate /* 6827c478bd9Sstevel@tonic-gate * check for conflicts 6837c478bd9Sstevel@tonic-gate * If we do find that the new driver is a more specific driver 6847c478bd9Sstevel@tonic-gate * than the driver already attached to the device, we'll save 6857c478bd9Sstevel@tonic-gate * away the node name for processing later. 6867c478bd9Sstevel@tonic-gate */ 6877c478bd9Sstevel@tonic-gate if (drv_name_match(compat_names, n_names, binding_name, new_drv)) { 6887c478bd9Sstevel@tonic-gate devfsnm = di_devfs_path(node); 6892e107de7SJerry Gilliam (void) snprintf(strbuf, sizeof (strbuf), 6902e107de7SJerry Gilliam "%s%s", DEVFS_ROOT, devfsnm); 6917c478bd9Sstevel@tonic-gate di_devfs_path_free(devfsnm); 6927c478bd9Sstevel@tonic-gate new_entry = (struct dev_list *)calloc(1, 6937c478bd9Sstevel@tonic-gate sizeof (struct dev_list)); 6947c478bd9Sstevel@tonic-gate if (new_entry == (struct dev_list *)NULL) { 6957c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_MEM)); 6967c478bd9Sstevel@tonic-gate err_exit(); 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate /* save the /devices name */ 6997c478bd9Sstevel@tonic-gate if ((new_entry->dev_name = strdup(strbuf)) == NULL) { 7007c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_MEM)); 7017c478bd9Sstevel@tonic-gate free(new_entry); 7027c478bd9Sstevel@tonic-gate err_exit(); 7037c478bd9Sstevel@tonic-gate } 7047c478bd9Sstevel@tonic-gate /* save the driver name */ 7057c478bd9Sstevel@tonic-gate if ((new_entry->driver_name = strdup(di_driver_name(node))) 7067c478bd9Sstevel@tonic-gate == NULL) { 7077c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_MEM)); 7087c478bd9Sstevel@tonic-gate free(new_entry->dev_name); 7097c478bd9Sstevel@tonic-gate free(new_entry); 7107c478bd9Sstevel@tonic-gate err_exit(); 7117c478bd9Sstevel@tonic-gate } 7127c478bd9Sstevel@tonic-gate /* check to see if this is a clone device */ 7137c478bd9Sstevel@tonic-gate if (clone(node)) 7147c478bd9Sstevel@tonic-gate new_entry->clone = 1; 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate /* add it to the list */ 7177c478bd9Sstevel@tonic-gate new_entry->next = conflict_lst; 7187c478bd9Sstevel@tonic-gate conflict_lst = new_entry; 7197c478bd9Sstevel@tonic-gate } 7207c478bd9Sstevel@tonic-gate 7217c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate static int 7257c478bd9Sstevel@tonic-gate clone(di_node_t node) 7267c478bd9Sstevel@tonic-gate { 7277c478bd9Sstevel@tonic-gate di_minor_t minor = DI_MINOR_NIL; 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) { 7307c478bd9Sstevel@tonic-gate if (di_minor_type(minor) == DDM_ALIAS) 7317c478bd9Sstevel@tonic-gate return (1); 7327c478bd9Sstevel@tonic-gate } 7337c478bd9Sstevel@tonic-gate return (0); 7347c478bd9Sstevel@tonic-gate } 7357c478bd9Sstevel@tonic-gate /* 7367c478bd9Sstevel@tonic-gate * check to see if the new_name shows up on the compat list before 7377c478bd9Sstevel@tonic-gate * the cur_name (driver currently attached to the device). 7387c478bd9Sstevel@tonic-gate */ 7397c478bd9Sstevel@tonic-gate static int 7407c478bd9Sstevel@tonic-gate drv_name_match(char *compat_names, int n_names, char *cur_name, char *new_name) 7417c478bd9Sstevel@tonic-gate { 7427c478bd9Sstevel@tonic-gate int i, ret = 0; 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate if (strcmp(cur_name, new_name) == 0) 7457c478bd9Sstevel@tonic-gate return (0); 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate /* parse the coompatible list */ 7487c478bd9Sstevel@tonic-gate for (i = 0; i < n_names; i++) { 7497c478bd9Sstevel@tonic-gate if (strcmp(compat_names, new_name) == 0) { 7507c478bd9Sstevel@tonic-gate ret = 1; 7517c478bd9Sstevel@tonic-gate break; 7527c478bd9Sstevel@tonic-gate } 7537c478bd9Sstevel@tonic-gate if (strcmp(compat_names, cur_name) == 0) { 7547c478bd9Sstevel@tonic-gate break; 7557c478bd9Sstevel@tonic-gate } 7567c478bd9Sstevel@tonic-gate compat_names += strlen(compat_names) + 1; 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate return (ret); 7597c478bd9Sstevel@tonic-gate } 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gate /* 7627c478bd9Sstevel@tonic-gate * A more specific driver is being added for a device already attached 7637c478bd9Sstevel@tonic-gate * to a less specific driver. Print out a general warning and if 7647c478bd9Sstevel@tonic-gate * the force flag was passed in, give the user a hint as to what 7657c478bd9Sstevel@tonic-gate * nodes may be affected in /devices and /dev 7667c478bd9Sstevel@tonic-gate */ 7677c478bd9Sstevel@tonic-gate static void 7687c478bd9Sstevel@tonic-gate print_drv_conflict_info(int force) 7697c478bd9Sstevel@tonic-gate { 7707c478bd9Sstevel@tonic-gate struct dev_list *ptr; 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate if (conflict_lst == NULL) 7737c478bd9Sstevel@tonic-gate return; 7747c478bd9Sstevel@tonic-gate if (force) { 7757c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 7767c478bd9Sstevel@tonic-gate "\nA reconfiguration boot must be performed to " 7777c478bd9Sstevel@tonic-gate "complete the\n"); 7787c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "installation of this driver.\n"); 7797c478bd9Sstevel@tonic-gate } 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate if (force) { 7827c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 7837c478bd9Sstevel@tonic-gate "\nThe following entries in /devices will be " 7847c478bd9Sstevel@tonic-gate "affected:\n\n"); 7857c478bd9Sstevel@tonic-gate } else { 7867c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 7877c478bd9Sstevel@tonic-gate "\nDriver installation failed because the following\n"); 7887c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 7897c478bd9Sstevel@tonic-gate "entries in /devices would be affected:\n\n"); 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate ptr = conflict_lst; 7937c478bd9Sstevel@tonic-gate while (ptr != NULL) { 7947c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\t%s", ptr->dev_name); 7957c478bd9Sstevel@tonic-gate if (ptr->clone) 7967c478bd9Sstevel@tonic-gate (void) fprintf(stderr, " (clone device)\n"); 7977c478bd9Sstevel@tonic-gate else 7987c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "[:*]\n"); 7997c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\t(Device currently managed by driver " 8007c478bd9Sstevel@tonic-gate "\"%s\")\n\n", ptr->driver_name); 8017c478bd9Sstevel@tonic-gate ptr = ptr->next; 8027c478bd9Sstevel@tonic-gate } 8037c478bd9Sstevel@tonic-gate check_dev_dir(force); 8047c478bd9Sstevel@tonic-gate } 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate /* 8077c478bd9Sstevel@tonic-gate * use nftw to walk through /dev looking for links that match 8087c478bd9Sstevel@tonic-gate * an entry in the conflict list. 8097c478bd9Sstevel@tonic-gate */ 8107c478bd9Sstevel@tonic-gate static void 8117c478bd9Sstevel@tonic-gate check_dev_dir(int force) 8127c478bd9Sstevel@tonic-gate { 8137c478bd9Sstevel@tonic-gate int walk_flags = FTW_PHYS | FTW_MOUNT; 8147c478bd9Sstevel@tonic-gate int ft_depth = 15; 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate if (force) { 8177c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\nThe following entries in /dev will " 8187c478bd9Sstevel@tonic-gate "be affected:\n\n"); 8197c478bd9Sstevel@tonic-gate } else { 8207c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\nThe following entries in /dev would " 8217c478bd9Sstevel@tonic-gate "be affected:\n\n"); 8227c478bd9Sstevel@tonic-gate } 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate (void) nftw("/dev", dev_node, ft_depth, walk_flags); 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 8277c478bd9Sstevel@tonic-gate } 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate /* 8307c478bd9Sstevel@tonic-gate * checks a /dev link to see if it matches any of the conlficting 8317c478bd9Sstevel@tonic-gate * /devices nodes in conflict_lst. 8327c478bd9Sstevel@tonic-gate */ 8337c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 8347c478bd9Sstevel@tonic-gate static int 8357c478bd9Sstevel@tonic-gate dev_node(const char *node, const struct stat *node_stat, int flags, 8367c478bd9Sstevel@tonic-gate struct FTW *ftw_info) 8377c478bd9Sstevel@tonic-gate { 8387c478bd9Sstevel@tonic-gate char linkbuf[MAXPATHLEN]; 8397c478bd9Sstevel@tonic-gate struct dev_list *ptr; 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate if (readlink(node, linkbuf, MAXPATHLEN) == -1) 8427c478bd9Sstevel@tonic-gate return (0); 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate ptr = conflict_lst; 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate while (ptr != NULL) { 8477c478bd9Sstevel@tonic-gate if (strstr(linkbuf, ptr->dev_name) != NULL) 8487c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\t%s\n", node); 8497c478bd9Sstevel@tonic-gate ptr = ptr->next; 8507c478bd9Sstevel@tonic-gate } 8517c478bd9Sstevel@tonic-gate return (0); 8527c478bd9Sstevel@tonic-gate } 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate static void 8567c478bd9Sstevel@tonic-gate free_conflict_list(struct dev_list *list) 8577c478bd9Sstevel@tonic-gate { 8587c478bd9Sstevel@tonic-gate struct dev_list *save; 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate /* free up any dev_list structs we allocated. */ 8617c478bd9Sstevel@tonic-gate while (list != NULL) { 8627c478bd9Sstevel@tonic-gate save = list; 8637c478bd9Sstevel@tonic-gate list = list->next; 8647c478bd9Sstevel@tonic-gate free(save->dev_name); 8657c478bd9Sstevel@tonic-gate free(save); 8667c478bd9Sstevel@tonic-gate } 8677c478bd9Sstevel@tonic-gate } 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate int 8707c478bd9Sstevel@tonic-gate elf_type(char *file, char **elfdesc, int *elf_type_ptr) 8717c478bd9Sstevel@tonic-gate { 8727c478bd9Sstevel@tonic-gate int fd; 8737c478bd9Sstevel@tonic-gate Elf *elf; 8747c478bd9Sstevel@tonic-gate char *ident; 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate if ((fd = open(file, O_RDONLY)) < 0) { 8777c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_CANNOT_OPEN), file, 8787c478bd9Sstevel@tonic-gate strerror(errno)); 8797c478bd9Sstevel@tonic-gate return (ERROR); 8807c478bd9Sstevel@tonic-gate } 8817c478bd9Sstevel@tonic-gate if (elf_version(EV_CURRENT) == EV_NONE) { 8827c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_ELF_VERSION), 8837c478bd9Sstevel@tonic-gate elf_errmsg(-1)); 8847c478bd9Sstevel@tonic-gate (void) close(fd); 8857c478bd9Sstevel@tonic-gate return (ERROR); 8867c478bd9Sstevel@tonic-gate } 8877c478bd9Sstevel@tonic-gate elf = elf_begin(fd, ELF_C_READ, NULL); 8887c478bd9Sstevel@tonic-gate if (elf_kind(elf) != ELF_K_ELF) { 8897c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_ELF_KIND), file); 8907c478bd9Sstevel@tonic-gate (void) elf_end(elf); 8917c478bd9Sstevel@tonic-gate (void) close(fd); 8927c478bd9Sstevel@tonic-gate return (ERROR); 8937c478bd9Sstevel@tonic-gate } 8947c478bd9Sstevel@tonic-gate ident = elf_getident(elf, 0); 8957c478bd9Sstevel@tonic-gate if (ident[EI_CLASS] == ELFCLASS32) { 8967c478bd9Sstevel@tonic-gate *elfdesc = "32"; 8977c478bd9Sstevel@tonic-gate *elf_type_ptr = ELFCLASS32; 8987c478bd9Sstevel@tonic-gate } else if (ident[EI_CLASS] == ELFCLASS64) { 8997c478bd9Sstevel@tonic-gate *elfdesc = "64"; 9007c478bd9Sstevel@tonic-gate *elf_type_ptr = ELFCLASS64; 9017c478bd9Sstevel@tonic-gate } else { 9027c478bd9Sstevel@tonic-gate *elfdesc = "none"; 9037c478bd9Sstevel@tonic-gate *elf_type_ptr = ELFCLASSNONE; 9047c478bd9Sstevel@tonic-gate } 9057c478bd9Sstevel@tonic-gate (void) elf_end(elf); 9067c478bd9Sstevel@tonic-gate (void) close(fd); 9077c478bd9Sstevel@tonic-gate return (NOERR); 9087c478bd9Sstevel@tonic-gate } 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate int 9117c478bd9Sstevel@tonic-gate correct_location(char *drv_path, char **drvelf_desc, int *drvelf_type_ptr) 9127c478bd9Sstevel@tonic-gate { 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate char copy_drv_path[MAXPATHLEN]; 9157c478bd9Sstevel@tonic-gate char *token = copy_drv_path; 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate (void) strcpy(copy_drv_path, drv_path); 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate if (elf_type(drv_path, drvelf_desc, drvelf_type_ptr) == ERROR) { 9207c478bd9Sstevel@tonic-gate err_exit(); 9217c478bd9Sstevel@tonic-gate } 9227c478bd9Sstevel@tonic-gate token = strtok(copy_drv_path, DIR_SEP); 9237c478bd9Sstevel@tonic-gate while (token != NULL) { 9247c478bd9Sstevel@tonic-gate if (strcmp("drv", token) == 0) { 9257c478bd9Sstevel@tonic-gate token = strtok((char *)NULL, DIR_SEP); 9267c478bd9Sstevel@tonic-gate if (strcmp(DRVDIR64, token) == 0) { 9277c478bd9Sstevel@tonic-gate if (*drvelf_type_ptr == ELFCLASS64) 9287c478bd9Sstevel@tonic-gate return (NOERR); 9297c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_LOCATION), 9307c478bd9Sstevel@tonic-gate *drvelf_desc, drv_path); 9317c478bd9Sstevel@tonic-gate return (ERROR); 9327c478bd9Sstevel@tonic-gate } else { 9337c478bd9Sstevel@tonic-gate if (*drvelf_type_ptr == ELFCLASS32) 9347c478bd9Sstevel@tonic-gate return (NOERR); 9357c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_LOCATION), 9367c478bd9Sstevel@tonic-gate *drvelf_desc, drv_path); 9377c478bd9Sstevel@tonic-gate return (ERROR); 9387c478bd9Sstevel@tonic-gate } 9397c478bd9Sstevel@tonic-gate } else { 9407c478bd9Sstevel@tonic-gate token = strtok((char *)NULL, DIR_SEP); 9417c478bd9Sstevel@tonic-gate } 9427c478bd9Sstevel@tonic-gate } 9437c478bd9Sstevel@tonic-gate return (ERROR); 9447c478bd9Sstevel@tonic-gate } 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate /* 9477c478bd9Sstevel@tonic-gate * Creates a two-element linked list of isa-specific subdirectories to 9487c478bd9Sstevel@tonic-gate * search for each driver, which is is used by the function 9497c478bd9Sstevel@tonic-gate * module_not_found() to convert the isa-independent modpath into an 9507c478bd9Sstevel@tonic-gate * isa-specific path . The list is ordered depending on the machine 9517c478bd9Sstevel@tonic-gate * architecture and instruction set architecture, corresponding to the 9527c478bd9Sstevel@tonic-gate * order in which module_not_found() will search for the driver. This 9537c478bd9Sstevel@tonic-gate * routine relies on an architecture not having more than two 9547c478bd9Sstevel@tonic-gate * sub-architectures (e.g., sparc/sparcv9 or i386/amd64). 9557c478bd9Sstevel@tonic-gate */ 9567c478bd9Sstevel@tonic-gate int 9577c478bd9Sstevel@tonic-gate isaspec_drvmod_discovery() 9587c478bd9Sstevel@tonic-gate { 9597c478bd9Sstevel@tonic-gate char arch[SYS_NMLN]; 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate moddir = (struct drvmod_dir *)calloc(1, sizeof (struct drvmod_dir)); 9627c478bd9Sstevel@tonic-gate if (moddir == NULL) { 9637c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_MEM)); 9647c478bd9Sstevel@tonic-gate return (ERROR); 9657c478bd9Sstevel@tonic-gate } 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate if (sysinfo(SI_ARCHITECTURE, arch, sizeof (arch)) == -1) { 9687c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_SYSINFO_ARCH)); 9697c478bd9Sstevel@tonic-gate return (ERROR); 9707c478bd9Sstevel@tonic-gate } 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate if (strcmp(arch, "sparc") == 0 || strcmp(arch, "i386") == 0) { 9737c478bd9Sstevel@tonic-gate moddir->next = (struct drvmod_dir *) 9747c478bd9Sstevel@tonic-gate calloc(1, sizeof (struct drvmod_dir)); 9757c478bd9Sstevel@tonic-gate if (moddir->next == NULL) { 9767c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_NO_MEM)); 9777c478bd9Sstevel@tonic-gate return (ERROR); 9787c478bd9Sstevel@tonic-gate } 9797c478bd9Sstevel@tonic-gate if (kelf_type == ELFCLASS64) { 9807c478bd9Sstevel@tonic-gate (void) strcpy(moddir->direc, DRVDIR64); 9817c478bd9Sstevel@tonic-gate (void) strcpy(moddir->next->direc, ""); 9827c478bd9Sstevel@tonic-gate } else { 9837c478bd9Sstevel@tonic-gate (void) strcpy(moddir->direc, ""); 9847c478bd9Sstevel@tonic-gate (void) strcpy(moddir->next->direc, DRVDIR64); 9857c478bd9Sstevel@tonic-gate } 9867c478bd9Sstevel@tonic-gate moddir->next->next = NULL; 9877c478bd9Sstevel@tonic-gate return (NOERR); 9887c478bd9Sstevel@tonic-gate } else { 9897c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_ARCH_NOT_SUPPORTED), arch); 9907c478bd9Sstevel@tonic-gate return (ERROR); 9917c478bd9Sstevel@tonic-gate } 9927c478bd9Sstevel@tonic-gate } 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate void 9957c478bd9Sstevel@tonic-gate remove_slashes(char *path) 9967c478bd9Sstevel@tonic-gate { 9977c478bd9Sstevel@tonic-gate char *slash = path; 9987c478bd9Sstevel@tonic-gate char *remain_str; 9997c478bd9Sstevel@tonic-gate int pathlen; 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate while ((slash = strchr(slash, '/')) != NULL) { 10027c478bd9Sstevel@tonic-gate remain_str = ++slash; 10037c478bd9Sstevel@tonic-gate while (*remain_str == '/') 10047c478bd9Sstevel@tonic-gate ++remain_str; 10057c478bd9Sstevel@tonic-gate if (slash != remain_str) 10067c478bd9Sstevel@tonic-gate (void) strcpy(slash, remain_str); 10077c478bd9Sstevel@tonic-gate } 10087c478bd9Sstevel@tonic-gate 10097c478bd9Sstevel@tonic-gate pathlen = strlen(path); 10107c478bd9Sstevel@tonic-gate if ((pathlen > 1) && path[pathlen - 1] == '/') 10117c478bd9Sstevel@tonic-gate path[pathlen - 1] = '\0'; 10127c478bd9Sstevel@tonic-gate } 10137c478bd9Sstevel@tonic-gate 10147c478bd9Sstevel@tonic-gate /* 10157c478bd9Sstevel@tonic-gate * This is for ITU floppies to add packages to the miniroot 10167c478bd9Sstevel@tonic-gate */ 10177c478bd9Sstevel@tonic-gate static int 10187c478bd9Sstevel@tonic-gate ignore_root_basedir(void) 10197c478bd9Sstevel@tonic-gate { 10207c478bd9Sstevel@tonic-gate struct stat statbuf; 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate return (stat("/ADD_DRV_IGNORE_ROOT_BASEDIR", &statbuf) == 0); 10237c478bd9Sstevel@tonic-gate } 1024