add support for terry lambert's loadable kernel modules.

needs a bit of cleanup, but overall: SLICK!
This commit is contained in:
cgd 1993-06-07 19:51:59 +00:00
parent 91016c92d6
commit 57d3a6d525
21 changed files with 2431 additions and 20 deletions

View File

@ -59,6 +59,7 @@
# bpf* packet filter
# speaker pc speaker
# dcf* dcf clock
# lkm loadable kernel modules interface
#
PATH=/sbin:/bin/:/usr/bin
@ -69,7 +70,7 @@ case $i in
all)
sh MAKEDEV std wt0 fd0 fd1 wd0 wd1 sd0 sd1 tty0 tty1 pty0 st0
sh MAKEDEV ch0 cd0 lpt0 lpt1 lpt2 lpa0 lpa1 lpa2 speaker
sh MAKEDEV ch0 cd0 lpt0 lpt1 lpt2 lpa0 lpa1 lpa2 speaker lkm
;;
std)
@ -300,6 +301,13 @@ speaker)
chown root.wheel speaker
;;
lkm)
rm -f lkm
mknod lkm c 28 0
chown root.kmem lkm
chmod 640 lkm
;;
local)
umask 0
sh MAKEDEV.local

View File

@ -1,14 +1,15 @@
# @(#)Makefile 5.4.1.1 (Berkeley) 5/7/91
#
# $Header: /cvsroot/src/sbin/Makefile,v 1.8 1993/04/09 23:13:38 cgd Exp $
# $Header: /cvsroot/src/sbin/Makefile,v 1.9 1993/06/07 19:52:08 cgd Exp $
# Not ported: XNSrouted enpload
# Missing: icheck ncheck
SUBDIR= badsect chown clri disklabel dmesg dump dumpfs fastboot fsck \
halt ifconfig init mknod mount mount_isofs mount_miscfs mount_pcfs \
mountd newfs nfsd nfsiod ping quotacheck reboot restore route \
routed savecore shutdown slattach swapon tunefs umount
halt ifconfig init mknod modload modunload mount mount_isofs \
mount_miscfs mount_pcfs mountd newfs nfsd nfsiod ping \
quotacheck reboot restore route routed savecore shutdown \
slattach swapon tunefs umount
.if make(clean) || make(cleandir)
SUBDIR+= fdisk

43
sbin/modload/Makefile Normal file
View File

@ -0,0 +1,43 @@
#
# Makefile for modload
#
# 25 May 93 Terry Lambert Original
#
# Copyright (c) 1993 Terrence R. Lambert.
# 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.
# 3. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by Terrence R. Lambert.
# 4. The name Terrence R. Lambert may not be used to endorse or promote
# products derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``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 TERRENCE R. LAMBERT 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.
#
# $Id: Makefile,v 1.1 1993/06/07 19:52:10 cgd Exp $
#
PROG= modload
CFLAGS=-DKERNEL
NOMAN= noman
.include <bsd.prog.mk>

548
sbin/modload/modload.c Normal file
View File

@ -0,0 +1,548 @@
/*
* modload.c
*
* This is the interface for the kernel module loader for statically
* loadable kernel modules. The interface is nearly identical to the
* SunOS 4.1.3 not because I lack imagination but because I liked Sun's
* approach in this particular revision of their BSD-derived OS.
*
* modload [-d] [-v] [-A <kernel>] [-e <entry] [-p <postinstall>]
* [-o <output file>] <input file>
*
* -d - debug
* -v - verbose
* -A <kernel> - specify symbol kernel (default="/386bsd")
* -e <entry> - entry point (default="xxxinit")
* -p <postinstall> - postinstall script or executable
* -o <output file> - output file (default=<input file>-".o")
*
* Copyright (c) 1993 Terrence R. Lambert.
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Terrence R. Lambert.
* 4. The name Terrence R. Lambert may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``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 TERRENCE R. LAMBERT 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.
*
* $Id: modload.c,v 1.1 1993/06/07 19:52:11 cgd Exp $
*/
#define printf I_HATE_ANSI
#include <stdio.h>
#undef printf
#include <stdlib.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/mount.h>
#include <sys/exec.h>
#include <sys/lkm.h>
#include <a.out.h>
#include <sys/file.h>
#include <sys/errno.h>
#include <paths.h>
#ifdef sun
/* these are defined in stdlib.h for everything but sun*/
extern char *optarg;
extern int optind;
#endif /* sun*/
#ifndef DFLT_KERNEL
#define DFLT_KERNEL _PATH_UNIX
#endif /* !DFLT_KERNEL*/
#ifndef DFLT_ENTRY
#define DFLT_ENTRY "xxxinit"
#endif /* !DFLT_ENTRY*/
/*
* Expected linker options:
*
* -A executable to link against
* -e entry point
* -o output file
* -T address to link to in hex (assumes it's a page boundry)
* <target> object file
*
*/
/*
#define LINKCMD "ld -f %s -e _%s -o %s -T %x %s"
*/
#define LINKCMD "ld -A %s -e _%s -o %s -T %x %s"
#define LKM_DEV "/dev/lkm"
#ifdef MIN
#undef MIN
#endif /* MIN*/
#define MIN(x,y) ((x)>(y) ? (y) : (x))
int debug = 0;
int verbose = 0;
linkcmd( kernel, entry, outfile, address, object)
char *kernel;
char *entry;
char *outfile;
unsigned int address;
char *object;
{
char cmdbuf[ 1024];
int err = 0;
sprintf( cmdbuf, LINKCMD, kernel, entry, outfile, address, object);
if( debug)
printf( "%s\n", cmdbuf);
switch( system( cmdbuf)) {
case 0: /* SUCCESS!*/
break;
case 1: /* uninformitive error*/
/*
* Someone needs to fix the return values from the 386BSD
* ld program -- it's totally uninformative.
*
* No such file (4 on SunOS)
* Can't write output (2 on SunOS)
* Undefined symbol (1 on SunOS)
* etc.
*/
case 127: /* can't load shell*/
case 32512:
default:
err = 1;
break;
}
return( err);
}
usage()
{
fprintf( stderr, "usage:\n");
fprintf( stderr,
"modload [-d] [-v] [-A <kernel>] [-e <entry]\n");
fprintf( stderr,
"[-p <postinstall>] [-o <output file>] <input file>\n");
exit( 1);
}
int filopen = 0;
#define DEV_OPEN 0x01
#define MOD_OPEN 0x02
#define PART_RESRV 0x04
main( ac, av)
int ac;
char *av[];
{
int ch;
char *kname = DFLT_KERNEL;
char *entry = DFLT_ENTRY;
char *post = NULL;
char *out = NULL;
char *modobj;
int devfd;
int modfd;
char modout[ 80];
char *p;
struct exec info_buf;
int err = 0;
unsigned long modsize;
unsigned long modentry;
struct lmc_resrv resrv;
struct lmc_loadbuf ldbuf;
int i;
int sz;
char buf[ MODIOBUF];
int bytesleft;
while( ( ch = getopt( ac, av, "dvA:e:p:o:")) != EOF) {
switch(ch) {
case 'd': debug = 1; break; /* debug*/
case 'v': verbose = 1; break; /* verbose*/
case 'A': kname = optarg; break; /* kernel*/
case 'e': entry = optarg; break; /* entry point*/
case 'p': post = optarg; break; /* postinstall*/
case 'o': out = optarg; break; /* output file*/
case '?': usage();
default: printf( "default!\n");
}
}
ac -= optind;
av += optind;
if( ac != 1)
usage();
modobj = av[ 0];
/*
* Open the virtual device device driver for exclusive use (needed
* to write the new module to it as our means of getting it in the
* kernel).
*/
if( ( devfd = open( LKM_DEV, O_RDONLY, 0)) == -1) {
perror( LKM_DEV);
err = 3;
goto done;
}
filopen |= DEV_OPEN;
strcpy( modout, modobj);
for( p = modout; *p && *p != '.'; p++)
continue;
if( !*p || strcmp( p, ".o")) {
fprintf( stderr, "Module object must end in .o\n");
err = 2;
goto done;
}
if( out == NULL) {
out = modout;
*p == 0;
}
/*
* Prelink to get file size
*/
if( linkcmd( kname, entry, out, 0, modobj)) {
fprintf( stderr,
"Can't prelink %s creating %s!\n", modobj, out);
err = 1;
goto done;
}
/*
* Pre-open the 0-linked module to get the size information
*/
if( ( modfd = open( out, O_RDONLY, 0)) == -1) {
perror( out);
err = 4;
goto done;
}
filopen |= MOD_OPEN;
/*
* Get the load module post load size... do this by reading the
* header and doing page counts.
*/
if( read( modfd, &info_buf, sizeof(struct exec)) == -1) {
perror( "read");
err = 3;
goto done;
}
/*
* Close the dummy module -- we have our sizing information.
*/
close( modfd);
filopen &= ~MOD_OPEN;
/*
* Magic number...
*/
if( N_BADMAG( info_buf)) {
fprintf( stderr, "Not an a.out format file\n");
err = 4;
goto done;
}
/*
* Calculate the size of the module
*/
modsize = info_buf.a_text + info_buf.a_data; /* amount to load*/
/*
* Reserve the required amount of kernel memory -- this may fail
* to be successful.
*/
resrv.size = modsize; /* size in bytes*/
resrv.name = modout; /* objname w/o ".o"*/
resrv.slot = -1; /* returned*/
resrv.addr = 0; /* returned*/
if( ioctl( devfd, LMRESERV, &resrv) == -1) {
perror( "LMRESERV");
fprintf( stderr, "Can't reserve memory\n");
err = 9;
goto done;
}
filopen |= PART_RESRV;
/*
* Relink at kernel load address
*/
if( linkcmd( kname, entry, out, resrv.addr, modobj)) {
fprintf( stderr,
"Can't link %s creating %s bound to 0x%08x!\n",
modobj, out, resrv.addr);
err = 1;
goto done;
}
/*
* Open the relinked module to load it...
*/
if( ( modfd = open( out, O_RDONLY, 0)) == -1) {
perror( out);
err = 4;
goto done;
}
filopen |= MOD_OPEN;
/*
* Reread the header to get the actual entry point *after* the
* relink.
*/
if( read( modfd, &info_buf, sizeof(struct exec)) == -1) {
perror( "read");
err = 3;
goto done;
}
/*
* Get the entry point (for initialization)
*/
modentry = info_buf.a_entry; /* place to call*/
/*
* Seek to the text offset to start loading...
*/
if( lseek( modfd, N_TXTOFF(info_buf), 0) == -1) {
perror( "lseek");
err = 12;
goto done;
}
/*
* Transfer the relinked module to kernel memory in chunks of
* MODIOBUF size at a time.
*/
bytesleft = modsize;
for( i = 0; i < (modsize + MODIOBUF-1)/MODIOBUF; i++) {
sz = MIN(bytesleft,MODIOBUF);
read( modfd, buf, sz);
ldbuf.cnt = sz;
ldbuf.data = buf;
if( ioctl( devfd, LMLOADBUF, &ldbuf) == -1) {
perror( "LMLOADBUF");
/* error*/
fprintf( stderr, "Error transferring buffer\n");
err = 11;
goto done;
}
bytesleft -= MODIOBUF;
if( bytesleft < 1)
break;
}
/*
* Save ourselves before disaster (potentitally) strikes...
*/
sync();
/*
* Trigger the module as loaded by calling the entry procedure;
* this will do all necessary table fixup to ensure that state
* is maintained on success, or blow everything back to ground
* zero on failure.
*/
if( ioctl( devfd, LMREADY, &modentry) == -1) {
perror( "LMREADY");
err = 14;
goto done;
}
/*
* Success!
*/
filopen &= ~PART_RESRV; /* loaded*/
printf( "Module loaded as ID %d\n", resrv.slot);
done:
if( filopen & PART_RESRV) {
/*
* Free up kernel memory
*/
if( ioctl( devfd, LMUNRESRV, 0) == -1) {
fprintf( stderr, "Can't release slot 0x%08x memory\n",
resrv.slot);
}
}
if( filopen & DEV_OPEN)
close( devfd);
if( filopen & MOD_OPEN)
close( modfd);
exit( err);
}
#ifdef OMIT
MODLOAD(8) MAINTENANCE COMMANDS MODLOAD(8)
NAME
modload - load a kernel module
SYNOPSIS
modload filename [ -d ] [ -v ] [ -sym ] [ -A vmunix_file ] [
-conf config_file ] [ -entry entry_point ] [ -exec exec_file
] [ -o output_file ]
DESCRIPTION
modload loads a loadable module into a running system. The
input file filename is an object file (.o file).
OPTIONS
-d Debug. Used to debug modload itself.
-v Verbose. Print comments on the loading process.
-sym Preserve symbols for use by kadb(8S).
-A vmunix_file
Specify the file that is passd to the linker to resolve
module references to kernel symbols. The default is
/vmunix. The symbol file must be for the currently
running kernel or the module is likely to crash the
system.
-conf config_file
Use this configuration file to configure the loadable
driver being loaded. The commands in this file are the
same as those that the config(8) program recognizes.
There are two additional commands recognized, blockma-
jor and charmajor. See the Writing Device Drivers for
information on these commands.
-entry entry_point
Specify the module entry point. This is passed by
modload to ld(1) when the module is linked. The
default module entry point name is `xxxinit`.
-exec exec_file
Specify the name of a shell script or executable image
file that will be executed if the module is success-
fully loaded. It is always passed the module id (in
decimal) and module type (in hexadecimal) as the first
two arguments. Module types are listed in
/usr/include/sun/vddrv.h. For loadable drivers, the
third and fourth arguments are the block major and
character major numbers respectively. For a loadable
system call, the third argument is the system call
number.
-o output_file
Sun Release 4.1 Last change: 31 May 1991 1
MODLOAD(8) MAINTENANCE COMMANDS MODLOAD(8)
Specify the name of the output file that is produced by
the linker. If this option is omitted, then the output
file name is filename without the `.o`.
BUGS
On Sun-3 machines, the config(8) program generates assembly
language wrappers to provide the proper linkage to device
interrupt handlers. modload does not generate these
wrappers; on interrupt, control passes directly to the load-
able drivers interrupt handler. Consequently, the driver
must provide its own wrapper. See the ioconf.c file gen-
erated by config(8) for examples of wrappers.
SEE ALSO
ld(1), config(8), kadb(8S), modunload(8), modstat(8)
Sun Release 4.1 Last change: 31 May 1991 2
#endif /* OMIT*/

43
sbin/modunload/Makefile Normal file
View File

@ -0,0 +1,43 @@
#
# Makefile for modunload
#
# 25 May 93 Terry Lambert Original
#
# Copyright (c) 1993 Terrence R. Lambert.
# 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.
# 3. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by Terrence R. Lambert.
# 4. The name Terrence R. Lambert may not be used to endorse or promote
# products derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``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 TERRENCE R. LAMBERT 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.
#
# $Id: Makefile,v 1.1 1993/06/07 19:52:14 cgd Exp $
#
PROG= modunload
CFLAGS=-DKERNEL
NOMAN= noman
.include <bsd.prog.mk>

166
sbin/modunload/modunload.c Normal file
View File

@ -0,0 +1,166 @@
/*
* modunload.c
*
* This is the loadable kernel module unload program. The interface
* is nearly identical to the SunOS 4.1.3 not because I lack
* imagination but because I liked Sun's approach in this particular
* revision of their BSD-derived OS.
*
* modunload [-i <module id>] [-n <module name>]
*
* Default behaviour is to provide a usage message.
*
* -i <module id> - unload module by id
* -n <module name> - unload module by name
*
* Copyright (c) 1993 Terrence R. Lambert.
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Terrence R. Lambert.
* 4. The name Terrence R. Lambert may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``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 TERRENCE R. LAMBERT 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.
*
* $Id: modunload.c,v 1.1 1993/06/07 19:52:16 cgd Exp $
*/
#define printf I_HATE_ANSI
#include <stdio.h>
#undef printf
#include <stdlib.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/mount.h>
#include <sys/exec.h>
#include <sys/lkm.h>
#include <a.out.h>
#include <sys/file.h>
#include <sys/errno.h>
extern int errno; /* should be in errno.h*/
#ifdef sun
/* these are defined in stdlib.h for everything but sun*/
extern char *optarg;
extern int optind;
#endif /* sun*/
#define LKM_DEV "/dev/lkm"
extern int dostat();
usage()
{
fprintf( stderr, "usage:\n");
fprintf( stderr,
"modunload [-i <module id>] [-n <module name>]\n");
exit( 1);
}
main( ac, av)
int ac;
char *av[];
{
int devfd;
int ch;
int err = 0;
int modnum = -1;
char *modname = NULL;
struct lmc_unload ulbuf;
while( ( ch = getopt( ac, av, "i:n:")) != EOF) {
switch(ch) {
case 'i': modnum = atoi( optarg); break; /* number*/
case 'n': modname = optarg; break; /* name*/
case '?': usage();
default: printf( "default!\n");
}
}
ac -= optind;
av += optind;
if( ac != 0)
usage();
/*
* Open the virtual device device driver for exclusive use (needed
* to ioctl() to retrive the loaded module(s) status).
*/
if( ( devfd = open( LKM_DEV, O_RDONLY, 0)) == -1) {
perror( LKM_DEV);
exit( 2);
}
/*
* Not specified?
*/
if( modnum == -1 && modname == NULL)
usage();
/*
* Unload the requested module.
*/
/*
if( modname != NULL)
strcpy( ulbuf.name, modname);
*/
ulbuf.name = modname;
ulbuf.id = modnum;
if( ioctl( devfd, LMUNLOAD, &ulbuf) == -1) {
switch( errno) {
case EINVAL: /* out of range*/
fprintf( stderr, "modunload: id out of range\n");
err = 3;
break;
case ENOENT: /* no such entry*/
fprintf( stderr, "modunload: no such module\n");
err = 4;
break;
default: /* other error (EFAULT, etc)*/
perror( "LMUNLOAD");
err = 5;
break;
}
}
done:
close( devfd);
exit( err);
}
/*
* EOF -- This file has not been truncated.
*/

View File

@ -1,7 +1,7 @@
#
# BOAT_ANCHOR -- kernel for the 386-20 the gang uses for testing
#
# $Id: BOAT_ANCHOR,v 1.17 1993/06/03 01:30:23 cgd Exp $
# $Id: BOAT_ANCHOR,v 1.18 1993/06/07 19:52:22 cgd Exp $
#
machine "i386"
cpu "I386_CPU"
@ -18,6 +18,7 @@ options KTRACE
options DDB
options FIFO
options "COMPAT_NOMID"
options LKM
options ACCOUNTING

View File

@ -1 +1 @@
revision 1.10 intentionally removed
revision 1.11 intentionally removed

View File

@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)machdep.c 7.4 (Berkeley) 6/3/91
* $Id: machdep.c,v 1.27 1993/06/06 04:16:14 cgd Exp $
* $Id: machdep.c,v 1.28 1993/06/07 19:52:28 cgd Exp $
*/
#include <stddef.h>
@ -892,8 +892,11 @@ init386(first)
cninit (KERNBASE+0xa0000);
#ifndef LKM /* don't do this if we're using LKM's */
/* make gdt memory segments */
gdt_segs[GCODE_SEL].ssd_limit = btoc((int) &etext + NBPG);
#endif
for (x=0; x < NGDT; x++) ssdtosd(gdt_segs+x, gdt+x);
/* make ldt memory segments */
ldt_segs[LUCODE_SEL].ssd_limit = btoc(UPT_MIN_ADDRESS);

View File

@ -1,4 +1,4 @@
# $Id: files,v 1.11 1993/05/31 01:40:53 cgd Exp $
# $Id: files,v 1.12 1993/06/07 19:52:32 cgd Exp $
#
ddb/db_access.c optional ddb
ddb/db_aout.c optional ddb
@ -35,6 +35,7 @@ kern/kern_exit.c standard
kern/kern_fork.c standard
kern/kern_kinfo.c standard
kern/kern_ktrace.c optional ktrace
kern/kern_lkm.c optional lkm
kern/kern_malloc.c standard
kern/kern_proc.c standard
kern/kern_prot.c standard

View File

@ -1,4 +1,4 @@
# $Id: files.oldconf,v 1.11 1993/05/31 01:40:53 cgd Exp $
# $Id: files.oldconf,v 1.12 1993/06/07 19:52:32 cgd Exp $
#
ddb/db_access.c optional ddb
ddb/db_aout.c optional ddb
@ -35,6 +35,7 @@ kern/kern_exit.c standard
kern/kern_fork.c standard
kern/kern_kinfo.c standard
kern/kern_ktrace.c optional ktrace
kern/kern_lkm.c optional lkm
kern/kern_malloc.c standard
kern/kern_proc.c standard
kern/kern_prot.c standard

View File

@ -168,6 +168,19 @@ int shmsys();
int setgid();
int setegid();
int seteuid();
#ifdef LKM
int lkmnosys();
int lkmnosys();
int lkmnosys();
int lkmnosys();
int lkmnosys();
int lkmnosys();
int lkmnosys();
int lkmnosys();
int lkmnosys();
int lkmnosys();
#else /* !LKM*/
#endif /* !LKM*/
#ifdef COMPAT_43
#define compat(n, name) n, __CONCAT(o,name)
@ -210,6 +223,9 @@ int ogetsockname();
#ifdef SYSVSHM
#else
#endif
#ifdef LKM
#else /* !LKM*/
#endif /* !LKM*/
#else /* COMPAT_43 */
#define compat(n, name) 0, nosys
@ -436,6 +452,38 @@ struct sysent sysent[] = {
0, nosys, /* 188 = nosys */
0, nosys, /* 189 = nosys */
0, nosys, /* 190 = nosys */
0, nosys, /* 191 = nosys */
0, nosys, /* 192 = nosys */
0, nosys, /* 193 = nosys */
0, nosys, /* 194 = nosys */
0, nosys, /* 195 = nosys */
0, nosys, /* 196 = nosys */
0, nosys, /* 197 = nosys */
0, nosys, /* 198 = nosys */
0, nosys, /* 199 = nosys */
#ifdef LKM
0, lkmnosys, /* 200 = lkmnosys */
0, lkmnosys, /* 201 = lkmnosys */
0, lkmnosys, /* 202 = lkmnosys */
0, lkmnosys, /* 203 = lkmnosys */
0, lkmnosys, /* 204 = lkmnosys */
0, lkmnosys, /* 205 = lkmnosys */
0, lkmnosys, /* 206 = lkmnosys */
0, lkmnosys, /* 207 = lkmnosys */
0, lkmnosys, /* 208 = lkmnosys */
0, lkmnosys, /* 209 = lkmnosys */
#else /* !LKM*/
0, nosys, /* 200 = nosys */
0, nosys, /* 201 = nosys */
0, nosys, /* 202 = nosys */
0, nosys, /* 203 = nosys */
0, nosys, /* 204 = nosys */
0, nosys, /* 205 = nosys */
0, nosys, /* 206 = nosys */
0, nosys, /* 207 = nosys */
0, nosys, /* 208 = nosys */
0, nosys, /* 209 = nosys */
#endif /* !LKM*/
};
int nsysent = sizeof(sysent) / sizeof(sysent[0]);

865
sys/kern/kern_lkm.c Normal file
View File

@ -0,0 +1,865 @@
/*
* kern_lkm.c
*
* functions and pseudo-device for loadable kernel modules
*
* 05 Jun 93 Terry Lambert Release cleanup
* 10 Feb 93 Terry Lambert Original
*
* Copyright (c) 1992 Terrence R. Lambert.
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Terrence R. Lambert.
* 4. The name Terrence R. Lambert may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``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 TERRENCE R. LAMBERT 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.
*
* $Id: kern_lkm.c,v 1.1 1993/06/07 19:52:39 cgd Exp $
*/
#include "param.h"
#include "systm.h"
#include "ioctl.h"
#include "tty.h"
#include "conf.h"
#include "file.h"
#include "proc.h"
#include "uio.h"
#include "kernel.h"
#include "vnode.h"
#include "malloc.h"
#include "vm/vm.h"
#include "vm/vm_param.h"
#include "vm/vm_kern.h"
#include "mount.h"
#include "exec.h"
#include "lkm.h"
#define PAGESIZE 1024 /* kmem_alloc() allocation quantum*/
#define LKM_ALLOC 0x01
#define LKM_WANT 0x02
#define LKMS_IDLE 0x00
#define LKMS_RESERVED 0x01
#define LKMS_LOADING 0x02
#define LKMS_LOADED 0x04
#define LKMS_UNLOADING 0x08
static int lkm_v = 0;
static int lkm_state = LKMS_IDLE;
#ifndef MAXLKMS
#define MAXLKMS 20
#endif
static struct lkm_table lkmods[ MAXLKMS]; /* table of loaded modules*/
static struct lkm_table *curp; /* global for in-progress ops*/
/*ARGSUSED*/
lkmopen( dev, flag, devtype, p)
dev_t dev;
int flag;
int devtype;
struct proc *p;
{
int error;
if( minor( dev) != 0)
return( ENXIO); /* bad minor #*/
/*
* Use of the loadable kernel module device must be exclusive; we
* may try to remove this restriction later, but it's really no
* hardship.
*/
while( lkm_v & LKM_ALLOC) {
if( flag & FNONBLOCK) /* don't hang*/
return( EBUSY);
lkm_v |= LKM_WANT;
/*
* Sleep pending unlock; we use tsleep() to allow
* an alarm out of the open.
*/
if( error = tsleep( (caddr_t)&lkm_v, TTIPRI|PCATCH, "LKM", 0))
return( error); /* leave LKM_WANT set -- no problem*/
}
lkm_v |= LKM_ALLOC;
return( 0); /* pseudo-device open*/
}
/*
* l k m u n r e s e r v e
*
* Unreserve the memory associated with the current loaded module; done on
* a coerced close of the lkm device (close on premature exit of modload)
* or explicitly by modload as a result of a link failure.
*/
static int
lkmunreserve()
{
if( lkm_state == LKMS_IDLE)
return;
/*
* Actually unreserve the memory
*/
kmem_free( buffer_map, curp->area, curp->size);/**/
lkm_state = LKMS_IDLE;
}
lkmclose( dev, flag, mode, p)
dev_t dev;
int flag;
int mode;
struct proc *p;
{
if( !( lkm_v & LKM_ALLOC)) {
#ifdef DEBUG
printf( "LKM: close before open!\n");
#endif /* DEBUG*/
return( EBADF);
}
/* do this before waking the herd...*/
if( !curp->used) {
/*
* If we close before setting used, we have aborted
* by way of error or by way of close-on-exit from
* a premature exit of "modload".
*/
lkmunreserve(); /* coerce state to LKM_IDLE*/
}
lkm_v &= ~LKM_ALLOC;
wakeup( (caddr_t)&lkm_v); /* thundering herd "problem" here*/
return( 0); /* pseudo-device closed*/
}
/*ARGSUSED*/
lkmioctl( dev, cmd, data, flag)
dev_t dev;
int cmd;
caddr_t data;
int flag;
{
int err = 0;
int i;
struct lmc_resrv *resrvp;
struct lmc_loadbuf *loadbufp;
struct lmc_unload *unloadp;
struct lmc_stat *statp;
int (*funcp)();
char istr[ MAXLKMNAME];
switch( cmd) {
case LMRESERV: /* reserve pages for a module*/
resrvp = (struct lmc_resrv *)data;
/*
* Find a free slot.
*/
for( i = 0; i < MAXLKMS; i++) {
if( !lkmods[ i].used)
break;
}
if( i == MAXLKMS) {
err = ENOMEM; /* no slots available*/
break;
}
curp = &lkmods[ i];
curp->id = i; /* self reference slot offset*/
resrvp->slot = i; /* return slot*/
/*
* Get memory for module
*/
curp->size = resrvp->size;
curp->area = (char *)kmem_alloc( buffer_map, curp->size);/**/
curp->offset = 0; /* load offset*/
resrvp->addr = (unsigned long)curp->area; /* ret kernel addr*/
#ifdef DEBUG
printf( "LKM: LMRESERV (actual = 0x%08x)\n", curp->area);
printf( "LKM: LMRESERV (adjusted = 0x%08x)\n",
trunc_page(curp->area));
#endif /* DEBUG*/
lkm_state = LKMS_RESERVED;
break;
case LMLOADBUF: /* Copy in; stateful, follows LMRESERV*/
loadbufp = (struct lmc_loadbuf *)data;
if( lkm_state != LKMS_RESERVED && lkm_state != LKMS_LOADING) {
err = ENOMEM;
break;
}
/* account for odd size (non-page multiple) copyin*/
i = MIN( curp->size - curp->offset, MODIOBUF);
/* copy in buffer full of data*/
if( err = copyin( (caddr_t)loadbufp->data, (caddr_t)curp->area + curp->offset, i))
break;
if( ( curp->offset + i) < curp->size) {
lkm_state = LKMS_LOADING;
#ifdef DEBUG
printf( "LKM: LMLOADBUF (loading @ %d of %d, i = %d)\n",
curp->offset, curp->size, i);
#endif /* DEBUG*/
} else {
lkm_state = LKMS_LOADED;
#ifdef DEBUG
printf( "LKM: LMLOADBUF (loaded)\n");
#endif /* DEBUG*/
}
curp->offset += MODIOBUF;
break;
case LMUNRESRV: /* discard reserved pages for a module*/
lkmunreserve(); /* coerce state to LKM_IDLE*/
#ifdef DEBUG
printf( "LKM: LMUNRESERV\n");
#endif /* DEBUG*/
break;
case LMREADY: /* module loaded: call entry*/
if( lkm_state != LKMS_LOADED) {
#ifdef DEBUG
printf( "lkm_state is %02x\n", lkm_state);
#endif /* DEBUG*/
err = ENXIO;
break;
}
curp->entry = (int (*)()) (*((int *) ( data)));
/* call entry(load)... (assigns "private" portion)*/
if( err = (*(curp->entry))( curp, LKM_E_LOAD, LKM_VERSION)) {
/*
* Module may refuse loading or may have a
* version mismatch...
*/
lkm_state = LKMS_UNLOADING; /* for lkmunreserve*/
lkmunreserve(); /* free memory*/
curp->used = 0; /* free slot*/
break;
}
curp->used = 1;
#ifdef DEBUG
printf( "LKM: LMREADY\n");
#endif /* DEBUG*/
lkm_state = LKMS_IDLE;
break;
case LMUNLOAD: /* unload a module*/
unloadp = (struct lmc_unload *)data;
if( ( i = unloadp->id) == -1) { /* unload by name*/
/*
* Copy name in and lookup id from all loaded
* modules. May fail.
*/
if( err = copyinstr( unloadp->name, istr, MAXLKMNAME-1, NULL))
break;
/*
* look up id...
*/
for( i = 0; i < MAXLKMS; i++) {
if( !lkmods[ i].used)
continue;
if( !strcmp( istr,
lkmods[ i].private.lkm_any->lkm_name))
break;
}
}
/*
* Range check the value; on failure, return EINVAL
*/
if( i < 0 || i >= MAXLKMS) {
err = EINVAL;
break;
}
curp = &lkmods[ i];
/* call entry(unload)*/
if( (*(curp->entry))( curp, LKM_E_UNLOAD, LKM_VERSION)) {
err = EBUSY;
break;
}
lkm_state = LKMS_UNLOADING; /* non-idle for lkmunreserve*/
lkmunreserve(); /* free memory*/
curp->used = 0; /* free slot*/
break;
case LMSTAT: /* stat a module by id/name*/
statp = (struct lmc_stat *)data;
if( ( i = statp->id) == -1) { /* stat by name*/
/*
* Copy name in and lookup id from all loaded
* modules. May fail.
*/
if( err = copyinstr( statp->name, istr, MAXLKMNAME-1, NULL))
break;
/*
* look up id...
*/
for( i = 0; i < MAXLKMS; i++) {
if( !lkmods[ i].used)
continue;
if( !strcmp( istr,
lkmods[ i].private.lkm_any->lkm_name))
break;
}
if( i == MAXLKMS) { /* Not found*/
err = ENOENT;
break;
}
}
/*
* Range check the value; on failure, return EINVAL
*/
if( i < 0 || i >= MAXLKMS) {
err = EINVAL;
break;
}
curp = &lkmods[ i];
if( !curp->used) { /* Not found*/
err = ENOENT;
break;
}
/*
* Copy out stat information for this module...
*/
statp->id = curp->id;
statp->offset = curp->private.lkm_any->lkm_offset;
statp->type = curp->private.lkm_any->lkm_type;
statp->area = curp->area;
statp->size = curp->size / PAGESIZE;
statp->private = (unsigned long)curp->private.lkm_any;
statp->ver = curp->private.lkm_any->lkm_ver;
err = copyoutstr( curp->private.lkm_any->lkm_name,
statp->name,
MAXLKMNAME - 2,
NULL);
break;
default: /* bad ioctl()...*/
err = ENOTTY;
break;
}
return (err);
}
/*********************************************************************/
/*
* l k m n o s y s
*
* Acts like "nosys" but can be identified in sysent for dynamic call
* number assignment for a limited number of calls.
*
* Place holder for system call slots reserved for loadable modules.
*/
lkmnosys()
{
return( nosys());
}
/*
* l k m e n o d e v
*
* Acts like "enodev", but can be identified in cdevsw and bdevsw for
* dynamic driver major number assignment for a limited number of
* drivers.
*
* Place holder for device switch slots reserved for loadable modules.
*/
int
lkmenodev()
{
return( enodev());
}
/*********************************************************************/
int
lkmexists( lkmtp)
struct lkm_table *lkmtp;
{
int i;
/*
* see if name exists...
*/
for( i = 0; i < MAXLKMS; i++) {
/*
* An unused module and the one we are testing are not
* considered.
*/
if( !lkmods[ i].used || &lkmods[ i] == lkmtp)
continue;
if( !strcmp( lkmtp->private.lkm_any->lkm_name,
lkmods[ i].private.lkm_any->lkm_name))
return( 1); /* already loaded...*/
}
return( 0); /* module not loaded...*/
}
/*
* For the loadable system call described by the structure pointed to
* by lkmtp, load/unload/stat it depending on the cmd requested.
*/
static int
_lkm_syscall( lkmtp, cmd)
struct lkm_table *lkmtp;
int cmd;
{
struct lkm_syscall *args = lkmtp->private.lkm_syscall;
int i;
int err = 0;
extern int nsysent; /* init_sysent.c*/
switch( cmd) {
case LKM_E_LOAD:
/* don't load twice!*/
if( lkmexists( lkmtp))
return( EEXIST);
if( ( i = args->lkm_offset) == -1) { /* auto*/
/*
* Search the table looking for a slot...
*/
for( i = 0; i < nsysent; i++)
if( sysent[ i].sy_call == lkmnosys)
break; /* found it!*/
/* out of allocable slots?*/
if( i == nsysent) {
err = ENFILE;
break;
}
} else { /* assign*/
if( i < 0 || i >= nsysent) {
err = EINVAL;
break;
}
}
/* save old*/
bcopy( &sysent[ i], &(args->lkm_oldent), sizeof( struct sysent));
/* replace with new*/
bcopy( args->lkm_sysent, &sysent[ i], sizeof( struct sysent));
/* done!*/
args->lkm_offset = i; /* slot in sysent[]*/
break;
case LKM_E_UNLOAD:
/* current slot...*/
i = args->lkm_offset;
/* replace current slot contents with old contents*/
bcopy( &(args->lkm_oldent), &sysent[ i], sizeof( struct sysent));
break;
case LKM_E_STAT: /* no special handling...*/
break;
}
return( err);
}
/*
* For the loadable virtual file system described by the structure pointed
* to by lkmtp, load/unload/stat it depending on the cmd requested.
*/
static int
_lkm_vfs( lkmtp, cmd)
struct lkm_table *lkmtp;
int cmd;
{
struct lkm_vfs *args = lkmtp->private.lkm_vfs;
int i;
int err = 0;
switch( cmd) {
case LKM_E_LOAD:
/* don't load twice!*/
if( lkmexists( lkmtp))
return( EEXIST);
/*
* Currently, the VFS and mount code in 386BSD is malformed;
* this means that the per volume file system identifier is
* the index into the table rather than the name; this means
* that only the file systems already known to 386BSD are
* allowable, since all others don't have fixed offsets.
* Interestingly, Dell UNIX has this same bug with their VFS
* implementation, but generic AT&T SVR4 does not.
*
* I will correct the VFS code when I get a chance.
*/
i = args->lkm_offset;
if( i < 0 || i > MOUNT_MAXTYPE) {
err = EINVAL;
break;
}
if( vfssw[ i] != (struct vfsops *)0) {
err = EEXIST;
break;
}
/*
* Set up file system
*/
vfssw[ i] = args->lkm_vfsops;
/*
* Call init function for this VFS...
*/
( *(vfssw[ i]->vfs_init))( args->lkm_flags);
/* done!*/
args->lkm_offset = i; /* slot in sysent[]*/
break;
case LKM_E_UNLOAD:
/* current slot...*/
i = args->lkm_offset;
/* replace current slot contents with old contents*/
vfssw[ i] = (struct vfsops *)0;
break;
case LKM_E_STAT: /* no special handling...*/
break;
}
return( err);
}
/*
* For the loadable device driver described by the structure pointed to
* by lkmtp, load/unload/stat it depending on the cmd requested.
*/
static int
_lkm_dev( lkmtp, cmd)
struct lkm_table *lkmtp;
int cmd;
{
struct lkm_dev *args = lkmtp->private.lkm_dev;
int i;
int err = 0;
extern int nblkdev; /* i386/i386/conf.c*/
extern int nchrdev; /* i386/i386/conf.c*/
switch( cmd) {
case LKM_E_LOAD:
/* don't load twice!*/
if( lkmexists( lkmtp))
return( EEXIST);
switch( args->lkm_devtype) {
case LM_DT_BLOCK:
if( ( i = args->lkm_offset) == -1) { /* auto*/
/*
* Search the table looking for a slot...
*/
for( i = 0; i < nblkdev; i++)
if( bdevsw[ i].d_open == lkmenodev)
break; /* found it!*/
/* out of allocable slots?*/
if( i == nblkdev) {
err = ENFILE;
break;
}
} else { /* assign*/
if( i < 0 || i >= nblkdev) {
err = EINVAL;
break;
}
}
/* save old*/
bcopy( &bdevsw[ i], &(args->lkm_olddev.bdev), sizeof( struct bdevsw));
/* replace with new*/
bcopy( args->lkm_dev.bdev, &bdevsw[ i], sizeof( struct bdevsw));
/* done!*/
args->lkm_offset = i; /* slot in bdevsw[]*/
break;
case LM_DT_CHAR:
if( ( i = args->lkm_offset) == -1) { /* auto*/
/*
* Search the table looking for a slot...
*/
for( i = 0; i < nchrdev; i++)
if( cdevsw[ i].d_open == lkmenodev)
break; /* found it!*/
/* out of allocable slots?*/
if( i == nchrdev) {
err = ENFILE;
break;
}
} else { /* assign*/
if( i < 0 || i >= nchrdev) {
err = EINVAL;
break;
}
}
/* save old*/
bcopy( &cdevsw[ i], &(args->lkm_olddev.cdev), sizeof( struct cdevsw));
/* replace with new*/
bcopy( args->lkm_dev.cdev, &cdevsw[ i], sizeof( struct cdevsw));
/* done!*/
args->lkm_offset = i; /* slot in cdevsw[]*/
break;
default:
err = ENODEV;
break;
}
break;
case LKM_E_UNLOAD:
/* current slot...*/
i = args->lkm_offset;
switch( args->lkm_devtype) {
case LM_DT_BLOCK:
/* replace current slot contents with old contents*/
bcopy( &(args->lkm_olddev.bdev), &bdevsw[ i], sizeof( struct bdevsw));
break;
case LM_DT_CHAR:
/* replace current slot contents with old contents*/
bcopy( &(args->lkm_olddev.cdev), &cdevsw[ i], sizeof( struct cdevsw));
break;
default:
err = ENODEV;
break;
}
break;
case LKM_E_STAT: /* no special handling...*/
break;
}
return( err);
}
#ifdef STREAMS
/*
* For the loadable streams module described by the structure pointed to
* by lkmtp, load/unload/stat it depending on the cmd requested.
*/
static int
_lkm_strmod( lkmtp, cmd)
struct lkm_table *lkmtp;
int cmd;
{
struct lkm_strmod *args = lkmtp->private.lkm_strmod;
int i;
int err = 0;
switch( cmd) {
case LKM_E_LOAD:
/* don't load twice!*/
if( lkmexists( lkmtp))
return( EEXIST);
break;
case LKM_E_UNLOAD:
break;
case LKM_E_STAT: /* no special handling...*/
break;
}
return( err);
}
#endif /* STREAMS*/
#ifdef LKM_EXEC /* XXX NOTDEF YET!!! - cgd */
/*
* For the loadable execution class described by the structure pointed to
* by lkmtp, load/unload/stat it depending on the cmd requested.
*/
static int
_lkm_exec( lkmtp, cmd)
struct lkm_table *lkmtp;
int cmd;
{
struct lkm_exec *args = lkmtp->private.lkm_exec;
int i;
int err = 0;
switch( cmd) {
case LKM_E_LOAD:
/* don't load twice!*/
if( lkmexists( lkmtp))
return( EEXIST);
if( ( i = args->lkm_offset) == -1) { /* auto*/
/*
* Search the table looking for a slot...
*/
for( i = 0; i < nexecs; i++)
if( execsw[ i].m_size == 0)
break; /* found it!*/
/* out of allocable slots?*/
if( i == nexecs) {
err = ENFILE;
break;
}
} else { /* assign*/
if( i < 0 || i >= nexecs) {
err = EINVAL;
break;
}
}
/* save old*/
bcopy( &execsw[ i], &(args->lkm_oldexec), sizeof( struct execsw));
/* replace with new*/
bcopy( args->lkm_exec, &execsw[ i], sizeof( struct execsw));
/* done!*/
args->lkm_offset = i; /* slot in execsw[]*/
break;
case LKM_E_UNLOAD:
/* current slot...*/
i = args->lkm_offset;
/* replace current slot contents with old contents*/
bcopy( &execsw[ i], &(args->lkm_oldexec), sizeof( struct execsw));
break;
case LKM_E_STAT: /* no special handling...*/
break;
}
return( err);
}
#endif /* LKM_EXEC */
/*
* This code handles the per-module type "wiring-in" of loadable modules
* into existing kernel tables. For "LM_MISC" modules, wiring and unwiring
* is assumed to be done in their entry routines internal to the module
* itself.
*/
lkmdispatch( lkmtp, cmd)
struct lkm_table *lkmtp;
int cmd;
{
int err = 0; /* default = success*/
switch( lkmtp->private.lkm_any->lkm_type) {
case LM_SYSCALL:
err = _lkm_syscall( lkmtp, cmd);
break;
case LM_VFS:
err = _lkm_vfs( lkmtp, cmd);
break;
case LM_DEV:
{
struct lkm_dev *args = lkmtp->private.lkm_dev;
}
break;
#ifdef STREAMS
case LM_STRMOD:
{
struct lkm_strmod *args = lkmtp->private.lkm_strmod;
}
break;
#endif /* STREAMS*/
#ifdef LKM_EXEC
case LM_EXEC:
err = _lkm_exec( lkmtp, cmd);
break;
#endif /* LKM_EXEC */
case LM_MISC: /* ignore content -- no "misc-specific" procedure*/
break;
default:
err = ENXIO; /* unknown type*/
break;
}
return( err);
}

View File

@ -1,6 +1,6 @@
#! /bin/sh -
# from: @(#)makesyscalls.sh 7.6 (Berkeley) 4/20/91
# $Id: makesyscalls.sh,v 1.4 1993/05/20 16:17:38 cgd Exp $
# $Id: makesyscalls.sh,v 1.5 1993/06/07 19:52:40 cgd Exp $
set -e
@ -104,14 +104,15 @@ awk < $1 "
if (NF < 5)
$5 = $4
}
$2 == "STD" {
$2 == "STD" || $2 == "NODEF" {
printf("int\t%s();\n", $4) > sysdcl
printf("\t%d, %s,\t\t\t/* %d = %s */\n", \
$3, $4, syscall, $5) > sysent
printf("\t\"%s\",\t\t\t/* %d = %s */\n", \
$5, syscall, $5) > sysnames
printf("#define\tSYS_%s\t%d\n", \
$5, syscall) > syshdr
if ($2 == "STD")
printf("#define\tSYS_%s\t%d\n", \
$5, syscall) > syshdr
syscall++
next
}

View File

@ -226,4 +226,36 @@ char *syscallnames[] = {
"#188", /* 188 = nosys */
"#189", /* 189 = nosys */
"#190", /* 190 = nosys */
"#191", /* 191 = nosys */
"#192", /* 192 = nosys */
"#193", /* 193 = nosys */
"#194", /* 194 = nosys */
"#195", /* 195 = nosys */
"#196", /* 196 = nosys */
"#197", /* 197 = nosys */
"#198", /* 198 = nosys */
"#199", /* 199 = nosys */
#ifdef LKM
"lkmnosys", /* 200 = lkmnosys */
"lkmnosys", /* 201 = lkmnosys */
"lkmnosys", /* 202 = lkmnosys */
"lkmnosys", /* 203 = lkmnosys */
"lkmnosys", /* 204 = lkmnosys */
"lkmnosys", /* 205 = lkmnosys */
"lkmnosys", /* 206 = lkmnosys */
"lkmnosys", /* 207 = lkmnosys */
"lkmnosys", /* 208 = lkmnosys */
"lkmnosys", /* 209 = lkmnosys */
#else /* !LKM*/
"#200", /* 200 = nosys */
"#201", /* 201 = nosys */
"#202", /* 202 = nosys */
"#203", /* 203 = nosys */
"#204", /* 204 = nosys */
"#205", /* 205 = nosys */
"#206", /* 206 = nosys */
"#207", /* 207 = nosys */
"#208", /* 208 = nosys */
"#209", /* 209 = nosys */
#endif /* !LKM*/
};

View File

@ -1,11 +1,11 @@
$Id: syscalls.master,v 1.5 1993/05/20 02:55:11 cgd Exp $
$Id: syscalls.master,v 1.6 1993/06/07 19:52:42 cgd Exp $
; from: @(#)syscalls.master 7.26 (Berkeley) 3/25/91
; System call name/number master file.
; Processed to created init_sysent.c, syscalls.c and syscall.h.
; Columns: number type nargs name altname/comments
; number system call number, must be in order
; type one of STD, OBSOL, UNIMPL, COMPAT
; type one of STD, OBSOL, UNIMPL, NODEF, COMPAT
; nargs number of arguments
; name name of syscall routine
; altname name of system call if different
@ -16,6 +16,7 @@
; COMPAT included on COMPAT #ifdef
; LIBCOMPAT included on COMPAT #ifdef, and placed in syscall.h
; OBSOL obsolete, not included in system, only specifies name
; NODEF do everything except include in syscall.h
; UNIMPL not implemented, placeholder only
; #ifdef's, etc. may be included, and are copied to the output files.
@ -253,3 +254,38 @@
188 UNIMPL 0 nosys
189 UNIMPL 0 nosys
190 UNIMPL 0 nosys
191 UNIMPL 0 nosys
192 UNIMPL 0 nosys
193 UNIMPL 0 nosys
194 UNIMPL 0 nosys
195 UNIMPL 0 nosys
196 UNIMPL 0 nosys
197 UNIMPL 0 nosys
198 UNIMPL 0 nosys
199 UNIMPL 0 nosys
;
; Syscalls 200-109 are reserved for dynamically loaded syscalls
;
#ifdef LKM
200 NODEF 0 lkmnosys
201 NODEF 0 lkmnosys
202 NODEF 0 lkmnosys
203 NODEF 0 lkmnosys
204 NODEF 0 lkmnosys
205 NODEF 0 lkmnosys
206 NODEF 0 lkmnosys
207 NODEF 0 lkmnosys
208 NODEF 0 lkmnosys
209 NODEF 0 lkmnosys
#else /* !LKM */
200 UNIMPL 0 nosys
201 UNIMPL 0 nosys
202 UNIMPL 0 nosys
203 UNIMPL 0 nosys
204 UNIMPL 0 nosys
205 UNIMPL 0 nosys
206 UNIMPL 0 nosys
207 UNIMPL 0 nosys
208 UNIMPL 0 nosys
209 UNIMPL 0 nosys
#endif /* !LKM */

View File

@ -1 +1 @@
revision 1.10 intentionally removed
revision 1.11 intentionally removed

366
sys/sys/lkm.h Normal file
View File

@ -0,0 +1,366 @@
/*
* lkm.h
*
* Header file used by loadable kernel modules and loadable kernel module
* utilities.
*
* 23 Jan 93 Terry Lambert Original
*
* Copyright (c) 1992 Terrence R. Lambert.
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Terrence R. Lambert.
* 4. The name Terrence R. Lambert may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``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 TERRENCE R. LAMBERT 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.
*
* $Id: lkm.h,v 1.1 1993/06/07 19:52:51 cgd Exp $
*/
#ifndef _SYS_LKM_H_
#define _SYS_LKM_H_
/*
* Supported module types
*/
typedef enum loadmod {
LM_SYSCALL,
LM_VFS,
LM_DEV,
LM_STRMOD,
LM_EXEC,
LM_MISC
} MODTYPE;
#define LKM_VERSION 1 /* version of module loader*/
/****************************************************************************/
/*
* Loadable system call
*/
struct lkm_syscall {
MODTYPE lkm_type;
int lkm_ver;
char *lkm_name;
int lkm_offset; /* save/assign area*/
struct sysent *lkm_sysent;
struct sysent lkm_oldent; /* save area for unload*/
};
/*
* Loadable file system
*/
struct lkm_vfs {
MODTYPE lkm_type;
int lkm_ver;
char *lkm_name;
int lkm_offset;
unsigned long lkm_flags;
struct vfsops *lkm_vfsops;
};
/*
* Supported device module types
*/
typedef enum devtype {
LM_DT_BLOCK,
LM_DT_CHAR
} DEVTYPE;
/*
* Loadable device driver
*/
struct lkm_dev {
MODTYPE lkm_type;
int lkm_ver;
char *lkm_name;
int lkm_offset;
DEVTYPE lkm_devtype;
union {
void *anon;
struct bdevsw *bdev;
struct cdevsw *cdev;
} lkm_dev;
union {
struct bdevsw bdev;
struct cdevsw cdev;
} lkm_olddev;
};
/*
* Loadable streams module
*/
struct lkm_strmod {
MODTYPE lkm_type;
int lkm_ver;
char *lkm_name;
int lkm_offset;
/*
* Removed: future release
*/
};
/*
* Exec loader
*/
struct lkm_exec {
MODTYPE lkm_type;
int lkm_ver;
char *lkm_name;
int lkm_offset;
struct execsw *lkm_exec;
struct execsw lkm_oldexec;
};
/*
* Miscellaneous module (complex load/unload, potentially complex stat
*/
struct lkm_misc {
MODTYPE lkm_type;
int lkm_ver;
char *lkm_name;
int lkm_offset;
};
/*
* Any module (to get type and name info without knowing type)
*/
struct lkm_any {
MODTYPE lkm_type;
int lkm_ver;
char *lkm_name;
int lkm_offset;
};
/*
* Generic reference ala XEvent to allow single entry point in the xxxinit()
* routine.
*/
union lkm_generic {
struct lkm_any *lkm_any;
struct lkm_syscall *lkm_syscall;
struct lkm_vfs *lkm_vfs;
struct lkm_dev *lkm_dev;
struct lkm_strmod *lkm_strmod;
struct lkm_exec *lkm_exec;
struct lkm_misc *lkm_misc;
};
union lkm_all {
struct lkm_any lkm_any;
struct lkm_syscall lkm_syscall;
struct lkm_vfs lkm_vfs;
struct lkm_dev lkm_dev;
struct lkm_strmod lkm_strmod;
struct lkm_exec lkm_exec;
struct lkm_misc lkm_misc;
};
/*
* Per module information structure
*/
#define MAXLKMNAME 32
struct lkm_table {
int type;
unsigned int size;
unsigned int offset;
char *area;
char used;
int ver; /* version (INIT)*/
int refcnt; /* reference count (INIT)*/
int depcnt; /* dependency count (INIT)*/
int id; /* identifier (INIT)*/
int (*entry)(); /* entry function*/
union lkm_generic private; /* module private data*/
};
#define LKM_E_LOAD 1
#define LKM_E_UNLOAD 2
#define LKM_E_STAT 3
#define MOD_SYSCALL(name,callslot,sysentp) \
static struct lkm_syscall _module = { \
LM_SYSCALL, \
LKM_VERSION, \
name, \
callslot, \
sysentp \
};
#define MOD_VFS(name,vfsslot,flags,vfsopsp) \
static struct lkm_vfs _module = { \
LM_VFS, \
LKM_VERSION, \
name, \
vfsslot, \
flags, \
vfsopsp \
};
#define MOD_DEV(name,devtype,devslot,devp) \
static struct lkm_dev _module = { \
LM_DEV, \
LKM_VERSION, \
name, \
devslot, \
devtype, \
(void *)devp \
};
#define MOD_EXEC(name,execslot,execsw) \
static struct lkm_exec _module = { \
LM_EXEC, \
LKM_VERSION, \
name, \
execslot, \
execsw \
};
#define MOD_MISC(name) \
static struct lkm_misc _module = { \
LM_MISC, \
LKM_VERSION, \
name \
};
extern int nosys();
/*
* DISPATCH -- body function for use in module entry point function;
* generally, the function body will consist entirely of a single
* DISPATCH line.
*
* If load/unload/stat are not "nosys", then they are called on each
* corresponding entry instance. "cmd" is passed to each function so
* that a single function can be used if desired.
*/
#define DISPATCH(lkmtp,cmd,ver,load,unload,stat) \
if( ver != LKM_VERSION) \
return( EINVAL); /* version mismatch*/ \
switch( cmd) { \
int _err; \
case LKM_E_LOAD: \
lkmtp->private.lkm_any = (struct lkm_any *)&_module; \
if( load != nosys && (_err = load( lkmtp, cmd))) \
return( _err); \
break; \
case LKM_E_UNLOAD: \
if( unload != nosys && (_err = unload( lkmtp, cmd))) \
return( _err); \
break; \
case LKM_E_STAT: \
if( stat != nosys && (_err = stat( lkmtp, cmd))) \
return( _err); \
break; \
} \
return( lkmdispatch( lkmtp, cmd));
/****************************************************************************/
/*
* IOCTL's recognized by /dev/lkm
*/
#define LMRESERV _IOWR( 'K', 0, struct lmc_resrv)
#define LMLOADBUF _IOW( 'K', 1, struct lmc_loadbuf)
#define LMUNRESRV _IO( 'K', 2)
#define LMREADY _IOW( 'K', 3, int)
#define LMLOAD _IOW( 'K', 9, struct lmc_load)
#define LMUNLOAD _IOWR( 'K', 10, struct lmc_unload)
#define LMSTAT _IOWR( 'K', 11, struct lmc_stat)
#define MODIOBUF 512 /* # of bytes at a time to loadbuf*/
/*
* IOCTL arguments
*/
/*
* Reserve a page-aligned block of kernel memory for the module
*/
struct lmc_resrv {
unsigned long size; /* IN: size of module to reserve*/
char *name; /* IN: name (must be provided*/
int slot; /* OUT: allocated slot (module ID)*/
unsigned long addr; /* OUT: Link-to address*/
};
/*
* Copy a buffer at a time into the allocated area in the kernel; writes
* are assumed to occur contiguously.
*/
struct lmc_loadbuf {
int cnt; /* IN: # of chars pointed to by data*/
char *data; /* IN: pointer to data buffer*/
};
/*
* Load a module (assumes it's been mmapped to address before call)
*/
struct lmc_load {
caddr_t address; /* IN: user space mmap address*/
int status; /* OUT: status of operation*/
int id; /* OUT: module ID if loaded*/
};
/*
* Unload a module (by name/id)
*/
struct lmc_unload {
int id; /* IN: module ID to unload*/
char *name; /* IN: module name to unload if id -1*/
int status; /* OUT: status of operation*/
};
/*
* Get module information for a given id (or name if id == -1).
*/
struct lmc_stat {
int id; /* IN: module ID to unload*/
char name[ MAXLKMNAME]; /* IN/OUT: name of module*/
int offset; /* OUT: target table offset*/
MODTYPE type; /* OUT: type of module*/
char *area; /* OUT: kernel load addr*/
int size; /* OUT: module size (pages)*/
unsigned long private; /* OUT: module private data*/
int ver; /* OUT: lkm compile version*/
};
#endif /* !_SYS_LKM_H_ */

View File

@ -1,6 +1,6 @@
# @(#)Makefile 5.8.1.1 (Berkeley) 5/8/91
#
# $Id: Makefile,v 1.22 1993/06/03 19:32:26 brezak Exp $
# $Id: Makefile,v 1.23 1993/06/07 19:52:54 cgd Exp $
SUBDIR= ar biff basename cal calendar cap_mkdb \
checknr chpass cksum cmp col colcrt colrm column comm compress \
@ -9,8 +9,8 @@ SUBDIR= ar biff basename cal calendar cap_mkdb \
fsplit fstat ftp gprof groups head hexdump \
id indent join ktrace last lastcomm leave locate lock logger \
login logname look lorder m4 machine mail make man mesg mkdep mkfifo \
mkstr more msgs netstat newsyslog nfsstat nice nm nohup pagesize \
passwd paste patch printenv printf quota ranlib \
mkstr modstat more msgs netstat newsyslog nfsstat nice nm nohup \
pagesize passwd paste patch printenv printf quota ranlib \
rdist ref renice rev rlogin rpcgen rpcinfo \
rsh rup ruptime rusers rwall rwho \
sccs script sed shar showmount size soelim split strings \

45
usr.bin/modstat/Makefile Normal file
View File

@ -0,0 +1,45 @@
#
# Makefile for modstat
#
# 25 May 93 Terry Lambert Original
#
# Copyright (c) 1993 Terrence R. Lambert.
# 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.
# 3. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by Terrence R. Lambert.
# 4. The name Terrence R. Lambert may not be used to endorse or promote
# products derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``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 TERRENCE R. LAMBERT 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.
#
# $Id: Makefile,v 1.1 1993/06/07 19:52:57 cgd Exp $
#
PROG= modstat
CFLAGS=-DKERNEL
NOMAN= noman
BINGRP= kmem
BINMODE=2555
.include <bsd.prog.mk>

203
usr.bin/modstat/modstat.c Normal file
View File

@ -0,0 +1,203 @@
/*
* modstat.c
*
* This is the loadable kernel module status display program. The
* interface is nearly identical to the SunOS 4.1.3 not because I
* lack imagination but because I liked Sun's approach in this
* particular revision of their BSD-derived OS.
*
* modstat [-i <module id>] [-n <module name>]
*
* Default behaviour is to report status for all modules.
*
* -i <module id> - status for module by id
* -n <module name> - status for module by name
*
* Copyright (c) 1993 Terrence R. Lambert.
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Terrence R. Lambert.
* 4. The name Terrence R. Lambert may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``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 TERRENCE R. LAMBERT 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.
*
* $Id: modstat.c,v 1.1 1993/06/07 19:52:58 cgd Exp $
*/
#define printf I_HATE_ANSI
#include <stdio.h>
#undef printf
#include <stdlib.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/mount.h>
#include <sys/exec.h>
#include <sys/lkm.h>
#include <a.out.h>
#include <sys/file.h>
#include <sys/errno.h>
extern int errno; /* should be in errno.h*/
#ifdef sun
/* these are defined in stdlib.h for everything but sun*/
extern char *optarg;
extern int optind;
#endif /* sun*/
#define LKM_DEV "/dev/lkm"
extern int dostat();
usage()
{
fprintf( stderr, "usage:\n");
fprintf( stderr,
"modstat [-i <module id>] [-n <module name>]\n");
exit( 1);
}
main( ac, av)
int ac;
char *av[];
{
int devfd;
int i;
int ch;
int err = 0;
int modnum = -1;
char *modname = NULL;
while( ( ch = getopt( ac, av, "i:n:")) != EOF) {
switch(ch) {
case 'i': modnum = atoi( optarg); break; /* number*/
case 'n': modname = optarg; break; /* name*/
case '?': usage();
default: printf( "default!\n");
}
}
ac -= optind;
av += optind;
if( ac != 0)
usage();
/*
* Open the virtual device device driver for exclusive use (needed
* to ioctl() to retrive the loaded module(s) status).
*/
if( ( devfd = open( LKM_DEV, O_RDONLY, 0)) == -1) {
perror( LKM_DEV);
exit( 2);
}
printf( "Type Id Off Loadaddr Size Info Rev Module Name\n");
/*
* Oneshot?
*/
if( modnum != -1 || modname != NULL) {
if( dostat( devfd, modnum, modname))
err = 3;
goto done;
}
/*
* Start at 0 and work up until "EEXIST"
*/
for( modnum = 0; dostat( devfd, modnum, NULL) < 2; modnum++)
continue;
done:
close( devfd);
exit( err);
}
static char *type_names[] = {
"SYSCALL",
"VFS",
"DEV",
"STRMOD",
"EXEC",
"MISC"
};
int
dostat( devfd, modnum, modname)
int devfd;
int modnum;
char *modname;
{
struct lmc_stat sbuf;
if( modname != NULL)
strcpy( sbuf.name, modname);
sbuf.id = modnum;
if( ioctl( devfd, LMSTAT, &sbuf) == -1) {
switch( errno) {
case EINVAL: /* out of range*/
return( 2);
case ENOENT: /* no such entry*/
return( 1);
default: /* other error (EFAULT, etc)*/
perror( "LMSTAT");
return( 4);
}
}
/*
* Decode this stat buffer...
*/
printf( "%-7s %3d %3d %08x %04x %8x %3d %s\n",
type_names[ sbuf.type],
sbuf.id, /* module id*/
sbuf.offset, /* offset into modtype struct*/
sbuf.area, /* address module loaded at*/
sbuf.size, /* size in pages(K)*/
sbuf.private, /* kernel address of private area*/
sbuf.ver, /* Version; always 1 for now*/
sbuf.name /* name from private area*/
);
/*
* Done (success).
*/
return( 0);
}
/*
* EOF -- This file has not been truncated.
*/