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