aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Robinson <andr345@gmail.com>2009-10-03 21:30:18 +0200
committerAndreas Robinson <andr345@gmail.com>2009-10-03 21:30:18 +0200
commitb8fef87bd628dfaf0f1e43420be1ed4e49f9d35b (patch)
tree469366570726adcf792ad686ac7c7c1044bec093
parent36b8d179a5ae4a3c2a27a869bcbfd535d7d4a2e0 (diff)
downloadmodule-init-tools-b8fef87bd628dfaf0f1e43420be1ed4e49f9d35b.tar.gz
modprobe: add softdep command
Imlementation notes ------------------- * find_softdep()/do_softdep() mirrors find_command()/do_command() precisely. (And if they don't, that's a bug.) * Failures in the indirect modprobes, ie. those run by the softdep command, are ignored. This seems correct for removing, but I'm unsure what the proper action is when installing. An example - or how it's supposed to work ----------------------------------------- Configuration: softdep foo --pre pre1 pre2 --post post1 post2 Installing a module: $modprobe foo <CMDLINE_OPTS> yields modprobe pre1 modprobe pre2 modprobe --ignore-install foo <CMDLINE_OPTS> modprobe post1 modprobe post2 Likewiese, removing a module: $modprobe -r foo yields modprobe -r post2 modprobe -r post1 modprobe --ignore-remove -r foo modprobe -r pre2 modprobe -r pre1 Signed-off-by: Andreas Robinson <andr345@gmail.com>
-rw-r--r--modprobe.c159
1 files changed, 152 insertions, 7 deletions
diff --git a/modprobe.c b/modprobe.c
index a1eb33a..4448dbc 100644
--- a/modprobe.c
+++ b/modprobe.c
@@ -381,12 +381,23 @@ struct module_blacklist
char *modulename;
};
+struct module_softdep
+{
+ struct module_softdep *next;
+ char *buf;
+ /* The modname and string tables point to buf. */
+ char *modname;
+ struct string_table *pre;
+ struct string_table *post;
+};
+
struct modprobe_conf
{
struct module_options *options;
struct module_command *commands;
struct module_alias *aliases;
struct module_blacklist *blacklist;
+ struct module_softdep *softdeps;
};
/* Link in a new option line from the config file. */
@@ -486,6 +497,18 @@ static const char *find_command(const char *modname,
return NULL;
}
+/* Find soft dependencies, if any. */
+static const struct module_softdep *
+find_softdep(const char *modname, const struct module_softdep *softdeps)
+{
+ while (softdeps) {
+ if (fnmatch(softdeps->modname, modname, 0) == 0)
+ return softdeps;
+ softdeps = softdeps->next;
+ }
+ return NULL;
+}
+
static char *append_option(char *options, const char *newoption)
{
options = NOFAIL(realloc(options, strlen(options) + 1
@@ -799,6 +822,43 @@ static int parse_config_file(const char *filename,
*commands = add_command(underscores(modname),
ptr, *commands);
}
+ } else if (streq(cmd, "softdep")) {
+ char *tk;
+ int pre = 0, post = 0;
+ struct string_table *pre_modnames = NULL;
+ struct string_table *post_modnames = NULL;
+ struct module_softdep *new;
+
+ modname = underscores(strsep_skipspace(&ptr, "\t "));
+ if (!modname || !ptr)
+ goto syntax_error;
+ while ((tk = strsep_skipspace(&ptr, "\t ")) != NULL) {
+ if (streq(tk, "--pre")) {
+ pre = 1; post = 0;
+ } else if (streq(tk, "--post")) {
+ pre = 0; post = 1;
+ } else if (pre) {
+ pre_modnames = NOFAIL(
+ strtbl_add(tk, pre_modnames));
+ } else if (post) {
+ post_modnames = NOFAIL(
+ strtbl_add(tk, post_modnames));
+ } else {
+ strtbl_free(pre_modnames);
+ strtbl_free(post_modnames);
+ goto syntax_error;
+ }
+ }
+ new = NOFAIL(malloc(sizeof(*new)));
+ new->buf = line;
+ new->modname = modname;
+ new->pre = pre_modnames;
+ new->post = post_modnames;
+ new->next = conf->softdeps;
+ conf->softdeps = new;
+
+ line = NULL; /* Don't free() this line. */
+
} else if (streq(cmd, "config")) {
char *tmp = strsep_skipspace(&ptr, "\t ");
@@ -1091,11 +1151,66 @@ static void do_command(const char *modname,
free(replaced_cmd);
}
+/* Forward declaration */
+int do_modprobe(const char *modname,
+ const char *newname,
+ const char *cmdline_opts,
+ const char *configname,
+ const char *dirname,
+ errfn_t error,
+ modprobe_flags_t flags);
+
+static void do_softdep(const struct module_softdep *softdep,
+ const char *cmdline_opts,
+ const char *configname,
+ const char *dirname,
+ errfn_t error,
+ modprobe_flags_t flags)
+{
+ struct string_table *pre_modnames, *post_modnames;
+ int i, j;
+
+ if (flags & mit_remove) {
+ /* Reverse module order if removing. */
+ pre_modnames = softdep->post;
+ post_modnames = softdep->pre;
+ } else {
+ pre_modnames = softdep->pre;
+ post_modnames = softdep->post;
+ }
+
+ /* Modprobe pre_modnames */
+
+ for (i = 0; i < pre_modnames->cnt; i++) {
+ /* Reverse module order if removing. */
+ j = (flags & mit_remove) ? pre_modnames->cnt-1 - i : i;
+
+ do_modprobe(pre_modnames->str[j], NULL, "",
+ configname, dirname, warn, flags);
+ }
+
+ /* Modprobe main module, passing cmdline_opts, ignoring softdep */
+
+ do_modprobe(softdep->modname, NULL, cmdline_opts,
+ configname, dirname, warn, flags | mit_ignore_commands);
+
+ /* Modprobe post_modnames */
+
+ for (i = 0; i < post_modnames->cnt; i++) {
+ /* Reverse module order if removing. */
+ j = (flags & mit_remove) ? post_modnames->cnt-1 - i : i;
+
+ do_modprobe(pre_modnames->str[j], NULL, "", configname,
+ dirname, warn, flags);
+ }
+}
+
/* Actually do the insert. Frees second arg. */
static int insmod(struct list_head *list,
char *optstring,
const char *newname,
const struct module_options *options,
+ const struct module_softdep *softdeps,
const struct module_command *commands,
const char *cmdline_opts,
const char *configname,
@@ -1105,6 +1220,7 @@ static int insmod(struct list_head *list,
{
int ret, fd;
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;
@@ -1118,7 +1234,7 @@ static int insmod(struct list_head *list,
f &= ~mit_first_time;
f &= ~mit_ignore_commands;
if ((rc = insmod(list, NOFAIL(strdup("")), NULL,
- options, commands, "",
+ options, softdeps, commands, "",
configname, dirname, warn, f)) != 0)
{
error("Error inserting %s (%s): %s\n",
@@ -1144,6 +1260,14 @@ static int insmod(struct list_head *list,
goto out_unlock;
}
+ softdep = find_softdep(mod->modname, softdeps);
+ if (softdep && !(flags & mit_ignore_commands)) {
+ close_file(fd);
+ do_softdep(softdep, cmdline_opts, configname, dirname,
+ error, flags & (mit_remove | mit_dry_run));
+ goto out_optstring;
+ }
+
command = find_command(mod->modname, commands);
if (command && !(flags & mit_ignore_commands)) {
close_file(fd);
@@ -1202,6 +1326,7 @@ static int insmod(struct list_head *list,
/* Do recursive removal. */
static void rmmod(struct list_head *list,
const char *name,
+ struct module_softdep *softdeps,
struct module_command *commands,
const char *cmdline_opts,
const char *configname,
@@ -1209,6 +1334,7 @@ static void rmmod(struct list_head *list,
errfn_t error,
modprobe_flags_t flags)
{
+ const struct module_softdep *softdep;
const char *command;
unsigned int usecount = 0;
struct module *mod = list_entry(list->next, struct module, list);
@@ -1219,7 +1345,15 @@ static void rmmod(struct list_head *list,
if (!name)
name = mod->modname;
- /* Even if renamed, find commands to orig. name. */
+ /* Even if renamed, find commands/softdeps to orig. name. */
+
+ softdep = find_softdep(mod->modname, softdeps);
+ if (softdep && !(flags & mit_ignore_commands)) {
+ do_softdep(softdep, cmdline_opts, configname, dirname,
+ error, flags & (mit_remove | mit_dry_run));
+ goto remove_rest;
+ }
+
command = find_command(mod->modname, commands);
if (command && !(flags & mit_ignore_commands)) {
do_command(mod->modname, command, flags & mit_dry_run, error,
@@ -1256,7 +1390,7 @@ static void rmmod(struct list_head *list,
flags &= ~mit_ignore_commands;
flags |= mit_ignore_loaded;
- rmmod(list, NULL, commands, "",
+ rmmod(list, NULL, softdeps, commands, "",
configname, dirname, warn, flags);
}
return;
@@ -1272,6 +1406,7 @@ static int handle_module(const char *modname,
const char *newname,
const char *options,
struct module_options *modoptions,
+ struct module_softdep *softdeps,
struct module_command *commands,
const char *cmdline_opts,
const char *configname,
@@ -1280,10 +1415,19 @@ static int handle_module(const char *modname,
modprobe_flags_t flags)
{
if (list_empty(todo_list)) {
+ const struct module_softdep *softdep;
const char *command;
/* The dependencies have to be real modules, but
handle case where the first is completely bogus. */
+
+ softdep = find_softdep(modname, softdeps);
+ if (softdep && !(flags & mit_ignore_commands)) {
+ do_softdep(softdep, cmdline_opts, configname, dirname,
+ error, flags & (mit_remove | mit_dry_run));
+ return 0;
+ }
+
command = find_command(modname, commands);
if (command && !(flags & mit_ignore_commands)) {
do_command(modname, command, flags & mit_dry_run, error,
@@ -1298,11 +1442,11 @@ static int handle_module(const char *modname,
if (flags & mit_remove) {
flags &= ~mit_ignore_loaded;
- rmmod(todo_list, newname, commands, cmdline_opts,
+ rmmod(todo_list, newname, softdeps, commands, cmdline_opts,
configname, dirname, error, flags);
} else
insmod(todo_list, NOFAIL(strdup(options)), newname,
- modoptions, commands, cmdline_opts,
+ modoptions, softdeps, commands, cmdline_opts,
configname, dirname, error, flags);
return 0;
@@ -1362,6 +1506,7 @@ int do_modprobe(const char *modulename,
/* We only use canned aliases as last resort. */
if (list_empty(&list)
+ && !find_softdep(modname, conf.softdeps)
&& !find_command(modname, conf.commands))
{
char *aliasfilename;
@@ -1403,7 +1548,7 @@ int do_modprobe(const char *modulename,
read_depends(dirname, aliases->module, &list);
failed |= handle_module(aliases->module,
&list, newname, opts, conf.options,
- conf.commands, cmdline_opts,
+ conf.softdeps, conf.commands, cmdline_opts,
configname, dirname, err, flags);
aliases = aliases->next;
@@ -1415,7 +1560,7 @@ int do_modprobe(const char *modulename,
goto out;
failed |= handle_module(modname, &list, newname, cmdline_opts,
- conf.options, conf.commands, cmdline_opts,
+ conf.options, conf.softdeps, conf.commands, cmdline_opts,
configname, dirname, error, flags);
}
out: