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