kldload.c revision 209971
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 1997 Doug Rabson
31590Srgrimes * All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes *
141590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241590Srgrimes * SUCH DAMAGE.
251590Srgrimes */
261590Srgrimes
271590Srgrimes#include <sys/cdefs.h>
281590Srgrimes__FBSDID("$FreeBSD: head/sbin/kldload/kldload.c 209971 2010-07-13 04:13:31Z maxim $");
291590Srgrimes
301590Srgrimes#include <sys/types.h>
311590Srgrimes#include <sys/param.h>
321590Srgrimes#include <sys/linker.h>
331590Srgrimes#include <sys/sysctl.h>
341590Srgrimes#include <sys/stat.h>
3519234Swollman#include <err.h>
361590Srgrimes#include <stdio.h>
3719234Swollman#include <stdlib.h>
3819234Swollman#include <string.h>
3950477Speter#include <unistd.h>
401590Srgrimes
411590Srgrimes#define	PATHCTL	"kern.module_path"
421590Srgrimes
431590Srgrimesstatic int	path_check(const char *, int);
441590Srgrimesstatic void	usage(void);
451590Srgrimes
4614543Sdg/*
471590Srgrimes * Check to see if the requested module is specified as a filename with no
481590Srgrimes * path.  If so and if a file by the same name exists in the module path,
491590Srgrimes * warn the user that the module in the path will be used in preference.
501590Srgrimes */
511590Srgrimesstatic int
521590Srgrimespath_check(const char *kldname, int quiet)
531590Srgrimes{
541590Srgrimes	int	mib[5], found;
551590Srgrimes	size_t	miblen, pathlen;
5636916Speter	char	kldpath[MAXPATHLEN];
571590Srgrimes	char	*path, *tmppath, *element;
581590Srgrimes	struct	stat sb;
591590Srgrimes	dev_t	dev;
601590Srgrimes	ino_t	ino;
611590Srgrimes
621590Srgrimes	if (strchr(kldname, '/') != NULL) {
631590Srgrimes		return (0);
641590Srgrimes	}
651590Srgrimes	if (strstr(kldname, ".ko") == NULL) {
661590Srgrimes		return (0);
671590Srgrimes	}
681590Srgrimes	if (stat(kldname, &sb) != 0) {
691590Srgrimes		return (0);
701590Srgrimes	}
711590Srgrimes
721590Srgrimes	found = 0;
731590Srgrimes	dev = sb.st_dev;
741590Srgrimes	ino = sb.st_ino;
751590Srgrimes
761590Srgrimes	miblen = sizeof(mib) / sizeof(mib[0]);
771590Srgrimes	if (sysctlnametomib(PATHCTL, mib, &miblen) != 0) {
781590Srgrimes		err(1, "sysctlnametomib(%s)", PATHCTL);
791590Srgrimes	}
801590Srgrimes	if (sysctl(mib, miblen, NULL, &pathlen, NULL, 0) == -1) {
811590Srgrimes		err(1, "getting path: sysctl(%s) - size only", PATHCTL);
821590Srgrimes	}
831590Srgrimes	path = malloc(pathlen + 1);
841590Srgrimes	if (path == NULL) {
851590Srgrimes		err(1, "allocating %lu bytes for the path",
861590Srgrimes		    (unsigned long)pathlen + 1);
8731522Ssteve	}
8831522Ssteve	if (sysctl(mib, miblen, path, &pathlen, NULL, 0) == -1) {
8931522Ssteve		err(1, "getting path: sysctl(%s)", PATHCTL);
9031522Ssteve	}
9131522Ssteve	tmppath = path;
9231522Ssteve
9331522Ssteve	while ((element = strsep(&tmppath, ";")) != NULL) {
9431522Ssteve		strlcpy(kldpath, element, MAXPATHLEN);
951590Srgrimes		if (kldpath[strlen(kldpath) - 1] != '/') {
961590Srgrimes			strlcat(kldpath, "/", MAXPATHLEN);
971590Srgrimes		}
981590Srgrimes		strlcat(kldpath, kldname, MAXPATHLEN);
991590Srgrimes
1001590Srgrimes		if (stat(kldpath, &sb) == -1) {
1011590Srgrimes			continue;
1021590Srgrimes		}
1031590Srgrimes
1041590Srgrimes		found = 1;
1051590Srgrimes
1061590Srgrimes		if (sb.st_dev != dev || sb.st_ino != ino) {
1071590Srgrimes			if (!quiet) {
1081590Srgrimes				warnx("%s will be loaded from %s, not the "
1091590Srgrimes				    "current directory", kldname, element);
1101590Srgrimes			}
1111590Srgrimes			break;
1121590Srgrimes		} else if (sb.st_dev == dev && sb.st_ino == ino) {
1131590Srgrimes			break;
1141590Srgrimes		}
1151590Srgrimes	}
1161590Srgrimes
1171590Srgrimes	free(path);
1181590Srgrimes
1191590Srgrimes	if (!found) {
1201590Srgrimes		if (!quiet) {
1211590Srgrimes			warnx("%s is not in the module path", kldname);
1221590Srgrimes		}
1231590Srgrimes		return (-1);
1241590Srgrimes	}
1251590Srgrimes
1261590Srgrimes	return (0);
1271590Srgrimes}
1281590Srgrimes
1291590Srgrimesstatic void
1301590Srgrimesusage(void)
1311590Srgrimes{
1321590Srgrimes	fprintf(stderr, "usage: kldload [-v] [-q] file ...\n");
1331590Srgrimes	exit(1);
1341590Srgrimes}
1351590Srgrimes
1361590Srgrimesint
1371590Srgrimesmain(int argc, char** argv)
1381590Srgrimes{
1391590Srgrimes	int c;
1401590Srgrimes	int errors;
1411590Srgrimes	int fileid;
1421590Srgrimes	int verbose;
1431590Srgrimes	int quiet;
1441590Srgrimes
1451590Srgrimes	errors = 0;
1461590Srgrimes	verbose = 0;
1471590Srgrimes	quiet = 0;
1481590Srgrimes
1491590Srgrimes	while ((c = getopt(argc, argv, "qv")) != -1) {
1501590Srgrimes		switch (c) {
1511590Srgrimes		case 'q':
1521590Srgrimes			quiet = 1;
1531590Srgrimes			verbose = 0;
1541590Srgrimes			break;
1551590Srgrimes		case 'v':
1561590Srgrimes			verbose = 1;
1571590Srgrimes			quiet = 0;
1581590Srgrimes			break;
1591590Srgrimes		default:
1601590Srgrimes			usage();
1611590Srgrimes		}
1621590Srgrimes	}
1631590Srgrimes	argc -= optind;
1641590Srgrimes	argv += optind;
1651590Srgrimes
1661590Srgrimes	if (argc == 0)
1671590Srgrimes		usage();
1681590Srgrimes
1691590Srgrimes	while (argc-- != 0) {
1701590Srgrimes		if (path_check(argv[0], quiet) == 0) {
1711590Srgrimes			fileid = kldload(argv[0]);
1721590Srgrimes			if (fileid < 0) {
1731590Srgrimes				warn("can't load %s", argv[0]);
1741590Srgrimes				errors++;
1751590Srgrimes			} else {
1761590Srgrimes				if (verbose)
1771590Srgrimes					printf("Loaded %s, id=%d\n", argv[0],
17831522Ssteve					    fileid);
1791590Srgrimes			}
18031522Ssteve		} else {
1811590Srgrimes			errors++;
18231522Ssteve		}
18331522Ssteve		argv++;
18431522Ssteve	}
18531522Ssteve
18631522Ssteve	return (errors ? 1 : 0);
1871590Srgrimes}
1881590Srgrimes