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