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