Add kldconfig(8), a utility to modify the kernel module search path.
Reviewed by: -arch, -audit
This commit is contained in:
parent
a15906e7aa
commit
48c8fe6863
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=78977
34
sbin/kldconfig/Makefile
Normal file
34
sbin/kldconfig/Makefile
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2001 Peter Pentchev
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
# 1. Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
# SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
# $FreeBSD$
|
||||||
|
#
|
||||||
|
|
||||||
|
PROG= kldconfig
|
||||||
|
MAN= kldconfig.8
|
||||||
|
|
||||||
|
WARNS?= 2
|
||||||
|
|
||||||
|
.include <bsd.prog.mk>
|
109
sbin/kldconfig/kldconfig.8
Normal file
109
sbin/kldconfig/kldconfig.8
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
.\"
|
||||||
|
.\" Copyright (c) 2001 Peter Pentchev
|
||||||
|
.\" All rights reserved.
|
||||||
|
.\"
|
||||||
|
.\" Redistribution and use in source and binary forms, with or without
|
||||||
|
.\" modification, are permitted provided that the following conditions
|
||||||
|
.\" are met:
|
||||||
|
.\" 1. Redistributions of source code must retain the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer.
|
||||||
|
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer in the
|
||||||
|
.\" documentation and/or other materials provided with the distribution.
|
||||||
|
.\"
|
||||||
|
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
.\" SUCH DAMAGE.
|
||||||
|
.\"
|
||||||
|
.\" $FreeBSD$
|
||||||
|
.\"
|
||||||
|
.Dd June 15, 2001
|
||||||
|
.Dt KLDCONFIG 8
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm kldconfig
|
||||||
|
.Nd display or modify the kernel module search path
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl dfimnUv
|
||||||
|
.Op Fl S Ar name
|
||||||
|
.Op Ar path ...
|
||||||
|
.Nm
|
||||||
|
.Fl r
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
displays or modifies the search path used by the kernel when loading modules
|
||||||
|
using the
|
||||||
|
.Xr kldload 8
|
||||||
|
utility or the
|
||||||
|
.Xr kldload 2
|
||||||
|
syscall.
|
||||||
|
.Pp
|
||||||
|
The following options are available:
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Fl d
|
||||||
|
Remove the specified paths from the module search path.
|
||||||
|
.It Fl f
|
||||||
|
Do not display a diagnostic message if a path specified for adding is
|
||||||
|
already present in the search path, or if a path specified for removing
|
||||||
|
is not present in the search path.
|
||||||
|
This may be useful in startup/shutdown scripts for adding a path to
|
||||||
|
a filesystem which is still not mounted, or in shutdown scripts for
|
||||||
|
unconditionally removing a path that may have been added during startup.
|
||||||
|
.It Fl i
|
||||||
|
Add the specified paths to the beginning of the search path, not to the end.
|
||||||
|
This option can only be used when adding paths.
|
||||||
|
.It Fl m
|
||||||
|
Instead of replacing the module search path with the set of paths
|
||||||
|
specified,
|
||||||
|
.Dq merge
|
||||||
|
in the new entries.
|
||||||
|
.It Fl n
|
||||||
|
Do not actually change the module search path.
|
||||||
|
.It Fl r
|
||||||
|
Display the current search path.
|
||||||
|
This option cannot be used if any paths are also specified.
|
||||||
|
.It Fl S Ar name
|
||||||
|
Specify the sysctl name to use instead of the default
|
||||||
|
.Va kern.module_path .
|
||||||
|
.It Fl U
|
||||||
|
.Dq Unique-ify
|
||||||
|
the current search path - if any of the directories is repeated one
|
||||||
|
or more times, only the first occurrence remains.
|
||||||
|
This option implies
|
||||||
|
.Fl m .
|
||||||
|
.It Fl v
|
||||||
|
Verbose output: display the new module search path.
|
||||||
|
If the path has been changed, and the
|
||||||
|
.Fl v
|
||||||
|
flag is specified more than once, the old path is displayed as well.
|
||||||
|
.El
|
||||||
|
.Sh FILES
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Pa /boot/kernel /boot/modules /modules
|
||||||
|
The default module search path used by the kernel.
|
||||||
|
.El
|
||||||
|
.Sh DIAGNOSTICS
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility exits with a status of 0 on success
|
||||||
|
and with a nonzero status if an error occurs.
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr kldload 2 ,
|
||||||
|
.Xr kldload 8 ,
|
||||||
|
.Xr sysctl 8
|
||||||
|
.Sh HISTORY
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility first appeared in
|
||||||
|
.Fx 5.0 .
|
||||||
|
.Sh AUTHORS
|
||||||
|
.An Peter Pentchev Aq roam@FreeBSD.org
|
444
sbin/kldconfig/kldconfig.c
Normal file
444
sbin/kldconfig/kldconfig.c
Normal file
@ -0,0 +1,444 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2001 Peter Pentchev
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef lint
|
||||||
|
static const char rcsid[] =
|
||||||
|
"$FreeBSD$";
|
||||||
|
#endif /* not lint */
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#if defined(__FreeBSD_version)
|
||||||
|
#if __FreeBSD_version < 500000
|
||||||
|
#define NEED_SLASHTERM
|
||||||
|
#endif /* < 500000 */
|
||||||
|
#else /* defined(__FreeBSD_version) */
|
||||||
|
/* just in case.. */
|
||||||
|
#define NEED_SLASHTERM
|
||||||
|
#endif /* defined(__FreeBSD_version) */
|
||||||
|
|
||||||
|
/* the default sysctl name */
|
||||||
|
#define PATHCTL "kern.module_path"
|
||||||
|
|
||||||
|
/* queue structure for the module path broken down into components */
|
||||||
|
TAILQ_HEAD(pathhead, pathentry);
|
||||||
|
struct pathentry {
|
||||||
|
char *path;
|
||||||
|
TAILQ_ENTRY(pathentry) next;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* the Management Information Base entries for the search path sysctl */
|
||||||
|
static int mib[5];
|
||||||
|
static size_t miblen;
|
||||||
|
/* the sysctl name, defaults to PATHCTL */
|
||||||
|
static char *pathctl;
|
||||||
|
/* the sysctl value - the current module search path */
|
||||||
|
static char *modpath;
|
||||||
|
/* flag whether user actions require changing the sysctl value */
|
||||||
|
static int changed;
|
||||||
|
|
||||||
|
/* Top-level path management functions */
|
||||||
|
static void addpath(struct pathhead *, char *, int, int);
|
||||||
|
static void rempath(struct pathhead *, char *, int, int);
|
||||||
|
static void showpath(struct pathhead *);
|
||||||
|
|
||||||
|
/* Low-level path management functions */
|
||||||
|
static char *qstring(struct pathhead *);
|
||||||
|
|
||||||
|
/* sysctl-related functions */
|
||||||
|
static void getmib(void);
|
||||||
|
static void getpath(void);
|
||||||
|
static void parsepath(struct pathhead *, char *, int);
|
||||||
|
static void setpath(struct pathhead *);
|
||||||
|
|
||||||
|
static void usage(void);
|
||||||
|
|
||||||
|
/* Get the MIB entry for our sysctl */
|
||||||
|
static void
|
||||||
|
getmib(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* have we already fetched it? */
|
||||||
|
if (miblen != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
miblen = sizeof(mib) / sizeof(mib[0]);
|
||||||
|
if (sysctlnametomib(pathctl, mib, &miblen) != 0)
|
||||||
|
err(1, "sysctlnametomib(%s)", pathctl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the current module search path */
|
||||||
|
static void
|
||||||
|
getpath(void)
|
||||||
|
{
|
||||||
|
char *path;
|
||||||
|
size_t sz;
|
||||||
|
|
||||||
|
if (modpath != NULL) {
|
||||||
|
free(modpath);
|
||||||
|
modpath = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (miblen == 0)
|
||||||
|
getmib();
|
||||||
|
if (sysctl(mib, miblen, NULL, &sz, NULL, NULL) == -1)
|
||||||
|
err(1, "getting path: sysctl(%s) - size only", pathctl);
|
||||||
|
if ((path = malloc(sz + 1)) == NULL) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
err(1, "allocating %u bytes for the path", sz+1);
|
||||||
|
}
|
||||||
|
if (sysctl(mib, miblen, path, &sz, NULL, NULL) == -1)
|
||||||
|
err(1, "getting path: sysctl(%s)", pathctl);
|
||||||
|
modpath = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the module search path after changing it */
|
||||||
|
static void
|
||||||
|
setpath(struct pathhead *pathq)
|
||||||
|
{
|
||||||
|
char *newpath;
|
||||||
|
|
||||||
|
if (miblen == 0)
|
||||||
|
getmib();
|
||||||
|
if ((newpath = qstring(pathq)) == NULL) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
err(1, "building path string");
|
||||||
|
}
|
||||||
|
if (sysctl(mib, miblen, NULL, NULL, newpath, strlen(newpath)+1) == -1)
|
||||||
|
err(1, "setting path: sysctl(%s)", pathctl);
|
||||||
|
|
||||||
|
if (modpath)
|
||||||
|
free(modpath);
|
||||||
|
modpath = newpath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add/insert a new component to the module search path */
|
||||||
|
static void
|
||||||
|
addpath(struct pathhead *pathq, char *path, int force, int insert)
|
||||||
|
{
|
||||||
|
struct pathentry *pe, *pskip;
|
||||||
|
char pathbuf[MAXPATHLEN+1];
|
||||||
|
size_t len;
|
||||||
|
static unsigned added = 0;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the path exists, use it; otherwise, take the user-specified
|
||||||
|
* path at face value - may be a removed directory.
|
||||||
|
*/
|
||||||
|
if (realpath(path, pathbuf) == NULL)
|
||||||
|
strlcpy(pathbuf, path, sizeof(pathbuf));
|
||||||
|
|
||||||
|
len = strlen(pathbuf);
|
||||||
|
#ifdef NEED_SLASHTERM
|
||||||
|
/* slash-terminate, because the kernel linker said so. */
|
||||||
|
if ((len == 0) || (pathbuf[len-1] != '/')) {
|
||||||
|
if (len == sizeof(pathbuf) - 1)
|
||||||
|
errx(1, "path too long: %s", pathbuf);
|
||||||
|
pathbuf[len] = '/';
|
||||||
|
}
|
||||||
|
#else /* NEED_SLASHTERM */
|
||||||
|
/* remove a terminating slash if present */
|
||||||
|
if ((len > 0) && (pathbuf[len-1] == '/'))
|
||||||
|
pathbuf[--len] = '\0';
|
||||||
|
#endif /* NEED_SLASHTERM */
|
||||||
|
|
||||||
|
/* is it already in there? */
|
||||||
|
TAILQ_FOREACH(pe, pathq, next)
|
||||||
|
if (!strcmp(pe->path, pathbuf))
|
||||||
|
break;
|
||||||
|
if (pe != NULL) {
|
||||||
|
if (force)
|
||||||
|
return;
|
||||||
|
errx(1, "already in the module search path: %s", pathbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OK, allocate and add it. */
|
||||||
|
if (((pe = malloc(sizeof(*pe))) == NULL) ||
|
||||||
|
((pe->path = strdup(pathbuf)) == NULL)) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
err(1, "allocating path component");
|
||||||
|
}
|
||||||
|
if (!insert) {
|
||||||
|
TAILQ_INSERT_TAIL(pathq, pe, next);
|
||||||
|
} else {
|
||||||
|
for (i = 0, pskip = TAILQ_FIRST(pathq); i < added; i++)
|
||||||
|
pskip = TAILQ_NEXT(pskip, next);
|
||||||
|
if (pskip != NULL)
|
||||||
|
TAILQ_INSERT_BEFORE(pskip, pe, next);
|
||||||
|
else
|
||||||
|
TAILQ_INSERT_TAIL(pathq, pe, next);
|
||||||
|
added++;
|
||||||
|
}
|
||||||
|
changed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove a path component from the module search path */
|
||||||
|
static void
|
||||||
|
rempath(struct pathhead *pathq, char *path, int force, int insert __unused)
|
||||||
|
{
|
||||||
|
char pathbuf[MAXPATHLEN+1];
|
||||||
|
struct pathentry *pe;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
/* same logic as in addpath() */
|
||||||
|
if (realpath(path, pathbuf) == NULL)
|
||||||
|
strlcpy(pathbuf, path, sizeof(pathbuf));
|
||||||
|
|
||||||
|
len = strlen(pathbuf);
|
||||||
|
#ifdef NEED_SLASHTERM
|
||||||
|
/* slash-terminate, because the kernel linker said so. */
|
||||||
|
if ((len == 0) || (pathbuf[len-1] != '/')) {
|
||||||
|
if (len == sizeof(pathbuf) - 1)
|
||||||
|
errx(1, "path too long: %s", pathbuf);
|
||||||
|
pathbuf[len] = '/';
|
||||||
|
}
|
||||||
|
#else /* NEED_SLASHTERM */
|
||||||
|
/* remove a terminating slash if present */
|
||||||
|
if ((len > 0) && (pathbuf[len-1] == '/'))
|
||||||
|
pathbuf[--len] = '\0';
|
||||||
|
#endif /* NEED_SLASHTERM */
|
||||||
|
|
||||||
|
/* Is it in there? */
|
||||||
|
TAILQ_FOREACH(pe, pathq, next)
|
||||||
|
if (!strcmp(pe->path, pathbuf))
|
||||||
|
break;
|
||||||
|
if (pe == NULL) {
|
||||||
|
if (force)
|
||||||
|
return;
|
||||||
|
errx(1, "not in module search path: %s", pathbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OK, remove it now.. */
|
||||||
|
TAILQ_REMOVE(pathq, pe, next);
|
||||||
|
changed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Display the retrieved module search path */
|
||||||
|
static void
|
||||||
|
showpath(struct pathhead *pathq)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
if ((s = qstring(pathq)) == NULL) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
err(1, "building path string");
|
||||||
|
}
|
||||||
|
printf("%s\n", s);
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Break a string down into path components, store them into a queue */
|
||||||
|
static void
|
||||||
|
parsepath(struct pathhead *pathq, char *path, int uniq)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
struct pathentry *pe;
|
||||||
|
|
||||||
|
while ((p = strsep(&path, ";")) != NULL)
|
||||||
|
if (!uniq) {
|
||||||
|
if (((pe = malloc(sizeof(pe))) == NULL) ||
|
||||||
|
((pe->path = strdup(p)) == NULL)) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
err(1, "allocating path element");
|
||||||
|
}
|
||||||
|
TAILQ_INSERT_TAIL(pathq, pe, next);
|
||||||
|
} else {
|
||||||
|
addpath(pathq, p, 1, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Recreate a path string from a components queue */
|
||||||
|
static char *
|
||||||
|
qstring(struct pathhead *pathq)
|
||||||
|
{
|
||||||
|
char *s, *p;
|
||||||
|
struct pathentry *pe;
|
||||||
|
|
||||||
|
s = strdup("");
|
||||||
|
TAILQ_FOREACH(pe, pathq, next) {
|
||||||
|
asprintf(&p, "%s%s%s",
|
||||||
|
s, pe->path, (TAILQ_NEXT(pe, next) != NULL? ";": ""));
|
||||||
|
free(s);
|
||||||
|
if (p == NULL)
|
||||||
|
return (NULL);
|
||||||
|
s = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Usage message */
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
fprintf(stderr, "%s\n%s\n",
|
||||||
|
"usage:\tkldconfig [-dfimnUv] [-S sysctlname] [path..]",
|
||||||
|
"\tkldconfig -r");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main function */
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
/* getopt() iterator */
|
||||||
|
int c;
|
||||||
|
/* iterator over argv[] path components */
|
||||||
|
int i;
|
||||||
|
/* Command-line flags: */
|
||||||
|
/* "-f" - no diagnostic messages */
|
||||||
|
int fflag;
|
||||||
|
/* "-i" - insert before the first element */
|
||||||
|
int iflag;
|
||||||
|
/* "-m" - merge into the existing path, do not replace it */
|
||||||
|
int mflag;
|
||||||
|
/* "-n" - do not actually set the new module path */
|
||||||
|
int nflag;
|
||||||
|
/* "-r" - print out the current search path */
|
||||||
|
int rflag;
|
||||||
|
/* "-U" - remove duplicate values from the path */
|
||||||
|
int uniqflag;
|
||||||
|
/* "-v" - verbose operation (currently a no-op) */
|
||||||
|
int vflag;
|
||||||
|
/* The higher-level function to call - add/remove */
|
||||||
|
void (*act)(struct pathhead *, char *, int, int);
|
||||||
|
/* The original path */
|
||||||
|
char *origpath;
|
||||||
|
/* The module search path broken down into components */
|
||||||
|
struct pathhead pathq;
|
||||||
|
|
||||||
|
fflag = iflag = mflag = nflag = rflag = uniqflag = vflag = 0;
|
||||||
|
act = addpath;
|
||||||
|
origpath = NULL;
|
||||||
|
if ((pathctl = strdup(PATHCTL)) == NULL) {
|
||||||
|
/* this is just too paranoid ;) */
|
||||||
|
errno = ENOMEM;
|
||||||
|
err(1, "initializing sysctl name %s", PATHCTL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If no arguments and no options are specified, force '-m' */
|
||||||
|
if (argc == 1)
|
||||||
|
mflag = 1;
|
||||||
|
|
||||||
|
while ((c = getopt(argc, argv, "dfimnrS:Uv")) != -1)
|
||||||
|
switch (c) {
|
||||||
|
case 'd':
|
||||||
|
if (iflag || mflag)
|
||||||
|
usage();
|
||||||
|
act = rempath;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
fflag = 1;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
if (act != addpath)
|
||||||
|
usage();
|
||||||
|
iflag = 1;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
if (act != addpath)
|
||||||
|
usage();
|
||||||
|
mflag = 1;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
nflag = 1;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
rflag = 1;
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
free(pathctl);
|
||||||
|
if ((pathctl = strdup(optarg)) == NULL) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
err(1, "sysctl name %s", optarg);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'U':
|
||||||
|
uniqflag = 1;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
vflag++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
/* The '-r' flag cannot be used when paths are also specified */
|
||||||
|
if (rflag && (argc > 0))
|
||||||
|
usage();
|
||||||
|
|
||||||
|
TAILQ_INIT(&pathq);
|
||||||
|
|
||||||
|
/* Retrieve and store the path from the sysctl value */
|
||||||
|
getpath();
|
||||||
|
if ((origpath = strdup(modpath)) == NULL) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
err(1, "saving the original search path");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Break down the path into the components queue if:
|
||||||
|
* - we are NOT adding paths, OR
|
||||||
|
* - the 'merge' flag is specified, OR
|
||||||
|
* - the 'print only' flag is specified, OR
|
||||||
|
* - the 'unique' flag is specified.
|
||||||
|
*/
|
||||||
|
if ((act != addpath) || mflag || rflag || uniqflag)
|
||||||
|
parsepath(&pathq, modpath, uniqflag);
|
||||||
|
else if (modpath[0] != '\0')
|
||||||
|
changed = 1;
|
||||||
|
|
||||||
|
/* Process the path arguments */
|
||||||
|
for (i = 0; i < argc; i++)
|
||||||
|
act(&pathq, argv[i], fflag, iflag);
|
||||||
|
|
||||||
|
if (changed && !nflag)
|
||||||
|
setpath(&pathq);
|
||||||
|
|
||||||
|
if (rflag || (changed && vflag)) {
|
||||||
|
if (changed && (vflag > 1))
|
||||||
|
printf("%s -> ", origpath);
|
||||||
|
showpath(&pathq);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user