xref: /freebsd/sbin/kldload/kldload.c (revision 2008043f386721d58158e37e0d7e50df8095942d)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 1997 Doug Rabson
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
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 					if (!quiet) {
173 						switch (errno) {
174 						case EEXIST:
175 							warnx("can't load %s: module "
176 							    "already loaded or "
177 							    "in kernel", argv[0]);
178 							break;
179 						case ENOEXEC:
180 							warnx("an error occurred while "
181 							    "loading module %s. "
182 							    "Please check dmesg(8) for "
183 							    "more details.", argv[0]);
184 							break;
185 						default:
186 							warn("can't load %s", argv[0]);
187 							break;
188 						}
189 					}
190 					errors++;
191 				}
192 			} else {
193 				if (verbose)
194 					printf("Loaded %s, id=%d\n", argv[0],
195 					    fileid);
196 			}
197 		} else
198 			errors++;
199 		argv++;
200 	}
201 
202 	return (errors ? 1 : 0);
203 }
204