[klibc] Re: klibc-0.72 released
Arnd Bergmann
arnd@bergmann-dalldorf.de
Sat, 11 Jan 2003 13:12:38 +0100
On Wednesday 08 January 2003 12:53, Rusty Russell wrote:
> I was hoping to test this first, but here's the mini-modprobe.
Ok, I just gave it a try, here's what I found so far.
I have attached a patch that adds this modprobe to klibc-0.72,
with the problems I found fixed. It now works on i386 and
at least compiles for s390 and s390x.
> #include <sys/unistd.h>
klibc only has <unistd.h>, not <sys/unistd.h>
> }
> fatal("Failed to open %s: %s\n", filename, strerror(errno));
> }
strerror() is disabled in klibc, you can only print errno here.
> ret = init_module(file, len, options);
The new system calls still have to be added to klibc/SYSCALLS
> if (symtab[j].st_shndx != SHN_UNDEF)
> continue;
> if ((sym = get_symbol(strtab + symtab[i].st_name)))
> modprobe(sym->owner, depth);
^^^^
that should read symtab[j]
> if (argc != 1)
> fatal("Usage: %s modulename\n"
> " Where modules are kept in "MODDIR"\n"
> " And options have extension "OPTEXT"\n", argv[0]);
and this should be 'if (argc != 2)'...
Arnd <><
--- klibc-0.72/utils/modprobe.c 1970-01-01 01:00:00.000000000 +0100
+++ klibc-0.72-modprobe/utils/modprobe.c 2003-01-10 19:48:47.000000000 +0100
@@ -0,0 +1,268 @@
+/* Minature, simplified, self-standing modprobe. */
+#include <stdio.h>
+#include <elf.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/module.h>
+
+/* All modules are in this directory. */
+#define MODDIR "/lib/modules"
+
+/* All modules end in this extension, eg. /lib/modules/rusty.ko */
+#define MODEXT ".ko"
+
+/* All option files end in this extension, eg. /lib/modules/rusty.ko.options */
+#define OPTEXT ".options"
+
+struct symbol
+{
+ struct symbol *next;
+ const char *owner;
+ char name[0];
+};
+
+#define SYMBOL_HASH_SIZE 1024
+static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
+
+#define error(fmt , ...) fprintf(stderr, fmt , ## __VA_ARGS__)
+#define fatal(fmt , ...) \
+ do { fprintf(stderr, fmt , ## __VA_ARGS__); exit(1); } while(0)
+
+static int modprobe(const char *modname, unsigned int depth);
+
+/* Read in the entire file. */
+static void *read_in(const char *entname, unsigned long *len, int noexistok)
+{
+ char *ret;
+ unsigned long done = 0;
+ int r, fd;
+ struct stat statbuf;
+ char filename[strlen(MODDIR) + 1 + strlen(entname) + 1];
+
+ sprintf(filename, "%s/%s", MODDIR, entname);
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ if (errno == ENOENT && noexistok) {
+ *len = 0;
+ return strdup("");
+ }
+ fatal("Failed to open %s: %d\n", filename, errno);
+ }
+ fstat(fd, &statbuf);
+ *len = statbuf.st_size;
+ ret = malloc(*len + 1);
+
+ while (done < *len) {
+ r = read(fd, ret + done, *len - done);
+ if (r <= 0)
+ fatal("Failed to read %s: %d\n", filename, errno);
+ done += r;
+ }
+ ret[*len] = '\0';
+ return ret;
+}
+
+/* This is based on the hash agorithm from gdbm, via tdb */
+static inline unsigned int tdb_hash(const char *name)
+{
+ unsigned value; /* Used to compute the hash value. */
+ unsigned i; /* Used to cycle through random values. */
+
+ /* Set the initial value from the key size. */
+ for (value = 0x238F13AF * strlen(name), i=0; name[i]; i++)
+ value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
+ return (1103515243 * value + 12345);
+}
+
+static void add_symbol(const char *name, const char *owner)
+{
+ unsigned int hash;
+ struct symbol *new = malloc(sizeof *new + strlen(name) + 1);
+
+ new->owner = owner;
+ strcpy(new->name, name);
+ hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
+ new->next = symbolhash[hash];
+ symbolhash[hash] = new;
+}
+
+static struct symbol *get_symbol(const char *name)
+{
+ struct symbol *s;
+
+ for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next)
+ if (strcmp(s->name, name) == 0)
+ break;
+ return s;
+}
+
+struct kernel_symbol32 {
+ char value[4];
+ char name[64 - 4];
+};
+
+struct kernel_symbol64 {
+ char value[8];
+ char name[64 - 8];
+};
+
+static void load_symbols32(Elf32_Ehdr *hdr, const char *module)
+{
+ unsigned int i, j;
+ struct kernel_symbol32 *ksyms;
+ Elf32_Shdr *sechdrs = (void *)hdr + hdr->e_shoff;
+ char *secnames = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+ for (i = 1; i < hdr->e_shnum; i++)
+ if (strcmp(secnames+sechdrs[i].sh_name, "__ksymtab") == 0) {
+ ksyms = (void *)hdr + sechdrs[i].sh_offset;
+ for (j = 0; j < sechdrs[i].sh_size/sizeof(*ksyms); j++)
+ add_symbol(ksyms[j].name, module);
+ }
+}
+
+static void load_symbols64(Elf64_Ehdr *hdr, const char *module)
+{
+ unsigned int i, j;
+ struct kernel_symbol64 *ksyms;
+ Elf64_Shdr *sechdrs = (void *)hdr + hdr->e_shoff;
+ char *secnames = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+ for (i = 1; i < hdr->e_shnum; i++)
+ if (strcmp(secnames+sechdrs[i].sh_name, "__ksymtab") == 0) {
+ ksyms = (void *)hdr + sechdrs[i].sh_offset;
+ for (j = 0; j < sechdrs[i].sh_size/sizeof(*ksyms); j++)
+ add_symbol(ksyms[j].name, module);
+ }
+}
+
+/* "\177ELF" <byte> where byte = 001 for 32-bit, 002 for 64 */
+static int elf_type(void *hdr, const char *entname)
+{
+ if (memcmp(hdr, ELFMAG, SELFMAG) != 0) {
+ error("Module %s is not ELF!\n", entname);
+ return ELFCLASSNONE;
+ }
+ return (((char *)hdr)[EI_CLASS]);
+}
+
+static void load_symbols(const char *entname)
+{
+ void *file;
+ unsigned long len;
+
+ file = read_in(entname, &len, 0);
+ if (elf_type(file, entname) == ELFCLASS32)
+ load_symbols32(file, entname);
+ else if (elf_type(file, entname) == ELFCLASS64)
+ load_symbols64(file, entname);
+ free(file);
+}
+
+static void get_needs32(Elf32_Ehdr *hdr, unsigned int depth)
+{
+ Elf32_Shdr *sechdrs = (void *)hdr + hdr->e_shoff;
+ Elf32_Sym *symtab;
+ char *strtab;
+ unsigned int i, j;
+ struct symbol *sym;
+
+ for (i = 1; i < hdr->e_shnum; i++) {
+ if (sechdrs[i].sh_type != SHT_SYMTAB)
+ continue;
+ symtab = (void *)hdr + sechdrs[i].sh_offset;
+ strtab = (void *)hdr + sechdrs[sechdrs[i].sh_link].sh_offset;
+ for (j = 0; j<sechdrs[i].sh_size/sizeof(*symtab); j++) {
+ if (symtab[j].st_shndx != SHN_UNDEF)
+ continue;
+ if ((sym = get_symbol(strtab + symtab[j].st_name)))
+ modprobe(sym->owner, depth);
+ }
+ }
+}
+
+static void get_needs64(Elf64_Ehdr *hdr, unsigned int depth)
+{
+ Elf64_Shdr *sechdrs = (void *)hdr + hdr->e_shoff;
+ Elf64_Sym *symtab;
+ char *strtab;
+ unsigned int i, j;
+ struct symbol *sym;
+
+ for (i = 1; i < hdr->e_shnum; i++) {
+ if (sechdrs[i].sh_type != SHT_SYMTAB)
+ continue;
+ symtab = (void *)hdr + sechdrs[i].sh_offset;
+ strtab = (void *)hdr + sechdrs[sechdrs[i].sh_link].sh_offset;
+ for (j = 0; j<sechdrs[i].sh_size/sizeof(*symtab); j++) {
+ if (symtab[j].st_shndx != SHN_UNDEF)
+ continue;
+ if ((sym = get_symbol(strtab + symtab[j].st_name)))
+ modprobe(sym->owner, depth);
+ }
+ }
+}
+
+static int modprobe(const char *modname, unsigned int depth)
+{
+ int ret;
+ void *file;
+ char *options, *ptr;
+ unsigned long len, optlen;
+ char optionname[strlen(modname) + 1 + sizeof(OPTEXT)];
+
+ if (depth > 50)
+ fatal("Modprobe loop: %s\n", modname);
+
+ /* Grab options if any: convert \n to ' ' */
+ sprintf(optionname, "%s%s", modname, OPTEXT);
+ options = read_in(optionname, &optlen, 1);
+ while ((ptr = strchr(options, '\n')) != NULL)
+ *ptr = ' ';
+
+ /* Grab dependencies */
+ file = read_in(modname, &len, 0);
+ if (elf_type(file, modname) == ELFCLASS32)
+ get_needs32(file, depth+1);
+ else if (elf_type(file, modname) == ELFCLASS64)
+ get_needs64(file, depth+1);
+
+ ret = init_module(file, len, options);
+ if (ret < 0 && errno != EEXIST)
+ fprintf(stderr, "Error loading module %s: %d\n",
+ modname, errno);
+ free(file);
+ free(options);
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ DIR *dir;
+ struct dirent *dirent;
+ char modname[strlen(argv[1]?:"") + sizeof(MODEXT)];
+
+ if (argc != 2)
+ fatal("Usage: %s modulename\n"
+ " Where modules are kept in "MODDIR"\n"
+ " And options have extension "OPTEXT"\n", argv[0]);
+
+ if (!(dir = opendir(MODDIR)))
+ fatal("Could not open directory %s\n", MODDIR);
+
+ while ((dirent = readdir(dir)) != NULL) {
+ unsigned int len = strlen(dirent->d_name);
+ if (len >= strlen(MODEXT)
+ && strcmp(dirent->d_name+len-strlen(MODEXT), MODEXT) == 0)
+ load_symbols(dirent->d_name);
+ }
+
+ sprintf(modname, "%s%s", argv[1], MODEXT);
+ return modprobe(modname, 0);
+}
diff -ur klibc-0.72/klibc/SYSCALLS klibc-0.72-modprobe/klibc/SYSCALLS
--- klibc-0.72/klibc/SYSCALLS 2002-09-11 07:00:58.000000000 +0200
+++ klibc-0.72-modprobe/klibc/SYSCALLS 2003-01-10 19:34:17.000000000 +0100
@@ -138,9 +138,7 @@
int uname(struct utsname *)
int setdomainname(const char *, size_t)
int sethostname(const char *, size_t)
-int init_module(const char *, struct module *)
-void * create_module(const char *, size_t)
-int delete_module(const char *)
-int query_module(const char *, int, void *, size_t, size_t)
+int init_module(void *, unsigned long, char *)
+long delete_module(const char *, unsigned int)
int reboot::__reboot(int, int, int, void *)
int syslog::klogctl(int, char *, int)
diff -ur klibc-0.72/klibc/include/sys/module.h klibc-0.72-modprobe/klibc/include/sys/module.h
--- klibc-0.72/klibc/include/sys/module.h 2002-08-06 06:28:41.000000000 +0200
+++ klibc-0.72-modprobe/klibc/include/sys/module.h 2003-01-10 20:03:06.000000000 +0100
@@ -1,158 +1,11 @@
/*
* sys/module.h
- *
- * This is a bastardized version of linux/module.h, since the latter
- * doesn't have __KERNEL__ guards where it needs them...
*/
#ifndef _SYS_MODULE_H
#define _SYS_MODULE_H
-/*
- * Dynamic loading of modules into the kernel.
- *
- * Rewritten by Richard Henderson <rth@tamu.edu> Dec 1996
- */
-
-#include <asm/atomic.h>
-
-/* Don't need to bring in all of uaccess.h just for this decl. */
-struct exception_table_entry;
-
-/* Used by get_kernel_syms, which is obsolete. */
-struct kernel_sym
-{
- unsigned long value;
- char name[60]; /* should have been 64-sizeof(long); oh well */
-};
-
-struct module_symbol
-{
- unsigned long value;
- const char *name;
-};
-
-struct module_ref
-{
- struct module *dep; /* "parent" pointer */
- struct module *ref; /* "child" pointer */
- struct module_ref *next_ref;
-};
-
-/* TBD */
-struct module_persist;
-
-struct module
-{
- unsigned long size_of_struct; /* == sizeof(module) */
- struct module *next;
- const char *name;
- unsigned long size;
-
- union
- {
- atomic_t usecount;
- long pad;
- } uc; /* Needs to keep its size - so says rth */
-
- unsigned long flags; /* AUTOCLEAN et al */
-
- unsigned nsyms;
- unsigned ndeps;
-
- struct module_symbol *syms;
- struct module_ref *deps;
- struct module_ref *refs;
- int (*init)(void);
- void (*cleanup)(void);
- const struct exception_table_entry *ex_table_start;
- const struct exception_table_entry *ex_table_end;
-#ifdef __alpha__
- unsigned long gp;
-#endif
- /* Members past this point are extensions to the basic
- module support and are optional. Use mod_member_present()
- to examine them. */
- const struct module_persist *persist_start;
- const struct module_persist *persist_end;
- int (*can_unload)(void);
- int runsize; /* In modutils, not currently used */
- const char *kallsyms_start; /* All symbols for kernel debugging */
- const char *kallsyms_end;
- const char *archdata_start; /* arch specific data for module */
- const char *archdata_end;
- const char *kernel_data; /* Reserved for kernel internal use */
-};
-
-struct module_info
-{
- unsigned long addr;
- unsigned long size;
- unsigned long flags;
- long usecount;
-};
-
-/* Bits of module.flags. */
-
-#define MOD_UNINITIALIZED 0
-#define MOD_RUNNING 1
-#define MOD_DELETED 2
-#define MOD_AUTOCLEAN 4
-#define MOD_VISITED 8
-#define MOD_USED_ONCE 16
-#define MOD_JUST_FREED 32
-#define MOD_INITIALIZING 64
-
-/* Values for query_module's which. */
-
-#define QM_MODULES 1
-#define QM_DEPS 2
-#define QM_REFS 3
-#define QM_SYMBOLS 4
-#define QM_INFO 5
-
-/* Can the module be queried? */
-#define MOD_CAN_QUERY(mod) (((mod)->flags & (MOD_RUNNING | MOD_INITIALIZING)) && !((mod)->flags & MOD_DELETED))
-
-/* When struct module is extended, we must test whether the new member
- is present in the header received from insmod before we can use it.
- This function returns true if the member is present. */
-
-#define mod_member_present(mod,member) \
- ((unsigned long)(&((struct module *)0L)->member + 1) \
- <= (mod)->size_of_struct)
-
-/*
- * Ditto for archdata. Assumes mod->archdata_start and mod->archdata_end
- * are validated elsewhere.
- */
-#define mod_archdata_member_present(mod, type, member) \
- (((unsigned long)(&((type *)0L)->member) + \
- sizeof(((type *)0L)->member)) <= \
- ((mod)->archdata_end - (mod)->archdata_start))
-
-
-/* Check if an address p with number of entries n is within the body of module m */
-#define mod_bound(p, n, m) ((unsigned long)(p) >= ((unsigned long)(m) + ((m)->size_of_struct)) && \
- (unsigned long)((p)+(n)) <= (unsigned long)(m) + (m)->size)
-
-/* Backwards compatibility definition. */
-
-#define GET_USE_COUNT(module) (atomic_read(&(module)->uc.usecount))
-
-/* Poke the use count of a module. */
-
-#define __MOD_INC_USE_COUNT(mod) \
- (atomic_inc(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED|MOD_USED_ONCE)
-#define __MOD_DEC_USE_COUNT(mod) \
- (atomic_dec(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED)
-#define __MOD_IN_USE(mod) \
- (mod_member_present((mod), can_unload) && (mod)->can_unload \
- ? (mod)->can_unload() : atomic_read(&(mod)->uc.usecount))
-
-/* Indirect stringification. */
-
-#define __MODULE_STRING_1(x) #x
-#define __MODULE_STRING(x) __MODULE_STRING_1(x)
+extern int init_module(void *, unsigned long, char *);
+extern long delete_module(const char *, unsigned int);
#endif /* _SYS_MODULE_H */
diff -ur klibc-0.72/utils/Makefile klibc-0.72-modprobe/utils/Makefile
--- klibc-0.72/utils/Makefile 2002-08-23 23:06:05.000000000 +0200
+++ klibc-0.72-modprobe/utils/Makefile 2003-01-10 19:44:15.000000000 +0100
@@ -4,7 +4,7 @@
MAKEDEPS = -Wp,-MD,.$(subst /,-,$*).d
CFLAGS = $(MAKEDEPS) $(OPTFLAGS) $(REQFLAGS) -W -Wall
LIBS = $(KLIBC) $(LIBGCC)
-PROGS = chroot dd fstype mkdir mkfifo mount pivot_root umount
+PROGS = chroot dd fstype mkdir mkfifo mount pivot_root umount modprobe
all: $(PROGS)
@@ -23,6 +23,9 @@
mkfifo: mkfifo.o file_mode.o $(CRT0) $(LIBS)
$(LD) $(LDFLAGS) -o $@ $(CRT0) mkfifo.o file_mode.o $(LIBS)
+modprobe: modprobe.o $(CRT0) $(LIBS)
+ $(LD) $(LDFLAGS) -o $@ $(CRT0) modprobe.o $(LIBS)
+
mount: mount.o mount_opts.o $(CRT0) $(LIBS)
$(LD) $(LDFLAGS) -o $@ $(CRT0) mount.o mount_opts.o $(LIBS)