Init
This commit is contained in:
63
usr.etc/mod/Makefile
Normal file
63
usr.etc/mod/Makefile
Normal file
@@ -0,0 +1,63 @@
|
||||
#
|
||||
# @(#)Makefile 1.1 94/10/31 SMI
|
||||
#
|
||||
|
||||
# makefile for loadable module utilities
|
||||
|
||||
# ASP is Architecture Specific; modload (specifically, modloadconf.c)
|
||||
# depends upon the kernel sub-architecture
|
||||
|
||||
BIN = modunload modstat
|
||||
ASP = modload
|
||||
ALL = ${BIN} ${ASP}
|
||||
|
||||
ARCH:sh = arch
|
||||
KARCH:sh = arch -k
|
||||
|
||||
COMMON = modsubr.o
|
||||
MODLOAD = modload.o modloadconf.o modloadsym.o modloadhdr.o
|
||||
OBJ = ${MODLOAD} modunload.o modstat.o ${COMMON}
|
||||
ASOBJ = modloadconf.o
|
||||
|
||||
DESTDIR =
|
||||
BINDIR = /usr/etc
|
||||
OWNER = root
|
||||
|
||||
# Install directory for architecture-specific programs, absolute path
|
||||
#
|
||||
ASDIR= /usr/kvm
|
||||
|
||||
# Install directory for architecture-specific programs, relative path
|
||||
#
|
||||
RELASDIR= ../kvm
|
||||
|
||||
CFLAGS = -O
|
||||
|
||||
${ASOBJ} := CFLAGS += -U${ARCH} -D${KARCH}
|
||||
|
||||
all: ${ALL}
|
||||
|
||||
modload: ${MODLOAD} ${COMMON}
|
||||
${CC} -o modload ${MODLOAD} ${COMMON} -lkvm
|
||||
|
||||
modunload: modunload.o ${COMMON}
|
||||
${CC} -o modunload modunload.o ${COMMON}
|
||||
|
||||
modstat: modstat.o ${COMMON}
|
||||
${CC} -o modstat modstat.o ${COMMON}
|
||||
|
||||
install: ${ALL}
|
||||
for i in ${BIN}; do \
|
||||
${RM} ${DESTDIR}${BINDIR}/$$i; \
|
||||
install -c -s -m 755 -o ${OWNER} \
|
||||
$$i ${DESTDIR}${BINDIR}/$$i ; \
|
||||
done
|
||||
for i in ${ASP}; do \
|
||||
${RM} ${DESTDIR}${BINDIR}/$$i; \
|
||||
install -c -s -m 755 -o ${OWNER} \
|
||||
$$i ${DESTDIR}${ASDIR}/$$i; \
|
||||
ln -s ${RELASDIR}/$$i ${DESTDIR}${BINDIR}/$$i ; \
|
||||
done
|
||||
|
||||
clean:
|
||||
rm -f ${OBJ} ${ALL}
|
||||
558
usr.etc/mod/modload.c
Normal file
558
usr.etc/mod/modload.c
Normal file
@@ -0,0 +1,558 @@
|
||||
/* @(#)modload.c 1.1 94/10/31 SMI */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1988 by Sun Microsystems, Inc.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sun/vddrv.h>
|
||||
#include <nlist.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <kvm.h>
|
||||
|
||||
char *rawinputfile = NULL; /* input file as specified by the user */
|
||||
char *inputfilename = NULL; /* input file name without any extension */
|
||||
char *outputfile = NULL; /* name of output file */
|
||||
|
||||
char *unixfile = "/vmunix"; /* default kernel image to link with */
|
||||
char *entrypoint; /* module entry point routine */
|
||||
char *execfile; /* name of user file to exec after loading */
|
||||
char *conffile; /* name of user configuration file */
|
||||
|
||||
int dopt = 0; /* debug option */
|
||||
int sopt = 0; /* option to generate a symbol table */
|
||||
int vopt = 0; /* verbose option */
|
||||
int mod_id = 0; /* module ID returned by driver */
|
||||
u_long mod_addr; /* virtual address at which module is loaded */
|
||||
u_int mod_size; /* size in bytes of module */
|
||||
int vd; /* file descriptor for /dev/vd */
|
||||
|
||||
void quit(), usage(), error(), fatal(), vinfo();
|
||||
static caddr_t linkmodule();
|
||||
static int checkversion();
|
||||
static void getargs(), exec_userfile();
|
||||
static void strip(), ld(), exec_ld();
|
||||
extern struct vdconf *getconfinfo();
|
||||
extern char *malloc();
|
||||
|
||||
/*
|
||||
* Load a module.
|
||||
*/
|
||||
|
||||
main(argc, argv, envp)
|
||||
int argc;
|
||||
char *argv[];
|
||||
char *envp[];
|
||||
{
|
||||
struct vdioctl_load vdiload; /* structure used with VDLOAD ioctl */
|
||||
|
||||
/*
|
||||
* Get arguments
|
||||
*/
|
||||
getargs(argc, argv);
|
||||
|
||||
/*
|
||||
* Open the pseudo driver to load the module
|
||||
*/
|
||||
if ((vd = open("/dev/vd", O_RDWR)) < 0)
|
||||
error("can't open /dev/vd");
|
||||
|
||||
/*
|
||||
* Catch signals so we can cleanup
|
||||
*/
|
||||
(void) signal(SIGINT, quit);
|
||||
|
||||
/*
|
||||
* Link the module at its proper virtual address.
|
||||
* Verify this it is being linked with the proper kernel.
|
||||
* Generate the symbol table.
|
||||
*/
|
||||
vdiload.vdi_mmapaddr = linkmodule(vd, &vdiload.vdi_symtabsize);
|
||||
vdiload.vdi_id = mod_id;
|
||||
|
||||
/*
|
||||
* Get configuration information
|
||||
*/
|
||||
vdiload.vdi_userconf = getconfinfo(conffile);
|
||||
|
||||
/*
|
||||
* Now load the module into the system
|
||||
*/
|
||||
if (!sopt)
|
||||
strip(outputfile);
|
||||
|
||||
if (ioctl(vd, VDLOAD, &vdiload) < 0)
|
||||
error("can't load this module");
|
||||
|
||||
/*
|
||||
* Exec the user's file (if any)
|
||||
*/
|
||||
if (execfile)
|
||||
exec_userfile(vd, mod_id, envp);
|
||||
|
||||
printf("module loaded; id = %d\n", mod_id);
|
||||
exit(0); /* success */
|
||||
}
|
||||
|
||||
/*
|
||||
* Link the module at its proper virtual address.
|
||||
*
|
||||
* First we have to link the module (any address will do!) to find out its size.
|
||||
* This is because the size of the bss is not determined until the final link.
|
||||
* After we know the size, we can ask the kernel (VDGETVADDR ioctl) for the
|
||||
* next available address of this size. Then we link the module at its
|
||||
* final virtual address.
|
||||
*
|
||||
* In order to get the actual module size, we have to generate the symbol
|
||||
* table here.
|
||||
*/
|
||||
static caddr_t
|
||||
linkmodule(vd, symtabsize)
|
||||
int vd;
|
||||
u_int *symtabsize;
|
||||
{
|
||||
register int fd;
|
||||
register caddr_t mmapaddr;
|
||||
|
||||
struct vdioctl_getvaddr vdigetvaddr;
|
||||
struct stat statbuf;
|
||||
|
||||
u_int tvaddr, tsize, toffset;
|
||||
u_int dvaddr, dsize, doffset;
|
||||
u_int bvaddr, bsize;
|
||||
|
||||
/*
|
||||
* Link at any address just so we can find out the size of the bss.
|
||||
*/
|
||||
ld((u_long)0);
|
||||
|
||||
/*
|
||||
* Make sure the version of unix that the module was linked with
|
||||
* is the same as the running version of unix.
|
||||
*/
|
||||
if (checkversion() != 0)
|
||||
fatal(
|
||||
"Module must be relinked with the running kernel (use modload -A option)\n");
|
||||
|
||||
if (!sopt)
|
||||
strip(outputfile);
|
||||
|
||||
if ((fd = open(outputfile, 0)) < 0)
|
||||
error("can't open %s", outputfile);
|
||||
|
||||
if (fstat(fd, &statbuf) < 0)
|
||||
error("can't stat %s", outputfile);
|
||||
|
||||
/*
|
||||
* mmap the module image file
|
||||
*/
|
||||
mmapaddr = mmap((caddr_t)0, (int)statbuf.st_size,
|
||||
PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, (off_t)0);
|
||||
if (mmapaddr == (caddr_t)-1)
|
||||
error("can't mmap %s", outputfile);
|
||||
|
||||
readhdr(mmapaddr, &tvaddr, &tsize, &toffset,
|
||||
&dvaddr, &dsize, &doffset, &bvaddr, &bsize);
|
||||
checkhdr(tvaddr, tsize, toffset, dvaddr, dsize, doffset, bvaddr, bsize);
|
||||
|
||||
vdigetvaddr.vdi_size = (bvaddr - tvaddr + bsize);
|
||||
|
||||
if (sopt) {
|
||||
/*
|
||||
* Generate symbol table and get its size.
|
||||
*/
|
||||
vdigetvaddr.vdi_size +=
|
||||
getsymtab(outputfile, mmapaddr,
|
||||
(u_long)0, vdigetvaddr.vdi_size);
|
||||
}
|
||||
|
||||
close(fd); /* close and munmap the image */
|
||||
|
||||
/*
|
||||
* Now that we know the module size, we ask the kernel for
|
||||
* the virtual address at which to link the module.
|
||||
*/
|
||||
if (ioctl(vd, VDGETVADDR, &vdigetvaddr) < 0)
|
||||
error("can't get a virtual address for this module");
|
||||
|
||||
/*
|
||||
* Add header sizes to the virtual address. This is the final
|
||||
* link address for the module.
|
||||
*/
|
||||
vdigetvaddr.vdi_vaddr += gethdrsize();
|
||||
|
||||
/*
|
||||
* Save module info for later use
|
||||
*/
|
||||
mod_id = vdigetvaddr.vdi_id;
|
||||
mod_addr = vdigetvaddr.vdi_vaddr;
|
||||
mod_size = vdigetvaddr.vdi_size;
|
||||
vinfo("module id = %d, vaddr = %x, size = %x\n",
|
||||
mod_id, mod_addr, mod_size);
|
||||
|
||||
ld(mod_addr); /* link the module again */
|
||||
|
||||
if ((fd = open(outputfile, 0)) < 0)
|
||||
error("can't open %s", outputfile);
|
||||
|
||||
if (fstat(fd, &statbuf) < 0)
|
||||
error("can't stat %s", outputfile);
|
||||
|
||||
/*
|
||||
* mmap the module image file again now that we've relinked.
|
||||
*/
|
||||
mmapaddr = mmap((caddr_t)0, (int)statbuf.st_size,
|
||||
PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, (off_t)0);
|
||||
if (mmapaddr == (caddr_t)-1)
|
||||
error("can't mmap %s", outputfile);
|
||||
|
||||
*symtabsize = (sopt) ?
|
||||
getsymtab(outputfile, mmapaddr, mod_addr, mod_size)
|
||||
: 0;
|
||||
return (mmapaddr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Exec "ld" to link the module at a specified virtual address.
|
||||
*/
|
||||
static void
|
||||
ld(vaddr)
|
||||
u_long vaddr;
|
||||
{
|
||||
int child;
|
||||
union wait status;
|
||||
|
||||
vinfo("Linking the module...\n");
|
||||
|
||||
child = fork();
|
||||
if (child == -1)
|
||||
error("can't fork ld");
|
||||
else if (child == 0)
|
||||
exec_ld(vaddr);
|
||||
else {
|
||||
wait(&status); /* wait for ld to finish */
|
||||
if (status.w_retcode != 0) {
|
||||
vinfo("ld failed, status = %x\n", status.w_retcode);
|
||||
exit(-2); /* ld already printed messages */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
strip(file)
|
||||
char *file;
|
||||
{
|
||||
int child;
|
||||
union wait status;
|
||||
|
||||
vinfo("Removing symbol table...\n");
|
||||
|
||||
child = fork();
|
||||
if (child == -1)
|
||||
error("can't fork strip");
|
||||
else if (child == 0) {
|
||||
execlp("/bin/strip", "strip", file, (char *)0);
|
||||
error("couldn't exec /bin/strip");
|
||||
} else {
|
||||
wait(&status); /* wait for ld to finish */
|
||||
if (status.w_retcode != 0) {
|
||||
vinfo("ld failed, status = %x\n", status.w_retcode);
|
||||
exit(-2); /* ld already printed messages */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Exec strip to remove symbol table
|
||||
*/
|
||||
#ifdef sun386
|
||||
#define EXECTYPE "-z"
|
||||
#define DEFAULTENTRY "xxxinit"
|
||||
#else
|
||||
#define EXECTYPE "-N"
|
||||
#define DEFAULTENTRY "_xxxinit"
|
||||
#endif sun386
|
||||
|
||||
static void
|
||||
exec_ld(vaddr)
|
||||
u_long vaddr;
|
||||
{
|
||||
char addr[12];
|
||||
|
||||
sprintf(addr, "%lx", vaddr);
|
||||
if (entrypoint == NULL)
|
||||
entrypoint = DEFAULTENTRY;
|
||||
|
||||
vinfo("/bin/ld -o %s -Bstatic -T %s -A %s %s -e %s %s %s\n",
|
||||
outputfile, addr, unixfile, EXECTYPE, entrypoint,
|
||||
sopt == 0 ? "-s": "", rawinputfile);
|
||||
|
||||
execlp("/bin/ld", "ld", "-o", outputfile, "-Bstatic", "-T", addr,
|
||||
"-A", unixfile, EXECTYPE, "-e", entrypoint,
|
||||
rawinputfile, (char *)0);
|
||||
error("couldn't exec /bin/ld");
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure that the module is being linked with the running kernel.
|
||||
*
|
||||
* The module has been linked with the kernel named <unixfile>.
|
||||
* This routine finds the version string in <unixfile> and compares
|
||||
* it to the version string in memory. They must match.
|
||||
*/
|
||||
|
||||
static struct nlist nl[] = {
|
||||
#ifdef COFF
|
||||
{ "version" },
|
||||
#else
|
||||
{ "_version"},
|
||||
#endif
|
||||
"",
|
||||
};
|
||||
|
||||
#define MAXVERSIONLEN 256 /* max length of kernel version string */
|
||||
|
||||
static int
|
||||
checkversion()
|
||||
{
|
||||
kvm_t *kd;
|
||||
int kmemf, unixf;
|
||||
char *kaddr, *uaddr;
|
||||
u_int datavaddr, dataoffset, voff;
|
||||
|
||||
struct stat statbuf; /* file status buffer */
|
||||
|
||||
if ((kmemf = open("/dev/kmem", 0)) < 0)
|
||||
error("can't open /dev/kmem");
|
||||
|
||||
if ((unixf = open(unixfile, 0)) < 0)
|
||||
error("can't open %s", unixfile);
|
||||
|
||||
if (fstat(unixf, &statbuf) < 0)
|
||||
error("can't stat %s", unixfile);
|
||||
|
||||
kd = kvm_open(unixfile, (char *)NULL, (char *)NULL,
|
||||
O_RDONLY, "kvm_open");
|
||||
if (kd == NULL)
|
||||
error("modload failed");
|
||||
|
||||
if (kvm_nlist(kd, nl) < 0)
|
||||
fatal("bad namelist in kernel symbol table\n");
|
||||
|
||||
if (nl[0].n_value == 0)
|
||||
fatal("missing 'version' symbol in kernel symbol table\n");
|
||||
|
||||
uaddr = mmap((caddr_t)0, (int)statbuf.st_size, PROT_READ,
|
||||
MAP_PRIVATE, unixf, (off_t)0);
|
||||
|
||||
if (uaddr == (caddr_t)-1)
|
||||
error("can't mmap %s", unixfile);
|
||||
|
||||
kaddr = mmap((caddr_t)0, 2 * MMU_PAGESIZE, PROT_READ, MAP_SHARED,
|
||||
kmemf, (off_t)(nl[0].n_value & ~PAGEOFFSET));
|
||||
|
||||
if (kaddr == (caddr_t)-1)
|
||||
error("can't mmap /dev/kmem");
|
||||
|
||||
/* get data virtual address and offset */
|
||||
getkerneldata(uaddr, &datavaddr, &dataoffset);
|
||||
|
||||
/* offset of version in image file */
|
||||
voff = nl[0].n_value - datavaddr + dataoffset;
|
||||
|
||||
if (strncmp(uaddr + voff, kaddr + (nl[0].n_value & PAGEOFFSET),
|
||||
MAXVERSIONLEN) != 0)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Exec the user's file
|
||||
*/
|
||||
static void
|
||||
exec_userfile(vd, id, envp)
|
||||
int vd;
|
||||
int id;
|
||||
char **envp;
|
||||
{
|
||||
struct vdioctl_stat vdistat;
|
||||
struct vdstat vdstat;
|
||||
|
||||
int child;
|
||||
union wait status;
|
||||
char module_id[8];
|
||||
char magic[16];
|
||||
char blockmajor[8];
|
||||
char charmajor[8];
|
||||
char sysnum[8];
|
||||
|
||||
child = fork();
|
||||
if (child == -1)
|
||||
error("can't fork %s", execfile);
|
||||
/*
|
||||
* exec the user program.
|
||||
*/
|
||||
if (child == 0) {
|
||||
vdistat.vdi_vdstat = &vdstat; /* status buf */
|
||||
vdistat.vdi_vdstatsize = sizeof (struct vdstat); /* size */
|
||||
vdistat.vdi_id = id; /* module id */
|
||||
vdistat.vdi_statsubfcn = SUNSTATSUBFCN; /* subfcn */
|
||||
|
||||
if (ioctl(vd, VDSTAT, &vdistat) < 0)
|
||||
error("can't get module status");
|
||||
|
||||
sprintf(module_id, "%d", vdstat.vds_id);
|
||||
sprintf(magic, "%x", vdstat.vds_magic);
|
||||
|
||||
if (vdstat.vds_magic == VDMAGIC_DRV ||
|
||||
vdstat.vds_magic == VDMAGIC_MBDRV ||
|
||||
vdstat.vds_magic == VDMAGIC_PSEUDO) {
|
||||
sprintf(blockmajor, "%d", vdstat.vds_modinfo[0] & 0xff);
|
||||
sprintf(charmajor, "%d", vdstat.vds_modinfo[1] & 0xff);
|
||||
execle(execfile, execfile, module_id, magic, blockmajor,
|
||||
charmajor, (char *)0, envp);
|
||||
} else if (vdstat.vds_magic == VDMAGIC_SYS) {
|
||||
sprintf(sysnum, "%d", vdstat.vds_modinfo[0] & 0xff);
|
||||
execle(execfile, execfile, module_id, magic,
|
||||
sysnum, (char *)0, envp);
|
||||
} else {
|
||||
execle(execfile, execfile, module_id, magic,
|
||||
(char *)0, envp);
|
||||
}
|
||||
|
||||
/* Shouldn't get here if execle was successful */
|
||||
|
||||
error("couldn't exec %s", execfile);
|
||||
} else {
|
||||
wait(&status); /* wait for exec'd program to finish */
|
||||
if (status.w_retcode != 0) {
|
||||
vinfo("%s returned error %d.\n", status.w_retcode);
|
||||
exit(-2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get user arguments.
|
||||
*/
|
||||
static void
|
||||
getargs(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
char *ap, *ext;
|
||||
|
||||
if (argc < 2)
|
||||
usage();
|
||||
|
||||
argc--; /* skip program name */
|
||||
argv++;
|
||||
|
||||
while (argc--) {
|
||||
ap = *argv++; /* point at next option */
|
||||
if (*ap++ == '-') {
|
||||
if (strcmp(ap, "conf") == 0) {
|
||||
if (--argc < 0)
|
||||
usage();
|
||||
conffile = *argv++;
|
||||
} else if (strcmp(ap, "d") == 0) {
|
||||
dopt = 1;
|
||||
} else if (strcmp(ap, "sym") == 0) {
|
||||
sopt = 1;
|
||||
} else if (strcmp(ap, "entry") == 0) {
|
||||
if (--argc < 0)
|
||||
usage();
|
||||
entrypoint = *argv++;
|
||||
} else if (strcmp(ap, "o") == 0) {
|
||||
if (--argc < 0)
|
||||
usage();
|
||||
outputfile = *argv++;
|
||||
} else if (strcmp(ap, "A") == 0) {
|
||||
if (--argc < 0)
|
||||
usage();
|
||||
unixfile = *argv++;
|
||||
} else if (strcmp(ap, "v") == 0) {
|
||||
vopt = 1;
|
||||
} else if (strcmp(ap, "exec") == 0) {
|
||||
if (--argc < 0)
|
||||
usage();
|
||||
execfile = *argv++;
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
} else if (rawinputfile == NULL) { /* module file */
|
||||
rawinputfile = *--argv;
|
||||
argv++;
|
||||
} else
|
||||
usage();
|
||||
}
|
||||
|
||||
if (rawinputfile == NULL)
|
||||
usage();
|
||||
|
||||
ext = strrchr(rawinputfile, '.');
|
||||
if (ext == NULL || strcmp(&ext[1], "o") != 0)
|
||||
fatal("file_name must end with .o\n");
|
||||
|
||||
inputfilename = malloc((u_int)(ext - rawinputfile + 1));
|
||||
if (inputfilename == NULL)
|
||||
error("malloc");
|
||||
(void) strncpy(inputfilename, rawinputfile, ext - rawinputfile);
|
||||
|
||||
if (outputfile == NULL)
|
||||
outputfile = inputfilename;
|
||||
|
||||
vinfo("infile %s, infilename %s, outfile %s, execfile %s\n",
|
||||
rawinputfile, inputfilename, outputfile, execfile);
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
printf("usage: modload filename [options]\n");
|
||||
printf(" where options are:\n");
|
||||
printf(" -A <vmunix_file>\n");
|
||||
printf(" -conf <configuration_file>\n");
|
||||
printf(" -entry <entry_point>\n");
|
||||
printf(" -exec <exec_file>\n");
|
||||
printf(" -o <output_file>\n");
|
||||
printf(" -sym\n"); /* keep symbols */
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
void
|
||||
quit()
|
||||
{
|
||||
struct vdioctl_freevaddr vdi;
|
||||
|
||||
vdi.vdi_id = mod_id;
|
||||
(void) ioctl(vd, VDFREEVADDR, (caddr_t)&vdi);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
#include <varargs.h>
|
||||
|
||||
/*VARARGS0*/
|
||||
void
|
||||
vinfo(va_alist)
|
||||
va_dcl
|
||||
{
|
||||
va_list args;
|
||||
char *fmt;
|
||||
|
||||
if (!vopt)
|
||||
return;
|
||||
|
||||
va_start(args);
|
||||
fmt = va_arg(args, char *);
|
||||
vprintf(fmt, args);
|
||||
}
|
||||
917
usr.etc/mod/modloadconf.c
Normal file
917
usr.etc/mod/modloadconf.c
Normal file
@@ -0,0 +1,917 @@
|
||||
/* @(#)modloadconf.c 1.1 94/10/31 */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1988 by Sun Microsystems, Inc.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <nlist.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sundev/mbvar.h>
|
||||
#include <sun/autoconf.h>
|
||||
#include <sun/vddrv.h>
|
||||
|
||||
/*
|
||||
* Process the configuration file. You could get as fancy as you like here.
|
||||
* The code from the config program could be used to do what we have
|
||||
* to do here. But for now, the simple table driven approach suffices.
|
||||
*
|
||||
* getconfinfo() reads each line of the configuration file and produces
|
||||
* a linked list of confinfo entries. There is one confinfo entry per
|
||||
* non-comment line in the configuration file. Then, the list of confinfo
|
||||
* entries is checked for consistency and if it's ok, an array of
|
||||
* vddrv entries is produced.
|
||||
*
|
||||
* The vddrv array is the actual output of this routine. A pointer to
|
||||
* the start of the array is then used in the VDLOAD ioctl to load the module.
|
||||
*
|
||||
* Here are the types of configuration commands that we support:
|
||||
*
|
||||
* 0) # a comment line begins with a "#"
|
||||
* 1) controller <name><number> at {atmem, atio, obmem} <options>
|
||||
* 2) device <name><number> at {<controller>, atmem, atio, obmem} <options>
|
||||
* 3) disk <name><number> at {<controller>, atmem, atio, obmem} <options>
|
||||
* 4) blockmajor <number>
|
||||
* 5) charmajor <number>
|
||||
*
|
||||
* where <options> are
|
||||
* drive <drive number>
|
||||
* csr <csr address>
|
||||
* irq <interrupt request line>
|
||||
* priority <interrupt priority>
|
||||
* dmachan <dma channel>
|
||||
* flags <flags>
|
||||
*
|
||||
* and <controller> on the "device" line means the <name><number> of
|
||||
* a controller. <name> must not have any numbers in it.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* controller fdc0 at atmem ? csr 0x001000 irq 6 priority 3
|
||||
* controller fdc2 at atmem ? csr 0x002000 irq 5 priority 2
|
||||
* disk fd0 at fdc0 drive 0
|
||||
* #disk fd0 at fdc0 drive 1
|
||||
* disk fd0 at fdc0 drive 2
|
||||
* device fd0 at fdc2 drive 0
|
||||
* disk fd0 at fdc2 drive 1
|
||||
* blockmajor 51
|
||||
* charmajor 52
|
||||
*/
|
||||
|
||||
extern char *calloc();
|
||||
extern long strtol();
|
||||
|
||||
extern char *outputfile;
|
||||
|
||||
#ifndef sun4c
|
||||
static void conf_controller(), conf_disk(), conf_device();
|
||||
#endif /* sun4c */
|
||||
static void conf_blockmajor(), conf_charmajor(), conf_syscallnum();
|
||||
|
||||
#ifndef sun4c
|
||||
static struct mb_ctlr *gen_ctlr();
|
||||
static struct mb_device *gen_device();
|
||||
#ifndef sun386
|
||||
static struct vec *gen_vector();
|
||||
#endif
|
||||
#endif /* sun4c */
|
||||
|
||||
static void parse_line(), read_literal();
|
||||
static struct vdconf *gen_vdconf();
|
||||
static struct confinfo *getcip();
|
||||
static char *alloc(), *getword(), *getname(), *getstring();
|
||||
static int getint();
|
||||
#ifndef sun4c
|
||||
static int getnum(), getctlrnum();
|
||||
#endif /* sun4c */
|
||||
|
||||
#ifndef sun4c
|
||||
static void getdrive(), getcsr(), getirq(), getpriority(), getvector();
|
||||
static void getdmachan(), getflags(), getbusconn();
|
||||
#endif /* sun4c */
|
||||
|
||||
struct veclist { /* List of VME interrupt vectors */
|
||||
struct veclist *next;
|
||||
struct vec vec;
|
||||
};
|
||||
|
||||
/*
|
||||
* An instance of this structure is malloc'd and filled in for each non-comment
|
||||
* line in the configuration file. After we've read the entire configuration
|
||||
* file, we go through this array checking for consistency and then generate
|
||||
* the vdconf array.
|
||||
*/
|
||||
static struct confinfo {
|
||||
struct confinfo *next; /* pointer to next */
|
||||
int type; /* type of configuration info */
|
||||
int linenum; /* linenumber this was gen'd for */
|
||||
char *name; /* controller or device name */
|
||||
char *conname; /* name of connection (ctlr or bus) */
|
||||
int disk; /* conf type is "disk" */
|
||||
int space; /* bus type */
|
||||
int drive; /* drive number */
|
||||
int csr; /* csr address */
|
||||
int irq; /* interrupt request number */
|
||||
int priority; /* interrupt priority */
|
||||
struct veclist *vectors; /* VME interrupt vectors */
|
||||
int dmachan; /* dma channel */
|
||||
int flags; /* flags */
|
||||
int majornum; /* major number */
|
||||
int syscallnum; /* system call number */
|
||||
caddr_t data; /* pointer to generic data */
|
||||
} *confinfo;
|
||||
|
||||
/*
|
||||
* Dispatch table for each type of configuration command.
|
||||
*/
|
||||
static struct confdispatch {
|
||||
char *conftype; /* configuration command */
|
||||
void (*conffcn)(); /* function to process this type */
|
||||
} confdispatch[] = {
|
||||
#ifndef sun4c
|
||||
{ "controller", conf_controller },
|
||||
{ "device", conf_device },
|
||||
{ "disk", conf_disk },
|
||||
#endif /* sun4c */
|
||||
{ "blockmajor", conf_blockmajor },
|
||||
{ "charmajor", conf_charmajor },
|
||||
{ "syscallnum", conf_syscallnum },
|
||||
{ NULL, 0 },
|
||||
};
|
||||
|
||||
/*
|
||||
* Various bus types.
|
||||
*/
|
||||
static struct bustype {
|
||||
char *name;
|
||||
int type;
|
||||
} bustype[] = {
|
||||
#ifdef sun386
|
||||
{ "obmem", SP_OBMEM },
|
||||
{ "atmem", SP_ATMEM },
|
||||
{ "atio", SP_ATIO },
|
||||
{ NULL, 0 }
|
||||
#else
|
||||
{ "obmem", SP_OBMEM },
|
||||
{ "obio", SP_OBIO },
|
||||
{ "mbmem", SP_MBMEM },
|
||||
{ "mbio", SP_MBIO },
|
||||
{ "vme16d16", SP_VME16D16 },
|
||||
{ "vme24d16", SP_VME24D16 },
|
||||
{ "vme32d16", SP_VME32D16 },
|
||||
{ "vme16d32", SP_VME16D32 },
|
||||
{ "vme24d32", SP_VME24D32 },
|
||||
{ "vme32d32", SP_VME32D32 },
|
||||
{ NULL, 0 }
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* Configuration options.
|
||||
*/
|
||||
static struct options {
|
||||
char *name;
|
||||
void (*optfcn)();
|
||||
} options[] = {
|
||||
#ifndef sun4c
|
||||
{ "drive", getdrive },
|
||||
{ "csr", getcsr },
|
||||
{ "vector", getvector },
|
||||
{ "priority", getpriority },
|
||||
{ "irq", getirq },
|
||||
#ifdef sun386
|
||||
{ "dmachan", getdmachan },
|
||||
#endif
|
||||
{ "flags", getflags },
|
||||
#endif /* sun4c */
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
#define MAXLINE 1000
|
||||
#define COMMENT_CHAR '#'
|
||||
#define streq(a, b) (strcmp(a, b) == 0)
|
||||
#define new_array(T, n) ((T *)alloc(n, sizeof (T)))
|
||||
#define new_struct(T) new_array(T, 1)
|
||||
#define new_string(n) new_array(char, n)
|
||||
|
||||
static char line[MAXLINE]; /* current input line */
|
||||
static int linenum = 0; /* configuration file line number */
|
||||
static int confentries = 0; /* number of confinfo entries */
|
||||
|
||||
extern int dopt; /* debug option */
|
||||
|
||||
/*
|
||||
* Process the configuration file. (See comments above.)
|
||||
*
|
||||
* Returns NULL if conffile is NULL.
|
||||
* Returns vdconf if all is well.
|
||||
* If there's a fatal error, this routine prints an error message and exits.
|
||||
*/
|
||||
struct vdconf *
|
||||
getconfinfo(conffile)
|
||||
char *conffile; /* pointer to configuration file name */
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
if (conffile == NULL)
|
||||
return (NULL); /* no configuration file */
|
||||
|
||||
if ((fp = fopen(conffile, "r")) == NULL)
|
||||
error("can't open configuration file");
|
||||
|
||||
while (!feof(fp))
|
||||
parse_line(fp);
|
||||
|
||||
return (gen_vdconf(confinfo)); /* generate vdconf table */
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
parse_line(fp)
|
||||
FILE *fp;
|
||||
{
|
||||
struct confdispatch *cdp;
|
||||
static struct confinfo *cip;
|
||||
char *word;
|
||||
int linelen;
|
||||
|
||||
linenum++;
|
||||
if (fgets(line, MAXLINE, fp) == NULL)
|
||||
return;
|
||||
|
||||
linelen = strlen(line);
|
||||
if (linelen == MAXLINE - 1 && line[linelen] != '\n')
|
||||
fatal("config file line %d too long\n", linenum);
|
||||
|
||||
word = getword(fp); /* get first word of next line */
|
||||
if (word == NULL) /* empty line */
|
||||
return;
|
||||
/*
|
||||
* dispatch to the appropriate configuration routine
|
||||
*/
|
||||
for (cdp = confdispatch; cdp->conftype != NULL; cdp++)
|
||||
if (streq(cdp->conftype, word))
|
||||
break;
|
||||
|
||||
if (cdp->conftype != NULL) {
|
||||
if (confinfo == NULL)
|
||||
confinfo = cip = getcip();
|
||||
else {
|
||||
cip->next = getcip();
|
||||
cip = cip->next;
|
||||
}
|
||||
cip->linenum = linenum;
|
||||
(*cdp->conffcn)(fp, cip);
|
||||
confentries++;
|
||||
} else
|
||||
fatal("Unrecognized config type '%s' on line %d\n",
|
||||
word, linenum);
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop through all of the confinfo entries and produce the vdconf array.
|
||||
*/
|
||||
static struct vdconf *
|
||||
gen_vdconf(confinfo)
|
||||
struct confinfo *confinfo;
|
||||
{
|
||||
struct confinfo *cip;
|
||||
struct vdconf *vdconf, *vdc;
|
||||
|
||||
vdconf = new_array(struct vdconf, confentries + 1);
|
||||
vdconf[confentries].vdc_type = VDCEND; /* terminate table */
|
||||
|
||||
for (cip = confinfo, vdc = vdconf; cip; cip = cip->next, vdc++) {
|
||||
vdc->vdc_type = cip->type;
|
||||
switch (cip->type) {
|
||||
#ifndef sun4c
|
||||
case VDCCONTROLLER:
|
||||
vdc->vdc_data = (long)gen_ctlr(cip);
|
||||
break;
|
||||
|
||||
case VDCDEVICE:
|
||||
vdc->vdc_data = (long)gen_device(cip);
|
||||
break;
|
||||
#endif /* sun4c */
|
||||
|
||||
case VDCBLOCKMAJOR:
|
||||
vdc->vdc_data = (long)cip->majornum;
|
||||
break;
|
||||
|
||||
case VDCCHARMAJOR:
|
||||
vdc->vdc_data = (long)cip->majornum;
|
||||
break;
|
||||
|
||||
case VDCSYSCALLNUM:
|
||||
vdc->vdc_data = (long)cip->syscallnum;
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Internal error: unknown type %x (line %d)\n",
|
||||
cip->type, cip->linenum);
|
||||
}
|
||||
}
|
||||
return (vdconf);
|
||||
}
|
||||
|
||||
#ifndef sun4c
|
||||
/*
|
||||
* Generate an mb_ctlr entry for this controller.
|
||||
*/
|
||||
static struct mb_ctlr *
|
||||
gen_ctlr(cip)
|
||||
struct confinfo *cip;
|
||||
{
|
||||
struct mb_ctlr *mc;
|
||||
struct confinfo *c;
|
||||
|
||||
if (dopt)
|
||||
printf("gen_ctlr\n");
|
||||
|
||||
/*
|
||||
* Check for duplicate controller names
|
||||
*/
|
||||
for (c = confinfo; c != NULL; c = c->next) {
|
||||
if (c == cip || c->type != VDCCONTROLLER)
|
||||
continue;
|
||||
|
||||
if (streq(c->name, cip->name))
|
||||
fatal(
|
||||
"Duplicate controller name '%s' (lines %d and %d)\n",
|
||||
c->name, c->linenum, cip->linenum);
|
||||
}
|
||||
|
||||
mc = new_struct(struct mb_ctlr);
|
||||
mc->mc_ctlr = getnum(cip);
|
||||
mc->mc_addr = (caddr_t)cip->csr;
|
||||
mc->mc_intpri = cip->priority;
|
||||
mc->mc_space = cip->space;
|
||||
#ifdef sun386
|
||||
mc->mc_intr = cip->irq;
|
||||
mc->mc_dmachan = cip->dmachan;
|
||||
#else
|
||||
mc->mc_intr = gen_vector(cip->vectors);
|
||||
#endif
|
||||
return (mc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate an mb_device entry for this device.
|
||||
*/
|
||||
static struct mb_device *
|
||||
gen_device(cip)
|
||||
struct confinfo *cip;
|
||||
{
|
||||
struct mb_device *md;
|
||||
struct confinfo *c;
|
||||
|
||||
if (dopt)
|
||||
printf("gen_device\n");
|
||||
|
||||
/*
|
||||
* Check for duplicate devices on the same controller
|
||||
*/
|
||||
for (c = confinfo; c; c = c->next) {
|
||||
if (c == cip || c->type != VDCDEVICE ||
|
||||
c->drive != cip->drive ||
|
||||
getctlrnum(c) != getctlrnum(cip))
|
||||
continue;
|
||||
|
||||
if (streq(c->name, cip->name))
|
||||
fatal(
|
||||
"Duplicate device name '%s' (lines %d and %d)\n",
|
||||
c->name, c->linenum, cip->linenum);
|
||||
}
|
||||
|
||||
md = new_struct(struct mb_device);
|
||||
md->md_unit = getnum(cip);
|
||||
md->md_ctlr = getctlrnum(cip);
|
||||
md->md_slave = cip->drive;
|
||||
md->md_addr = (caddr_t)cip->csr;
|
||||
md->md_intpri = cip->priority;
|
||||
md->md_space = cip->space;
|
||||
#ifdef sun386
|
||||
md->md_intr = cip->irq;
|
||||
md->md_dmachan = cip->dmachan;
|
||||
#else
|
||||
md->md_intr = gen_vector(cip->vectors);
|
||||
#endif
|
||||
return (md);
|
||||
}
|
||||
|
||||
#ifndef sun386
|
||||
|
||||
static struct vec *
|
||||
gen_vector(veclist)
|
||||
struct veclist *veclist;
|
||||
{
|
||||
int nvec;
|
||||
struct veclist *vp, *nvp;
|
||||
struct vec *v, *v0;
|
||||
int *ip;
|
||||
|
||||
nvec = 0;
|
||||
for (vp = veclist; vp != NULL; vp = vp->next)
|
||||
nvec++;
|
||||
|
||||
if (nvec == 0)
|
||||
return (NULL);
|
||||
|
||||
v0 = v = new_array(struct vec, nvec + 1);
|
||||
ip = new_array(int, nvec + 1);
|
||||
|
||||
for (vp = veclist; vp != NULL; vp = nvp) {
|
||||
*v = vp->vec;
|
||||
v->v_vptr = ip;
|
||||
*ip++ = v->v_vec;
|
||||
v++;
|
||||
nvp = vp->next;
|
||||
free((char *)vp);
|
||||
}
|
||||
v = NULL;
|
||||
|
||||
return ((struct vec *)v0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Get the number from the controller or device name.
|
||||
* For example, if the name is fdc2 then this routine will return 2.
|
||||
*/
|
||||
static int
|
||||
getnum(cip)
|
||||
struct confinfo *cip;
|
||||
{
|
||||
char *np = cip->name, *p;
|
||||
long num;
|
||||
|
||||
while (*np != '\0' && !isdigit(*np))
|
||||
np++;
|
||||
|
||||
if (*np == '\0')
|
||||
fatal("missing unit number in '%s' on line %d\n",
|
||||
cip->name, cip->linenum);
|
||||
num = strtol(np, &p, 10);
|
||||
if (*p != '\0')
|
||||
fatal("Invalid device or controller name '%s' (line %d)\n",
|
||||
cip->name, cip->linenum);
|
||||
|
||||
return (num);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the controller number for this device.
|
||||
* returns -1 if there is no controller.
|
||||
*/
|
||||
static int
|
||||
getctlrnum(cip)
|
||||
struct confinfo *cip;
|
||||
{
|
||||
struct confinfo *c;
|
||||
char *name, *cname;
|
||||
int namelen;
|
||||
|
||||
if (dopt)
|
||||
printf("getctlrnum\n");
|
||||
|
||||
if (cip->space != 0)
|
||||
return (-1); /* no controller */
|
||||
|
||||
for (c = confinfo; c; c = c->next) {
|
||||
if (c->type != VDCCONTROLLER)
|
||||
continue;
|
||||
|
||||
if (streq(cip->conname, c->name)) {
|
||||
/*
|
||||
* We've found the controller that we're connected to.
|
||||
* Now let's make sure that our name makes sense.
|
||||
* For example, controller "fdc0" is supposed to have
|
||||
* devices with names such as "fd0", "fd1", etc.
|
||||
*/
|
||||
name = getname(cip); /* get dev name without num */
|
||||
cname = getname(c); /* get ctrl name without num */
|
||||
namelen = strlen(name);
|
||||
|
||||
if (strncmp(name, cname, namelen) != 0 ||
|
||||
cname[namelen] != 'c')
|
||||
fatal(
|
||||
"invalid device name '%s' for controller %s (lines %d and %d)\n",
|
||||
cip->name, c->name, cip->linenum, c->linenum);
|
||||
|
||||
return (getnum(c));
|
||||
}
|
||||
}
|
||||
fatal(
|
||||
"Device '%s' is connected to an unknown controller '%s' (line %d)\n",
|
||||
cip->name, cip->conname, cip->linenum);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the name (minus the number) of a controller or device.
|
||||
*/
|
||||
static char *
|
||||
getname(cip)
|
||||
struct confinfo *cip;
|
||||
{
|
||||
int len;
|
||||
char *p;
|
||||
|
||||
if (dopt)
|
||||
printf("getname\n");
|
||||
|
||||
p = cip->name;
|
||||
while (*p != '\0' && !isdigit(*p))
|
||||
p++;
|
||||
|
||||
len = p - cip->name;
|
||||
p = new_string(len);
|
||||
strncpy(p, cip->name, len);
|
||||
p[len] = '\0';
|
||||
|
||||
return (p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a confinfo entry for a controller.
|
||||
*/
|
||||
static void
|
||||
conf_controller(fp, cip)
|
||||
FILE *fp;
|
||||
struct confinfo *cip;
|
||||
{
|
||||
if (dopt)
|
||||
printf("conf_controller\n");
|
||||
|
||||
cip->type = VDCCONTROLLER;
|
||||
cip->name = getstring(fp);
|
||||
read_literal(fp, "at");
|
||||
getbusconn(fp, cip, VDCCONTROLLER); /* get bus that controller is on */
|
||||
read_literal(fp, "?");
|
||||
getoptions(fp, cip);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a confinfo entry for a disk.
|
||||
*/
|
||||
static void
|
||||
conf_disk(fp, cip)
|
||||
FILE *fp;
|
||||
struct confinfo *cip;
|
||||
{
|
||||
if (dopt)
|
||||
printf("conf_disk\n");
|
||||
|
||||
conf_device(fp, cip);
|
||||
cip->disk = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a confinfo entry for a device.
|
||||
*/
|
||||
static void
|
||||
conf_device(fp, cip)
|
||||
FILE *fp;
|
||||
struct confinfo *cip;
|
||||
{
|
||||
|
||||
if (dopt)
|
||||
printf("conf_device\n");
|
||||
|
||||
cip->type = VDCDEVICE;
|
||||
cip->name = getstring(fp); /* get device name and number */
|
||||
read_literal(fp, "at");
|
||||
getbusconn(fp, cip, VDCDEVICE); /* get bus connection */
|
||||
if (cip->space != 0)
|
||||
read_literal(fp, "?");
|
||||
getoptions(fp, cip); /* get the rest of the options */
|
||||
}
|
||||
#endif /* sun4c */
|
||||
|
||||
/*
|
||||
* Generate a confinfo entry for a blockmajor configuration line.
|
||||
*/
|
||||
static void
|
||||
conf_blockmajor(fp, cip)
|
||||
FILE *fp;
|
||||
struct confinfo *cip;
|
||||
{
|
||||
cip->type = VDCBLOCKMAJOR;
|
||||
cip->majornum = getint(fp, 0, 255);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a confinfo entry for a charmajor configuration line.
|
||||
*/
|
||||
static void
|
||||
conf_charmajor(fp, cip)
|
||||
FILE *fp;
|
||||
struct confinfo *cip;
|
||||
{
|
||||
cip->type = VDCCHARMAJOR;
|
||||
cip->majornum = getint(fp, 0, 255);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a confinfo entry for a system call number configuration line.
|
||||
*/
|
||||
static void
|
||||
conf_syscallnum(fp, cip)
|
||||
FILE *fp;
|
||||
struct confinfo *cip;
|
||||
{
|
||||
cip->type = VDCSYSCALLNUM;
|
||||
cip->syscallnum = getint(fp, 0, 255);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a confinfo entry for this line in the configuration file.
|
||||
*/
|
||||
static struct confinfo *
|
||||
getcip()
|
||||
{
|
||||
struct confinfo *cip;
|
||||
|
||||
cip = new_struct(struct confinfo);
|
||||
bzero((char *)cip, sizeof (struct confinfo));
|
||||
return (cip);
|
||||
}
|
||||
|
||||
#ifndef sun4c
|
||||
/*
|
||||
* Get a bus connection. For a controller it must be on the names
|
||||
* in the table "bustype". For a device it can either be one of
|
||||
* names in the table "bustype" or the name of a controller.
|
||||
*/
|
||||
static void
|
||||
getbusconn(fp, cip, type)
|
||||
FILE *fp;
|
||||
struct confinfo *cip;
|
||||
int type;
|
||||
{
|
||||
register struct bustype *btp;
|
||||
|
||||
cip->conname = getstring(fp); /* get bus connection */
|
||||
|
||||
for (btp = bustype; btp->name != NULL; btp++) {
|
||||
if (streq(btp->name, cip->conname))
|
||||
break;
|
||||
}
|
||||
|
||||
if (btp->name != NULL)
|
||||
cip->space = btp->type;
|
||||
else if (type == VDCCONTROLLER) {
|
||||
fatal("Unrecognized bus type '%s' on line %d\n",
|
||||
cip->conname, cip->linenum);
|
||||
} else
|
||||
cip->space = 0;
|
||||
}
|
||||
#endif /* sun4c */
|
||||
|
||||
/*
|
||||
* Copy a string from the configuration file.
|
||||
*/
|
||||
static char *
|
||||
getstring(fp)
|
||||
FILE *fp;
|
||||
{
|
||||
char *word;
|
||||
|
||||
word = getword(fp);
|
||||
if (word == NULL)
|
||||
fatal("missing string at line %d\n", linenum);
|
||||
return (strdup(word));
|
||||
}
|
||||
|
||||
/*
|
||||
* Get an integer from the next word in the configuration file.
|
||||
*/
|
||||
static int
|
||||
getint(fp, min, max)
|
||||
FILE *fp;
|
||||
int min, max;
|
||||
{
|
||||
char *word, *p;
|
||||
long n;
|
||||
|
||||
if (dopt)
|
||||
printf("getint\n");
|
||||
|
||||
word = getword(fp);
|
||||
if (word == NULL)
|
||||
fatal("missing integer at line %d\n", linenum);
|
||||
|
||||
n = strtol(word, &p, 0);
|
||||
if (*p != '\0' || (min != -1 && n < min) || (max != -1 && n > max))
|
||||
fatal("Invalid number '%s' on line %d\n", word, linenum);
|
||||
|
||||
if (dopt)
|
||||
printf("word: %s, value %x\n", word, n);
|
||||
|
||||
return (n);
|
||||
}
|
||||
|
||||
#ifndef sun4c
|
||||
/*
|
||||
* Get device and controller options.
|
||||
*/
|
||||
static int
|
||||
getoptions(fp, cip)
|
||||
FILE *fp;
|
||||
register struct confinfo *cip;
|
||||
{
|
||||
register struct options *opt;
|
||||
|
||||
char *word;
|
||||
|
||||
if (dopt)
|
||||
printf("getoptions\n");
|
||||
|
||||
while ((word = getword(fp)) != NULL) {
|
||||
if (dopt)
|
||||
printf("option: %s\n", word);
|
||||
|
||||
for (opt = options; opt->name != NULL; opt++) {
|
||||
if (streq(opt->name, word))
|
||||
break;
|
||||
}
|
||||
|
||||
if (opt->name != NULL)
|
||||
(*opt->optfcn)(fp, cip);
|
||||
else
|
||||
fatal("Unrecognized keyword '%s' on line %d\n",
|
||||
word, cip->linenum);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the drive number.
|
||||
*/
|
||||
static void
|
||||
getdrive(fp, cip)
|
||||
FILE *fp;
|
||||
struct confinfo *cip;
|
||||
{
|
||||
if (dopt)
|
||||
printf("getdrive\n");
|
||||
|
||||
cip->drive = getint(fp, 0, 255);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the csr.
|
||||
*/
|
||||
static void
|
||||
getcsr(fp, cip)
|
||||
FILE *fp;
|
||||
struct confinfo *cip;
|
||||
{
|
||||
if (dopt)
|
||||
printf("getcsr\n");
|
||||
|
||||
cip->csr = getint(fp, -1, -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the interrupt request number.
|
||||
*/
|
||||
static void
|
||||
getirq(fp, cip)
|
||||
FILE *fp;
|
||||
struct confinfo *cip;
|
||||
{
|
||||
if (dopt)
|
||||
printf("getirq\n");
|
||||
|
||||
cip->irq = getint(fp, 0, 15);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get VME interrupt vector
|
||||
*/
|
||||
static void
|
||||
getvector(fp, cip)
|
||||
FILE *fp;
|
||||
struct confinfo *cip;
|
||||
{
|
||||
struct veclist *v;
|
||||
char *handler_name;
|
||||
struct nlist n[2];
|
||||
int vecno;
|
||||
|
||||
if (dopt)
|
||||
printf("getvector\n");
|
||||
|
||||
v = new_struct(struct veclist);
|
||||
handler_name = getstring(fp);
|
||||
vecno = getint(fp, 0x40, 0xff);
|
||||
bzero((char *)n, sizeof (n));
|
||||
n[0].n_name = new_string(strlen(handler_name) + 2);
|
||||
n[0].n_name[0] = '_';
|
||||
strcpy(&n[0].n_name[1], handler_name);
|
||||
if (nlist(outputfile, n) == -1)
|
||||
fatal("can't read %s symbol table\n", outputfile);
|
||||
if ((n[0].n_type & N_TYPE) != N_TEXT)
|
||||
fatal("lookup of %s failed\n", handler_name);
|
||||
v->vec.v_func = (int (*)()) n[0].n_value;
|
||||
v->vec.v_vec = vecno;
|
||||
v->vec.v_vptr = NULL;
|
||||
v->next = cip->vectors;
|
||||
cip->vectors = v;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the interrupt priority.
|
||||
*/
|
||||
static void
|
||||
getpriority(fp, cip)
|
||||
FILE *fp;
|
||||
struct confinfo *cip;
|
||||
{
|
||||
if (dopt)
|
||||
printf("getpriority\n");
|
||||
|
||||
cip->priority = getint(fp, 0, 7);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the dma channel.
|
||||
*/
|
||||
static void
|
||||
getdmachan(fp, cip)
|
||||
FILE *fp;
|
||||
struct confinfo *cip;
|
||||
{
|
||||
if (dopt)
|
||||
printf("getdmachan\n");
|
||||
|
||||
cip->dmachan = getint(fp, -1, -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the flags.
|
||||
*/
|
||||
static void
|
||||
getflags(fp, cip)
|
||||
FILE *fp;
|
||||
struct confinfo *cip;
|
||||
{
|
||||
if (dopt)
|
||||
printf("getflags\n");
|
||||
|
||||
cip->flags = getint(fp, -1, -1);
|
||||
}
|
||||
#endif /* sun4c */
|
||||
|
||||
/*
|
||||
* Allocate a block of memory.
|
||||
*/
|
||||
static char *
|
||||
alloc(nelem, elsize)
|
||||
u_int nelem, elsize;
|
||||
{
|
||||
register char *addr = calloc(nelem, elsize);
|
||||
|
||||
if (addr == NULL)
|
||||
fatal("out of memory (size = %x)\n", nelem * elsize);
|
||||
|
||||
return (addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* getword
|
||||
* return next word of current input line; returns NULL on EOF,
|
||||
* end of line, or comment.
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
static char *
|
||||
getword(fp)
|
||||
FILE *fp;
|
||||
{
|
||||
static char *word = NULL;
|
||||
|
||||
word = strtok((word == NULL) ? line : NULL, " \t\n");
|
||||
if (word != NULL && *word == COMMENT_CHAR)
|
||||
word = NULL; /* skip comments */
|
||||
|
||||
return (word);
|
||||
}
|
||||
|
||||
static void
|
||||
read_literal(fp, literal)
|
||||
FILE *fp;
|
||||
char *literal;
|
||||
{
|
||||
char *s = getword(fp);
|
||||
|
||||
if (s == NULL || !streq(s, literal))
|
||||
fatal("missing keyword '%s' at line %d\n", literal, linenum);
|
||||
}
|
||||
235
usr.etc/mod/modloadhdr.c
Normal file
235
usr.etc/mod/modloadhdr.c
Normal file
@@ -0,0 +1,235 @@
|
||||
/* @(#)modloadhdr.c 1.1 94/10/31 SMI */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1988 by Sun Microsystems, Inc.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#ifdef sun386
|
||||
#include <sys/filehdr.h>
|
||||
#include <sys/scnhdr.h>
|
||||
#include <sys/aouthdr.h>
|
||||
#endif
|
||||
|
||||
#include <sys/exec.h>
|
||||
|
||||
void fatal(), vinfo();
|
||||
|
||||
#ifdef sun386
|
||||
|
||||
#define NUMSECS 4 /* number of section headers in the image */
|
||||
/* (text, data, bss, and comment) */
|
||||
/*
|
||||
* Get information about an image file. This is called to read
|
||||
* the headers of either the module being loaded or the kernel image file.
|
||||
*/
|
||||
readhdr(mmapaddr, tvaddr, tsize, toffset, dvaddr, dsize, doffset, bvaddr, bsize)
|
||||
caddr_t mmapaddr;
|
||||
u_int *tvaddr;
|
||||
u_int *tsize;
|
||||
u_int *toffset;
|
||||
u_int *dvaddr;
|
||||
u_int *dsize;
|
||||
u_int *doffset;
|
||||
u_int *bvaddr;
|
||||
u_int *bsize;
|
||||
{
|
||||
struct filehdr *fhdr;
|
||||
struct aouthdr *optaout; /* optional a.out header */
|
||||
struct scnhdr *scn; /* COFF per-section info */
|
||||
unsigned int numsecs; /* number of COFF sections in file */
|
||||
unsigned int scns = 0; /* must have all three sections! */
|
||||
|
||||
/*
|
||||
* Read the image file header to get module sizes.
|
||||
*/
|
||||
fhdr = (struct filehdr *)mmapaddr;
|
||||
|
||||
/* check and see if this is a COFF header. */
|
||||
if (!ISCOFF(fhdr->f_magic))
|
||||
fatal("module image is not a valid COFF file\n");
|
||||
|
||||
numsecs = fhdr->f_nscns; /* get number of section headers */
|
||||
|
||||
if (numsecs != NUMSECS)
|
||||
fatal("there must be only text, data, bss, and comment sections\n");
|
||||
if (fhdr->f_opthdr != sizeof(struct aouthdr))
|
||||
fatal("invalid a.out header\n");
|
||||
|
||||
optaout = (struct aouthdr *)(mmapaddr +sizeof(struct filehdr));
|
||||
|
||||
/*
|
||||
* let's get magic number and entry location from optional
|
||||
* a.out header.
|
||||
*/
|
||||
if (optaout->magic != ZMAGIC && optaout->magic != OMAGIC &&
|
||||
optaout->magic != NMAGIC)
|
||||
fatal("bad a.out header magic number\n", optaout->magic);
|
||||
|
||||
/*
|
||||
* go through each COFF section header and get
|
||||
* text, data, and bss sizes.
|
||||
*/
|
||||
scn = (struct scnhdr *)(mmapaddr + sizeof(struct filehdr) +
|
||||
sizeof(struct aouthdr));
|
||||
|
||||
while (numsecs-- > 0) {
|
||||
switch ((int) scn->s_flags) {
|
||||
case STYP_TEXT:
|
||||
if (scn->s_size == 0)
|
||||
fatal("text size is 0\n");
|
||||
|
||||
*tvaddr = ptob(btop(scn->s_vaddr));
|
||||
*tsize = scn->s_size;
|
||||
if (optaout->magic == ZMAGIC)
|
||||
*tsize += gethdrsize();
|
||||
|
||||
scns |= STYP_TEXT;
|
||||
break;
|
||||
|
||||
case STYP_DATA:
|
||||
if (scn->s_size == 0)
|
||||
fatal("data size is 0\n");
|
||||
|
||||
*dvaddr = scn->s_vaddr;
|
||||
*dsize = scn->s_size;
|
||||
*doffset = scn->s_scnptr;
|
||||
|
||||
scns |= STYP_DATA;
|
||||
break;
|
||||
|
||||
case STYP_BSS:
|
||||
*bvaddr = scn->s_vaddr;
|
||||
*bsize = ctob(btoc(scn->s_size));
|
||||
scns |= STYP_BSS;
|
||||
break;
|
||||
}
|
||||
|
||||
scn++; /* point to next section header */
|
||||
}
|
||||
|
||||
/*
|
||||
* For now, we assume there must be data and bss sections.
|
||||
* Someday, we can ease this restriction.
|
||||
*/
|
||||
if (scns != (STYP_TEXT|STYP_DATA|STYP_BSS))
|
||||
fatal("missing text, data, or bss sections\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the size of the file headers in the memory image for the file.
|
||||
*/
|
||||
gethdrsize()
|
||||
{
|
||||
return (sizeof(struct filehdr) + sizeof(struct aouthdr) +
|
||||
NUMSECS * sizeof(struct scnhdr));
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the virtual address and offset of the kernel data segment
|
||||
*/
|
||||
getkerneldata(mmapaddr, daddr, doffset)
|
||||
caddr_t mmapaddr;
|
||||
u_int *daddr;
|
||||
u_int *doffset;
|
||||
{
|
||||
u_int xxx;
|
||||
|
||||
readhdr(mmapaddr, &xxx, &xxx, &xxx, daddr, &xxx, doffset, &xxx, &xxx);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* Get information about an image file. This is called to read
|
||||
* the headers of either the module being loaded or the kernel image file.
|
||||
*/
|
||||
readhdr(mmapaddr, tvaddr, tsize, toffset, dvaddr, dsize, doffset, bvaddr, bsize)
|
||||
addr_t mmapaddr;
|
||||
u_int *tvaddr;
|
||||
u_int *tsize;
|
||||
u_int *toffset;
|
||||
u_int *dvaddr;
|
||||
u_int *dsize;
|
||||
u_int *doffset;
|
||||
u_int *bvaddr;
|
||||
u_int *bsize;
|
||||
{
|
||||
register struct exec *exec = (struct exec *)mmapaddr;
|
||||
|
||||
extern u_long mod_addr;
|
||||
|
||||
if (exec->a_magic != OMAGIC)
|
||||
fatal("module image is not a valid OMAGIC a.out file\n");
|
||||
|
||||
*tvaddr = mod_addr;
|
||||
*tsize = exec->a_text;
|
||||
*toffset = sizeof(struct exec);
|
||||
|
||||
*dvaddr = *tvaddr + exec->a_text;
|
||||
*dsize = exec->a_data;
|
||||
*doffset = *toffset + exec->a_text;
|
||||
|
||||
*bvaddr = *dvaddr + exec->a_data;
|
||||
*bsize = exec->a_bss;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the size of the file headers in the memory image for the file.
|
||||
*/
|
||||
gethdrsize()
|
||||
{
|
||||
return (0); /* OMAGIC has no header in memory */
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the virtual address and offset of the kernel data segment
|
||||
*/
|
||||
getkerneldata(mmapaddr, daddr, doffset)
|
||||
caddr_t mmapaddr;
|
||||
u_int *daddr;
|
||||
u_int *doffset;
|
||||
{
|
||||
register struct exec *exec = (struct exec *)mmapaddr;
|
||||
|
||||
if (exec->a_magic != OMAGIC)
|
||||
fatal("module image is not a valid OMAGIC a.out file\n");
|
||||
|
||||
*daddr = exec->a_entry + exec->a_text;
|
||||
*doffset = sizeof(struct exec) + exec->a_text;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Verify that virtual addresses and sizes are ok.
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
checkhdr(tvaddr, tsize, toffset, dvaddr, dsize, doffset, bvaddr, bsize)
|
||||
u_int tvaddr;
|
||||
u_int tsize;
|
||||
u_int toffset;
|
||||
u_int dvaddr;
|
||||
u_int dsize;
|
||||
u_int doffset;
|
||||
u_int bvaddr;
|
||||
u_int bsize;
|
||||
{
|
||||
vinfo("textv %x, ts %x, datav %x, ds %x, bssv %x, bs %x\n",
|
||||
tvaddr, tsize, dvaddr, dsize, bvaddr, bsize);
|
||||
|
||||
if (tsize == 0)
|
||||
fatal("text size is 0\n");
|
||||
|
||||
if (tvaddr + tsize != dvaddr)
|
||||
fatal("data must immediately follow the text\n");
|
||||
|
||||
#ifdef COFF
|
||||
if (bvaddr < dvaddr || ctob(btoc(dvaddr + dsize)) != bvaddr)
|
||||
fatal("bss must start in the page following the data\n");
|
||||
#endif
|
||||
}
|
||||
260
usr.etc/mod/modloadsym.c
Normal file
260
usr.etc/mod/modloadsym.c
Normal file
@@ -0,0 +1,260 @@
|
||||
/* @(#)modloadsym.c 1.1 94/10/31 SMI */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1988 by Sun Microsystems, Inc.
|
||||
*/
|
||||
|
||||
#ifdef sun386
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <filehdr.h>
|
||||
#include <ldfcn.h>
|
||||
#include <stab.h>
|
||||
#include <syms.h>
|
||||
#include <ar.h>
|
||||
#include <sun/vddrv.h>
|
||||
|
||||
#define SYMESZ 18 /* number of bytes in one symbol table entry */
|
||||
|
||||
void fatal();
|
||||
|
||||
/*
|
||||
* Read the symbol table (if any) and keep only those symbols which
|
||||
* are within the module.
|
||||
*
|
||||
* This code from taken from nm.c.
|
||||
*
|
||||
* Someday we'll have support from the linker to do all this.
|
||||
*/
|
||||
|
||||
LDFILE *fi;
|
||||
|
||||
getsymtab(filename, mmapaddr, modstart, modsize)
|
||||
char *filename;
|
||||
addr_t mmapaddr;
|
||||
u_long modstart;
|
||||
u_int modsize;
|
||||
{
|
||||
long symindx; /* symbol table index */
|
||||
u_int sym_tab_size; /* symbol table size */
|
||||
|
||||
SYMENT *symp; /* pointer to symbol table */
|
||||
SYMENT sym; /* symbol table entry */
|
||||
AUXENT aux;
|
||||
|
||||
char *malloc();
|
||||
char *symnametmp; /* ptr to symbol name in file*/
|
||||
|
||||
int i;
|
||||
int nsyms; /* number of symbols we'll keep */
|
||||
struct vdsym *vdsym; /* start of sym tab in mmap'd image */
|
||||
int vdstroff; /* offset of sym name in mmap'd image */
|
||||
char *vdstraddr; /* address of name in mmap'd image */
|
||||
struct filehdr *fhdr; /* pointer to filehdr in mmap'd image */
|
||||
|
||||
extern int ncompare();
|
||||
|
||||
if ((fi = ldopen(filename, fi)) == NULL)
|
||||
fatal("modload: %s: cannot open\n", filename);
|
||||
|
||||
if (!ISCOFF(HEADER(fi).f_magic))
|
||||
fatal("modload: %s: bad magic\n", filename);
|
||||
|
||||
if (HEADER(fi).f_nsyms == 0)
|
||||
return (0); /* no symbols */
|
||||
|
||||
/*
|
||||
* seek to the symbol table
|
||||
*/
|
||||
if (ldtbseek(fi) != SUCCESS)
|
||||
fatal("modload: %s: symbols missing from file", filename);
|
||||
|
||||
/*
|
||||
* allocate symbol table memory
|
||||
* the amount of memory needed is calculated by the
|
||||
* number of entries multiplied by the size of each entry
|
||||
*/
|
||||
sym_tab_size = HEADER(fi).f_nsyms * sizeof (struct syment);
|
||||
symp = (struct syment *)malloc(sym_tab_size);
|
||||
if (symp == NULL)
|
||||
fatal("ran out of memory processing symbol table", filename);
|
||||
|
||||
/*
|
||||
* read the symbol table
|
||||
*/
|
||||
nsyms = 0;
|
||||
for (symindx = 0L; symindx < HEADER(fi).f_nsyms; ++symindx) {
|
||||
|
||||
if (FREAD(&sym, SYMESZ, 1, fi) != 1)
|
||||
fatal("error reading symbol table", filename);
|
||||
|
||||
/*
|
||||
* read in and skip over any aux entries (if there are any)
|
||||
*/
|
||||
for (i = 1; i <= sym.n_numaux; ++i) {
|
||||
if (FREAD(&aux, AUXESZ, 1, fi) != 1)
|
||||
fatal("error reading symnbol table", filename);
|
||||
++symindx;
|
||||
}
|
||||
|
||||
if ((u_int)sym.n_value < modstart ||
|
||||
(u_int)sym.n_value > modstart + modsize)
|
||||
continue; /* skip symbols out of range */
|
||||
|
||||
if (sym.n_name[0] == '.')
|
||||
continue; /* skip names starting with '.' */
|
||||
|
||||
symp[nsyms++] = sym;
|
||||
}
|
||||
|
||||
qsort((char *)symp, nsyms, sizeof(struct syment), ncompare);
|
||||
|
||||
/*
|
||||
* At this point we have the symbols that we're interested in
|
||||
* sorted by value. Now we will generate our own symbol table
|
||||
* and place it in our (private) mmap'd copy of the image.
|
||||
*
|
||||
* Our symbol table entry has 2 elements. The first is the offset
|
||||
* from the start of the symbol table to the name of the symbol.
|
||||
* This offset is converted to a virtual address by the VDLOAD ioctl
|
||||
* to /dev/vd. The second element is the symbol value.
|
||||
*/
|
||||
vdsym = (struct vdsym *)(mmapaddr + (int)(HEADER(fi).f_symptr));
|
||||
vdstroff = nsyms * sizeof(struct vdsym);
|
||||
vdstraddr = (char *)&vdsym[nsyms];
|
||||
|
||||
for (i = 0 ; i < nsyms; i++) {
|
||||
vdsym->vdsym_name = vdstroff;
|
||||
vdsym->vdsym_value = symp[i].n_value;
|
||||
vdsym++;
|
||||
symnametmp = (char *)ldgetname(fi, &symp[i]);
|
||||
strcpy(vdstraddr, symnametmp);
|
||||
vdstraddr += strlen(symnametmp) + 1;
|
||||
vdstroff += strlen(symnametmp) + 1;
|
||||
}
|
||||
fhdr = (struct filehdr *)mmapaddr;
|
||||
fhdr->f_nsyms = nsyms;
|
||||
|
||||
ldclose(fi);
|
||||
return (vdstroff); /* return symbol table size */
|
||||
}
|
||||
|
||||
static int ncompare(p1, p2)
|
||||
register struct syment *p1, *p2;
|
||||
{
|
||||
if (p1->n_value > p2->n_value)
|
||||
return(1);
|
||||
if (p1->n_value < p2->n_value)
|
||||
return(-1);
|
||||
return (0);
|
||||
}
|
||||
#else
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <a.out.h>
|
||||
#include <strings.h>
|
||||
#include <sun/vddrv.h>
|
||||
|
||||
void fatal();
|
||||
|
||||
/*
|
||||
* Read the symbol table (if any) and keep only those symbols which
|
||||
* are within the module.
|
||||
*
|
||||
* Some of this code if from _nlist.c.
|
||||
*/
|
||||
|
||||
getsymtab(filename, mmapaddr, modstart, modsize)
|
||||
char *filename;
|
||||
addr_t mmapaddr;
|
||||
u_long modstart;
|
||||
u_int modsize;
|
||||
{
|
||||
struct nlist *ksymp; /* pointer to symbols we're keeping */
|
||||
struct nlist *symp; /* pointer to sym table in a.out image*/
|
||||
struct nlist *symaddr; /* ptr to start of sym tab in image */
|
||||
char *symnametmp; /* ptr to symbol name in file*/
|
||||
|
||||
int i;
|
||||
int n;
|
||||
int nsyms; /* number of symbols we'll keep */
|
||||
struct vdsym *vdsym; /* start of sym tab in mmap'd image */
|
||||
int vdstroff; /* offset of sym name in mmap'd image */
|
||||
char *vdstraddr; /* address of name in mmap'd image */
|
||||
struct exec *exec; /* pointer to hdr in mmap'd image */
|
||||
|
||||
long straddr; /* start of strings in a.out image */
|
||||
|
||||
extern char *malloc();
|
||||
extern int ncompare();
|
||||
|
||||
exec = (struct exec *)mmapaddr; /* pointer to a.out header */
|
||||
|
||||
if (exec->a_magic != OMAGIC)
|
||||
fatal("modload: %s: bad magic %o\n", filename, exec->a_magic);
|
||||
|
||||
if (exec->a_syms == 0)
|
||||
return (0); /* no symbols */
|
||||
|
||||
nsyms = 0; /* number of syms we'll keep */
|
||||
|
||||
symaddr = (struct nlist *)(mmapaddr + N_SYMOFF(*exec));
|
||||
|
||||
symp = symaddr; /* ptr to first sym tab entry */
|
||||
ksymp = (struct nlist *)malloc((u_int)exec->a_syms);
|
||||
|
||||
if (ksymp == NULL)
|
||||
fatal("ran out of memory processing symbol table", filename);
|
||||
|
||||
for (n = exec->a_syms; n > 0; n -= sizeof(struct nlist), symp++) {
|
||||
if ((u_int)symp->n_value < modstart ||
|
||||
(u_int)symp->n_value > modstart + modsize)
|
||||
continue; /* skip symbols out of range */
|
||||
|
||||
ksymp[nsyms++] = *symp; /* keep this symtab entry */
|
||||
}
|
||||
|
||||
qsort((char *)ksymp, nsyms, sizeof(struct nlist), ncompare);
|
||||
|
||||
/*
|
||||
* At this point we have the symbols that we're interested in
|
||||
* sorted by value. Now we will generate our own symbol table
|
||||
* and place it in our (private) mmap'd copy of the image.
|
||||
*
|
||||
* Our symbol table entry has 2 elements. The first is the offset
|
||||
* from the start of the symbol table to the name of the symbol.
|
||||
* This offset is converted to a virtual address by the VDLOAD ioctl
|
||||
* to /dev/vd. The second element is the symbol value.
|
||||
*/
|
||||
vdsym = (struct vdsym *)symaddr;
|
||||
vdstroff = nsyms * sizeof(struct vdsym);
|
||||
vdstraddr = (char *)&vdsym[nsyms];
|
||||
straddr = (long)((long)symaddr + exec->a_syms);
|
||||
|
||||
for (i = 0; i < nsyms; i++) {
|
||||
symnametmp = (char *)(straddr + ksymp[i].n_un.n_strx);
|
||||
vdsym->vdsym_value = ksymp[i].n_value;
|
||||
vdsym->vdsym_name = vdstroff;
|
||||
vdsym++;
|
||||
|
||||
strcpy(vdstraddr, symnametmp);
|
||||
vdstraddr += strlen(symnametmp) + 1;
|
||||
vdstroff += strlen(symnametmp) + 1;
|
||||
}
|
||||
exec->a_syms = nsyms;
|
||||
|
||||
return (vdstroff); /* return symbol table size */
|
||||
}
|
||||
|
||||
static int ncompare(p1, p2)
|
||||
register struct nlist *p1, *p2;
|
||||
{
|
||||
if (p1->n_value > p2->n_value)
|
||||
return(1);
|
||||
if (p1->n_value < p2->n_value)
|
||||
return(-1);
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
194
usr.etc/mod/modstat.c
Normal file
194
usr.etc/mod/modstat.c
Normal file
@@ -0,0 +1,194 @@
|
||||
/* @(#)modstat.c 1.1 94/10/31 SMI */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1988 by Sun Microsystems, Inc.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <machine/param.h>
|
||||
#include <sun/vddrv.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern void error();
|
||||
|
||||
struct vdioctl_stat vdistat;
|
||||
int stat_all, verbose;
|
||||
|
||||
/*
|
||||
* Display status of all loaded modules
|
||||
*/
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
struct vdstat vdstat;
|
||||
int first_mod = 1, fd;
|
||||
|
||||
/*
|
||||
* Open the pseudo-driver.
|
||||
*/
|
||||
if ((fd = open("/dev/vd", O_RDONLY, 0)) < 0)
|
||||
error("can't open /dev/vd");
|
||||
|
||||
get_args(argc, argv);
|
||||
|
||||
do {
|
||||
vdistat.vdi_vdstat = &vdstat; /* status buffer */
|
||||
vdistat.vdi_vdstatsize = sizeof (struct vdstat); /* buf size*/
|
||||
/*
|
||||
* Get info about a loaded module.
|
||||
*/
|
||||
if (ioctl(fd, VDSTAT, (char *)&vdistat) < 0)
|
||||
error("can't get module status");
|
||||
|
||||
if (vdistat.vdi_vdstatsize == 0) {
|
||||
if (verbose)
|
||||
printf("no modules loaded\n");
|
||||
exit(0); /* nothing loaded */
|
||||
}
|
||||
if (first_mod) {
|
||||
first_mod = 0;
|
||||
printf(
|
||||
"Id Type Loadaddr Size B-major C-major Sysnum Mod Name\n");
|
||||
}
|
||||
print_status(&vdstat);
|
||||
} while (stat_all && vdistat.vdi_id != -1);
|
||||
|
||||
exit(0);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
get_args(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
verbose = 0;
|
||||
stat_all = 1;
|
||||
vdistat.vdi_id = -1;
|
||||
|
||||
while (--argc != 0) {
|
||||
if (**++argv != '-')
|
||||
usage("Invalid option %s\n", *argv);
|
||||
|
||||
switch ((*argv)[1]) {
|
||||
case 'i':
|
||||
if ((*argv)[2] != 'd')
|
||||
usage("Invalid option %s\n", *argv);
|
||||
if (--argc == 0)
|
||||
usage("Missing module id\n");
|
||||
++argv;
|
||||
if (sscanf(*argv, "%d", &vdistat.vdi_id) != 1)
|
||||
usage("Invalid id %s\n", *argv);
|
||||
if (vdistat.vdi_id <= 0 || vdistat.vdi_id > VD_MAXID)
|
||||
usage("Invalid id %d\n", vdistat.vdi_id);
|
||||
stat_all = 0;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
usage("Invalid option %s\n", *argv);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Display info about a loaded module.
|
||||
*/
|
||||
print_status(vds)
|
||||
struct vdstat *vds;
|
||||
{
|
||||
register int magic = vds->vds_magic;
|
||||
register char *type;
|
||||
|
||||
printf("%2d ", vds->vds_id);
|
||||
|
||||
switch (magic) {
|
||||
case VDMAGIC_DRV:
|
||||
type = " Drv";
|
||||
break;
|
||||
|
||||
case VDMAGIC_NET:
|
||||
type = " Net";
|
||||
break;
|
||||
|
||||
case VDMAGIC_SYS:
|
||||
type = " Sys";
|
||||
break;
|
||||
|
||||
case VDMAGIC_USER:
|
||||
type = "User";
|
||||
break;
|
||||
|
||||
case VDMAGIC_PSEUDO:
|
||||
type = "Pdrv";
|
||||
break;
|
||||
|
||||
case VDMAGIC_MBDRV:
|
||||
type = "Mdrv";
|
||||
break;
|
||||
|
||||
case VDMAGIC_MBNET:
|
||||
type = "Mnet";
|
||||
break;
|
||||
|
||||
default:
|
||||
type = "????";
|
||||
break;
|
||||
}
|
||||
|
||||
printf("%4.4s %8x %8x ", type, vds->vds_vaddr, vds->vds_size);
|
||||
|
||||
switch (magic) {
|
||||
case VDMAGIC_DRV:
|
||||
case VDMAGIC_PSEUDO:
|
||||
case VDMAGIC_MBDRV:
|
||||
if (vds->vds_modinfo[0])
|
||||
printf("%3d. ", (vds->vds_modinfo[0] & 0xff));
|
||||
else
|
||||
printf(" ");
|
||||
|
||||
if (vds->vds_modinfo[1])
|
||||
printf("%3d. ", (vds->vds_modinfo[1] & 0xff));
|
||||
else
|
||||
printf(" ");
|
||||
|
||||
printf(" ");
|
||||
break;
|
||||
|
||||
case VDMAGIC_SYS:
|
||||
printf(" %3d ",
|
||||
(vds->vds_modinfo[0] & 0xff));
|
||||
break;
|
||||
|
||||
default:
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
vds->vds_modname[VDMAXNAMELEN - 1] = '\0';
|
||||
printf("%s\n",vds->vds_modname);
|
||||
}
|
||||
|
||||
#include <varargs.h>
|
||||
|
||||
/* VARARGS */
|
||||
usage(va_alist)
|
||||
va_dcl
|
||||
{
|
||||
va_list args;
|
||||
char *fmt;
|
||||
|
||||
va_start(args);
|
||||
fmt = va_arg(args, char *);
|
||||
(void)vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
(void)fprintf(stderr, "Usage: modstat [-v] [-id <N>]\n");
|
||||
exit(1);
|
||||
}
|
||||
37
usr.etc/mod/modsubr.c
Normal file
37
usr.etc/mod/modsubr.c
Normal file
@@ -0,0 +1,37 @@
|
||||
/* @(#)modsubr.c 1.1 94/10/31 SMI */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <varargs.h>
|
||||
|
||||
extern int errno;
|
||||
|
||||
/*VARARGS0*/
|
||||
void
|
||||
error(va_alist)
|
||||
va_dcl
|
||||
{
|
||||
va_list args;
|
||||
char *fmt;
|
||||
|
||||
va_start(args);
|
||||
fmt = va_arg(args, char *);
|
||||
vfprintf(stderr, fmt, args);
|
||||
fprintf(stderr, ": ");
|
||||
perror("");
|
||||
exit(errno);
|
||||
}
|
||||
|
||||
/*VARARGS0*/
|
||||
void
|
||||
fatal(va_alist)
|
||||
va_dcl
|
||||
{
|
||||
va_list args;
|
||||
char *fmt;
|
||||
|
||||
va_start(args);
|
||||
fmt = va_arg(args, char *);
|
||||
(void) vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
exit(-1);
|
||||
}
|
||||
151
usr.etc/mod/modunload.c
Normal file
151
usr.etc/mod/modunload.c
Normal file
@@ -0,0 +1,151 @@
|
||||
/* @(#)modunload.c 1.1 94/10/31 SMI */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1988 by Sun Microsystems, Inc.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <machine/param.h>
|
||||
|
||||
#include <sun/vddrv.h>
|
||||
|
||||
void error(), fatal();
|
||||
|
||||
char *execfile = NULL;
|
||||
struct vdioctl_unload vdiunload;
|
||||
|
||||
/*
|
||||
* Unload a loaded module.
|
||||
*/
|
||||
main(argc,argv,envp)
|
||||
int argc;
|
||||
char *argv[];
|
||||
char *envp[];
|
||||
{
|
||||
int child, fd;
|
||||
union wait status;
|
||||
|
||||
getargs(argc, argv); /* get arguments */
|
||||
|
||||
/*
|
||||
* Open the pseudo driver.
|
||||
*/
|
||||
if ((fd = open("/dev/vd",2)) < 0)
|
||||
error("can't open /dev/vd");
|
||||
|
||||
if (execfile) {
|
||||
child = fork();
|
||||
if (child == -1)
|
||||
error("can't fork %s", execfile);
|
||||
else if (child == 0)
|
||||
exec_userfile(fd, envp);
|
||||
else {
|
||||
wait(&status);
|
||||
if (status.w_retcode != 0) {
|
||||
printf("%s returned error %d.\n",
|
||||
execfile, status.w_retcode);
|
||||
exit((int)status.w_retcode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* issue an ioctl to unload the module.
|
||||
*/
|
||||
if (ioctl(fd, VDUNLOAD, &vdiunload) < 0)
|
||||
if (errno == EPERM)
|
||||
fatal("You must be superuser to unload a module\n");
|
||||
else
|
||||
error("can't unload the module");
|
||||
|
||||
exit(0); /* success */
|
||||
}
|
||||
|
||||
/*
|
||||
* Get user arguments.
|
||||
*/
|
||||
getargs(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
char *ap;
|
||||
|
||||
if (argc < 3)
|
||||
usage();
|
||||
|
||||
argc--; /* skip program name */
|
||||
argv++;
|
||||
|
||||
while (argc--) {
|
||||
ap = *argv++; /* point at next option */
|
||||
|
||||
if (*ap++ == '-') {
|
||||
if (strcmp(ap,"id") == 0) {
|
||||
if (--argc < 0)
|
||||
usage();
|
||||
if (sscanf(*argv++,"%d",&vdiunload.vdi_id) != 1)
|
||||
usage();
|
||||
} else if (strcmp(ap,"exec") == 0) {
|
||||
if (--argc < 0)
|
||||
usage();
|
||||
execfile = *argv++;
|
||||
} else
|
||||
usage();
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
usage()
|
||||
{
|
||||
fatal("usage: modunload -id <module_id> [-exec <exec_file>]\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* exec the user file.
|
||||
*/
|
||||
exec_userfile(fd, envp)
|
||||
int fd;
|
||||
char **envp;
|
||||
{
|
||||
struct vdioctl_stat vdistat;
|
||||
struct vdstat vdstat;
|
||||
|
||||
char id[8];
|
||||
char magic[16];
|
||||
char blockmajor[8];
|
||||
char charmajor[8];
|
||||
char sysnum[8];
|
||||
|
||||
vdistat.vdi_id = vdiunload.vdi_id; /* copy module id */
|
||||
vdistat.vdi_vdstat = &vdstat; /* status buffer */
|
||||
vdistat.vdi_vdstatsize = sizeof(struct vdstat); /* buf size */
|
||||
|
||||
if (ioctl(fd, VDSTAT, &vdistat) < 0)
|
||||
error("can't get module status");
|
||||
|
||||
sprintf(id, "%d", vdstat.vds_id);
|
||||
sprintf(magic, "%x", vdstat.vds_magic);
|
||||
|
||||
if (vdstat.vds_magic == VDMAGIC_DRV ||
|
||||
vdstat.vds_magic == VDMAGIC_MBDRV ||
|
||||
vdstat.vds_magic == VDMAGIC_PSEUDO) {
|
||||
sprintf(blockmajor, "%d", vdstat.vds_modinfo[0] & 0xff);
|
||||
sprintf(charmajor, "%d", vdstat.vds_modinfo[1] & 0xff);
|
||||
execle(execfile, execfile, id, magic, blockmajor,
|
||||
charmajor, (char *)0, envp);
|
||||
} else if (vdstat.vds_magic == VDMAGIC_SYS) {
|
||||
sprintf(sysnum, "%d", vdstat.vds_modinfo[0] & 0xff);
|
||||
execle(execfile, execfile, id, magic, sysnum, (char *)0, envp);
|
||||
} else
|
||||
execle(execfile, execfile, id, magic, (char *)0, envp);
|
||||
|
||||
error("couldn't exec %s\n", execfile);
|
||||
}
|
||||
Reference in New Issue
Block a user