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