What are the plans for the include config command? Do you intend to keep it around for a while, or could it be dropped in the next release? I'm asking, because it is easy to share parts of the config file readers in depmod and modprobe, if include goes away. Basically, you could have a generic function like this to read in the configuration into a pair of lists: int read_config_d(const char *pathname, const char *const valid_ext[], struct list_head *file_list, struct list_head *cmd_list); where struct conf_file { struct list_head node; char name[]; }; struct conf_cmd { struct list_head node; const char *filename; int linenum; char cmd[]; }; Command parsing would still happen separately in dep/modprobe, like before. Cheers, Andreas Here is a draft of what I have in mind: #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <dirent.h> #include <fnmatch.h> #include <stdarg.h> #include "list.h" #include "util.h" #include "logging.h" extern unsigned int make_map_files; extern unsigned int use_binary_indexes; struct conf_file { struct list_head node; char name[]; }; struct conf_cmd { struct list_head node; const char *filename; int linenum; char cmd[]; }; static struct conf_file *make_conf_file(const char *pathname, const char *filename) { struct conf_file *cf; cf = malloc(sizeof(struct conf_file) + strlen(pathname) + 1 + strlen(filename) + 1); if (cf) { if (strlen(pathname) != 0) sprintf(cf->name, "%s/%s", pathname, filename); else strcpy(cf->name, filename); } return cf; } static struct conf_cmd *make_conf_cmd(const char *filename, int linenum, const char *s) { struct conf_cmd *ccmd; ccmd = malloc(sizeof(struct conf_cmd) + strlen(s) + 1); if (ccmd != NULL) { ccmd->filename = filename; ccmd->linenum = linenum; strcpy(ccmd->cmd, s); } return ccmd; } /* * Return true if string a ends with b. */ int __attribute__ ((pure)) ends_in(const char *a, const char *b) { return strlen(a) >= strlen(b) && streq(a + strlen(a) - strlen(b), b); } int config_filter(const char *name, const char *const keep_ext[]) { const char *const *p; static const char *const skip_prefix[] = { ".", "~", "CVS", NULL }; #if 0 static const char *const keep_ext[] = { ".conf", ".alias", NULL }; #endif for (p = skip_prefix; *p; p++) { if (strstarts(name, *p)) return 0; } for (p = keep_ext; *p; p++) { if (ends_in(name, *p)) return 1; } return 0; } int read_config_d(const char *pathname, const char *const valid_ext[], struct list_head *file_list, struct list_head *cmd_list) { DIR *dir; struct conf_file *cf, *cf_tmp; /* Scan directory */ dir = opendir(pathname); if (dir) { struct dirent *i; /* Sort files from directory into list. */ while ((i = readdir(dir)) != NULL) { if (!config_filter(i->d_name, valid_ext)) continue; cf = make_conf_file(pathname, i->d_name); if (cf == NULL) continue; list_for_each_entry(cf_tmp, file_list, node) if (strcmp(cf_tmp->name, cf->name) >= 0) break; list_add_tail(&cf->node, &cf_tmp->node); } closedir(dir); } else { /* Add single configuration file to list. */ cf = make_conf_file("", pathname); if (cf != NULL) list_add_tail(&cf->node, file_list); } /* Read files */ list_for_each_entry_safe(cf, cf_tmp, file_list, node) { FILE *cfile; char *line; unsigned int linenum = 0; cfile = fopen(cf->name, "r"); if (!cfile) { warn("Failed to open config file " "%s: %s\n", cf->name, strerror(errno)); list_del(&cf->node); free(cf); continue; } /* Read commands */ while ((line = getline_wrapped(cfile, &linenum)) != NULL) { char *s; struct conf_cmd *ccmd; s = line + strspn(line, "\t "); if (s[0] != '#' && s[0] != '\0') { ccmd = make_conf_cmd(cf->name, linenum, s); if (ccmd) list_add_tail(cmd_list, &ccmd->node); } free(line); } fclose(cfile); } return 1; } void dump_config(struct list_head *cmd_list) { const char *curfile = ""; struct conf_cmd *cmd; list_for_each_entry(cmd, cmd_list, node) { if (!streq(cmd->filename, curfile)) { curfile = cmd->filename; printf("FILE: %s\n", curfile); } printf("%s\n", cmd->cmd); } } #if 0 /* * Allocate 'size' bytes + enough space for 'nstr' strings * following the nstr parameter. */ static void *alloc_str_struct(size_t size, unsigned int nstr, ...) { va_list ap; unsigned int i; size_t buflen; va_start(ap, nstr); for (i = 0, buflen = size; i < n; i++) { char **s = va_arg(ap, char **); buflen += strlen(*s) + 1; } va_end(ap); return malloc(buflen); } #endif /* In depmod.c */ static int parse_depmod_config(struct list_head *cmd_list, const char *basedir, const char *kernelversion, struct module_search **search, struct module_overrides **overrides) { struct conf_cmd *ccmd, *ccmd_tmp; list_for_each_entry_safe(ccmd, ccmd_tmp, cmd_list, node) { char *line, *s, *cmd, *modname; s = line = NOFAIL(strdup(ccmd->cmd)); cmd = next_token(&s); if (streq(cmd, "search")) { char *search_path; while ((search_path = next_token(&s))) { char *dirname; if (streq(search_path, MODULE_BUILTIN_KEY)) { *search = add_search(MODULE_BUILTIN_KEY, 0, *search); continue; } nofail_asprintf(&dirname, "%s%s%s/%s", basedir, MODULE_DIR, kernelversion, search_path); *search = add_search(dirname, strlen(dirname), *search); free(dirname); } } else if (streq(cmd, "override")) { char *pathname = NULL, *version, *subdir; modname = next_token(&s); version = next_token(&s); subdir = next_token(&s); if (!modname || !version || !subdir) goto bad_grammar; if (!streq(version, kernelversion) && !streq(version, "*")) continue; nofail_asprintf(&pathname, "%s%s%s/%s/%s.ko", basedir, MODULE_DIR, kernelversion, subdir, modname); *overrides = add_override(pathname, *overrides); free(pathname); } else if (streq(cmd, "make_map_files")) { char *option = next_token(&s); if (!option) goto bad_grammar; if (streq(option, "yes")) make_map_files = 1; else if (streq(option, "no")) make_map_files = 0; else goto bad_grammar; } else { bad_grammar: grammar(cmd, ccmd->filename, ccmd->linenum); list_del(&ccmd->node); free(ccmd); } free(line); } return 1; } /* In modprobe.c */ static int parse_modprobe_config(struct list_head *cmd_list, const char *name, int dump_only, int removing, struct module_options **options, struct module_command **commands, struct module_alias **aliases, struct module_blacklist **blacklist) { struct conf_cmd *ccmd, *ccmd_tmp; list_for_each_entry_safe(ccmd, ccmd_tmp, cmd_list, node) { char *line, *s, *cmd, *modname; s = line = NOFAIL(strdup(ccmd->cmd)); cmd = next_token(&s); if (streq(cmd, "alias")) { char *wildcard = underscores(next_token(&s)); char *realname = underscores(next_token(&s)); if (!wildcard || !realname) goto bad_grammar; if (fnmatch(wildcard, name, 0) == 0) *aliases = add_alias(realname, *aliases); } else if (streq(cmd, "options")) { modname = underscores(next_token(&s)); s = skip_space(s); if (!modname || !s) goto bad_grammar; *options = add_options(modname, s, *options); } else if (streq(cmd, "install")) { modname = underscores(next_token(&s)); s = skip_space(s); if (!modname || !s) goto bad_grammar; if (!removing) *commands = add_command(modname, s, *commands); } else if (streq(cmd, "blacklist")) { modname = underscores(next_token(&s)); if (!modname) goto bad_grammar; if (!removing) *blacklist = add_blacklist(modname, *blacklist); } else if (streq(cmd, "remove")) { modname = underscores(next_token(&s)); s = skip_space(s); if (!modname || !s) goto bad_grammar; if (removing) *commands = add_command(modname, s, *commands); } else if (streq(cmd, "config")) { char *tmp = next_token(&s); if (!tmp) goto bad_grammar; else if (streq(tmp, "binary_indexes")) { tmp = next_token(&s); if (streq(tmp, "yes")) use_binary_indexes = 1; if (streq(tmp, "no")) use_binary_indexes = 0; } } else { bad_grammar: grammar(cmd, ccmd->filename, ccmd->linenum); list_del(&ccmd->node); free(ccmd); } free(line); } return 1; } -- To unsubscribe from this list: send the line "unsubscribe linux-modules" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html