freebsd-skq/sbin/kldload/kldload.c
Marcelo Araujo 8ee0576c6b Use nitems() from sys/param.h.
MFC after:	2 weeks.
2016-04-19 04:52:51 +00:00

215 lines
4.9 KiB
C

/*-
* Copyright (c) 1997 Doug Rabson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/param.h>
#include <sys/linker.h>
#include <sys/sysctl.h>
#include <sys/stat.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#define PATHCTL "kern.module_path"
static int path_check(const char *, int);
static void usage(void);
/*
* Check to see if the requested module is specified as a filename with no
* path. If so and if a file by the same name exists in the module path,
* warn the user that the module in the path will be used in preference.
*/
static int
path_check(const char *kldname, int quiet)
{
int mib[5], found;
size_t miblen, pathlen;
char kldpath[MAXPATHLEN];
char *path, *tmppath, *element;
struct stat sb;
dev_t dev;
ino_t ino;
if (strchr(kldname, '/') != NULL) {
return (0);
}
if (strstr(kldname, ".ko") == NULL) {
return (0);
}
if (stat(kldname, &sb) != 0) {
return (0);
}
found = 0;
dev = sb.st_dev;
ino = sb.st_ino;
miblen = nitems(mib);
if (sysctlnametomib(PATHCTL, mib, &miblen) != 0) {
err(1, "sysctlnametomib(%s)", PATHCTL);
}
if (sysctl(mib, miblen, NULL, &pathlen, NULL, 0) == -1) {
err(1, "getting path: sysctl(%s) - size only", PATHCTL);
}
path = malloc(pathlen + 1);
if (path == NULL) {
err(1, "allocating %lu bytes for the path",
(unsigned long)pathlen + 1);
}
if (sysctl(mib, miblen, path, &pathlen, NULL, 0) == -1) {
err(1, "getting path: sysctl(%s)", PATHCTL);
}
tmppath = path;
while ((element = strsep(&tmppath, ";")) != NULL) {
strlcpy(kldpath, element, MAXPATHLEN);
if (kldpath[strlen(kldpath) - 1] != '/') {
strlcat(kldpath, "/", MAXPATHLEN);
}
strlcat(kldpath, kldname, MAXPATHLEN);
if (stat(kldpath, &sb) == -1) {
continue;
}
found = 1;
if (sb.st_dev != dev || sb.st_ino != ino) {
if (!quiet) {
warnx("%s will be loaded from %s, not the "
"current directory", kldname, element);
}
break;
} else if (sb.st_dev == dev && sb.st_ino == ino) {
break;
}
}
free(path);
if (!found) {
if (!quiet) {
warnx("%s is not in the module path", kldname);
}
return (-1);
}
return (0);
}
static void
usage(void)
{
fprintf(stderr, "usage: kldload [-nqv] file ...\n");
exit(1);
}
int
main(int argc, char** argv)
{
int c;
int errors;
int fileid;
int verbose;
int quiet;
int check_loaded;
errors = 0;
verbose = 0;
quiet = 0;
check_loaded = 0;
while ((c = getopt(argc, argv, "nqv")) != -1) {
switch (c) {
case 'q':
quiet = 1;
verbose = 0;
break;
case 'v':
verbose = 1;
quiet = 0;
break;
case 'n':
check_loaded = 1;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc == 0)
usage();
while (argc-- != 0) {
if (path_check(argv[0], quiet) == 0) {
fileid = kldload(argv[0]);
if (fileid < 0) {
if (check_loaded != 0 && errno == EEXIST) {
if (verbose)
printf("%s is already "
"loaded\n", argv[0]);
} else {
switch (errno) {
case EEXIST:
warnx("can't load %s: module "
"already loaded or "
"in kernel", argv[0]);
break;
case ENOEXEC:
warnx("an error occurred while "
"loading the module. "
"Please check dmesg(8) for "
"more details.");
break;
default:
warn("can't load %s", argv[0]);
break;
}
errors++;
}
} else {
if (verbose)
printf("Loaded %s, id=%d\n", argv[0],
fileid);
}
} else {
errors++;
}
argv++;
}
return (errors ? 1 : 0);
}