kldload.c revision 260483
18876Srgrimes/*-
24Srgrimes * Copyright (c) 1997 Doug Rabson
34Srgrimes * All rights reserved.
44Srgrimes *
58876Srgrimes * Redistribution and use in source and binary forms, with or without
64Srgrimes * modification, are permitted provided that the following conditions
74Srgrimes * are met:
84Srgrimes * 1. Redistributions of source code must retain the above copyright
94Srgrimes *    notice, this list of conditions and the following disclaimer.
104Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
118876Srgrimes *    notice, this list of conditions and the following disclaimer in the
128876Srgrimes *    documentation and/or other materials provided with the distribution.
134Srgrimes *
144Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
158876Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
164Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
178876Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
184Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
194Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
204Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
214Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
228876Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
234Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
244Srgrimes * SUCH DAMAGE.
254Srgrimes */
264Srgrimes
274Srgrimes#include <sys/cdefs.h>
284Srgrimes__FBSDID("$FreeBSD: head/sbin/kldload/kldload.c 260483 2014-01-09 15:34:23Z bapt $");
294Srgrimes
304Srgrimes#include <sys/types.h>
31116176Sobrien#include <sys/param.h>
32116176Sobrien#include <sys/linker.h>
33116176Sobrien#include <sys/sysctl.h>
342056Swollman#include <sys/stat.h>
3547098Sbde#include <err.h>
3612734Sbde#include <stdio.h>
372056Swollman#include <stdlib.h>
384Srgrimes#include <string.h>
394Srgrimes#include <unistd.h>
404Srgrimes#include <errno.h>
4192756Salfred
424Srgrimes#define	PATHCTL	"kern.module_path"
4312515Sphk
444Srgrimesstatic int	path_check(const char *, int);
4537504Sbdestatic void	usage(void);
464Srgrimes
474Srgrimes/*
484Srgrimes * Check to see if the requested module is specified as a filename with no
49131952Smarcel * path.  If so and if a file by the same name exists in the module path,
50131952Smarcel * warn the user that the module in the path will be used in preference.
514Srgrimes */
5212515Sphkstatic int
53131952Smarcelpath_check(const char *kldname, int quiet)
544Srgrimes{
554Srgrimes	int	mib[5], found;
56131952Smarcel	size_t	miblen, pathlen;
574Srgrimes	char	kldpath[MAXPATHLEN];
584Srgrimes	char	*path, *tmppath, *element;
594Srgrimes	struct	stat sb;
60131952Smarcel	dev_t	dev;
61131952Smarcel	ino_t	ino;
62131952Smarcel
63131952Smarcel	if (strchr(kldname, '/') != NULL) {
64131952Smarcel		return (0);
654Srgrimes	}
66131952Smarcel	if (strstr(kldname, ".ko") == NULL) {
67131952Smarcel		return (0);
68131952Smarcel	}
69131952Smarcel	if (stat(kldname, &sb) != 0) {
70131952Smarcel		return (0);
714Srgrimes	}
724Srgrimes
734Srgrimes	found = 0;
744Srgrimes	dev = sb.st_dev;
754Srgrimes	ino = sb.st_ino;
764Srgrimes
774Srgrimes	miblen = sizeof(mib) / sizeof(mib[0]);
78131952Smarcel	if (sysctlnametomib(PATHCTL, mib, &miblen) != 0) {
794Srgrimes		err(1, "sysctlnametomib(%s)", PATHCTL);
804Srgrimes	}
814Srgrimes	if (sysctl(mib, miblen, NULL, &pathlen, NULL, 0) == -1) {
824Srgrimes		err(1, "getting path: sysctl(%s) - size only", PATHCTL);
83131952Smarcel	}
844Srgrimes	path = malloc(pathlen + 1);
85131952Smarcel	if (path == NULL) {
864Srgrimes		err(1, "allocating %lu bytes for the path",
874Srgrimes		    (unsigned long)pathlen + 1);
88131952Smarcel	}
89131952Smarcel	if (sysctl(mib, miblen, path, &pathlen, NULL, 0) == -1) {
904Srgrimes		err(1, "getting path: sysctl(%s)", PATHCTL);
914Srgrimes	}
924Srgrimes	tmppath = path;
934Srgrimes
94131952Smarcel	while ((element = strsep(&tmppath, ";")) != NULL) {
954Srgrimes		strlcpy(kldpath, element, MAXPATHLEN);
96131952Smarcel		if (kldpath[strlen(kldpath) - 1] != '/') {
974Srgrimes			strlcat(kldpath, "/", MAXPATHLEN);
984Srgrimes		}
99131952Smarcel		strlcat(kldpath, kldname, MAXPATHLEN);
100131952Smarcel
1014Srgrimes		if (stat(kldpath, &sb) == -1) {
102131952Smarcel			continue;
1034Srgrimes		}
104131952Smarcel
105131952Smarcel		found = 1;
106131952Smarcel
107131952Smarcel		if (sb.st_dev != dev || sb.st_ino != ino) {
108131952Smarcel			if (!quiet) {
1094Srgrimes				warnx("%s will be loaded from %s, not the "
1104Srgrimes				    "current directory", kldname, element);
111131952Smarcel			}
112131952Smarcel			break;
1134Srgrimes		} else if (sb.st_dev == dev && sb.st_ino == ino) {
114131952Smarcel			break;
1154Srgrimes		}
116131952Smarcel	}
117131952Smarcel
118131952Smarcel	free(path);
119131952Smarcel
120131952Smarcel	if (!found) {
1214Srgrimes		if (!quiet) {
1224Srgrimes			warnx("%s is not in the module path", kldname);
1234Srgrimes		}
124131952Smarcel		return (-1);
1254Srgrimes	}
1264Srgrimes
127131952Smarcel	return (0);
128131952Smarcel}
1294Srgrimes
1304Srgrimesstatic void
1314Srgrimesusage(void)
132131952Smarcel{
133131952Smarcel	fprintf(stderr, "usage: kldload [-nqv] file ...\n");
1344Srgrimes	exit(1);
1354Srgrimes}
136131952Smarcel
137131952Smarcelint
1384Srgrimesmain(int argc, char** argv)
1394Srgrimes{
1404Srgrimes	int c;
1414Srgrimes	int errors;
142131952Smarcel	int fileid;
1434Srgrimes	int verbose;
1444Srgrimes	int quiet;
145131952Smarcel	int check_loaded;
146131952Smarcel
1474Srgrimes	errors = 0;
148131952Smarcel	verbose = 0;
149131952Smarcel	quiet = 0;
1504Srgrimes	check_loaded = 0;
151131952Smarcel
1524Srgrimes	while ((c = getopt(argc, argv, "nqv")) != -1) {
153		switch (c) {
154		case 'q':
155			quiet = 1;
156			verbose = 0;
157			break;
158		case 'v':
159			verbose = 1;
160			quiet = 0;
161			break;
162		case 'n':
163			check_loaded = 1;
164			break;
165		default:
166			usage();
167		}
168	}
169	argc -= optind;
170	argv += optind;
171
172	if (argc == 0)
173		usage();
174
175	while (argc-- != 0) {
176		if (path_check(argv[0], quiet) == 0) {
177			fileid = kldload(argv[0]);
178			if (fileid < 0) {
179				if (check_loaded != 0 && errno == EEXIST) {
180					if (verbose)
181						printf("%s is already "
182						    "loaded\n", argv[0]);
183				} else {
184					if (errno == EEXIST) {
185						warnx("can't load %s: module "
186						    "already loaded or "
187						    "in kernel", argv[0]);
188					} else {
189						warn("can't load %s", argv[0]);
190						errors++;
191					}
192				}
193			} else {
194				if (verbose)
195					printf("Loaded %s, id=%d\n", argv[0],
196					    fileid);
197			}
198		} else {
199			errors++;
200		}
201		argv++;
202	}
203
204	return (errors ? 1 : 0);
205}
206