xref: /illumos-gate/usr/src/cmd/modload/add_drv.c (revision c9cc1492)
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
main(int argc,char * argv[])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),
1547e485317SJerry Gilliam 				    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)
4307e485317SJerry Gilliam 		    == 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
module_not_found(char * drv_name,char * drv_path,int drv_path_size,char ** drvelf_desc,int * drvelf_type_ptr)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
usage()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
update_driver_classes(char * driver_name,char * classes)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
update_minor_perm(char * driver_name,char * perm_list)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
devfs_update_minor_perm(char * basedir,char * driver_name)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
update_extra_privs(char * driver_name,char * privlist)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
drv_name_conflict(di_node_t root_node)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
devfs_node(di_node_t node,void * arg)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
clone(di_node_t node)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
drv_name_match(char * compat_names,int n_names,char * cur_name,char * new_name)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
print_drv_conflict_info(int force)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
check_dev_dir(int force)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
dev_node(const char * node,const struct stat * node_stat,int flags,struct FTW * ftw_info)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
free_conflict_list(struct dev_list * list)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
elf_type(char * file,char ** elfdesc,int * elf_type_ptr)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
correct_location(char * drv_path,char ** drvelf_desc,int * drvelf_type_ptr)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
isaspec_drvmod_discovery()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
remove_slashes(char * path)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
ignore_root_basedir(void)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