#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 *kldname, int quiet)
{
char *path, *tmppath, *element;
struct stat sb;
int mib[5];
char kldpath[MAXPATHLEN];
size_t miblen, pathlen;
dev_t dev;
ino_t ino;
int found;
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 check_loaded;
int errors;
int fileid;
int quiet;
int verbose;
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 {
if (!quiet) {
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 module %s. "
"Please check dmesg(8) for "
"more details.", argv[0]);
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);
}