2 * Copyright (c) 2001 Peter Pentchev
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/sbin/kldconfig/kldconfig.c,v 1.3.2.1 2001/08/01 05:52:36 obrien Exp $
27 * $DragonFly: src/sbin/kldconfig/kldconfig.c,v 1.2 2003/06/17 04:27:33 dillon Exp $
30 #include <sys/param.h>
31 #include <sys/types.h>
32 #include <sys/queue.h>
33 #include <sys/sysctl.h>
43 #if defined(__FreeBSD_version)
44 #if __FreeBSD_version < 500000
45 #define NEED_SLASHTERM
47 #else /* defined(__FreeBSD_version) */
49 #define NEED_SLASHTERM
50 #endif /* defined(__FreeBSD_version) */
52 /* the default sysctl name */
53 #define PATHCTL "kern.module_path"
55 /* queue structure for the module path broken down into components */
56 TAILQ_HEAD(pathhead
, pathentry
);
59 TAILQ_ENTRY(pathentry
) next
;
62 /* the Management Information Base entries for the search path sysctl */
65 /* the sysctl name, defaults to PATHCTL */
67 /* the sysctl value - the current module search path */
69 /* flag whether user actions require changing the sysctl value */
72 /* Top-level path management functions */
73 static void addpath(struct pathhead
*, char *, int, int);
74 static void rempath(struct pathhead
*, char *, int, int);
75 static void showpath(struct pathhead
*);
77 /* Low-level path management functions */
78 static char *qstring(struct pathhead
*);
80 /* sysctl-related functions */
81 static void getmib(void);
82 static void getpath(void);
83 static void parsepath(struct pathhead
*, char *, int);
84 static void setpath(struct pathhead
*);
86 static void usage(void);
88 /* Get the MIB entry for our sysctl */
93 /* have we already fetched it? */
97 miblen
= sizeof(mib
) / sizeof(mib
[0]);
98 if (sysctlnametomib(pathctl
, mib
, &miblen
) != 0)
99 err(1, "sysctlnametomib(%s)", pathctl
);
102 /* Get the current module search path */
109 if (modpath
!= NULL
) {
116 if (sysctl(mib
, miblen
, NULL
, &sz
, NULL
, NULL
) == -1)
117 err(1, "getting path: sysctl(%s) - size only", pathctl
);
118 if ((path
= malloc(sz
+ 1)) == NULL
) {
120 err(1, "allocating %lu bytes for the path",
121 (unsigned long)sz
+1);
123 if (sysctl(mib
, miblen
, path
, &sz
, NULL
, NULL
) == -1)
124 err(1, "getting path: sysctl(%s)", pathctl
);
128 /* Set the module search path after changing it */
130 setpath(struct pathhead
*pathq
)
136 if ((newpath
= qstring(pathq
)) == NULL
) {
138 err(1, "building path string");
140 if (sysctl(mib
, miblen
, NULL
, NULL
, newpath
, strlen(newpath
)+1) == -1)
141 err(1, "setting path: sysctl(%s)", pathctl
);
148 /* Add/insert a new component to the module search path */
150 addpath(struct pathhead
*pathq
, char *path
, int force
, int insert
)
152 struct pathentry
*pe
, *pskip
;
153 char pathbuf
[MAXPATHLEN
+1];
155 static unsigned added
= 0;
159 * If the path exists, use it; otherwise, take the user-specified
160 * path at face value - may be a removed directory.
162 if (realpath(path
, pathbuf
) == NULL
)
163 strlcpy(pathbuf
, path
, sizeof(pathbuf
));
165 len
= strlen(pathbuf
);
166 #ifdef NEED_SLASHTERM
167 /* slash-terminate, because the kernel linker said so. */
168 if ((len
== 0) || (pathbuf
[len
-1] != '/')) {
169 if (len
== sizeof(pathbuf
) - 1)
170 errx(1, "path too long: %s", pathbuf
);
173 #else /* NEED_SLASHTERM */
174 /* remove a terminating slash if present */
175 if ((len
> 0) && (pathbuf
[len
-1] == '/'))
176 pathbuf
[--len
] = '\0';
177 #endif /* NEED_SLASHTERM */
179 /* is it already in there? */
180 TAILQ_FOREACH(pe
, pathq
, next
)
181 if (!strcmp(pe
->path
, pathbuf
))
186 errx(1, "already in the module search path: %s", pathbuf
);
189 /* OK, allocate and add it. */
190 if (((pe
= malloc(sizeof(*pe
))) == NULL
) ||
191 ((pe
->path
= strdup(pathbuf
)) == NULL
)) {
193 err(1, "allocating path component");
196 TAILQ_INSERT_TAIL(pathq
, pe
, next
);
198 for (i
= 0, pskip
= TAILQ_FIRST(pathq
); i
< added
; i
++)
199 pskip
= TAILQ_NEXT(pskip
, next
);
201 TAILQ_INSERT_BEFORE(pskip
, pe
, next
);
203 TAILQ_INSERT_TAIL(pathq
, pe
, next
);
209 /* Remove a path component from the module search path */
211 rempath(struct pathhead
*pathq
, char *path
, int force
, int insert __unused
)
213 char pathbuf
[MAXPATHLEN
+1];
214 struct pathentry
*pe
;
217 /* same logic as in addpath() */
218 if (realpath(path
, pathbuf
) == NULL
)
219 strlcpy(pathbuf
, path
, sizeof(pathbuf
));
221 len
= strlen(pathbuf
);
222 #ifdef NEED_SLASHTERM
223 /* slash-terminate, because the kernel linker said so. */
224 if ((len
== 0) || (pathbuf
[len
-1] != '/')) {
225 if (len
== sizeof(pathbuf
) - 1)
226 errx(1, "path too long: %s", pathbuf
);
229 #else /* NEED_SLASHTERM */
230 /* remove a terminating slash if present */
231 if ((len
> 0) && (pathbuf
[len
-1] == '/'))
232 pathbuf
[--len
] = '\0';
233 #endif /* NEED_SLASHTERM */
235 /* Is it in there? */
236 TAILQ_FOREACH(pe
, pathq
, next
)
237 if (!strcmp(pe
->path
, pathbuf
))
242 errx(1, "not in module search path: %s", pathbuf
);
245 /* OK, remove it now.. */
246 TAILQ_REMOVE(pathq
, pe
, next
);
250 /* Display the retrieved module search path */
252 showpath(struct pathhead
*pathq
)
256 if ((s
= qstring(pathq
)) == NULL
) {
258 err(1, "building path string");
264 /* Break a string down into path components, store them into a queue */
266 parsepath(struct pathhead
*pathq
, char *path
, int uniq
)
269 struct pathentry
*pe
;
271 while ((p
= strsep(&path
, ";")) != NULL
)
273 if (((pe
= malloc(sizeof(pe
))) == NULL
) ||
274 ((pe
->path
= strdup(p
)) == NULL
)) {
276 err(1, "allocating path element");
278 TAILQ_INSERT_TAIL(pathq
, pe
, next
);
280 addpath(pathq
, p
, 1, 0);
284 /* Recreate a path string from a components queue */
286 qstring(struct pathhead
*pathq
)
289 struct pathentry
*pe
;
292 TAILQ_FOREACH(pe
, pathq
, next
) {
293 asprintf(&p
, "%s%s%s",
294 s
, pe
->path
, (TAILQ_NEXT(pe
, next
) != NULL
? ";": ""));
309 fprintf(stderr
, "%s\n%s\n",
310 "usage:\tkldconfig [-dfimnUv] [-S sysctlname] [path..]",
317 main(int argc
, char *argv
[])
319 /* getopt() iterator */
321 /* iterator over argv[] path components */
323 /* Command-line flags: */
324 /* "-f" - no diagnostic messages */
326 /* "-i" - insert before the first element */
328 /* "-m" - merge into the existing path, do not replace it */
330 /* "-n" - do not actually set the new module path */
332 /* "-r" - print out the current search path */
334 /* "-U" - remove duplicate values from the path */
336 /* "-v" - verbose operation (currently a no-op) */
338 /* The higher-level function to call - add/remove */
339 void (*act
)(struct pathhead
*, char *, int, int);
340 /* The original path */
342 /* The module search path broken down into components */
343 struct pathhead pathq
;
345 fflag
= iflag
= mflag
= nflag
= rflag
= uniqflag
= vflag
= 0;
348 if ((pathctl
= strdup(PATHCTL
)) == NULL
) {
349 /* this is just too paranoid ;) */
351 err(1, "initializing sysctl name %s", PATHCTL
);
354 /* If no arguments and no options are specified, force '-m' */
358 while ((c
= getopt(argc
, argv
, "dfimnrS:Uv")) != -1)
386 if ((pathctl
= strdup(optarg
)) == NULL
) {
388 err(1, "sysctl name %s", optarg
);
404 /* The '-r' flag cannot be used when paths are also specified */
405 if (rflag
&& (argc
> 0))
410 /* Retrieve and store the path from the sysctl value */
412 if ((origpath
= strdup(modpath
)) == NULL
) {
414 err(1, "saving the original search path");
418 * Break down the path into the components queue if:
419 * - we are NOT adding paths, OR
420 * - the 'merge' flag is specified, OR
421 * - the 'print only' flag is specified, OR
422 * - the 'unique' flag is specified.
424 if ((act
!= addpath
) || mflag
|| rflag
|| uniqflag
)
425 parsepath(&pathq
, modpath
, uniqflag
);
426 else if (modpath
[0] != '\0')
429 /* Process the path arguments */
430 for (i
= 0; i
< argc
; i
++)
431 act(&pathq
, argv
[i
], fflag
, iflag
);
433 if (changed
&& !nflag
)
436 if (rflag
|| (changed
&& vflag
)) {
437 if (changed
&& (vflag
> 1))
438 printf("%s -> ", origpath
);