diff -Nur modutils-2.3.13/ChangeLog modutils-2.3.14/ChangeLog --- modutils-2.3.13/ChangeLog Tue Jul 25 16:31:08 2000 +++ modutils-2.3.14/ChangeLog Mon Aug 7 18:07:12 2000 @@ -1,3 +1,11 @@ +2000-08-07 Keith Owens + + modutils 2.3.14 + + * Replace ftw() with modutils specific xftw(). + * Use absolute filename in __insmod symbol. + * Generate modules.pcimap from MODULE_DEVICE_TABLE(). + 2000-07-20 Keith Owens modutils 2.3.13 diff -Nur modutils-2.3.13/depmod/depmod.c modutils-2.3.14/depmod/depmod.c --- modutils-2.3.13/depmod/depmod.c Sun Jul 9 14:19:11 2000 +++ modutils-2.3.14/depmod/depmod.c Mon Aug 7 18:09:03 2000 @@ -37,7 +37,7 @@ Keith Owens April 2000. */ -#ident "$Id: depmod.c 1.15 Sun, 09 Jul 2000 14:19:11 +1000 kaos $" +#ident "$Id: depmod.c 1.18 Mon, 07 Aug 2000 18:09:03 +1000 kaos $" #include #include @@ -75,6 +75,14 @@ char status; } SYMBOL; +/* Extracted from 2.4.0-test6-pre6/include/linux/pci.h */ +struct pci_device_id { + unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */ + unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ + unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */ + unsigned long driver_data; /* Data private to the driver */ +}; + typedef struct MODULE { char *name; int resolved; @@ -82,6 +90,8 @@ SYMBOL **symtab; int n_syms; } defsym, undefs; + struct pci_device_id *pci; + int n_pci; } MODULE; typedef enum SYM_STATUS { @@ -106,7 +116,7 @@ static int quiet; /* Don't print errors */ static int showerror; /* Shows undefined symbols */ -static int verbose; /* Print all modules visiteds */ +int flag_verbose = 0; extern int depmod_main(int argc, char **argv); extern int depmod_main_32(int argc, char **argv); @@ -253,6 +263,38 @@ } /* + * Verify that an "address" falls within the module image. + * Note: assumes same machine and arch for depmod and module. + */ +static int in_range(const struct obj_file *f, unsigned long m_size, + ElfW(Addr) start, unsigned int length) +{ + return(start >= f->baseaddr && (start + length - 1 - f->baseaddr) <= m_size); +} + +/* + * Extract any pci_device_table from the module. + * Note: assumes same machine and arch for depmod and module. + */ +static void extract_pci_device_id(struct obj_file *f, void *image, unsigned long m_size, MODULE *mod) +{ + struct pci_device_id pci; + ElfW(Addr) ref_pci; + ElfW(Addr) ref_ref_pci = obj_symbol_final_value(f, obj_find_symbol(f, "__module_pci_device_table")); + if (!in_range(f, m_size, ref_ref_pci, sizeof(ref_pci))) + return; + memcpy(&ref_pci, (char *)image + ref_ref_pci - f->baseaddr, sizeof(ref_pci)); + while (in_range(f, m_size, ref_pci, sizeof(pci))) { + memcpy(&pci, (char *)image + ref_pci - f->baseaddr, sizeof(pci)); + ref_pci += sizeof(pci); + if (!pci.vendor) + break; + mod->pci = xrealloc(mod->pci, ++(mod->n_pci)*sizeof(*(mod->pci))); + mod->pci[mod->n_pci-1] = pci; + } +} + +/* * Read the symbols in an object and register them in the symbol table. * Return -1 if there is an error. */ @@ -274,6 +316,8 @@ int n_undefs = 0; int n_defsym = 0; char *p; + void *image; + unsigned long m_size; p = strrchr(objname, '/'); len = 1 + (int)(p - objname); @@ -406,8 +450,25 @@ mod->resolved = 1; } - obj_free(f); + /* Do a pseudo relocation to base address 0x1000 (arbitrary). + * All undefined symbols are treated as absolute 0. This builds + * enough of a module to allow extraction of internal data such + * as device tables. + */ + obj_clear_undefineds(f); + obj_allocate_commons(f); + arch_create_got(f); + m_size = obj_load_size(f); + if (!obj_relocate(f, 0x1000)) { + error("depmod obj_relocate failed\n"); + return(-1); + } + image = xmalloc(m_size); + obj_create_image(f, image); + extract_pci_device_id(f, image, m_size, mod); + free(image); + obj_free(f); return 0; } @@ -420,7 +481,6 @@ * OR * from a file containing kernel symbols from a different kernel. * The file can be either a "System.map" file or a copy of "/proc/ksyms". - * Use a copy of "/proc/ksyms" if you are using versioned symbols! * * Return -1 if any error. */ @@ -528,25 +588,35 @@ /* * Format the dependancy list of a module into a simple makefile. * Print the dependancies in the depfile (or stdout if depfile is NULL). + * Print the pcimap in the pcimapfile (or stdout if pcimapfile is NULL). */ -static void prtdepend(const char *pdepfile, char *base_dir) +static void prtdepend(const char *pdepfile, const char *ppcimapfile, char *base_dir) { - FILE *out = stdout; + FILE *dep = stdout; + FILE *pcimap = stdout; MODULE **tbdep; - MODULE *ptmod = modules; + MODULE *ptmod; int i; int skipchars; /* For depmod -a in image of a tree */ if (pdepfile != NULL) { - if ((out = fopen(pdepfile, "w")) == NULL) { + if ((dep = fopen(pdepfile, "w")) == NULL) { error("Can't open %s for writing", pdepfile); exit(-1); } } + if (ppcimapfile != NULL) { + if ((pcimap = fopen(ppcimapfile, "w")) == NULL) { + error("Can't open %s for writing", ppcimapfile); + exit(-1); + } + } + skipchars = (base_dir ? strlen(base_dir) : 0); tbdep = (MODULE **)alloca(sizeof(MODULE) * n_modules); + ptmod = modules; for (i = 0; i < n_modules; i++, ptmod++) { SYMBOL **undefs = ptmod->undefs.symtab; int n_undefs = ptmod->undefs.n_syms; @@ -585,18 +655,63 @@ nberr++; } } + verbose("%s\n", ptmod->name + skipchars); - if (verbose) - printf("%s\n", ptmod->name + skipchars); - - fprintf(out, "%s:", ptmod->name + skipchars); + fprintf(dep, "%s:", ptmod->name + skipchars); for (m = 0; m < nbdepmod; m++) { if (m != 0 /*&& (m & 3) == 0*/) - fprintf(out, " \\\n"); - fprintf(out, "\t%s", tbdep[m]->name + skipchars); + fprintf(dep, " \\\n"); + fprintf(dep, "\t%s", tbdep[m]->name + skipchars); } - fprintf(out, "\n\n"); + fprintf(dep, "\n\n"); } + + ptmod = modules; + fprintf(pcimap, "# module vendor device subvendor subdevice class class_mask driver_data\n"); + for (i = 0; i < n_modules; i++, ptmod++) { + int j, l; + struct pci_device_id *pci = ptmod->pci; + char *name, *shortname; + if (!ptmod->n_pci) + continue; + name = xstrdup(ptmod->name); + shortname = strrchr(name, '/'); + if (!shortname) + shortname = name; /* should never happen */ + else { + ++shortname; + l = strlen(shortname); + if (l > 3 && strcmp(shortname+l-3, ".gz") == 0) { + *(shortname+l-3) = '\0'; + l -= 3; + } + if (l > 2 && strcmp(shortname+l-2, ".o") == 0) { + *(shortname+l-2) = '\0'; + l -= 2; + } else if (l > 4 && strcmp(shortname+l-4, ".mod") == 0) { + *(shortname+l-4) = '\0'; + l -= 4; + } + } + for (j = 0; j < ptmod->n_pci; j++, pci++) { + fprintf(pcimap, "%-20s 0x%0*x 0x%0*x 0x%0*x 0x%0*x 0x%0*x 0x%0*x 0x%0*lx\n", + shortname, + 2*sizeof(pci->vendor), pci->vendor, + 2*sizeof(pci->device), pci->device, + 2*sizeof(pci->subvendor), pci->subvendor, + 2*sizeof(pci->subdevice), pci->subdevice, + 2*sizeof(pci->class), pci->class, + 2*sizeof(pci->class_mask), pci->class_mask, + 2*sizeof(pci->driver_data), pci->driver_data); + } + free(name); + } + + /* Close depfile last, critical timestamp */ + if (ppcimapfile != NULL) + fclose(pcimap); + if (pdepfile != NULL) + fclose(dep); } /* For common 3264, only compile the usage message once, in the 64 bit version */ @@ -741,7 +856,7 @@ break; case 'v': - verbose = 1; + flag_verbose = 1; break; case 'V': @@ -785,7 +900,7 @@ for (i = 0; g && i < g->pathc; i++) loadobj(g->pathv[i], ignore_suffix); resolve(); - prtdepend(nflag ? NULL : depfile, base_dir); + prtdepend(nflag ? NULL : depfile, nflag ? NULL : pcimapfile, base_dir); } } else { /* not stdmode */ @@ -793,7 +908,7 @@ for (; argc > 0 && ret != -1; ++argv, --argc) loadobj(*argv, ignore_suffix); resolve(); - prtdepend(NULL, base_dir); + prtdepend(NULL, NULL, base_dir); } } diff -Nur modutils-2.3.13/include/config.h modutils-2.3.14/include/config.h --- modutils-2.3.13/include/config.h Tue Jul 11 16:38:38 2000 +++ modutils-2.3.14/include/config.h Mon Aug 7 18:07:12 2000 @@ -25,6 +25,7 @@ #ifndef _CONFIG_H #define _CONFIG_H +#include #include #define ETC_MODULES_CONF "/etc/modules.conf" @@ -63,11 +64,14 @@ extern int nexecs; extern char *insmod_opt; extern char *depfile; +extern char *pcimapfile; extern char *config_file; extern char *optlist[]; +extern char *prune[]; extern OPT_LIST *opt_list; extern OPT_LIST *abovelist; extern OPT_LIST *belowlist; +extern OPT_LIST *prunelist; extern OPT_LIST *probe_list; extern OPT_LIST *probeall_list; extern OPT_LIST *aliases; diff -Nur modutils-2.3.13/include/obj.h modutils-2.3.14/include/obj.h --- modutils-2.3.13/include/obj.h Tue Jul 25 16:31:08 2000 +++ modutils-2.3.14/include/obj.h Mon Aug 7 18:07:12 2000 @@ -24,7 +24,7 @@ #ifndef MODUTILS_OBJ_H #define MODUTILS_OBJ_H 1 -#ident "$Id: obj.h 1.8 Tue, 25 Jul 2000 16:31:08 +1000 kaos $" +#ident "$Id: obj.h 1.9 Mon, 07 Aug 2000 18:07:12 +1000 kaos $" /* The relocatable object is manipulated using elfin types. */ @@ -151,6 +151,7 @@ #define obj_string_patch ObjW(string_patch) #define obj_symbol_patch ObjW(symbol_patch) #define obj_check_undefineds ObjW(check_undefineds) +#define obj_clear_undefineds ObjW(clear_undefineds) #define obj_allocate_commons ObjW(allocate_commons) #define obj_load_size ObjW(load_size) #define obj_relocate ObjW(relocate) @@ -209,6 +210,8 @@ struct obj_symbol *sym); int obj_check_undefineds (struct obj_file *f, int quiet); + +void obj_clear_undefineds (struct obj_file *f); void obj_allocate_commons (struct obj_file *f); diff -Nur modutils-2.3.13/include/util.h modutils-2.3.14/include/util.h --- modutils-2.3.13/include/util.h Tue Jul 25 11:43:00 2000 +++ modutils-2.3.14/include/util.h Mon Aug 7 01:20:16 2000 @@ -23,7 +23,9 @@ #ifndef MODUTILS_UTIL_H #define MODUTILS_UTIL_H 1 -#ident "$Id: util.h 1.5 Tue, 25 Jul 2000 11:43:00 +1000 kaos $" +#ident "$Id: util.h 1.6 Mon, 07 Aug 2000 01:20:16 +1000 kaos $" + +#include #define SHELL_META "&();|<>$`\"'\\!{}[]~=+:?*" /* Sum of bj0rn and Debian */ @@ -32,10 +34,16 @@ char *xstrdup(const char *); int arch64(void); +typedef int (*xftw_func_t)(const char *, const struct stat *); +extern int xftw(const char *directory, xftw_func_t); + /* Error logging */ extern int log; extern int errors; extern const char *error_file; + +extern int flag_verbose; +extern void verbose(const char *ctl,...); void error(const char *fmt, ...) #ifdef __GNUC__ diff -Nur modutils-2.3.13/include/version.h modutils-2.3.14/include/version.h --- modutils-2.3.13/include/version.h Sun Jul 9 22:23:15 2000 +++ modutils-2.3.14/include/version.h Wed Aug 2 10:39:12 2000 @@ -1 +1 @@ -#define MODUTILS_VERSION "2.3.13" +#define MODUTILS_VERSION "2.3.14" diff -Nur modutils-2.3.13/insmod/insmod.c modutils-2.3.14/insmod/insmod.c --- modutils-2.3.13/insmod/insmod.c Sun Jul 9 22:30:18 2000 +++ modutils-2.3.14/insmod/insmod.c Mon Aug 7 18:07:12 2000 @@ -48,7 +48,7 @@ Keith Owens April 2000. */ -#ident "$Id: insmod.c 1.21 Sun, 09 Jul 2000 22:30:18 +1000 kaos $" +#ident "$Id: insmod.c 1.24 Mon, 07 Aug 2000 18:07:12 +1000 kaos $" #include #include @@ -78,7 +78,6 @@ static int flag_force_load = 0; static int flag_silent_poll = 0; -static int flag_verbose = 0; static int flag_export = 1; static int flag_load_map = 0; static int flag_ksymoops = 1; @@ -612,8 +611,8 @@ { struct obj_section *sec; struct obj_symbol *sym; - char *name; - char str[STRVERSIONLEN]; + char *name, *absolute_filename; + char str[STRVERSIONLEN], real[PATH_MAX]; const char symprefix[] = "__insmod_"; int i, l, lm_name, lfilename, use_ksymtab, version; struct stat statbuf; @@ -625,8 +624,19 @@ ".bss" }; + if (realpath(filename, real)) { + absolute_filename = xstrdup(real); + } + else { + int save_errno = errno; + error("cannot get realpath for %s", filename); + errno = save_errno; + perror(""); + absolute_filename = xstrdup(filename); + } + lm_name = strlen(m_name); - lfilename = strlen(filename); + lfilename = strlen(absolute_filename); /* add to ksymtab if it already exists or there is no ksymtab and other symbols * are not to be exported. otherwise leave ksymtab alone for now, the @@ -651,11 +661,11 @@ 8+ /* version in dec */ 1; /* nul */ name = xmalloc(l); - if (stat(filename, &statbuf) != 0) + if (stat(absolute_filename, &statbuf) != 0) statbuf.st_mtime = 0; version = get_module_version(f, str); /* -1 if not found */ snprintf(name, l, "%s%s_O%s_M%0*lX_V%d", - symprefix, m_name, filename, + symprefix, m_name, absolute_filename, 2*sizeof(statbuf.st_mtime), statbuf.st_mtime, version); sym = obj_add_symbol(f, name, -1, @@ -664,6 +674,7 @@ if (use_ksymtab) add_ksymtab(f, sym); } + free(absolute_filename); /* tag the desired sections if size is non-zero */ @@ -1422,7 +1433,13 @@ /* Let the module know about the kernel symbols. */ add_kernel_symbols(f); - /* Allocate common symbols, symbol tables, and string tables. */ + /* Allocate common symbols, symbol tables, and string tables. + * + * The calls marked DEPMOD indicate the bits of code that depmod + * uses to do a pseudo relocation, ignoring undefined symbols. + * Any changes made to the relocation sequence here should be + * checked against depmod. + */ #ifdef COMPAT_2_0 if (k_new_syscalls ? !create_this_module(f, m_name) @@ -1433,15 +1450,15 @@ goto out; #endif - if (!obj_check_undefineds(f, quiet)) + if (!obj_check_undefineds(f, quiet)) /* DEPMOD, obj_clear_undefineds */ goto out; - obj_allocate_commons(f); + obj_allocate_commons(f); /* DEPMOD */ if (optind < argc) { if (!process_module_arguments(f, argc - optind, argv + optind)) goto out; } - arch_create_got(f); + arch_create_got(f); /* DEPMOD */ hide_special_symbols(f); if (flag_ksymoops) add_ksymoops_symbols(f, filename, m_name); @@ -1463,7 +1480,7 @@ goto out; } /* Module has now finished growing; find its size and install it. */ - m_size = obj_load_size(f); + m_size = obj_load_size(f); /* DEPMOD */ if (noload) { /* Don't bother actually touching the kernel. */ @@ -1496,7 +1513,7 @@ } } - if (!obj_relocate(f, m_addr)) { + if (!obj_relocate(f, m_addr)) { /* DEPMOD */ if (!noload) delete_module(m_name); goto out; diff -Nur modutils-2.3.13/insmod/modprobe.c modutils-2.3.14/insmod/modprobe.c --- modutils-2.3.13/insmod/modprobe.c Tue Jul 11 16:38:38 2000 +++ modutils-2.3.14/insmod/modprobe.c Mon Aug 7 02:14:58 2000 @@ -83,7 +83,6 @@ static char *conf_file = NULL; -static char verbose_flag = 0; static int runit = 1; static int quiet = 0; static int debug = 0; @@ -91,17 +90,6 @@ static NODE *in_kernel; static NODE *in_depfile; -static void verbose(const char *ctl,...) -{ - if (verbose_flag) { - va_list list; - va_start(list, ctl); - vprintf(ctl, list); - va_end(list); - fflush(stdout); - } -} - /* * Strip the path and extension off a file name */ @@ -623,6 +611,18 @@ } } + if (prunelist) { + puts("# Prune"); + for (op = prunelist; op->name; ++op) { + GLOB_LIST *g = op->opts; + int n; + printf("prune %s", op->name); + for (n = 0; n < g->pathc; ++n) + printf(" %s", g->pathv[n]); + printf("\n"); + } + } + if (abovelist) { puts("# Above"); for (op = abovelist; op->name; ++op) { @@ -1529,7 +1529,7 @@ break; case 'v': - verbose_flag = 1; + flag_verbose = 1; break; case 'k': diff -Nur modutils-2.3.13/man/modules.conf.5 modutils-2.3.14/man/modules.conf.5 --- modutils-2.3.13/man/modules.conf.5 Thu Jul 20 13:19:39 2000 +++ modutils-2.3.14/man/modules.conf.5 Mon Aug 7 18:07:12 2000 @@ -40,6 +40,7 @@ [add] options module MODULE_SPECIFIC_OPTIONS path=A_PATH path[TAG]=A_PATH + pcimapfile=A_PATH [add] probe name module_list [add] probeall name module_list post-install module command ... @@ -249,6 +250,12 @@ which can be used to mark all directories containing modules that should be loaded at boot-time. .TP +.I "pcimapfile=A_PATH" +This is the path to the pcimap file that will be created by +.B depmod +and used by install scripts to find the module that supports a pci device. +Normally the default value should be used, see below. +.TP .I "alias alias_name result" The "alias" directive can be used to give alias names to modules. A line in /etc/modules.conf that looks like this: @@ -494,8 +501,10 @@ the following defaults are assumed: .PP depfile=/lib/modules/`uname \-r`/modules.dep + pcimapfile=/lib/modules/`uname \-r`/modules.pcimap path[boot]=/lib/modules/boot + path[kernel]=/lib/modules/`uname \-r`/kernel path[fs]=/lib/modules/`uname \-r`/fs path[net]=/lib/modules/`uname \-r`/net path[scsi]=/lib/modules/`uname \-r`/scsi @@ -513,8 +522,8 @@ path[ide]=/lib/modules/`uname \-r`/ide path[ieee1394]=/lib/modules/`uname \-r`/ieee1394 path[mtd]=/lib/modules/`uname \-r`/mtd - path[kernel]=/lib/modules/`uname \-r`/kernel + path[kernel]=/lib/modules/`kernelversion`/kernel path[fs]=/lib/modules/`kernelversion`/fs path[net]=/lib/modules/`kernelversion`/net path[scsi]=/lib/modules/`kernelversion`/scsi @@ -532,8 +541,8 @@ path[ide]=/lib/modules/`kernelversion`/ide path[ieee1394]=/lib/modules/`kernelversion`/ieee1394 path[mtd]=/lib/modules/`kernelversion`/mtd - path[kernel]=/lib/modules/`kernelversion`/kernel + path[kernel]=/lib/modules/default/kernel path[fs]=/lib/modules/default/fs path[net]=/lib/modules/default/net path[scsi]=/lib/modules/default/scsi @@ -551,8 +560,8 @@ path[ide]=/lib/modules/default/ide path[ieee1394]=/lib/modules/default/ieee1394 path[mtd]=/lib/modules/default/mtd - path[kernel]=/lib/modules/default/kernel + path[kernel]=/lib/modules/kernel path[fs]=/lib/modules/fs path[net]=/lib/modules/net path[scsi]=/lib/modules/scsi @@ -570,7 +579,6 @@ path[ide]=/lib/modules/ide path[ieee1394]=/lib/modules/ieee1394 path[mtd]=/lib/modules/mtd - path[kernel]=/lib/modules/kernel .PP There are also a set of default .I alias diff -Nur modutils-2.3.13/man/rmmod.8 modutils-2.3.14/man/rmmod.8 --- modutils-2.3.13/man/rmmod.8 Wed Aug 25 16:26:49 1999 +++ modutils-2.3.14/man/rmmod.8 Mon Aug 7 01:20:16 2000 @@ -2,9 +2,9 @@ .\" Copyright (c) 1996 Free Software Foundation, Inc. (via rth) .\" This program is distributed according to the Gnu General Public License. .\" See the file COPYING in the distribution source directory -.\" $Id: rmmod.8 1.1 Wed, 25 Aug 1999 16:26:49 +1000 keith $ +.\" $Id: rmmod.8 1.2 Mon, 07 Aug 2000 01:20:16 +1000 kaos $ .\" -.TH RMMOD 1 "March 6, 1999" Linux "Linux Module Support" +.TH RMMOD 8 "March 6, 1999" Linux "Linux Module Support" .SH NAME rmmod \- unload loadable modules .SH SYNOPSIS diff -Nur modutils-2.3.13/modutils.spec modutils-2.3.14/modutils.spec --- modutils-2.3.13/modutils.spec Mon Jul 10 14:35:18 2000 +++ modutils-2.3.14/modutils.spec Wed Aug 2 10:39:12 2000 @@ -1,6 +1,6 @@ Summary: Module utilities Name: modutils -Version: 2.3.13 +Version: 2.3.14 Release: 1 Copyright: GPL Group: Utilities/System diff -Nur modutils-2.3.13/obj/obj_reloc.c modutils-2.3.14/obj/obj_reloc.c --- modutils-2.3.13/obj/obj_reloc.c Tue Jul 25 16:31:08 2000 +++ modutils-2.3.14/obj/obj_reloc.c Mon Aug 7 18:07:12 2000 @@ -19,7 +19,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ident "$Id: obj_reloc.c 1.7 Tue, 25 Jul 2000 16:31:08 +1000 kaos $" +#ident "$Id: obj_reloc.c 1.8 Mon, 07 Aug 2000 18:07:12 +1000 kaos $" #include #include @@ -105,6 +105,22 @@ } return ret; +} + +void +obj_clear_undefineds(struct obj_file *f) +{ + unsigned long i; + struct obj_symbol *sym; + for (i = 0; i < HASH_BUCKETS; ++i) + { + for (sym = f->symtab[i]; sym ; sym = sym->next) + if (sym->secidx == SHN_UNDEF) + { + sym->secidx = SHN_ABS; + sym->value = 0; + } + } } void diff -Nur modutils-2.3.13/util/Makefile.in modutils-2.3.14/util/Makefile.in --- modutils-2.3.13/util/Makefile.in Sun Jul 9 15:44:35 2000 +++ modutils-2.3.14/util/Makefile.in Mon Aug 7 01:20:16 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile.in 1.12 Sun, 09 Jul 2000 15:44:35 +1000 kaos $ +# $Id: Makefile.in 1.13 Mon, 07 Aug 2000 01:20:16 +1000 kaos $ VPATH = @srcdir@ srcdir = @srcdir@ @@ -15,7 +15,8 @@ all: .depend libutil.a OBJS = xmalloc.o xrealloc.o xstrdup.o logger.o modstat.o \ - meta_expand.o config.o snap_shot.o arch64.o gzfiles.o sys_nim.o + meta_expand.o config.o snap_shot.o arch64.o gzfiles.o sys_nim.o \ + xftw.o ifneq ($(USE_SYSCALL),n) OBJS += sys_cm.o sys_dm.o sys_gks.o sys_oim.o sys_qm.o endif diff -Nur modutils-2.3.13/util/alias.h modutils-2.3.14/util/alias.h --- modutils-2.3.13/util/alias.h Thu Jul 20 13:19:39 2000 +++ modutils-2.3.14/util/alias.h Mon Aug 7 02:14:58 2000 @@ -15,8 +15,9 @@ NULL /* marks the end of the list! */ }; -static char *tbtype[] = +char *tbtype[] = { + "kernel", /* as of 2.3.14 this must be first */ "fs", "net", "scsi", @@ -34,7 +35,6 @@ "ide", "ieee1394", "mtd", - "kernel", NULL /* marks the end of the list! */ }; @@ -201,5 +201,20 @@ */ char *below[] = { + NULL /* marks the end of the list! */ +}; + +/* + * This is the list of pre-defined "prune"s, + * used to exclude paths from scan of /lib/modules. + * Each entry can be overridden by an entry in /etc/modules.conf + */ +char *prune[] = +{ + "modules.dep", + "modules.pcimap", + "System.map", + ".config", + "build", /* symlink to source tree */ NULL /* marks the end of the list! */ }; diff -Nur modutils-2.3.13/util/config.c modutils-2.3.14/util/config.c --- modutils-2.3.13/util/config.c Tue Jul 11 16:38:38 2000 +++ modutils-2.3.14/util/config.c Mon Aug 7 18:07:12 2000 @@ -54,10 +54,10 @@ #include #include #include -#include #include #include #include +#include #include #include "util.h" @@ -85,6 +85,9 @@ OPT_LIST *belowlist; static int n_belowlist; +OPT_LIST *prunelist; +static int n_prunelist; + OPT_LIST *probe_list; static int n_probe_list; @@ -96,22 +99,41 @@ char *insmod_opt = NULL; char *depfile = NULL; +char *pcimapfile = NULL; char *config_file = NULL; /* Which file was actually used */ time_t config_mtime; int root_check_off = 0; /* Default, modules must be owned by root */ static char *config_version; /* Hack for config_add */ int quick = 0; /* Option -A */ +int flag_verbose; + +void verbose(const char *ctl,...) +{ + if (flag_verbose) { + va_list list; + va_start(list, ctl); + vprintf(ctl, list); + va_end(list); + fflush(stdout); + } +} + + /* - * Check to see if the existing modules.dep file needs updating, + * Check to see if the existing modules.xxx files need updating, * based on the timestamps of the modules and the config file. */ static time_t dep_mtime; -static int check_update (const char *file, const struct stat *sb, int flag) +static time_t pcimap_mtime; +static int check_update (const char *file, const struct stat *sb) { int len = strlen(file); - if (sb->st_mtime <= dep_mtime) + if (!S_ISREG(sb->st_mode)) + return 0; + if (sb->st_mtime <= dep_mtime && + sb->st_mtime <= pcimap_mtime) return 0; if (len > 2 && !strcmp(file + len - 2, ".o")) @@ -127,7 +149,7 @@ static int need_update (const char *force_ver, const char *base_dir) { - struct stat statdep, tmp; + struct stat statdep, statpcimap, tmp; char dep[PATH_MAX]; uname (&uts_info); if (!force_ver) @@ -139,7 +161,8 @@ /* That's just silly. */ return 1; - if (stat (depfile, &statdep)) + if (stat (depfile, &statdep) || + stat (pcimapfile, &statpcimap)) /* No dependency file yet, so we need to build it. */ return 1; @@ -147,13 +170,15 @@ stat ("/etc/conf.modules", &tmp)) return 1; - if (tmp.st_mtime > statdep.st_mtime) + if (tmp.st_mtime > statdep.st_mtime || + tmp.st_mtime > statpcimap.st_mtime) /* Config file is newer. */ return 1; dep_mtime = statdep.st_mtime; + pcimap_mtime = statpcimap.st_mtime; sprintf (dep, "%s/lib/modules/%s", base_dir, force_ver); - return ftw (dep, check_update, 2); + return xftw (dep, check_update); } @@ -387,6 +412,7 @@ char *version; char *type; char depfile_tmp[PATH_MAX]; + char pcimapfile_tmp[PATH_MAX]; char **glb; char old_name[] = "/etc/conf.modules"; int conf_file_specified = 0; @@ -452,6 +478,8 @@ * [add] below module module1 ... * Specify additional modules needed to be able to load a module * + * [add] prune filename ... + * * [add] probe name module1 ... * When "name" is requested, modprobe tries to install each * module in the list until it succeeds. @@ -529,6 +557,7 @@ config_version = xstrdup(version); depfile_tmp[0] = '\0'; + pcimapfile_tmp[0] = '\0'; /* Only read the default entries on the first file */ if (depth == 0) { @@ -559,6 +588,12 @@ n_belowlist = build_list(below, &belowlist, version, 0); /* + * Build predef prune list + */ + if (prune[0]) + n_prunelist = build_list(prune, &prunelist, version, 0); + + /* * Build predef aliases */ if (all && aliaslist[0]) @@ -648,6 +683,11 @@ strncpy(depfile_tmp, envpath, sizeof(depfile_tmp)); } + /* PCIMAPPATH is intended for testing only */ + if ((envpath = getenv("PCIMAPPATH")) != NULL) { + strncpy(pcimapfile_tmp, envpath, sizeof(pcimapfile_tmp)); + } + } /* End of depth == 0 */ if (conf_file || @@ -977,6 +1017,14 @@ } /* + * prune + */ + else if (all && !assgn && strcmp(parm, "prune") == 0) { + decode_list(&n_prunelist, &prunelist, arg, adding, version, 0); + one_err = 0; + } + + /* * probe */ else if (all && !assgn && strcmp(parm, "probe") == 0) { @@ -1100,6 +1148,24 @@ } /* + * pcimapfile= + */ + else if (assgn && (strcmp(parm, "pcimapfile") == 0) && + (pcimapfile_tmp[0] == '\0')) { + /* + * The default value for the pcimapfile parameter is: + * + * pcimapfile=/lib/modules/`uname -r`/modules.pcimap + * + * If the config file exist but doesn't have a pcimapfile + * specification, the default is used since modprobe + * can't work without one. + */ + strcpy(pcimapfile_tmp, arg); + one_err = 0; + } + + /* * keep */ else if (!assgn && (strcmp(parm, "keep") == 0)) { @@ -1247,6 +1313,36 @@ depfile = g.pathv[0]; } + /* + * Make sure we have a definition of "pcimapfile" + */ + if (pcimapfile_tmp[0] == '\0') { + /* + * Specification: config file / no pcimapfile parameter + * The default value for the pcimapfile parameter is: + * + * pcimapfile=/lib/modules/`uname -r`/modules.pcimap + * + * If the config file exists but lack a pcimapfile + * specification, the default value is used since + * the system can't work without one. + */ + sprintf(pcimapfile_tmp, "%s/lib/modules/%s/modules.pcimap", + (base_dir ? base_dir : ""), version); + pcimapfile = xstrdup(pcimapfile_tmp); + } else { /* pcimapfile defined in modules.conf */ + /* + * If we have a pcimapfile definition in the configuration file + * we must resolve any shell meta-chars in its value. + */ + if (meta_expand(pcimapfile_tmp, &g, base_dir, version)) + ret = -1; + else if (!g.pathv || g.pathv[0] == NULL) + ret = -1; + else + pcimapfile = g.pathv[0]; + } + return ret; } @@ -1283,7 +1379,7 @@ /* * Add a file name if it exist */ -static int config_add(const char *file, const struct stat *sb, int flag) +static int config_add(const char *file, const struct stat *sb) { int i; int npaths = 0; @@ -1294,7 +1390,7 @@ char **p; char full[PATH_MAX]; - if (flag != FTW_D) + if (!S_ISDIR(sb->st_mode)) return 0; sprintf(full, "%s/%s", file, looking_for); @@ -1306,10 +1402,7 @@ paths[npaths++] = *p; } } else { /* normal path match or match with "*" */ - if (flag != FTW_F) - return 0; - - if (strstr(file, "modules.dep") != NULL) + if (!S_ISREG(sb->st_mode)) return 0; if (strcmp(looking_for, "*") != 0) { @@ -1331,7 +1424,7 @@ for (i = 0; i < npaths; ++i) { struct stat sbuf; - if (flag == FTW_D) { + if (S_ISDIR(sb->st_mode)) { if (stat(paths[i], &sbuf) == 0) sb = &sbuf; } @@ -1363,7 +1456,7 @@ for (j = i + 1; j < npaths; ++j) free(paths[j]); free(paths); - return 1; /* finish ftw */ + return 1; /* finish xftw */ } } next: @@ -1416,13 +1509,13 @@ sprintf(this, "%s/%s/%s", modpath[i].path, modpath[i].type, match); if (stat(this, &sb) == 0 && - config_add(this, &sb, FTW_F)) + config_add(this, &sb)) break; /* End fix for "2.1.121 syntax */ sprintf(this, "%s/%s", modpath[i].path, match); if (stat(this, &sb) == 0 && - config_add(this, &sb, FTW_F)) + config_add(this, &sb)) break; } @@ -1430,28 +1523,15 @@ #if 0 /* Fix for "2.1.121 syntax */ sprintf(this, "%s/%s", modpath[i].path, modpath[i].type); - if (stat(this, &sb) == 0 && S_ISDIR(sb.st_mode)) + if (stat(this, &sb) == 0 && S_ISDIR(sb->st_mode)) path = this; else /* End fix for "2.1.121 syntax */ #endif path = modpath[i].path; - /* - * Different definitions for the called function - * on different versions of include files :-( - * gcc -Wall might complain, but it _is_ OK! - */ - if ((ret = ftw(path, config_add, 32 /* whatever */))) { - /* - * Some versions of ftw don't like non-existant paths - */ - if (errno == ENOENT) - ret = 0; /* Pretend it didn't happen */ - else { - perror(path); - break; - } + if ((ret = xftw(path, config_add))) { + break; } } if (ret >= 0) { diff -Nur modutils-2.3.13/util/xftw.c modutils-2.3.14/util/xftw.c --- modutils-2.3.13/util/xftw.c Thu Jan 1 10:00:00 1970 +++ modutils-2.3.14/util/xftw.c Mon Aug 7 18:07:12 2000 @@ -0,0 +1,422 @@ +/* + * modutils specific implementation of ftw(). + * + * Copyright 2000: + * Keith Owens August 2000 + * + * This file is part of the Linux modutils. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + modutils requires special processing during the file tree walk + of /lib/modules/ and any paths that the user specifies. + The standard ftw() does a blind walk of all paths and can end + up following the build symlink down the kernel source tree. + Although nftw() has the option to get more control such as not + automatically following symbolic links, even that is not enough + for modutils. The requirements are: + + Paths must be directories or symlinks to directories. + + Each directory is read and sorted into alphabetical order + before processing. + + A directory is type 1 iff it was specified on a path statement + (either explicit or default) and the directory contains a + subdirectory with one of the known names and the directory name + does not end with "/kernel". Otherwise it is type 2. + + In a type 1 directory, walk the kernel subdirectory if it exists, + then the old known names in their historical order then any + remaining directory entries in alphabetical order and finally any + non-directory entries in alphabetical order. + + Entries in a type 1 directory are filtered against the "prune" + list. A type 1 directory can contain additional files which + are not modules nor symlinks to modules. The prune list skips + known additional files, if a distribution wants to store + additional text files in the top level directory they should be + added to the prune list. + + A type 2 directory must contain only modules or symlinks to + modules. They are processed in alphabetical order, without + pruning. Symlinks to directories are an error in type 2 + directories. + + The user function is not called for type 1 directories, nor for + pruned entries. It is called for type 2 directories and their + contents. It is also called for any files left in a type 1 + directory after pruning and processing type 2 subdirectories. + The user function never sees symlinks, they are resolved before + calling the function. + + Why have different directory types? The original file tree + walk was not well defined. Some users specified each directory + individually, others just pointed at the top level directory. + Either version worked until the "build" symlink was added. Now + users who specify the top level directory end up running the + entire kernel source tree looking for modules, not nice. We + cannot just ignore symlinks because pcmcia uses symlinks to + modules for backwards compatibility. + + Type 1 is when a user specifies the top level directory which needs + special processing, type 2 is individual subdirectories. But the + only way to tell the difference is by looking at the contents. The + "/kernel" directory introduced in 2.3.12 either contains nothing + (old make modules_install) or contains all the kernel modules using + the same tree structure as the source. Because "/kernel" can + contain old names but is really a type 2 directory, it is detected + as a special case. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "config.h" + +extern char *tbpath[]; + +extern OPT_LIST *prune_list; +extern int n_prune_list; + +extern char *tbtype[]; + +struct xftw_dirent { + struct stat statbuf; + char *name; + char *fullname; +}; + +#define XFTW_MAXDEPTH 64 /* Maximum directory depth handled */ + +typedef struct { + struct xftw_dirent *contents; + int size; + int used; +} xftw_tree_t; + +static xftw_tree_t tree[XFTW_MAXDEPTH]; + +/* Free all data for one tree level */ +static void xftw_free_tree(int depth) +{ + int i; + xftw_tree_t *t = tree+depth; + for (i = 0; i < t->size; ++i) { + free(t->contents[i].name); + free(t->contents[i].fullname); + } + free(t->contents); + t->contents = NULL; + t->size = 0; + t->used = 0; +} + +/* Increment dirents used at this depth, resizing if necessary */ +static void xftw_add_dirent(int depth) +{ + xftw_tree_t *t = tree+depth; + int i, size = t->size; + if (++t->used < size) + return; + size += 10; /* arbitrary increment */ + t->contents = xrealloc(t->contents, size*sizeof(*(t->contents))); + for (i = t->size; i < size; ++i) { + memset(&(t->contents[i].statbuf), 0, sizeof(t->contents[i].statbuf)); + t->contents[i].name = NULL; + t->contents[i].fullname = NULL; + } + t->size = size; +} + +/* Concatenate directory name and entry name into one string. + * Note: caller must free result or leak. + */ +static char *xftw_dir_name(const char *directory, const char *entry) +{ + int i = strlen(directory); + char *name; + if (entry) + i += strlen(entry); + i += 2; + name = xmalloc(i); + strcpy(name, directory); + if (*directory && entry) + strcat(name, "/"); + if (entry) + strcat(name, entry); + return(name); +} + +/* Call the user function for a directory entry */ +static int xftw_do_name(const char *directory, const char *entry, struct stat *sb, xftw_func_t funcptr) +{ + int ret = 0; + char *name = xftw_dir_name(directory, entry); + + if (S_ISLNK(sb->st_mode)) { + char real[PATH_MAX], *newname; + verbose("resolving %s symlink to ", name); + if (!(newname = realpath(name, real))) { + if (errno == ENOENT) { + verbose("%s: does not exist, dangling symlink ignored\n", real); + goto cleanup; + } + perror("... failed"); + goto cleanup; + } + verbose("%s ", newname); + if (lstat(newname, sb)) { + error("lstat on %s failed ", newname); + perror(""); + goto cleanup; + } + free(name); + name = xstrdup(newname); + } + + if (!S_ISREG(sb->st_mode) && + !S_ISDIR(sb->st_mode)) { + error("%s is not plain file nor directory\n", name); + goto cleanup; + } + + verbose("user function %s\n", name); + ret = (*funcptr)(name, sb); +cleanup: + free(name); + return(ret); +} + +/* Sort directory entries into alphabetical order */ +static int xftw_sortdir(const void *a, const void *b) +{ + return(strcmp(((struct xftw_dirent *)a)->name, ((struct xftw_dirent *)b)->name)); +} + +/* Read a directory and sort it, ignoring "." and ".." */ +static int xftw_readdir(const char *directory, int depth) +{ + DIR *d; + struct dirent *ent; + verbose("xftw_readdir %s\n", directory); + if (!(d = opendir(directory))) { + perror(directory); + return(1); + } + while ((ent = readdir(d))) { + char *name; + struct xftw_dirent *f; + if (strcmp(ent->d_name, ".") == 0 || + strcmp(ent->d_name, "..") == 0) + continue; + name = xftw_dir_name(directory, ent->d_name); + xftw_add_dirent(depth); + f = tree[depth].contents+tree[depth].used-1; + f->name = xstrdup(ent->d_name); + f->fullname = name; /* do not free name, it is in use */ + if (lstat(name, &(f->statbuf))) { + perror(name); + return(1); + } + } + closedir(d); + qsort(tree[depth].contents, tree[depth].used, sizeof(*(tree[0].contents)), &xftw_sortdir); + return(0); +} + +/* Process a type 2 directory */ +int xftw_type2(const char *directory, const char *entry, int depth, xftw_func_t funcptr) +{ + int ret, i; + xftw_tree_t *t = tree+depth; + struct stat statbuf; + char *dirname = xftw_dir_name(directory, entry); + + verbose("type 2 %s\n", dirname); + if (depth > XFTW_MAXDEPTH) { + error("xftw_type2 exceeded maxdepth\n"); + ret = 1; + goto cleanup; + } + if ((ret = xftw_readdir(dirname, depth))) + goto cleanup; + + t = tree+depth; + /* user function sees type 2 directories */ + if ((ret = lstat(dirname, &statbuf)) || + (ret = xftw_do_name("", dirname, &statbuf, funcptr))) + goto cleanup; + + /* user sees all contents of type 2 directory, no pruning */ + for (i = 0; i < t->used; ++i) { + struct xftw_dirent *c = t->contents+i; + if (S_ISLNK(c->statbuf.st_mode)) { + if (!stat(c->name, &(c->statbuf))) { + if (S_ISDIR(c->statbuf.st_mode)) { + error("symlink to directory is not allowed, %s ignored\n", c->name); + *(c->name) = '\0'; /* ignore it */ + } + } + } + if (!*(c->name)) + continue; + if (S_ISDIR(c->statbuf.st_mode)) { + /* recursion is the curse of the programming classes */ + ret = xftw_type2(dirname, c->name, depth+1, funcptr); + if (ret) + goto cleanup; + } + else if ((ret = xftw_do_name(dirname, c->name, &(c->statbuf), funcptr))) + goto cleanup; + *(c->name) = '\0'; /* processed */ + } + + ret = 0; +cleanup: + free(dirname); + return(ret); +} + +/* Only external visible function. Decide on the type of directory and + * process accordingly. + */ +int xftw(const char *directory, xftw_func_t funcptr) +{ + struct stat statbuf; + int ret, i, j, type; + xftw_tree_t *t; + struct xftw_dirent *c; + + verbose("xftw starting at %s ", directory); + if (lstat(directory, &statbuf)) { + verbose("lstat on %s failed\n", directory); + return(0); + } + if (S_ISLNK(statbuf.st_mode)) { + char real[PATH_MAX]; + verbose("resolving symlink to "); + if (!(directory = realpath(directory, real))) { + if (errno == ENOENT) { + verbose("%s: does not exist, dangling symlink ignored\n", real); + return(0); + } + perror("... failed"); + return(-1); + } + verbose("%s ", directory); + if (lstat(directory, &statbuf)) { + error("lstat on %s failed ", directory); + perror(""); + return(-1); + } + } + if (!S_ISDIR(statbuf.st_mode)) { + error("%s is not a directory\n", directory); + return(-1); + } + verbose("\n"); + + /* All returns after this point must be via cleanup */ + + if ((ret = xftw_readdir(directory, 0))) + goto cleanup; + + t = tree; /* depth 0 */ + type = 2; + for (i = 0 ; type == 2 && i < t->used; ++i) { + c = t->contents+i; + for (j = 0; tbtype[j]; ++j) { + if (strcmp(c->name, tbtype[j]) == 0 && + S_ISDIR(c->statbuf.st_mode)) { + const char *p = directory + strlen(directory) - 1; + if (*p == '/') + --p; + if (p - directory >= 6 && strncmp(p-6, "/kernel", 7) == 0) + continue; /* "/kernel" path is a special case, type 2 */ + type = 1; /* known subdirectory */ + break; + } + } + } + + if (type == 1) { + OPT_LIST *p; + /* prune entries in type 1 directories only */ + for (i = 0 ; i < t->used; ++i) { + for (p = prunelist; p->name; ++p) { + c = t->contents+i; + if (strcmp(p->name, c->name) == 0) { + verbose("pruned %s\n", c->name); + *(c->name) = '\0'; /* ignore */ + } + } + } + /* run known subdirectories first in historical order, "kernel" is now top of list */ + for (i = 0 ; i < t->used; ++i) { + c = t->contents+i; + for (j = 0; tbtype[j]; ++j) { + if (*(c->name) && + strcmp(c->name, tbtype[j]) == 0 && + S_ISDIR(c->statbuf.st_mode)) { + if ((ret = xftw_type2(directory, c->name, 1, funcptr))) + goto cleanup; + *(c->name) = '\0'; /* processed */ + } + } + } + /* any other directories left, in alphabetical order */ + for (i = 0 ; i < t->used; ++i) { + c = t->contents+i; + if (*(c->name) && + S_ISDIR(c->statbuf.st_mode)) { + if ((ret = xftw_type2(directory, c->name, 1, funcptr))) + goto cleanup; + *(c->name) = '\0'; /* processed */ + } + } + /* anything else is passed to the user function */ + for (i = 0 ; i < t->used; ++i) { + c = t->contents+i; + if (*(c->name)) { + verbose("%s found in type 1 directory %s\n", c->name, directory); + if ((ret = xftw_do_name(directory, c->name, &(c->statbuf), funcptr))) + goto cleanup; + *(c->name) = '\0'; /* processed */ + } + } + } + else { + /* type 2 */ + xftw_free_tree(0); + if ((ret = xftw_type2(directory, NULL, 0, funcptr))) + goto cleanup; + } + + /* amazing, it all worked */ + ret = 0; +cleanup: + for (i = 0; i < XFTW_MAXDEPTH; ++i) + xftw_free_tree(i); + return(ret); +}