xref: /freebsd/sbin/kldload/kldload.c (revision ca987d4641cdcd7f27e153db17c5bf064934faf5)
1 /*-
2  * Copyright (c) 1997 Doug Rabson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/types.h>
31 #include <sys/param.h>
32 #include <sys/linker.h>
33 #include <sys/sysctl.h>
34 #include <sys/stat.h>
35 #include <err.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <errno.h>
41 
42 #define	PATHCTL	"kern.module_path"
43 
44 /*
45  * Check to see if the requested module is specified as a filename with no
46  * path.  If so and if a file by the same name exists in the module path,
47  * warn the user that the module in the path will be used in preference.
48  */
49 static int
50 path_check(const char *kldname, int quiet)
51 {
52 	char	*path, *tmppath, *element;
53 	struct	stat sb;
54 	int	mib[5];
55 	char	kldpath[MAXPATHLEN];
56 	size_t	miblen, pathlen;
57 	dev_t	dev;
58 	ino_t	ino;
59 	int	found;
60 
61 	if (strchr(kldname, '/') != NULL)
62 		return (0);
63 	if (strstr(kldname, ".ko") == NULL)
64 		return (0);
65 	if (stat(kldname, &sb) != 0)
66 		return (0);
67 
68 	found = 0;
69 	dev = sb.st_dev;
70 	ino = sb.st_ino;
71 
72 	miblen = nitems(mib);
73 	if (sysctlnametomib(PATHCTL, mib, &miblen) != 0)
74 		err(1, "sysctlnametomib(%s)", PATHCTL);
75 	if (sysctl(mib, miblen, NULL, &pathlen, NULL, 0) == -1)
76 		err(1, "getting path: sysctl(%s) - size only", PATHCTL);
77 	path = malloc(pathlen + 1);
78 	if (path == NULL)
79 		err(1, "allocating %lu bytes for the path",
80 		    (unsigned long)pathlen + 1);
81 	if (sysctl(mib, miblen, path, &pathlen, NULL, 0) == -1)
82 		err(1, "getting path: sysctl(%s)", PATHCTL);
83 	tmppath = path;
84 
85 	while ((element = strsep(&tmppath, ";")) != NULL) {
86 		strlcpy(kldpath, element, MAXPATHLEN);
87 		if (kldpath[strlen(kldpath) - 1] != '/') {
88 			strlcat(kldpath, "/", MAXPATHLEN);
89 		}
90 		strlcat(kldpath, kldname, MAXPATHLEN);
91 
92 		if (stat(kldpath, &sb) == -1)
93 			continue;
94 
95 		found = 1;
96 
97 		if (sb.st_dev != dev || sb.st_ino != ino) {
98 			if (!quiet)
99 				warnx("%s will be loaded from %s, not the "
100 				    "current directory", kldname, element);
101 			break;
102 		} else if (sb.st_dev == dev && sb.st_ino == ino)
103 			break;
104 	}
105 
106 	free(path);
107 
108 	if (!found) {
109 		if (!quiet)
110 			warnx("%s is not in the module path", kldname);
111 		return (-1);
112 	}
113 
114 	return (0);
115 }
116 
117 static void
118 usage(void)
119 {
120 
121 	fprintf(stderr, "usage: kldload [-nqv] file ...\n");
122 	exit(1);
123 }
124 
125 int
126 main(int argc, char** argv)
127 {
128 	int c;
129 	int check_loaded;
130 	int errors;
131 	int fileid;
132 	int quiet;
133 	int verbose;
134 
135 	errors = 0;
136 	verbose = 0;
137 	quiet = 0;
138 	check_loaded = 0;
139 
140 	while ((c = getopt(argc, argv, "nqv")) != -1) {
141 		switch (c) {
142 		case 'q':
143 			quiet = 1;
144 			verbose = 0;
145 			break;
146 		case 'v':
147 			verbose = 1;
148 			quiet = 0;
149 			break;
150 		case 'n':
151 			check_loaded = 1;
152 			break;
153 		default:
154 			usage();
155 		}
156 	}
157 	argc -= optind;
158 	argv += optind;
159 
160 	if (argc == 0)
161 		usage();
162 
163 	while (argc-- != 0) {
164 		if (path_check(argv[0], quiet) == 0) {
165 			fileid = kldload(argv[0]);
166 			if (fileid < 0) {
167 				if (check_loaded != 0 && errno == EEXIST) {
168 					if (verbose)
169 						printf("%s is already "
170 						    "loaded\n", argv[0]);
171 				} else {
172 					switch (errno) {
173 					case EEXIST:
174 						warnx("can't load %s: module "
175 						    "already loaded or "
176 						    "in kernel", argv[0]);
177 						break;
178 					case ENOEXEC:
179 						warnx("an error occurred while "
180 						    "loading module %s. "
181 						    "Please check dmesg(8) for "
182 						    "more details.", argv[0]);
183 						break;
184 					default:
185 						warn("can't load %s", argv[0]);
186 						break;
187 					}
188 					errors++;
189 				}
190 			} else {
191 				if (verbose)
192 					printf("Loaded %s, id=%d\n", argv[0],
193 					    fileid);
194 			}
195 		} else
196 			errors++;
197 		argv++;
198 	}
199 
200 	return (errors ? 1 : 0);
201 }
202