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 static int path_check(const char *, int); 45 static void usage(void); 46 47 /* 48 * Check to see if the requested module is specified as a filename with no 49 * path. If so and if a file by the same name exists in the module path, 50 * warn the user that the module in the path will be used in preference. 51 */ 52 static int 53 path_check(const char *kldname, int quiet) 54 { 55 int mib[5], found; 56 size_t miblen, pathlen; 57 char kldpath[MAXPATHLEN]; 58 char *path, *tmppath, *element; 59 struct stat sb; 60 dev_t dev; 61 ino_t ino; 62 63 if (strchr(kldname, '/') != NULL) { 64 return (0); 65 } 66 if (strstr(kldname, ".ko") == NULL) { 67 return (0); 68 } 69 if (stat(kldname, &sb) != 0) { 70 return (0); 71 } 72 73 found = 0; 74 dev = sb.st_dev; 75 ino = sb.st_ino; 76 77 miblen = sizeof(mib) / sizeof(mib[0]); 78 if (sysctlnametomib(PATHCTL, mib, &miblen) != 0) { 79 err(1, "sysctlnametomib(%s)", PATHCTL); 80 } 81 if (sysctl(mib, miblen, NULL, &pathlen, NULL, 0) == -1) { 82 err(1, "getting path: sysctl(%s) - size only", PATHCTL); 83 } 84 path = malloc(pathlen + 1); 85 if (path == NULL) { 86 err(1, "allocating %lu bytes for the path", 87 (unsigned long)pathlen + 1); 88 } 89 if (sysctl(mib, miblen, path, &pathlen, NULL, 0) == -1) { 90 err(1, "getting path: sysctl(%s)", PATHCTL); 91 } 92 tmppath = path; 93 94 while ((element = strsep(&tmppath, ";")) != NULL) { 95 strlcpy(kldpath, element, MAXPATHLEN); 96 if (kldpath[strlen(kldpath) - 1] != '/') { 97 strlcat(kldpath, "/", MAXPATHLEN); 98 } 99 strlcat(kldpath, kldname, MAXPATHLEN); 100 101 if (stat(kldpath, &sb) == -1) { 102 continue; 103 } 104 105 found = 1; 106 107 if (sb.st_dev != dev || sb.st_ino != ino) { 108 if (!quiet) { 109 warnx("%s will be loaded from %s, not the " 110 "current directory", kldname, element); 111 } 112 break; 113 } else if (sb.st_dev == dev && sb.st_ino == ino) { 114 break; 115 } 116 } 117 118 free(path); 119 120 if (!found) { 121 if (!quiet) { 122 warnx("%s is not in the module path", kldname); 123 } 124 return (-1); 125 } 126 127 return (0); 128 } 129 130 static void 131 usage(void) 132 { 133 fprintf(stderr, "usage: kldload [-nqv] file ...\n"); 134 exit(1); 135 } 136 137 int 138 main(int argc, char** argv) 139 { 140 int c; 141 int errors; 142 int fileid; 143 int verbose; 144 int quiet; 145 int check_loaded; 146 147 errors = 0; 148 verbose = 0; 149 quiet = 0; 150 check_loaded = 0; 151 152 while ((c = getopt(argc, argv, "nqv")) != -1) { 153 switch (c) { 154 case 'q': 155 quiet = 1; 156 verbose = 0; 157 break; 158 case 'v': 159 verbose = 1; 160 quiet = 0; 161 break; 162 case 'n': 163 check_loaded = 1; 164 break; 165 default: 166 usage(); 167 } 168 } 169 argc -= optind; 170 argv += optind; 171 172 if (argc == 0) 173 usage(); 174 175 while (argc-- != 0) { 176 if (path_check(argv[0], quiet) == 0) { 177 fileid = kldload(argv[0]); 178 if (fileid < 0) { 179 if (check_loaded != 0 && errno == EEXIST) { 180 if (verbose) 181 printf("%s is already " 182 "loaded\n", argv[0]); 183 } else { 184 switch (errno) { 185 case EEXIST: 186 warnx("can't load %s: module " 187 "already loaded or " 188 "in kernel", argv[0]); 189 break; 190 case ENOEXEC: 191 warnx("an error occurred while " 192 "loading the module. " 193 "Please check dmesg(8) for " 194 "more details."); 195 break; 196 default: 197 warn("can't load %s", argv[0]); 198 break; 199 } 200 errors++; 201 } 202 } else { 203 if (verbose) 204 printf("Loaded %s, id=%d\n", argv[0], 205 fileid); 206 } 207 } else { 208 errors++; 209 } 210 argv++; 211 } 212 213 return (errors ? 1 : 0); 214 } 215