diff options
author | Alan Jenkins <alan-jenkins@tuffmail.co.uk> | 2010-03-02 09:59:00 +0000 |
---|---|---|
committer | Alan Jenkins <alan-jenkins@tuffmail.co.uk> | 2010-03-02 09:59:27 +0000 |
commit | 7bfbf4ba583f5da45795856accc9cf1c7bd5623f (patch) | |
tree | 56ac40758a8685bb9c4b20b2d84ea1361525f160 | |
parent | 66876e3ee43d52f1b41c56e5bab542b7c205b91b (diff) | |
parent | 8c7c5c102426cafcb2d118e307f246df66d650de (diff) | |
download | module-init-tools-7bfbf4ba583f5da45795856accc9cf1c7bd5623f.tar.gz |
Merge branch 'cleanups' into softdep-merge
Conflicts:
modprobe.c
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | depmod.c | 4 | ||||
-rw-r--r-- | doc/modprobe.sgml | 12 | ||||
-rw-r--r-- | elfops.c | 39 | ||||
-rw-r--r-- | elfops.h | 1 | ||||
-rw-r--r-- | insmod.c | 13 | ||||
-rw-r--r-- | m4/ax_enable_builddir.m4 | 5 | ||||
-rw-r--r-- | modprobe.c | 231 | ||||
-rwxr-xr-x | tests/test-modprobe/02proc.sh | 103 | ||||
-rwxr-xr-x | tests/test-modprobe/04config.sh | 72 | ||||
-rwxr-xr-x | tests/test-modprobe/12whitespace.sh | 57 | ||||
-rwxr-xr-x | tests/test-modprobe/22recursiveinstall.sh | 6 | ||||
-rwxr-xr-x | tests/test-modprobe/27cmdline-install-remove.sh | 3 | ||||
-rw-r--r-- | util.c | 29 | ||||
-rw-r--r-- | util.h | 2 | ||||
-rw-r--r-- | zlibsupport.c | 17 |
16 files changed, 421 insertions, 175 deletions
diff --git a/configure.ac b/configure.ac index 75d3b15..b374c33 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT(module-init-tools,3.11-rc1) +AC_INIT(module-init-tools,3.12-pre1) AC_CANONICAL_SYSTEM @@ -1,6 +1,7 @@ /* New simplified depmod without backwards compat stuff and not requiring ksyms. + (C) 2010 Jon Masters <jcm@jonmasters.org>, and others. (C) 2002 Rusty Russell IBM Corporation */ #define _GNU_SOURCE /* asprintf */ @@ -1150,8 +1151,7 @@ static int parse_config_file(const char *filename, version = strsep_skipspace(&ptr, "\t "); subdir = strsep_skipspace(&ptr, "\t "); - if (strcmp(version, kernelversion) != 0 && - strcmp(version, "*") != 0) + if (!regex_match(kernelversion, (const char *)version)) continue; nofail_asprintf(&pathname, "%s%s%s/%s/%s.ko", basedir, diff --git a/doc/modprobe.sgml b/doc/modprobe.sgml index 69b2d84..9e41dde 100644 --- a/doc/modprobe.sgml +++ b/doc/modprobe.sgml @@ -187,13 +187,13 @@ </term> <listitem> <para> - Normally <command>modprobe</command> will report an error - if you try to remove or insert a module it can't find (and + With this flag, <command>modprobe</command> won't print an error + message if you try to remove or insert a module it can't find (and isn't an alias or - <command>install</command>/<command>remove</command> - command). With this flag, <command>modprobe</command> - will simply ignore any bogus names (the kernel uses this - to opportunistically probe for modules which might exist). + <command>install</command>/<command>remove</command> command). + However, it will still return with a non-zero exit status. The + kernel uses this to opportunistically probe for modules which might + exist. </para> </listitem> </varlistentry> @@ -62,46 +62,21 @@ static int elf_ident(void *file, unsigned long fsize, int *conv) */ struct elf_file *grab_elf_file(const char *pathname) { - int fd; - int err; - struct elf_file *file; - - fd = open(pathname, O_RDONLY, 0); - if (fd < 0) - return NULL; - file = grab_elf_file_fd(pathname, fd); - - err = errno; - close(fd); - errno = err; - return file; -} - -/* - * grab_elf_file_fd - read ELF file from file descriptor into memory - * @pathame: name of file to load - * @fd: file descriptor of file to load - * - * Returns NULL, and errno set on error. - */ -struct elf_file *grab_elf_file_fd(const char *pathname, int fd) -{ struct elf_file *file; file = malloc(sizeof(*file)); if (!file) { errno = ENOMEM; - return NULL; + goto fail; } file->pathname = strdup(pathname); if (!file->pathname) { - free(file); errno = ENOMEM; - return NULL; + goto fail_free_file; } - file->data = grab_fd(fd, &file->len); + file->data = grab_file(pathname, &file->len); if (!file->data) - goto fail; + goto fail_free_pathname; switch (elf_ident(file->data, file->len, &file->conv)) { case ELFCLASS32: @@ -117,8 +92,12 @@ struct elf_file *grab_elf_file_fd(const char *pathname, int fd) goto fail; } return file; + +fail_free_pathname: + free(file->pathname); +fail_free_file: + free(file); fail: - release_elf_file(file); return NULL; } @@ -79,7 +79,6 @@ struct module_ops extern struct module_ops mod_ops32, mod_ops64; struct elf_file *grab_elf_file(const char *pathname); -struct elf_file *grab_elf_file_fd(const char *pathname, int fd); void release_elf_file(struct elf_file *file); #endif /* MODINITTOOLS_MODULEOPS_H */ @@ -60,9 +60,7 @@ static void *grab_file(const char *filename, unsigned long *size) { unsigned int max = 16384; int ret, fd, err_save; - void *buffer = malloc(max); - if (!buffer) - return NULL; + void *buffer; if (streq(filename, "-")) fd = dup(STDIN_FILENO); @@ -72,6 +70,10 @@ static void *grab_file(const char *filename, unsigned long *size) if (fd < 0) return NULL; + buffer = malloc(max); + if (!buffer) + goto out_error; + *size = 0; while ((ret = read(fd, buffer + *size, max - *size)) > 0) { *size += ret; @@ -158,7 +160,10 @@ int main(int argc, char *argv[]) if (ret != 0) { fprintf(stderr, "insmod: error inserting '%s': %li %s\n", filename, ret, moderror(errno)); - exit(1); } + free(file); + + if (ret != 0) + exit(1); exit(0); } diff --git a/m4/ax_enable_builddir.m4 b/m4/ax_enable_builddir.m4 index 49b3eb9..4273a53 100644 --- a/m4/ax_enable_builddir.m4 +++ b/m4/ax_enable_builddir.m4 @@ -187,8 +187,9 @@ s/^srcdir *=.*/srcdir = ./ s/^top_srcdir *=.*/top_srcdir = ./ /[[:=]]/!d /^\\./d -dnl Now handle rules (i.e. lines containing /:/ but not /:=/). -/:=/b +dnl Now handle rules (i.e. lines containing ":" but not " = "). +/ = /b +/ .= /b /:/!b s/:.*/:/ s/ / /g @@ -75,9 +75,10 @@ typedef enum mit_use_blacklist = 8, mit_ignore_commands = 16, mit_ignore_loaded = 32, - mit_strip_vermagic = 64, - mit_strip_modversion = 128, - mit_resolve_alias = 256 + mit_quiet_inuse = 64, + mit_strip_vermagic = 128, + mit_strip_modversion = 256, + mit_resolve_alias = 512 } modprobe_flags_t; @@ -106,24 +107,6 @@ static struct module *find_module(const char *filename, struct list_head *list) return NULL; } -/* We used to lock with a write flock but that allows regular users to block - * module load by having a read lock on the module file (no way to bust the - * existing locks without killing the offending process). Instead, we now - * do the system call/init_module and allow the kernel to fail us instead. - */ -static int open_file(const char *filename) -{ - int fd = open(filename, O_RDONLY, 0); - - return fd; -} - -static void close_file(int fd) -{ - /* Valgrind is picky... */ - close(fd); -} - static void add_module(char *filename, int namelen, struct list_head *list) { struct module *mod; @@ -588,15 +571,70 @@ static char *prepend_option(char *options, const char *newoption) /* Add to options */ static char *add_extra_options(const char *modname, - char *optstring, + const char *optstring, const struct module_options *options) { + char *opts = NOFAIL(strdup(optstring)); + while (options) { if (streq(options->modulename, modname)) - optstring = prepend_option(optstring, options->options); + opts = prepend_option(opts, options->options); options = options->next; } - return optstring; + return opts; +} + +/* Is module in /proc/modules? If so, fill in usecount if not NULL. + 0 means no, 1 means yes, -1 means unknown. + */ +static int module_in_procfs(const char *modname, unsigned int *usecount) +{ + FILE *proc_modules; + char *line; + +again: + /* Might not be mounted yet. Don't fail. */ + proc_modules = fopen("/proc/modules", "r"); + if (!proc_modules) + return -1; + + while ((line = getline_wrapped(proc_modules, NULL)) != NULL) { + char *entry = strtok(line, " \n"); + + if (entry && streq(entry, modname)) { + /* If it exists, usecount is the third entry. */ + if (!strtok(NULL, " \n")) + goto out; + + if (!(entry = strtok(NULL, " \n"))) /* usecount */ + goto out; + else + if (usecount) + *usecount = atoi(entry); + + /* Followed by - then status. */ + if (strtok(NULL, " \n") + && (entry = strtok(NULL, " \n")) != NULL) { + /* No locking, we might hit cases + * where module is in flux. Spin. */ + if (streq(entry, "Loading") + || streq(entry, "Unloading")) { + usleep(100000); + free(line); + fclose(proc_modules); + goto again; + } + } + + out: + free(line); + fclose(proc_modules); + return 1; + } + free(line); + } + fclose(proc_modules); + return 0; } /* Read sysfs attribute into a buffer. @@ -638,7 +676,7 @@ static int module_builtin(const char *dirname, const char *modname) /* Is module in /sys/module? If so, fill in usecount if not NULL. 0 means no, 1 means yes, -1 means unknown. */ -static int module_in_kernel(const char *modname, unsigned int *usecount) +static int module_in_sysfs(const char *modname, unsigned int *usecount) { int ret; char *name; @@ -658,14 +696,26 @@ static int module_in_kernel(const char *modname, unsigned int *usecount) if (ret < 0) return (errno == ENOENT) ? 0 : -1; /* Not found or unknown. */ - /* Wait for the existing module to either go live or disappear. */ nofail_asprintf(&name, "/sys/module/%s/initstate", modname); - while (1) { - ret = read_attribute(name, attr, ATTR_LEN); - if (ret != 1 || streq(attr, "live\n")) - break; + ret = read_attribute(name, attr, ATTR_LEN); + if (ret == 0) { + free(name); + nofail_asprintf(&name, "/sys/module/%s", modname); + if (stat(name, &finfo) < 0) { + /* module was removed before we could read initstate */ + ret = 0; + } else { + /* initstate not available (2.6.19 or earlier) */ + ret = -1; + } + free(name); + return ret; + } + /* Wait for the existing module to either go live or disappear. */ + while (ret == 1 && !streq(attr, "live\n")) { usleep(100000); + ret = read_attribute(name, attr, ATTR_LEN); } free(name); @@ -684,6 +734,22 @@ static int module_in_kernel(const char *modname, unsigned int *usecount) return 1; } +/* Is module loaded? If so, fill in usecount if not NULL. + 0 means no, 1 means yes, -1 means unknown. + */ +static int module_in_kernel(const char *modname, unsigned int *usecount) +{ + int result; + + result = module_in_sysfs(modname, usecount); + if (result != -1) + return result; + + /* /sys/module/%s/initstate is only available since 2.6.20, + fallback to /proc/modules to get module state on earlier kernels. */ + return module_in_procfs(modname, usecount); +} + void dump_modversions(const char *filename, errfn_t error) { struct elf_file *module; @@ -1301,9 +1367,9 @@ static void do_softdep(const struct module_softdep *softdep, } } -/* Actually do the insert. Frees second arg. */ +/* Actually do the insert. */ static int insmod(struct list_head *list, - char *optstring, + const char *optstring, const char *newname, const char *cmdline_opts, const struct modprobe_conf *conf, @@ -1311,12 +1377,14 @@ static int insmod(struct list_head *list, errfn_t error, modprobe_flags_t flags) { - int ret, fd; + int ret; struct elf_file *module; const struct module_softdep *softdep; const char *command; struct module *mod = list_entry(list->next, struct module, list); int rc = 0; + int already_loaded; + char *opts = NULL; /* Take us off the list. */ list_del(&mod->list); @@ -1326,54 +1394,54 @@ static int insmod(struct list_head *list, modprobe_flags_t f = flags; f &= ~mit_first_time; f &= ~mit_ignore_commands; - if ((rc = insmod(list, NOFAIL(strdup("")), NULL, + if ((rc = insmod(list, "", NULL, "", conf, dirname, warn, f)) != 0) { error("Error inserting %s (%s): %s\n", mod->modname, mod->filename, insert_moderror(errno)); - goto out_optstring; + goto out; } } - fd = open_file(mod->filename); - if (fd < 0) { - error("Could not open '%s': %s\n", - mod->filename, strerror(errno)); - goto out_optstring; - } - /* Don't do ANYTHING if already in kernel. */ - if (!(flags & mit_ignore_loaded) - && module_in_kernel(newname ?: mod->modname, NULL) == 1) { + already_loaded = module_in_kernel(newname ?: mod->modname, NULL); + + if (!(flags & mit_ignore_loaded) && already_loaded == 1) { if (flags & mit_first_time) error("Module %s already in kernel.\n", newname ?: mod->modname); - goto out_unlock; + goto out; } softdep = find_softdep(mod->modname, conf->softdeps); if (softdep && !(flags & mit_ignore_commands)) { - close_file(fd); do_softdep(softdep, cmdline_opts, conf, dirname, error, flags & (mit_remove | mit_dry_run)); - goto out_optstring; + goto out; } command = find_command(mod->modname, conf->commands); if (command && !(flags & mit_ignore_commands)) { - close_file(fd); - do_command(mod->modname, command, flags & mit_dry_run, error, - "install", cmdline_opts); - goto out_optstring; + if (already_loaded == -1) { + warn("/sys/module/ not present or too old," + " and /proc/modules does not exist.\n"); + warn("Ignoring install commands for %s" + " in case it is already loaded.\n", + newname ?: mod->modname); + } else { + do_command(mod->modname, command, flags & mit_dry_run, + error, "install", cmdline_opts); + goto out; + } } - module = grab_elf_file_fd(mod->filename, fd); + module = grab_elf_file(mod->filename); if (!module) { error("Could not read '%s': %s\n", mod->filename, (errno == ENOEXEC) ? "Invalid module format" : strerror(errno)); - goto out_unlock; + goto out; } if (newname) rename_module(module, mod->modname, newname); @@ -1383,20 +1451,20 @@ static int insmod(struct list_head *list, clear_magic(module); /* Config file might have given more options */ - optstring = add_extra_options(mod->modname, optstring, conf->options); + opts = add_extra_options(mod->modname, optstring, conf->options); - info("insmod %s %s\n", mod->filename, optstring); + info("insmod %s %s\n", mod->filename, opts); if (flags & mit_dry_run) - goto out; + goto out_elf_file; - ret = init_module(module->data, module->len, optstring); + ret = init_module(module->data, module->len, opts); if (ret != 0) { if (errno == EEXIST) { if (flags & mit_first_time) error("Module %s already in kernel.\n", newname ?: mod->modname); - goto out_unlock; + goto out_elf_file; } /* don't warn noisely if we're loading multiple aliases. */ /* one of the aliases may try to use hardware we don't have. */ @@ -1406,12 +1474,10 @@ static int insmod(struct list_head *list, insert_moderror(errno)); rc = 1; } - out: + out_elf_file: release_elf_file(module); - out_unlock: - close_file(fd); - out_optstring: - free(optstring); + free(opts); + out: free_module(mod); return rc; } @@ -1429,6 +1495,7 @@ static void rmmod(struct list_head *list, const char *command; unsigned int usecount = 0; struct module *mod = list_entry(list->next, struct module, list); + int exists; /* Take first one off the list. */ list_del(&mod->list); @@ -1436,6 +1503,11 @@ static void rmmod(struct list_head *list, if (!name) name = mod->modname; + /* Don't do ANYTHING if not loaded. */ + exists = module_in_kernel(name, &usecount); + if (exists == 0) + goto nonexistent_module; + /* Even if renamed, find commands/softdeps to orig. name. */ softdep = find_softdep(mod->modname, conf->softdeps); @@ -1447,16 +1519,21 @@ static void rmmod(struct list_head *list, command = find_command(mod->modname, conf->commands); if (command && !(flags & mit_ignore_commands)) { - do_command(mod->modname, command, flags & mit_dry_run, error, - "remove", cmdline_opts); - goto remove_rest; + if (exists == -1) { + warn("/sys/module/ not present or too old," + " and /proc/modules does not exist.\n"); + warn("Ignoring remove commands for %s" + " in case it is not loaded.\n", + mod->modname); + } else { + do_command(mod->modname, command, flags & mit_dry_run, + error, "remove", cmdline_opts); + goto remove_rest; + } } - if (module_in_kernel(name, &usecount) == 0) - goto nonexistent_module; - if (usecount != 0) { - if (!(flags & mit_ignore_loaded)) + if (!(flags & mit_quiet_inuse)) error("Module %s is in use.\n", name); goto remove_rest; } @@ -1479,7 +1556,7 @@ static void rmmod(struct list_head *list, if (!list_empty(list)) { flags &= ~mit_first_time; flags &= ~mit_ignore_commands; - flags |= mit_ignore_loaded; + flags |= mit_quiet_inuse; rmmod(list, NULL, "", conf, dirname, warn, flags); } @@ -1528,12 +1605,11 @@ static int handle_module(const char *modname, return 1; } - if (flags & mit_remove) { - flags &= ~mit_ignore_loaded; + if (flags & mit_remove) rmmod(todo_list, newname, cmdline_opts, conf, dirname, error, flags); - } else - insmod(todo_list, NOFAIL(strdup(options)), newname, + else + insmod(todo_list, options, newname, cmdline_opts, conf, dirname, error, flags); return 0; @@ -1624,8 +1700,8 @@ int do_modprobe(const char *modulename, err = warn; while (aliases) { /* Add the options for this alias. */ - char *opts = NOFAIL(strdup(cmdline_opts)); - opts = add_extra_options(modname, opts, conf->options); + char *opts; + opts = add_extra_options(modname, cmdline_opts, conf->options); read_depends(dirname, aliases->module, &list); failed |= handle_module(aliases->module, @@ -1633,6 +1709,7 @@ int do_modprobe(const char *modulename, conf, dirname, err, flags); aliases = aliases->next; + free(opts); INIT_LIST_HEAD(&list); } } else { diff --git a/tests/test-modprobe/02proc.sh b/tests/test-modprobe/02proc.sh new file mode 100755 index 0000000..d7db770 --- /dev/null +++ b/tests/test-modprobe/02proc.sh @@ -0,0 +1,103 @@ +#! /bin/sh + +# Test handling of /proc/modules. + +BITNESS=32 + +rm -rf tests/tmp/* + +# Create inputs +MODULE_DIR=tests/tmp/lib/modules/$MODTEST_UNAME +mkdir -p $MODULE_DIR +ln tests/data/$BITNESS/normal/export_nodep-$BITNESS.ko \ + tests/data/$BITNESS/normal/noexport_nodep-$BITNESS.ko \ + $MODULE_DIR + +mkdir tests/tmp/proc + +# Now create modules.dep +cat > tests/tmp/lib/modules/$MODTEST_UNAME/modules.dep <<EOF +noexport_nodep-$BITNESS.ko: +export_nodep-$BITNESS.ko: +EOF + +SIZE_NOEXPORT_NODEP=$(echo `wc -c < tests/data/$BITNESS/normal/noexport_nodep-$BITNESS.ko`) +SIZE_EXPORT_NODEP=$(echo `wc -c < tests/data/$BITNESS/normal/export_nodep-$BITNESS.ko`) + +# If it can't open /proc/modules, it should try anyway. +rm -f tests/tmp/proc/modules + +[ "`modprobe noexport_nodep-$BITNESS 2>&1`" = "INIT_MODULE: $SIZE_NOEXPORT_NODEP " ] +[ "`modprobe export_nodep-$BITNESS 2>&1`" = "INIT_MODULE: $SIZE_EXPORT_NODEP " ] + +[ "`modprobe -r noexport_nodep-$BITNESS 2>&1`" = "DELETE_MODULE: noexport_nodep_$BITNESS EXCL " ] +[ "`modprobe -r export_nodep-$BITNESS 2>&1`" = "DELETE_MODULE: export_nodep_$BITNESS EXCL " ] + +# If it doesn't exist in /proc/modules, remove should succeed. +touch tests/tmp/proc/modules +[ "`modprobe noexport_nodep-$BITNESS 2>&1`" = "INIT_MODULE: $SIZE_NOEXPORT_NODEP " ] +[ "`modprobe export_nodep-$BITNESS 2>&1`" = "INIT_MODULE: $SIZE_EXPORT_NODEP " ] +[ "`modprobe -r -v noexport_nodep-$BITNESS 2>&1; echo $?`" = "0" ] +[ "`modprobe -r -v export_nodep-$BITNESS 2>&1; echo $?`" = "0" ] +[ "`modprobe -r -v noexport-nodep-$BITNESS 2>&1; echo $?`" = "0" ] +[ "`modprobe -r -v export-nodep-$BITNESS 2>&1; echo $?`" = "0" ] +# ... unless --first-time is specified (won't print status due to set -e). +[ "`modprobe --first-time -r noexport_nodep-$BITNESS 2>&1`" = "FATAL: Module noexport_nodep_$BITNESS is not in kernel." ] +[ "`modprobe --first-time -r export_nodep-$BITNESS 2>&1`" = "FATAL: Module export_nodep_$BITNESS is not in kernel." ] +[ "`modprobe --first-time -r noexport-nodep-$BITNESS 2>&1`" = "FATAL: Module noexport_nodep_$BITNESS is not in kernel." ] +[ "`modprobe --first-time -r export-nodep-$BITNESS 2>&1`" = "FATAL: Module export_nodep_$BITNESS is not in kernel." ] + +# Old-style /proc (no unload support). +echo "noexport_nodep_$BITNESS $SIZE_NOEXPORT_NODEP" > tests/tmp/proc/modules +echo "export_nodep_$BITNESS $SIZE_EXPORT_NODEP" >> tests/tmp/proc/modules + +# If it does exist, insertion should "succeed". +[ "`modprobe -v noexport_nodep-$BITNESS 2>&1; echo $?`" = "0" ] +[ "`modprobe -v export_nodep-$BITNESS 2>&1; echo $?`" = "0" ] +[ "`modprobe -v noexport-nodep-$BITNESS 2>&1; echo $?`" = "0" ] +[ "`modprobe -v export-nodep-$BITNESS 2>&1; echo $?`" = "0" ] +# .. unless --first-time is specified. +[ "`modprobe --first-time noexport_nodep-$BITNESS 2>&1`" = "FATAL: Module noexport_nodep_$BITNESS already in kernel." ] +[ "`modprobe --first-time export_nodep-$BITNESS 2>&1`" = "FATAL: Module export_nodep_$BITNESS already in kernel." ] +[ "`modprobe --first-time noexport-nodep-$BITNESS 2>&1`" = "FATAL: Module noexport_nodep_$BITNESS already in kernel." ] +[ "`modprobe --first-time export-nodep-$BITNESS 2>&1`" = "FATAL: Module export_nodep_$BITNESS already in kernel." ] + +# Removal should still try. +[ "`modprobe -r noexport_nodep-$BITNESS 2>&1`" = "DELETE_MODULE: noexport_nodep_$BITNESS EXCL " ] +[ "`modprobe -r export_nodep-$BITNESS 2>&1`" = "DELETE_MODULE: export_nodep_$BITNESS EXCL " ] + +# New-style /proc without unload support +echo "noexport_nodep_$BITNESS $SIZE_NOEXPORT_NODEP - -" > tests/tmp/proc/modules +echo "export_nodep_$BITNESS $SIZE_EXPORT_NODEP - -" >> tests/tmp/proc/modules + +[ "`modprobe --first-time noexport_nodep-$BITNESS 2>&1`" = "FATAL: Module noexport_nodep_$BITNESS already in kernel." ] +[ "`modprobe --first-time export_nodep-$BITNESS 2>&1`" = "FATAL: Module export_nodep_$BITNESS already in kernel." ] +[ "`modprobe --first-time noexport-nodep-$BITNESS 2>&1`" = "FATAL: Module noexport_nodep_$BITNESS already in kernel." ] +[ "`modprobe --first-time export-nodep-$BITNESS 2>&1`" = "FATAL: Module export_nodep_$BITNESS already in kernel." ] +# Removal should still try. +[ "`modprobe -r noexport_nodep-$BITNESS 2>&1`" = "DELETE_MODULE: noexport_nodep_$BITNESS EXCL " ] +[ "`modprobe -r export_nodep-$BITNESS 2>&1`" = "DELETE_MODULE: export_nodep_$BITNESS EXCL " ] + +# Should fail if refcounts non-zero. Old-style +echo "noexport_nodep_$BITNESS $SIZE_NOEXPORT_NODEP 1" > tests/tmp/proc/modules +echo "export_nodep_$BITNESS $SIZE_EXPORT_NODEP 1" >> tests/tmp/proc/modules + +[ "`modprobe -r noexport_nodep-$BITNESS 2>&1`" = "FATAL: Module noexport_nodep_$BITNESS is in use." ] +[ "`modprobe -r export_nodep-$BITNESS 2>&1`" = "FATAL: Module export_nodep_$BITNESS is in use." ] +[ "`modprobe -r noexport-nodep-$BITNESS 2>&1`" = "FATAL: Module noexport_nodep_$BITNESS is in use." ] +[ "`modprobe -r export-nodep-$BITNESS 2>&1`" = "FATAL: Module export_nodep_$BITNESS is in use." ] + +# New-style /proc +echo "noexport_nodep_$BITNESS $SIZE_NOEXPORT_NODEP 1 -" > tests/tmp/proc/modules +echo "export_nodep_$BITNESS $SIZE_EXPORT_NODEP 1 something_else, extrafield" >> tests/tmp/proc/modules + +[ "`modprobe --first-time noexport_nodep-$BITNESS 2>&1`" = "FATAL: Module noexport_nodep_$BITNESS already in kernel." ] +[ "`modprobe --first-time export_nodep-$BITNESS 2>&1`" = "FATAL: Module export_nodep_$BITNESS already in kernel." ] +[ "`modprobe --first-time noexport-nodep-$BITNESS 2>&1`" = "FATAL: Module noexport_nodep_$BITNESS already in kernel." ] +[ "`modprobe --first-time export-nodep-$BITNESS 2>&1`" = "FATAL: Module export_nodep_$BITNESS already in kernel." ] + +[ "`modprobe -r noexport_nodep-$BITNESS 2>&1`" = "FATAL: Module noexport_nodep_$BITNESS is in use." ] +[ "`modprobe -r export_nodep-$BITNESS 2>&1`" = "FATAL: Module export_nodep_$BITNESS is in use." ] +[ "`modprobe -r noexport-nodep-$BITNESS 2>&1`" = "FATAL: Module noexport_nodep_$BITNESS is in use." ] +[ "`modprobe -r export-nodep-$BITNESS 2>&1`" = "FATAL: Module export_nodep_$BITNESS is in use." ] + diff --git a/tests/test-modprobe/04config.sh b/tests/test-modprobe/04config.sh index cb85422..342cc18 100755 --- a/tests/test-modprobe/04config.sh +++ b/tests/test-modprobe/04config.sh @@ -88,38 +88,29 @@ SIZE_NOEXPORT_DEP=`wc -c < tests/data/$BITNESS/normal/noexport_dep-$BITNESS.ko` SIZE_EXPORT_DEP=`wc -c < tests/data/$BITNESS/normal/export_dep-$BITNESS.ko` SIZE_NOEXPORT_DOUBLEDEP=`wc -c < tests/data/$BITNESS/normal/noexport_doubledep-$BITNESS.ko` -# Test ignoring install & remove. +# Empty /sys/module/ for install commands +mkdir -p tests/tmp/sys/module +# Test ignoring install commands [ "`modprobe --ignore-install export_nodep-$BITNESS 2>&1`" = "INIT_MODULE: $SIZE_EXPORT_NODEP " ] [ "`modprobe -i export_nodep-$BITNESS 2>&1`" = "INIT_MODULE: $SIZE_EXPORT_NODEP " ] [ "`modprobe -i foo 2>&1`" = "FATAL: Module foo not found." ] -[ "`modprobe -r --ignore-remove export_nodep-$BITNESS 2>&1`" = "DELETE_MODULE: export_nodep_$BITNESS EXCL " ] -[ "`modprobe -r -i export_nodep-$BITNESS 2>&1`" = "DELETE_MODULE: export_nodep_$BITNESS EXCL " ] -[ "`modprobe -i -r foo 2>&1`" = "FATAL: Module foo not found." ] -# Test install & remove (fake modules) +# Test install commands (fake modules) [ "`modprobe foo 2>&1`" = "SYSTEM: echo Installing foo" ] [ "`modprobe bar 2>&1`" = "SYSTEM: echo Installing bar" ] [ "`modprobe baz 2>&1`" = "SYSTEM: echo Installing baz" ] -[ "`modprobe -r foo 2>&1`" = "SYSTEM: echo Removing foo" ] -[ "`modprobe -r bar 2>&1`" = "SYSTEM: echo Removing bar" ] -[ "`modprobe -r baz 2>&1`" = "SYSTEM: echo Removing baz" ] -# Test install & remove of a what is also a real module. +# Test install of a what is also a real module. [ "`modprobe export_nodep-$BITNESS 2>&1`" = "SYSTEM: echo Installing export_nodep" ] -[ "`modprobe -r export_nodep-$BITNESS 2>&1`" = "SYSTEM: echo Removing export_nodep" ] -# Test install & remove of what is also a real module via dependency. +# Test install of what is also a real module via dependency. [ "`modprobe noexport_dep-$BITNESS 2>&1`" = "SYSTEM: echo Installing export_nodep INIT_MODULE: $SIZE_NOEXPORT_DEP I am noexport_dep" ] -[ "`modprobe -r noexport_dep-$BITNESS 2>&1`" = "DELETE_MODULE: noexport_dep_$BITNESS EXCL -SYSTEM: echo Removing export_nodep" ] -# Test ignoring install & remove: only effects commandline. +# Test ignoring install commands: only effects commandline. [ "`modprobe -i noexport_dep-$BITNESS 2>&1`" = "SYSTEM: echo Installing export_nodep INIT_MODULE: $SIZE_NOEXPORT_DEP I am noexport_dep" ] -[ "`modprobe -r -i noexport_dep-$BITNESS 2>&1`" = "DELETE_MODULE: noexport_dep_$BITNESS EXCL -SYSTEM: echo Removing export_nodep" ] # Test options [ "`modprobe noexport_nodep-$BITNESS 2>&1`" = "INIT_MODULE: $SIZE_NOEXPORT_NODEP I am noexport_nodep" ] @@ -173,6 +164,39 @@ INIT_MODULE: $SIZE_NOEXPORT_DOUBLEDEP I am noexport_doubledep I am alias to noex # Test tab-to-spaces conversion, and \ wrapping. [ "`modprobe alias_to_noexport_nodep-$BITNESS_with_tabbed_options 2>&1`" = "INIT_MODULE: $SIZE_NOEXPORT_NODEP I am noexport_nodep index=0 id=\"Thinkpad\" isapnp=0 port=0x530 cport=0x538 fm_port=0x388 mpu_port=-1 mpu_irq=-1 irq=9 dma1=1 dma2=3 enable=1 isapnp=0" ] +# Populate /sys/module/ for remove commands +mkdir -p tests/tmp/sys/module/noexport_nodep_$BITNESS +mkdir -p tests/tmp/sys/module/noexport_dep_$BITNESS +mkdir -p tests/tmp/sys/module/noexport_doubledep_$BITNESS +mkdir -p tests/tmp/sys/module/export_nodep_$BITNESS +mkdir -p tests/tmp/sys/module/export_dep_$BITNESS +echo live > tests/tmp/sys/module/noexport_nodep_$BITNESS/initstate +echo live > tests/tmp/sys/module/noexport_dep_$BITNESS/initstate +echo live > tests/tmp/sys/module/noexport_doubledep_$BITNESS/initstate +echo live > tests/tmp/sys/module/export_nodep_$BITNESS/initstate +echo live > tests/tmp/sys/module/export_dep_$BITNESS/initstate + +# Test ignoring remove commands. +[ "`modprobe -r --ignore-remove export_nodep-$BITNESS 2>&1`" = "DELETE_MODULE: export_nodep_$BITNESS EXCL " ] +[ "`modprobe -r -i export_nodep-$BITNESS 2>&1`" = "DELETE_MODULE: export_nodep_$BITNESS EXCL " ] +[ "`modprobe -i -r foo 2>&1`" = "FATAL: Module foo not found." ] + +# Test remove commands (fake modules) +[ "`modprobe -r foo 2>&1`" = "SYSTEM: echo Removing foo" ] +[ "`modprobe -r bar 2>&1`" = "SYSTEM: echo Removing bar" ] +[ "`modprobe -r baz 2>&1`" = "SYSTEM: echo Removing baz" ] + +# Test remove of a what is also a real module. +[ "`modprobe -r export_nodep-$BITNESS 2>&1`" = "SYSTEM: echo Removing export_nodep" ] + +# Test remove of what is also a real module via dependency. +[ "`modprobe -r noexport_dep-$BITNESS 2>&1`" = "DELETE_MODULE: noexport_dep_$BITNESS EXCL +SYSTEM: echo Removing export_nodep" ] + +# Test ignoring remove commands: only effects commandline. +[ "`modprobe -r -i noexport_dep-$BITNESS 2>&1`" = "DELETE_MODULE: noexport_dep_$BITNESS EXCL +SYSTEM: echo Removing export_nodep" ] + # Test aliases doing removal. [ "`modprobe -r alias_to_noexport_nodep-$BITNESS 2>&1`" = "DELETE_MODULE: noexport_nodep_$BITNESS EXCL " ] [ "`modprobe -r alias_to_noexport_dep-$BITNESS 2>&1`" = "DELETE_MODULE: noexport_dep_$BITNESS EXCL @@ -186,3 +210,19 @@ SYSTEM: echo Removing export_nodep" ] [ "`modprobe -r alias_to_foo 2>&1`" = "SYSTEM: echo Removing foo" ] [ "`modprobe -r alias_to_bar 2>&1`" = "SYSTEM: echo Removing bar" ] [ "`modprobe -r alias_to_baz 2>&1`" = "SYSTEM: echo Removing baz" ] + +# Now test install precaution in the absence of /sys/modules +rm -r tests/tmp/sys/module + +# Test install and remove commands (fake modules) +# No caution necessary here +[ "`modprobe foo 2>&1`" = "SYSTEM: echo Installing foo" ] +[ "`modprobe -r foo 2>&1`" = "SYSTEM: echo Removing foo" ] + +# Test install and remove of a what is also a real module. +[ "`modprobe export_nodep-$BITNESS 2>&1`" = "WARNING: /sys/module/ not present or too old, and /proc/modules does not exist. +WARNING: Ignoring install commands for export_nodep_$BITNESS in case it is already loaded. +INIT_MODULE: $SIZE_EXPORT_NODEP " ] +[ "`modprobe -r export_nodep-$BITNESS 2>&1`" = "WARNING: /sys/module/ not present or too old, and /proc/modules does not exist. +WARNING: Ignoring remove commands for export_nodep_$BITNESS in case it is not loaded. +DELETE_MODULE: export_nodep_32 EXCL " ] diff --git a/tests/test-modprobe/12whitespace.sh b/tests/test-modprobe/12whitespace.sh index 159c4c2..5a1d817 100755 --- a/tests/test-modprobe/12whitespace.sh +++ b/tests/test-modprobe/12whitespace.sh @@ -82,38 +82,29 @@ SIZE_NOEXPORT_DEP=`wc -c < tests/data/$BITNESS/normal/noexport_dep-$BITNESS.ko` SIZE_EXPORT_DEP=`wc -c < tests/data/$BITNESS/normal/export_dep-$BITNESS.ko` SIZE_NOEXPORT_DOUBLEDEP=`wc -c < tests/data/$BITNESS/normal/noexport_doubledep-$BITNESS.ko` -# Test ignoring install & remove. +# Empty /sys/module/ for install commands +mkdir -p tests/tmp/sys/module +# Test ignoring install commands. [ "`modprobe --ignore-install export_nodep-$BITNESS 2>&1`" = "INIT_MODULE: $SIZE_EXPORT_NODEP " ] [ "`modprobe -i export_nodep-$BITNESS 2>&1`" = "INIT_MODULE: $SIZE_EXPORT_NODEP " ] [ "`modprobe -i foo 2>&1`" = "FATAL: Module foo not found." ] -[ "`modprobe -r --ignore-remove export_nodep-$BITNESS 2>&1`" = "DELETE_MODULE: export_nodep_$BITNESS EXCL " ] -[ "`modprobe -r -i export_nodep-$BITNESS 2>&1`" = "DELETE_MODULE: export_nodep_$BITNESS EXCL " ] -[ "`modprobe -i -r foo 2>&1`" = "FATAL: Module foo not found." ] -# Test install & remove (fake modules) +# Test install commands (fake modules) [ "`modprobe foo 2>&1`" = "SYSTEM: echo Installing foo" ] [ "`modprobe bar 2>&1`" = "SYSTEM: echo Installing bar" ] [ "`modprobe baz 2>&1`" = "SYSTEM: echo Installing baz" ] -[ "`modprobe -r foo 2>&1`" = "SYSTEM: echo Removing foo" ] -[ "`modprobe -r bar 2>&1`" = "SYSTEM: echo Removing bar" ] -[ "`modprobe -r baz 2>&1`" = "SYSTEM: echo Removing baz" ] -# Test install & remove of a what is also a real module. +# Test install of a what is also a real module. [ "`modprobe export_nodep-$BITNESS 2>&1`" = "SYSTEM: echo Installing export_nodep" ] -[ "`modprobe -r export_nodep-$BITNESS 2>&1`" = "SYSTEM: echo Removing export_nodep" ] -# Test install & remove of what is also a real module via dependency. +# Test install of what is also a real module via dependency. [ "`modprobe noexport_dep-$BITNESS 2>&1`" = "SYSTEM: echo Installing export_nodep INIT_MODULE: $SIZE_NOEXPORT_DEP I am noexport_dep" ] -[ "`modprobe -r noexport_dep-$BITNESS 2>&1`" = "DELETE_MODULE: noexport_dep_$BITNESS EXCL -SYSTEM: echo Removing export_nodep" ] -# Test ignoring install & remove: only effects commandline. +# Test ignoring install commands: only effects commandline. [ "`modprobe -i noexport_dep-$BITNESS 2>&1`" = "SYSTEM: echo Installing export_nodep INIT_MODULE: $SIZE_NOEXPORT_DEP I am noexport_dep" ] -[ "`modprobe -r -i noexport_dep-$BITNESS 2>&1`" = "DELETE_MODULE: noexport_dep_$BITNESS EXCL -SYSTEM: echo Removing export_nodep" ] # Test options [ "`modprobe noexport_nodep-$BITNESS 2>&1`" = "INIT_MODULE: $SIZE_NOEXPORT_NODEP I am noexport_nodep" ] @@ -164,6 +155,40 @@ INIT_MODULE: $SIZE_NOEXPORT_DOUBLEDEP I am noexport_doubledep I am alias to noex [ "`modprobe alias_to_bar 2>&1`" = "SYSTEM: echo Installing bar" ] [ "`modprobe alias_to_baz 2>&1`" = "SYSTEM: echo Installing baz" ] +# Populate /sys/module/ for remove commands +mkdir -p tests/tmp/sys/module/noexport_nodep_$BITNESS +mkdir -p tests/tmp/sys/module/noexport_dep_$BITNESS +mkdir -p tests/tmp/sys/module/noexport_doubledep_$BITNESS +mkdir -p tests/tmp/sys/module/export_nodep_$BITNESS +mkdir -p tests/tmp/sys/module/export_dep_$BITNESS +echo live > tests/tmp/sys/module/noexport_nodep_$BITNESS/initstate +echo live > tests/tmp/sys/module/noexport_dep_$BITNESS/initstate +echo live > tests/tmp/sys/module/noexport_doubledep_$BITNESS/initstate +echo live > tests/tmp/sys/module/export_nodep_$BITNESS/initstate +echo live > tests/tmp/sys/module/export_dep_$BITNESS/initstate + +# Test ignoring remove commands. + +[ "`modprobe -r --ignore-remove export_nodep-$BITNESS 2>&1`" = "DELETE_MODULE: export_nodep_$BITNESS EXCL " ] +[ "`modprobe -r -i export_nodep-$BITNESS 2>&1`" = "DELETE_MODULE: export_nodep_$BITNESS EXCL " ] +[ "`modprobe -i -r foo 2>&1`" = "FATAL: Module foo not found." ] + +# Test remove commands (fake modules) +[ "`modprobe -r foo 2>&1`" = "SYSTEM: echo Removing foo" ] +[ "`modprobe -r bar 2>&1`" = "SYSTEM: echo Removing bar" ] +[ "`modprobe -r baz 2>&1`" = "SYSTEM: echo Removing baz" ] + +# Test remove of a what is also a real module. +[ "`modprobe -r export_nodep-$BITNESS 2>&1`" = "SYSTEM: echo Removing export_nodep" ] + +# Test remove of what is also a real module via dependency. +[ "`modprobe -r noexport_dep-$BITNESS 2>&1`" = "DELETE_MODULE: noexport_dep_$BITNESS EXCL +SYSTEM: echo Removing export_nodep" ] + +# Test ignoring remove commands: only effects commandline. +[ "`modprobe -r -i noexport_dep-$BITNESS 2>&1`" = "DELETE_MODULE: noexport_dep_$BITNESS EXCL +SYSTEM: echo Removing export_nodep" ] + # Test aliases doing removal. [ "`modprobe -r alias_to_noexport_nodep-$BITNESS 2>&1`" = "DELETE_MODULE: noexport_nodep_$BITNESS EXCL " ] [ "`modprobe -r alias_to_noexport_dep-$BITNESS 2>&1`" = "DELETE_MODULE: noexport_dep_$BITNESS EXCL diff --git a/tests/test-modprobe/22recursiveinstall.sh b/tests/test-modprobe/22recursiveinstall.sh index 0c98e1a..53b0c60 100755 --- a/tests/test-modprobe/22recursiveinstall.sh +++ b/tests/test-modprobe/22recursiveinstall.sh @@ -28,7 +28,7 @@ mkdir -p tests/tmp/sys/module [ "`modprobe noexport_dep-$BITNESS 2>&1`" = "INIT_MODULE: $SIZE_EXPORT_NODEP INIT_MODULE: $SIZE_NOEXPORT_DEP " ] -# Check it's happy if we tell it dep is already instealled +# Check it's happy if we tell it dep is already installed mkdir -p tests/tmp/sys/module mkdir -p tests/tmp/sys/module/export_nodep_$BITNESS echo "live" >tests/tmp/sys/module/export_nodep_$BITNESS/initstate @@ -37,7 +37,7 @@ echo "live" >tests/tmp/sys/module/export_nodep_$BITNESS/initstate # If there's an install command, it will be done. # Clean up sysfs (so we don't think it's loaded) -rm -rf tests/tmp/sys +rm -rf tests/tmp/sys/module/* mkdir -p tests/tmp/etc/modprobe.d echo "install export_nodep-$BITNESS COMMAND" > tests/tmp/etc/modprobe.d/modprobe.conf @@ -53,7 +53,7 @@ echo "live" >tests/tmp/sys/module/export_nodep_$BITNESS/initstate # Do dependencies even if install command. # clean up sysfs (so we don't think it's loaded) -rm -rf tests/tmp/sys +rm -rf tests/tmp/sys/module/* echo "install noexport_dep-$BITNESS COMMAND" > tests/tmp/etc/modprobe.d/modprobe.conf diff --git a/tests/test-modprobe/27cmdline-install-remove.sh b/tests/test-modprobe/27cmdline-install-remove.sh index fef02ff..9411222 100755 --- a/tests/test-modprobe/27cmdline-install-remove.sh +++ b/tests/test-modprobe/27cmdline-install-remove.sh @@ -19,6 +19,9 @@ echo "options noexport_nodep-$BITNESS file-options" > tests/tmp/etc/modprobe.d/m echo "install noexport_nodep-$BITNESS modprobe --ignore-install noexport_nodep-$BITNESS \$CMDLINE_OPTS" >> tests/tmp/etc/modprobe.d/modprobe.conf echo "install othertarget echo \$CMDLINE_OPTS otheropts" >> tests/tmp/etc/modprobe.d/modprobe.conf +# Empty /sys/module/ for install commands +mkdir -p tests/tmp/sys/module + # With quoted args [ "`modprobe noexport_nodep-$BITNESS 'foo="bar baz"' 2>&1`" = "SYSTEM: modprobe --ignore-install noexport_nodep-$BITNESS foo=\"bar baz\"" ] # With unquoted args @@ -4,6 +4,8 @@ #include <string.h> #include <errno.h> #include <elf.h> +#include <sys/types.h> +#include <regex.h> #include "logging.h" #include "util.h" @@ -203,3 +205,30 @@ int __attribute__ ((pure)) native_endianness() return (char) *((uint32_t*)("\1\0\0\2")); } +/* + * Compare "string" with extended regex "pattern". Include backward compatible + * matching of "*" as a wildcard by replacing it with ".*" automatically. + */ +int regex_match(const char *string, const char *pattern) +{ + int status; + regex_t re; + char *fix_pattern; + + /* backward compatibility with old "match" code */ + if (strncmp("*", pattern, 1) != 0) + fix_pattern = (char *)pattern; + else + fix_pattern = ".*"; /* match everything */ + + if (regcomp(&re, fix_pattern, REG_EXTENDED|REG_NOSUB) != 0) + return 0; /* alloc failure */ + + status = regexec(&re, string, (size_t) 0, NULL, 0); + regfree(&re); + + if (status != 0) + return 0; /* no match */ + + return 1; /* match */ +} @@ -44,4 +44,6 @@ int native_endianness(void); #define streq(a,b) (strcmp((a),(b)) == 0) #define strstarts(a,start) (strncmp((a),(start), strlen(start)) == 0) +int regex_match(const char *string, const char *pattern); + #endif diff --git a/zlibsupport.c b/zlibsupport.c index b159765..597820e 100644 --- a/zlibsupport.c +++ b/zlibsupport.c @@ -40,23 +40,6 @@ void *grab_contents(gzFile *gzfd, unsigned long *size) return buffer; } -void *grab_fd(int fd, unsigned long *size) -{ - gzFile gzfd; - - gzfd = gzdopen(fd, "rb"); - if (!gzfd) { - if (errno == ENOMEM) - fatal("Memory allocation failure in gzdopen\n"); - return NULL; - } - - /* gzclose(gzfd) would close fd, which would drop locks. - Don't blame zlib: POSIX locking semantics are so horribly - broken that they should be ripped out. */ - return grab_contents(gzfd, size); -} - /* gzopen handles uncompressed files transparently. */ void *grab_file(const char *filename, unsigned long *size) { |