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