125540Sdfr/*-
2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3330449Seadler *
425540Sdfr * Copyright (c) 1997 Doug Rabson
525540Sdfr * All rights reserved.
625540Sdfr *
725540Sdfr * Redistribution and use in source and binary forms, with or without
825540Sdfr * modification, are permitted provided that the following conditions
925540Sdfr * are met:
1025540Sdfr * 1. Redistributions of source code must retain the above copyright
1125540Sdfr *    notice, this list of conditions and the following disclaimer.
1225540Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1325540Sdfr *    notice, this list of conditions and the following disclaimer in the
1425540Sdfr *    documentation and/or other materials provided with the distribution.
1525540Sdfr *
1625540Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1725540Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1825540Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1925540Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2025540Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2125540Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2225540Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2325540Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2425540Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2525540Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2625540Sdfr * SUCH DAMAGE.
2725540Sdfr */
2825540Sdfr
29114589Sobrien#include <sys/cdefs.h>
30114589Sobrien__FBSDID("$FreeBSD: stable/11/sbin/kldload/kldload.c 330449 2018-03-05 07:26:05Z eadler $");
3132269Scharnier
32193475Sbenno#include <sys/types.h>
33193473Sbenno#include <sys/param.h>
34193473Sbenno#include <sys/linker.h>
35193475Sbenno#include <sys/sysctl.h>
36193475Sbenno#include <sys/stat.h>
3730573Sjmg#include <err.h>
3825540Sdfr#include <stdio.h>
3978732Sdd#include <stdlib.h>
40193475Sbenno#include <string.h>
4125540Sdfr#include <unistd.h>
42233109Shselasky#include <errno.h>
4325540Sdfr
44193475Sbenno#define	PATHCTL	"kern.module_path"
45193475Sbenno
46193475Sbenno/*
47193475Sbenno * Check to see if the requested module is specified as a filename with no
48193475Sbenno * path.  If so and if a file by the same name exists in the module path,
49193475Sbenno * warn the user that the module in the path will be used in preference.
50193475Sbenno */
51193475Sbennostatic int
52193475Sbennopath_check(const char *kldname, int quiet)
53193475Sbenno{
54193475Sbenno	char	*path, *tmppath, *element;
55193475Sbenno	struct	stat sb;
56313681Sngie	int	mib[5];
57313681Sngie	char	kldpath[MAXPATHLEN];
58313681Sngie	size_t	miblen, pathlen;
59193475Sbenno	dev_t	dev;
60193475Sbenno	ino_t	ino;
61313681Sngie	int	found;
62193475Sbenno
63313681Sngie	if (strchr(kldname, '/') != NULL)
64193475Sbenno		return (0);
65313681Sngie	if (strstr(kldname, ".ko") == NULL)
66193475Sbenno		return (0);
67313681Sngie	if (stat(kldname, &sb) != 0)
68193475Sbenno		return (0);
69193475Sbenno
70193475Sbenno	found = 0;
71193475Sbenno	dev = sb.st_dev;
72193475Sbenno	ino = sb.st_ino;
73193475Sbenno
74298249Saraujo	miblen = nitems(mib);
75313681Sngie	if (sysctlnametomib(PATHCTL, mib, &miblen) != 0)
76193475Sbenno		err(1, "sysctlnametomib(%s)", PATHCTL);
77313681Sngie	if (sysctl(mib, miblen, NULL, &pathlen, NULL, 0) == -1)
78193475Sbenno		err(1, "getting path: sysctl(%s) - size only", PATHCTL);
79193475Sbenno	path = malloc(pathlen + 1);
80313681Sngie	if (path == NULL)
81193475Sbenno		err(1, "allocating %lu bytes for the path",
82193475Sbenno		    (unsigned long)pathlen + 1);
83313681Sngie	if (sysctl(mib, miblen, path, &pathlen, NULL, 0) == -1)
84193475Sbenno		err(1, "getting path: sysctl(%s)", PATHCTL);
85193475Sbenno	tmppath = path;
86193475Sbenno
87193475Sbenno	while ((element = strsep(&tmppath, ";")) != NULL) {
88193475Sbenno		strlcpy(kldpath, element, MAXPATHLEN);
89193475Sbenno		if (kldpath[strlen(kldpath) - 1] != '/') {
90193475Sbenno			strlcat(kldpath, "/", MAXPATHLEN);
91193475Sbenno		}
92193475Sbenno		strlcat(kldpath, kldname, MAXPATHLEN);
93313681Sngie
94313681Sngie		if (stat(kldpath, &sb) == -1)
95193475Sbenno			continue;
96193475Sbenno
97193475Sbenno		found = 1;
98193475Sbenno
99193475Sbenno		if (sb.st_dev != dev || sb.st_ino != ino) {
100313681Sngie			if (!quiet)
101193475Sbenno				warnx("%s will be loaded from %s, not the "
102193475Sbenno				    "current directory", kldname, element);
103193475Sbenno			break;
104313681Sngie		} else if (sb.st_dev == dev && sb.st_ino == ino)
105193475Sbenno			break;
106193475Sbenno	}
107193475Sbenno
108193475Sbenno	free(path);
109313681Sngie
110193475Sbenno	if (!found) {
111313681Sngie		if (!quiet)
112193475Sbenno			warnx("%s is not in the module path", kldname);
113193475Sbenno		return (-1);
114193475Sbenno	}
115313681Sngie
116193475Sbenno	return (0);
117193475Sbenno}
118193475Sbenno
11930627Sjmgstatic void
12030627Sjmgusage(void)
12125540Sdfr{
122313681Sngie
123233109Shselasky	fprintf(stderr, "usage: kldload [-nqv] file ...\n");
124193473Sbenno	exit(1);
12525540Sdfr}
12625540Sdfr
12730627Sjmgint
12830627Sjmgmain(int argc, char** argv)
12925540Sdfr{
130193473Sbenno	int c;
131313681Sngie	int check_loaded;
132193473Sbenno	int errors;
133193473Sbenno	int fileid;
134313681Sngie	int quiet;
135193473Sbenno	int verbose;
13625540Sdfr
137193473Sbenno	errors = 0;
138193473Sbenno	verbose = 0;
139193475Sbenno	quiet = 0;
140233109Shselasky	check_loaded = 0;
141313681Sngie
142233109Shselasky	while ((c = getopt(argc, argv, "nqv")) != -1) {
143193473Sbenno		switch (c) {
144193475Sbenno		case 'q':
145193475Sbenno			quiet = 1;
146193475Sbenno			verbose = 0;
147193475Sbenno			break;
148193473Sbenno		case 'v':
149193473Sbenno			verbose = 1;
150193475Sbenno			quiet = 0;
151193473Sbenno			break;
152233109Shselasky		case 'n':
153233109Shselasky			check_loaded = 1;
154233109Shselasky			break;
155193473Sbenno		default:
156193473Sbenno			usage();
157193473Sbenno		}
15825540Sdfr	}
159193473Sbenno	argc -= optind;
160193473Sbenno	argv += optind;
16125540Sdfr
162193473Sbenno	if (argc == 0)
163193473Sbenno		usage();
16425540Sdfr
165193473Sbenno	while (argc-- != 0) {
166193475Sbenno		if (path_check(argv[0], quiet) == 0) {
167193475Sbenno			fileid = kldload(argv[0]);
168193475Sbenno			if (fileid < 0) {
169233109Shselasky				if (check_loaded != 0 && errno == EEXIST) {
170233109Shselasky					if (verbose)
171233109Shselasky						printf("%s is already "
172233109Shselasky						    "loaded\n", argv[0]);
173233109Shselasky				} else {
174260594Sbapt					switch (errno) {
175260594Sbapt					case EEXIST:
176260483Sbapt						warnx("can't load %s: module "
177260483Sbapt						    "already loaded or "
178260483Sbapt						    "in kernel", argv[0]);
179260594Sbapt						break;
180260594Sbapt					case ENOEXEC:
181260596Sbapt						warnx("an error occurred while "
182260594Sbapt						    "loading the module. "
183260597Sbapt						    "Please check dmesg(8) for "
184260594Sbapt						    "more details.");
185260594Sbapt						break;
186260594Sbapt					default:
187260483Sbapt						warn("can't load %s", argv[0]);
188260594Sbapt						break;
189260594Sbapt					}
190260484Sbapt					errors++;
191233109Shselasky				}
192193475Sbenno			} else {
193193475Sbenno				if (verbose)
194193475Sbenno					printf("Loaded %s, id=%d\n", argv[0],
195193475Sbenno					    fileid);
196193475Sbenno			}
197313681Sngie		} else
198193473Sbenno			errors++;
199193473Sbenno		argv++;
200193473Sbenno	}
20125540Sdfr
202193473Sbenno	return (errors ? 1 : 0);
20325540Sdfr}
204