Date: Fri, 15 Jun 2001 15:06:39 +0300 From: Peter Pentchev <roam@orbitel.bg> To: audit@FreeBSD.org Cc: arch@FreeBSD.org Subject: new kldpath(8): display/modify the module search path Message-ID: <20010615150639.D94445@ringworld.oblivion.bg>
next in thread | raw e-mail | index | archive | help
Hi, Attached is a shar of a new kld-family utility, which parses and modifies the kern.module_path sysctl in a script-friendly way. It might be useful in startup/shutdown scripts for programs using more than one module, or just to allow startup scripts to specify additional module directories (e.g. /usr/local/libexec/modules, or /usr/local/lib/au88x0). Sample use: [root@edge:p0 ~]# mkdir -p /usr/local/libexec/modules [root@edge:p0 ~]# mv /boot/kernel/accf_data.ko /usr/local/libexec/modules [root@edge:p0 ~]# mv /boot/kernel/accf_http.ko /usr/local/libexec/modules [root@edge:p0 ~]# kldpath -p Module path: /boot/kernel;/boot/modules;/modules [root@edge:p0 ~]# kldload accf_http.ko kldload: can't load accf_http.ko: No such file or directory [root@edge:p0 ~]# kldpath /usr/local/libexec/modules/ Module path: /boot/kernel;/boot/modules;/modules;/usr/local/libexec/modules [root@edge:p0 ~]# kldload accf_http.ko [root@edge:p0 ~]# kldpath -r /usr/local/libexec/modules Module path: /boot/kernel;/boot/modules;/modules [root@edge:p0 ~]# kldload accf_data.ko kldload: can't load accf_data.ko: No such file or directory [root@edge:p0 ~]# As shown, kldpath strips the trailing slash in the directory name, as this is the format the kernel linker wants the path in. There is an automatic __FreeBSD_version-based detection if the kernel linker might like the trailing slash present, and in RELENG_4 it is added. (OK, so 500000 might not be the best signpost for the point at which the kernel linker became able to deal with paths without kernel slashes, but I think this would be the slightest nit in anyone's comments/objections to this new utility :P ) Comments? Objections? Flames? Overwhelming reasons this should *not* go into base, other than 'it goes against the POLA of making the user tweak obscure, undocumented sysctl's, instead of using command-line utilities'? :) (not that this applies to FreeBSD in particular; I've found more than enough command-line utilities in FreeBSD to control all kinds of system behavior.) (And yes, kern.module_path is indeed undocumented..) G'luck, Peter -- This sentence no verb. # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # kldpath # kldpath/Makefile # kldpath/kldpath.8 # kldpath/kldpath.c # echo c - kldpath mkdir -p kldpath > /dev/null 2>&1 echo x - kldpath/Makefile sed 's/^X//' >kldpath/Makefile << 'END-of-kldpath/Makefile' X# X# Copyright (c) 2001 Peter Pentchev X# All rights reserved. X# X# Redistribution and use in source and binary forms, with or without X# modification, are permitted provided that the following conditions X# are met: X# 1. Redistributions of source code must retain the above copyright X# notice, this list of conditions and the following disclaimer. X# 2. Redistributions in binary form must reproduce the above copyright X# notice, this list of conditions and the following disclaimer in the X# documentation and/or other materials provided with the distribution. X# X# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND X# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE X# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE X# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE X# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL X# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS X# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT X# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY X# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF X# SUCH DAMAGE. X# X# $FreeBSD$ X# X XPROG= kldpath XMAN8= kldpath.8 X XWARNS?= 2 XFORMAT_AUDIT?= 1 X X.include <bsd.prog.mk> END-of-kldpath/Makefile echo x - kldpath/kldpath.8 sed 's/^X//' >kldpath/kldpath.8 << 'END-of-kldpath/kldpath.8' X.\" X.\" Copyright (c) 2001 Peter Pentchev X.\" All rights reserved. X.\" X.\" Redistribution and use in source and binary forms, with or without X.\" modification, are permitted provided that the following conditions X.\" are met: X.\" 1. Redistributions of source code must retain the above copyright X.\" notice, this list of conditions and the following disclaimer. X.\" 2. Redistributions in binary form must reproduce the above copyright X.\" notice, this list of conditions and the following disclaimer in the X.\" documentation and/or other materials provided with the distribution. X.\" X.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND X.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE X.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE X.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE X.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL X.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS X.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT X.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY X.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF X.\" SUCH DAMAGE. X.\" X.\" $FreeBSD$ X.\" X.Dd June 15, 2001 X.Dt KLDPATH 8 X.Os FreeBSD X.Sh NAME X.Nm kldpath X.Nd display or modify the kernel module search path X.Sh SYNOPSIS X.Nm X.Op Fl fipqrv X.Op Fl S Ar name X.Op Ar path .. X.Sh DESCRIPTION XThe X.Nm Xdisplays or modifies the paths used by the kernel when loading modules Xusing the X.Xr kldload 8 Xutility or the X.Xr kldload 2 Xsyscall. X.Pp XThe following options are available: X.Bl -tag -width indent X.It Fl f XDo not display a diagnostic message if a path specified for adding does not Xpoint to an existing directory, or if a path specified for removing is not Xreally a part of the current module search path. XThis may be useful in startup/shutdown scripts for adding a path to Xa filesystem which is still not mounted, or in shutdown scripts for Xunconditionally removing a path that may have been added during startup. X.It Fl i XAdd a path to the beginning of the search path, not to the end. XThis option can only be used when adding paths. X.It Fl p XDisplay the current search path. XThe X.Fl p Xoption overrides any previous X.Fl q Xoptions. X.It Fl q XSuppress printing the result search path after adding or removing paths. X.It Fl r XRemove the specified path(s) from the module search path. X.It Fl S Ar name XSpecify the sysctl name to use instead of the default X.Sy kern.module_path . X.It Fl v XBe more verbose. X.El X.Sh FILES X.Bl -tag -width indent X.It Pa /boot/kernel/ /boot/modules/ /modules/ XThe default module search path used by the kernel. X.El X.Sh DIAGNOSTICS XThe X.Nm Xutility exits with a status of 0 on success Xand with a nonzero status if an error occurs. X.Sh SEE ALSO X.Xr kldload 2 , X.Xr kldload 8 , X.Xr sysctl 8 . X.Sh HISTORY XThe X.Nm Xcommand first appeared in X.Fx 5.0 . X.Sh AUTHORS X.An Peter Pentchev Aq roam@FreeBSD.org END-of-kldpath/kldpath.8 echo x - kldpath/kldpath.c sed 's/^X//' >kldpath/kldpath.c << 'END-of-kldpath/kldpath.c' X/* X * Copyright (c) 2001 Peter Pentchev X * All rights reserved. X * X * Redistribution and use in source and binary forms, with or without X * modification, are permitted provided that the following conditions X * are met: X * 1. Redistributions of source code must retain the above copyright X * notice, this list of conditions and the following disclaimer. X * 2. Redistributions in binary form must reproduce the above copyright X * notice, this list of conditions and the following disclaimer in the X * documentation and/or other materials provided with the distribution. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE X * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF X * SUCH DAMAGE. X */ X X#ifndef lint Xstatic const char rcsid[] = X "$FreeBSD$"; X#endif /* not lint */ X X#include <sys/param.h> X#include <sys/types.h> X#include <sys/queue.h> X#include <sys/stat.h> X#include <sys/sysctl.h> X X#include <err.h> X#include <errno.h> X#include <limits.h> X#include <stdio.h> X#include <stdlib.h> X#include <string.h> X#include <unistd.h> X X#if defined(__FreeBSD_version) X#if __FreeBSD_version < 500000 X#define NEED_SLASHTERM X#endif /* < 500000 */ X#else /* defined(__FreeBSD_version) */ X/* just in case.. */ X#define NEED_SLASHTERM X#endif /* defined(__FreeBSD_version) */ X X/* the default sysctl name */ X#define PATHCTL "kern.module_path" X X/* queue structure for the module path broken down into components */ XTAILQ_HEAD(pathhead, pathentry); Xstruct pathentry { X char *path; X TAILQ_ENTRY(pathentry) next; X}; X X/* Command-line options */ X/* "-f" - no diag messages */ Xstatic int fflag; X/* "-i" - insert at the start of the path */ Xstatic int iflag; X X/* the Management Information Base entries for the search path sysctl */ Xstatic int mib[5]; Xstatic size_t miblen; X/* the sysctl name, defaults to PATHCTL */ Xstatic char *pathctl; X/* the sysctl value - the current module search path */ Xstatic char *modpath; X/* flag whether user actions require changing the sysctl value */ Xstatic int changed; X X/* Top-level path management functions */ Xstatic void addpath(struct pathhead *pathq, char *); Xstatic void rempath(struct pathhead *pathq, char *); Xstatic void showpath(struct pathhead *pathq); X X/* Low-level path management functions */ Xstatic void qclean(struct pathhead *pathq); Xstatic void qadd(struct pathhead *pathq, char *); Xstatic char *qstring(struct pathhead *pathq); X X/* sysctl-related functions */ Xstatic void getmib(void); Xstatic void getpath(struct pathhead *pathq); Xstatic void setpath(struct pathhead *pathq); X Xstatic void usage(void); X X/* Get the MIB entry for our sysctl */ Xstatic void Xgetmib(void) { X X /* have we already fetched it? */ X if (miblen != 0) X return; X X miblen = sizeof(mib) / sizeof(mib[0]); X if (sysctlnametomib(pathctl, mib, &miblen) != 0) X err(1, "sysctlnametomib(%s)", pathctl); X} X X/* Get the current module search path */ Xstatic void Xgetpath(struct pathhead *pathq) { X char *path; X size_t sz; X X if (modpath != NULL) X return; X X if (miblen == 0) X getmib(); X if (sysctl(mib, miblen, NULL, &sz, NULL, NULL) == -1) X err(1, "getting path: sysctl(%s) - size only", pathctl); X if ((path = malloc(sz + 1)) == NULL) { X errno = ENOMEM; X err(1, "allocating %u bytes for the path", sz+1); X } X if (sysctl(mib, miblen, path, &sz, NULL, NULL) == -1) X err(1, "getting path: sysctl(%s)", pathctl); X modpath = path; X X qclean(pathq); X qadd(pathq, modpath); X} X X/* Set the module search path after changing it */ Xstatic void Xsetpath(struct pathhead *pathq) { X char *newpath; X X if (miblen == 0) X getmib(); X if ((newpath = qstring(pathq)) == NULL) { X errno = ENOMEM; X err(1, "building path string"); X } X if (sysctl(mib, miblen, NULL, NULL, newpath, strlen(newpath)+1) == -1) X err(1, "setting path: sysctl(%s)", pathctl); X X if (modpath) X free(modpath); X modpath = newpath; X} X X/* Add/insert a new component to the module search path */ Xstatic void Xaddpath(struct pathhead *pathq, char *path) { X struct pathentry *pe; X char pathbuf[MAXPATHLEN+1]; X struct stat sb; X size_t len; X X /* is there such a thing? */ X if (realpath(path, pathbuf) == NULL) { X if (!fflag) X err(1, "resolving path %s: %s", path, pathbuf); X /* X * if -f specified, take the user path at face value X * (may be created later) X */ X strlcpy(pathbuf, path, sizeof(pathbuf)); X } X if (stat(pathbuf, &sb) == -1) { X if (!fflag) X err(1, "examining path %s", pathbuf); X } else if (!S_ISDIR(sb.st_mode)) { X if (!fflag) { X errno = ENOTDIR; X err(1, "%s", pathbuf); X } X } X X len = strlen(pathbuf); X#ifdef NEED_SLASHTERM X /* slash-terminate, because the kernel linker said so. */ X if ((len == 0) || (pathbuf[len-1] != '/')) { X if (len == sizeof(pathbuf) - 1) X errx(1, "path too long: %s", pathbuf); X pathbuf[len] = '/'; X } X#else /* NEED_SLASHTERM */ X /* remove a terminating slash if present */ X if ((len > 0) && (pathbuf[len-1] == '/')) X pathbuf[--len] = '\0'; X#endif /* NEED_SLASHTERM */ X X /* is it already in there? */ X TAILQ_FOREACH(pe, pathq, next) X if (!strcmp(pe->path, pathbuf)) X break; X if (pe != NULL) { X if (fflag) X return; X errx(1, "already in the module search path: %s", pathbuf); X } X X /* OK, allocate and add it. */ X if (((pe = malloc(sizeof(*pe))) == NULL) || X ((pe->path = strdup(pathbuf)) == NULL)) { X errno = ENOMEM; X err(1, "allocating path component"); X } X if (iflag) X TAILQ_INSERT_HEAD(pathq, pe, next); X else X TAILQ_INSERT_TAIL(pathq, pe, next); X changed = 1; X} X X/* Remove a path component from the module search path */ Xstatic void Xrempath(struct pathhead *pathq, char *path) { X char pathbuf[MAXPATHLEN+1]; X struct stat sb; X int valid; X struct pathentry *pe; X size_t len; X X /* X * If the path exists, use it; otherwise, take the user-specified X * path at face value - may be a removed directory. X */ X valid = 0; X if ((realpath(path, pathbuf) != NULL) && X (stat(pathbuf, &sb) == 0) && X S_ISDIR(sb.st_mode)) X valid = 1; X if (!valid) X strlcpy(pathbuf, path, sizeof(pathbuf)); X X len = strlen(pathbuf); X#ifdef NEED_SLASHTERM X /* slash-terminate, because the kernel linker said so. */ X if ((len == 0) || (pathbuf[len-1] != '/')) { X if (len == sizeof(pathbuf) - 1) X errx(1, "path too long: %s", pathbuf); X pathbuf[len] = '/'; X } X#else /* NEED_SLASHTERM */ X /* remove a terminating slash if present */ X if ((len > 0) && (pathbuf[len-1] == '/')) X pathbuf[--len] = '\0'; X#endif /* NEED_SLASHTERM */ X X /* Is it in there? */ X TAILQ_FOREACH(pe, pathq, next) X if (!strcmp(pe->path, pathbuf)) X break; X if (pe == NULL) { X if (fflag) X return; X errx(1, "not in module search path: %s", pathbuf); X } X X /* OK, remove it now.. */ X TAILQ_REMOVE(pathq, pe, next); X changed = 1; X} X X/* Display the retrieved module search path */ Xstatic void Xshowpath(struct pathhead *pathq) { X char *s; X X getpath(pathq); X if ((s = qstring(pathq)) == NULL) { X errno = ENOMEM; X err(1, "building path string"); X } X printf("Module path: %s\n", s); X free(s); X} X X/* Remove all queue entries */ Xstatic void Xqclean(struct pathhead *pathq) { X struct pathentry *pe; X X while (!TAILQ_EMPTY(pathq)) { X pe = TAILQ_FIRST(pathq); X TAILQ_REMOVE(pathq, pe, next); X free(pe->path); X free(pe); X } X} X X/* Break a string down into path components, store them into a queue */ Xstatic void Xqadd(struct pathhead *pathq, char *s) { X char *p; X struct pathentry *pe __unused; X X while ((p = strsep(&s, ";")) != NULL) { X if (((pe = malloc(sizeof(pe))) == NULL) || X ((pe->path = strdup(p)) == NULL)) { X errno = ENOMEM; X err(1, "allocating path element"); X } X TAILQ_INSERT_TAIL(pathq, pe, next); X } X} X X/* Recreate a path string from a components queue */ Xstatic char * Xqstring(struct pathhead *pathq) { X char *s, *p; X struct pathentry *pe; X X s = strdup(""); X TAILQ_FOREACH(pe, pathq, next) { X asprintf(&p, "%s%s%s", X s, pe->path, (TAILQ_NEXT(pe, next) != NULL? ";": "")); X free(s); X if (p == NULL) X return (NULL); X s = p; X } X X return (s); X} X X/* Usage message */ Xstatic void Xusage(void) { X X fprintf(stderr, "%s\n", X "usage: kldpath [-fipqrv] [-S sysctlname] [path..]"); X exit(1); X} X X/* Main function */ Xint Xmain(int argc, char *argv[]) { X /* getopt() iterator */ X int c; X /* iterator over argv[] path components */ X int i; X /* Command-line flags: */ X /* "-p" - print out the current search path */ X int pflag; X /* "-q" - quiet, do not print out the new path after changing it */ X int qflag; X /* "-v" - verbose operation (currently a no-op) */ X int vflag; X /* The higher-level function to call - add/remove */ X void (*act)(struct pathhead *, char *); X /* The module search path broken down into components */ X struct pathhead pathq; X X pflag = qflag = vflag = 0; X act = addpath; X if ((pathctl = strdup(PATHCTL)) == NULL) { X /* this is just too paranoid ;) */ X errno = ENOMEM; X err(1, "initializing sysctl name %s", PATHCTL); X } X X while ((c = getopt(argc, argv, "fipqrS:v")) != -1) X switch (c) { X case 'f': X fflag = 1; X break; X case 'i': X if (act != addpath) X usage(); X iflag = 1; X break; X case 'p': X pflag = 1; X break; X case 'q': X qflag = 1; X break; X case 'r': X if (iflag) X usage(); X act = rempath; X break; X case 'S': X free(pathctl); X if ((pathctl = strdup(optarg)) == NULL) { X errno = ENOMEM; X err(1, "sysctl name %s", optarg); X } X break; X case 'v': X vflag = 1; X break; X default: X usage(); X } X X argc -= optind; X argv += optind; X X TAILQ_INIT(&pathq); X X if (!pflag && (argc == 0)) X usage(); X X getpath(&pathq); X X /* Process the path arguments */ X for (i = 0; i < argc; i++) X act(&pathq, argv[i]); X X if (changed) X setpath(&pathq); X X if (pflag || (changed && !qflag)) X showpath(&pathq); X X return (0); X} END-of-kldpath/kldpath.c exit To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-audit" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010615150639.D94445>