kldload.c revision 260596
125540Sdfr/*- 225540Sdfr * Copyright (c) 1997 Doug Rabson 325540Sdfr * All rights reserved. 425540Sdfr * 525540Sdfr * Redistribution and use in source and binary forms, with or without 625540Sdfr * modification, are permitted provided that the following conditions 725540Sdfr * are met: 825540Sdfr * 1. Redistributions of source code must retain the above copyright 925540Sdfr * notice, this list of conditions and the following disclaimer. 1025540Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1125540Sdfr * notice, this list of conditions and the following disclaimer in the 1225540Sdfr * documentation and/or other materials provided with the distribution. 1325540Sdfr * 1425540Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1525540Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1625540Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1725540Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1825540Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1925540Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2025540Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2125540Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2225540Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2325540Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2425540Sdfr * SUCH DAMAGE. 2525540Sdfr */ 2625540Sdfr 27114589Sobrien#include <sys/cdefs.h> 28114589Sobrien__FBSDID("$FreeBSD: head/sbin/kldload/kldload.c 260596 2014-01-13 16:47:25Z bapt $"); 2932269Scharnier 30193475Sbenno#include <sys/types.h> 31193473Sbenno#include <sys/param.h> 32193473Sbenno#include <sys/linker.h> 33193475Sbenno#include <sys/sysctl.h> 34193475Sbenno#include <sys/stat.h> 3530573Sjmg#include <err.h> 3625540Sdfr#include <stdio.h> 3778732Sdd#include <stdlib.h> 38193475Sbenno#include <string.h> 3925540Sdfr#include <unistd.h> 40233109Shselasky#include <errno.h> 4125540Sdfr 42193475Sbenno#define PATHCTL "kern.module_path" 43193475Sbenno 44193475Sbennostatic int path_check(const char *, int); 45193473Sbennostatic void usage(void); 46193473Sbenno 47193475Sbenno/* 48193475Sbenno * Check to see if the requested module is specified as a filename with no 49193475Sbenno * path. If so and if a file by the same name exists in the module path, 50193475Sbenno * warn the user that the module in the path will be used in preference. 51193475Sbenno */ 52193475Sbennostatic int 53193475Sbennopath_check(const char *kldname, int quiet) 54193475Sbenno{ 55193475Sbenno int mib[5], found; 56193475Sbenno size_t miblen, pathlen; 57193475Sbenno char kldpath[MAXPATHLEN]; 58193475Sbenno char *path, *tmppath, *element; 59193475Sbenno struct stat sb; 60193475Sbenno dev_t dev; 61193475Sbenno ino_t ino; 62193475Sbenno 63193475Sbenno if (strchr(kldname, '/') != NULL) { 64193475Sbenno return (0); 65193475Sbenno } 66193475Sbenno if (strstr(kldname, ".ko") == NULL) { 67193475Sbenno return (0); 68193475Sbenno } 69193475Sbenno if (stat(kldname, &sb) != 0) { 70193475Sbenno return (0); 71193475Sbenno } 72193475Sbenno 73193475Sbenno found = 0; 74193475Sbenno dev = sb.st_dev; 75193475Sbenno ino = sb.st_ino; 76193475Sbenno 77193475Sbenno miblen = sizeof(mib) / sizeof(mib[0]); 78193475Sbenno if (sysctlnametomib(PATHCTL, mib, &miblen) != 0) { 79193475Sbenno err(1, "sysctlnametomib(%s)", PATHCTL); 80193475Sbenno } 81193475Sbenno if (sysctl(mib, miblen, NULL, &pathlen, NULL, 0) == -1) { 82193475Sbenno err(1, "getting path: sysctl(%s) - size only", PATHCTL); 83193475Sbenno } 84193475Sbenno path = malloc(pathlen + 1); 85193475Sbenno if (path == NULL) { 86193475Sbenno err(1, "allocating %lu bytes for the path", 87193475Sbenno (unsigned long)pathlen + 1); 88193475Sbenno } 89193475Sbenno if (sysctl(mib, miblen, path, &pathlen, NULL, 0) == -1) { 90193475Sbenno err(1, "getting path: sysctl(%s)", PATHCTL); 91193475Sbenno } 92193475Sbenno tmppath = path; 93193475Sbenno 94193475Sbenno while ((element = strsep(&tmppath, ";")) != NULL) { 95193475Sbenno strlcpy(kldpath, element, MAXPATHLEN); 96193475Sbenno if (kldpath[strlen(kldpath) - 1] != '/') { 97193475Sbenno strlcat(kldpath, "/", MAXPATHLEN); 98193475Sbenno } 99193475Sbenno strlcat(kldpath, kldname, MAXPATHLEN); 100193475Sbenno 101193475Sbenno if (stat(kldpath, &sb) == -1) { 102193475Sbenno continue; 103193475Sbenno } 104193475Sbenno 105193475Sbenno found = 1; 106193475Sbenno 107193475Sbenno if (sb.st_dev != dev || sb.st_ino != ino) { 108193475Sbenno if (!quiet) { 109193475Sbenno warnx("%s will be loaded from %s, not the " 110193475Sbenno "current directory", kldname, element); 111193475Sbenno } 112193475Sbenno break; 113193475Sbenno } else if (sb.st_dev == dev && sb.st_ino == ino) { 114193475Sbenno break; 115193475Sbenno } 116193475Sbenno } 117193475Sbenno 118193475Sbenno free(path); 119193475Sbenno 120193475Sbenno if (!found) { 121193475Sbenno if (!quiet) { 122193475Sbenno warnx("%s is not in the module path", kldname); 123193475Sbenno } 124193475Sbenno return (-1); 125193475Sbenno } 126193475Sbenno 127193475Sbenno return (0); 128193475Sbenno} 129193475Sbenno 13030627Sjmgstatic void 13130627Sjmgusage(void) 13225540Sdfr{ 133233109Shselasky fprintf(stderr, "usage: kldload [-nqv] file ...\n"); 134193473Sbenno exit(1); 13525540Sdfr} 13625540Sdfr 13730627Sjmgint 13830627Sjmgmain(int argc, char** argv) 13925540Sdfr{ 140193473Sbenno int c; 141193473Sbenno int errors; 142193473Sbenno int fileid; 143193473Sbenno int verbose; 144193475Sbenno int quiet; 145233109Shselasky int check_loaded; 14625540Sdfr 147193473Sbenno errors = 0; 148193473Sbenno verbose = 0; 149193475Sbenno quiet = 0; 150233109Shselasky check_loaded = 0; 151193475Sbenno 152233109Shselasky while ((c = getopt(argc, argv, "nqv")) != -1) { 153193473Sbenno switch (c) { 154193475Sbenno case 'q': 155193475Sbenno quiet = 1; 156193475Sbenno verbose = 0; 157193475Sbenno break; 158193473Sbenno case 'v': 159193473Sbenno verbose = 1; 160193475Sbenno quiet = 0; 161193473Sbenno break; 162233109Shselasky case 'n': 163233109Shselasky check_loaded = 1; 164233109Shselasky break; 165193473Sbenno default: 166193473Sbenno usage(); 167193473Sbenno } 16825540Sdfr } 169193473Sbenno argc -= optind; 170193473Sbenno argv += optind; 17125540Sdfr 172193473Sbenno if (argc == 0) 173193473Sbenno usage(); 17425540Sdfr 175193473Sbenno while (argc-- != 0) { 176193475Sbenno if (path_check(argv[0], quiet) == 0) { 177193475Sbenno fileid = kldload(argv[0]); 178193475Sbenno if (fileid < 0) { 179233109Shselasky if (check_loaded != 0 && errno == EEXIST) { 180233109Shselasky if (verbose) 181233109Shselasky printf("%s is already " 182233109Shselasky "loaded\n", argv[0]); 183233109Shselasky } else { 184260594Sbapt switch (errno) { 185260594Sbapt case EEXIST: 186260483Sbapt warnx("can't load %s: module " 187260483Sbapt "already loaded or " 188260483Sbapt "in kernel", argv[0]); 189260594Sbapt break; 190260594Sbapt case ENOEXEC: 191260596Sbapt warnx("an error occurred while " 192260594Sbapt "loading the module. " 193260594Sbapt "Please check dmesg(1) for " 194260594Sbapt "more details."); 195260594Sbapt break; 196260594Sbapt default: 197260483Sbapt warn("can't load %s", argv[0]); 198260594Sbapt break; 199260594Sbapt } 200260484Sbapt errors++; 201233109Shselasky } 202193475Sbenno } else { 203193475Sbenno if (verbose) 204193475Sbenno printf("Loaded %s, id=%d\n", argv[0], 205193475Sbenno fileid); 206193475Sbenno } 207193475Sbenno } else { 208193473Sbenno errors++; 209193473Sbenno } 210193473Sbenno argv++; 211193473Sbenno } 21225540Sdfr 213193473Sbenno return (errors ? 1 : 0); 21425540Sdfr} 215