summaryrefslogtreecommitdiffstats
path: root/mdk-stage1/insmod-modutils/util
diff options
context:
space:
mode:
Diffstat (limited to 'mdk-stage1/insmod-modutils/util')
-rw-r--r--mdk-stage1/insmod-modutils/util/Makefile39
-rw-r--r--mdk-stage1/insmod-modutils/util/alias.h244
-rw-r--r--mdk-stage1/insmod-modutils/util/arch64.c35
-rw-r--r--mdk-stage1/insmod-modutils/util/config.c1591
-rw-r--r--mdk-stage1/insmod-modutils/util/gzfiles.c74
-rw-r--r--mdk-stage1/insmod-modutils/util/logger.c163
-rw-r--r--mdk-stage1/insmod-modutils/util/meta_expand.c339
-rw-r--r--mdk-stage1/insmod-modutils/util/modstat.c419
-rw-r--r--mdk-stage1/insmod-modutils/util/snap_shot.c154
-rw-r--r--mdk-stage1/insmod-modutils/util/sys_cm.c88
-rw-r--r--mdk-stage1/insmod-modutils/util/sys_dm.c37
-rw-r--r--mdk-stage1/insmod-modutils/util/sys_gks.c37
-rw-r--r--mdk-stage1/insmod-modutils/util/sys_nim.c53
-rw-r--r--mdk-stage1/insmod-modutils/util/sys_oim.c40
-rw-r--r--mdk-stage1/insmod-modutils/util/sys_qm.c56
-rw-r--r--mdk-stage1/insmod-modutils/util/xftw.c422
-rw-r--r--mdk-stage1/insmod-modutils/util/xmalloc.c39
-rw-r--r--mdk-stage1/insmod-modutils/util/xrealloc.c39
-rw-r--r--mdk-stage1/insmod-modutils/util/xstrcat.c40
-rw-r--r--mdk-stage1/insmod-modutils/util/xstrdup.c41
-rw-r--r--mdk-stage1/insmod-modutils/util/xsystem.c51
21 files changed, 4001 insertions, 0 deletions
diff --git a/mdk-stage1/insmod-modutils/util/Makefile b/mdk-stage1/insmod-modutils/util/Makefile
new file mode 100644
index 000000000..844f8c0dc
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/Makefile
@@ -0,0 +1,39 @@
+ #******************************************************************************
+ #
+ # insmod from modutils (generic)
+ #
+ # $Id$
+ #
+ # Copyright 1996, 1997 Linux International.
+ #
+ #*****************************************************************************
+
+top_dir = ../..
+
+include $(top_dir)/Makefile.common
+
+
+all: libutil.a libutil-STANDALONE.a #libutil-DIET.a
+
+clean:
+ rm -f *.o *.a
+
+
+FLAGS = -c -Wall -Os -fomit-frame-pointer -I./../include -D_GNU_SOURCE -DELF_MACHINE_H='"elf_$(ARCH).h"' -DARCH_$(ARCH) -DHAVE_WORDEXP=1 -DHAVE_GLOB=1 -DCONFIG_ROOT_CHECK_OFF=0
+
+OBJS = xmalloc.o xrealloc.o xstrcat.o xstrdup.o xsystem.o xftw.o \
+ modstat.o meta_expand.o config.o snap_shot.o arch64.o gzfiles.o sys_nim.o sys_oim.o
+
+libutil.a: $(OBJS) logger.o
+ ar cru $@ $^
+ ranlib $@
+
+libutil-STANDALONE.a: $(OBJS) logger-standalone.o
+ ar cru $@ $^
+ ranlib $@
+
+logger-standalone.o: logger.c
+ gcc $(FLAGS) $(GLIBC_INCLUDES) -o $@ -D_STANDALONE_ logger.c
+
+.c.o:
+ gcc $(FLAGS) $(GLIBC_INCLUDES) -c $<
diff --git a/mdk-stage1/insmod-modutils/util/alias.h b/mdk-stage1/insmod-modutils/util/alias.h
new file mode 100644
index 000000000..c925a04f3
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/alias.h
@@ -0,0 +1,244 @@
+/*
+ * This file is split out from config.c for easier editing
+ */
+
+/*
+ * tbpath and tbtype are used to build the complete set of paths for finding
+ * modules, but only when we search for individual directories, they are not
+ * used for [boot] and [toplevel] searches.
+ */
+static char *tbpath[] =
+{
+ "/lib/modules",
+ NULL /* marks the end of the list! */
+};
+
+char *tbtype[] =
+{
+ "kernel", /* as of 2.3.14 this must be first */
+ "fs",
+ "net",
+ "scsi",
+ "block",
+ "cdrom",
+ "ipv4",
+ "ipv6",
+ "sound",
+ "fc4",
+ "video",
+ "misc",
+ "pcmcia",
+ "atm",
+ "usb",
+ "ide",
+ "ieee1394",
+ "mtd",
+ NULL /* marks the end of the list! */
+};
+
+/*
+ * This is the list of pre-defined aliases.
+ * Each entry can be overridden by an entry in /etc/modules.conf
+ */
+char *aliaslist[] =
+{
+ "binfmt-204 binfmt_aout",
+ "binfmt-263 binfmt_aout",
+ "binfmt-264 binfmt_aout",
+ "binfmt-267 binfmt_aout",
+ "binfmt-387 binfmt_aout",
+ "binfmt-332 iBCS",
+ "binfmt--310 binfmt_java",
+
+ "block-major-1 rd",
+ "block-major-2 floppy",
+ "block-major-3 ide-probe-mod",
+ "block-major-7 loop",
+ "block-major-8 sd_mod",
+ "block-major-9 md", /* For modular RAID */
+ "block-major-11 sr_mod",
+ "block-major-13 xd",
+ "block-major-15 cdu31a",
+ "block-major-16 gscd",
+ "block-major-17 optcd",
+ "block-major-18 sjcd",
+ "block-major-20 mcdx",
+ "block-major-22 ide-probe-mod",
+ "block-major-23 mcd",
+ "block-major-24 sonycd535",
+ "block-major-25 sbpcd",
+ "block-major-26 sbpcd",
+ "block-major-27 sbpcd",
+ "block-major-29 aztcd",
+ "block-major-32 cm206",
+ "block-major-33 ide-probe-mod",
+ "block-major-34 ide-probe-mod",
+ "block-major-37 ide-tape",
+ "block-major-44 ftl", /* from David Woodhouse <dwmw2@infradead.org> */
+ "block-major-56 ide-probe-mod",
+ "block-major-57 ide-probe-mod",
+ "block-major-88 ide-probe-mod",
+ "block-major-89 ide-probe-mod",
+ "block-major-90 ide-probe-mod",
+ "block-major-91 ide-probe-mod",
+ "block-major-93 nftl", /* from David Woodhouse <dwmw2@infradead.org> */
+
+ "char-major-4 serial",
+ "char-major-5 serial",
+ "char-major-6 lp",
+ "char-major-9 st",
+ "char-major-10 off", /* was: mouse, was: misc */
+ "char-major-10-0 busmouse", /* /dev/logibm Logitech bus mouse */
+ "char-major-10-1 off", /* /dev/psaux PS/2-style mouse port */
+ "char-major-10-2 msbusmouse", /* /dev/inportbm Microsoft Inport bus mouse */
+ "char-major-10-3 atixlmouse", /* /dev/atibm ATI XL bus mouse */
+ /* /dev/jbm J-mouse */
+ /* /dev/amigamouse Amiga mouse (68k/Amiga) */
+ /* /dev/atarimouse Atari mouse */
+ /* /dev/sunmouse Sun mouse */
+ /* /dev/beep Fancy beep device */
+ /* /dev/modreq Kernel module load request */
+ "char-major-10-130 wdt", /* /dev/watchdog Watchdog timer port */
+ "char-major-10-131 wdt", /* /dev/temperature Machine internal temperature */
+ /* /dev/hwtrap Hardware fault trap */
+ /* /dev/exttrp External device trap */
+ "char-major-10-135 off", /* rtc cannot be compiled as a module */
+ "char-major-10-139 openprom", /* /dev/openprom Linux/Sparc interface */
+ "char-major-10-144 nvram", /* from Tigran Aivazian <tigran@sco.COM> */
+ "char-major-10-157 applicom", /* from David Woodhouse <dwmw2@infradead.org> */
+ "char-major-10-175 agpgart", /* /dev/agpgart GART AGP mapping access */
+ "char-major-10-184 microcode", /* Tigran Aivazian <tigran@veritas.com> */
+
+ "char-major-14 soundcore",
+ "char-major-19 cyclades",
+ "char-major-20 cyclades",
+ "char-major-21 sg",
+ "char-major-22 pcxx", /* ?? */
+ "char-major-23 pcxx", /* ?? */
+ "char-major-27 ftape",
+ "char-major-34 scc",
+ "char-major-35 tclmidi",
+ "char-major-36 netlink",
+ "char-major-37 ide-tape",
+ "char-major-48 riscom8",
+ "char-major-49 riscom8",
+ "char-major-57 esp",
+ "char-major-58 esp",
+ "char-major-63 kdebug",
+ "char-major-90 mtdchar", /* from David Woodhouse <dwmw2@infradead.org> */
+ "char-major-99 ppdev",
+ "char-major-107 3dfx", /* from Tigran Aivazian <tigran@sco.COM> */
+ "char-major-161 ircomm-tty",
+
+ "dos msdos",
+ "dummy0 dummy",
+ "dummy1 dummy",
+ "eth0 off",
+ "iso9660 isofs",
+ "md-personality-1 linear",
+ "md-personality-2 raid0",
+ "md-personality-3 raid1",
+ "md-personality-4 raid5",
+
+ "net-pf-1 unix", /* PF_UNIX 1 Unix domain sockets */
+ "net-pf-2 ipv4", /* PF_INET 2 Internet IP Protocol */
+ "net-pf-3 off", /* PF_AX25 3 Amateur Radio AX.25 */
+ "net-pf-4 ipx", /* PF_IPX 4 Novell IPX */
+ "net-pf-5 appletalk", /* PF_APPLETALK 5 Appletalk DDP */
+ "net-pf-6 off", /* PF_NETROM 6 Amateur radio NetROM */
+ /* PF_BRIDGE 7 Multiprotocol bridge */
+ /* PF_AAL5 8 Reserved for Werner's ATM */
+ /* PF_X25 9 Reserved for X.25 project */
+ /* PF_INET6 10 IP version 6 */
+
+ /* next two from <dairiki@matthews.dairiki.org> Thanks! */
+ "net-pf-17 af_packet",
+ "net-pf-19 off", /* acorn econet */
+
+ "netalias-2 ip_alias",
+ "plip0 plip",
+ "plip1 plip",
+ "cipcb0 cipcb",
+ "cipcb1 cipcb",
+ "cipcb2 cipcb",
+ "cipcb3 cipcb",
+ "ppp0 ppp",
+ "ppp1 ppp",
+ "scsi_hostadapter off", /* if not in config file */
+ "slip0 slip",
+ "slip1 slip",
+ "tty-ldisc-1 slip",
+ "tty-ldisc-3 ppp",
+ "ppp-compress-21 bsd_comp",
+ "ppp-compress-24 ppp_deflate",
+ "ppp-compress-26 ppp_deflate",
+
+#ifndef __sparc__
+ "parport_lowlevel parport_pc",
+#else
+ "parport_lowlevel parport_ax",
+#endif
+
+ "tty-ldisc-11 irtty",
+
+ "usbdevfs usbcore",
+
+ NULL /* marks the end of the list! */
+};
+
+/*
+ * This is the list of pre-defined options.
+ * Each entry can be overridden by an entry in /etc/modules.conf
+ */
+char *optlist[] =
+{
+ "dummy0 -o dummy0",
+ "dummy1 -o dummy1",
+ "sb io=0x220 irq=7 dma=1 dma16=5 mpu_io=0x330",
+ NULL /* marks the end of the list! */
+};
+
+/*
+ * This is the list of pre-defined "above"s,
+ * used for pull-in of additional modules
+ * Each entry can be overridden by an entry in /etc/modules.conf
+ */
+char *above[] =
+{
+ NULL /* marks the end of the list! */
+};
+
+/*
+ * This is the list of pre-defined "below"s,
+ * used for push-in of additional modules
+ * Each entry can be overridden by an entry in /etc/modules.conf
+ */
+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.
+ * /etc/modules.conf can add entries but not remove them.
+ */
+char *prune[] =
+{
+ ".rhkmvtag",
+ "modules.dep",
+ "modules.generic_string",
+ "modules.pcimap",
+ "modules.isapnpmap",
+ "modules.usbmap",
+ "modules.parportmap",
+ "System.map",
+ ".config",
+ "build", /* symlink to source tree */
+ "vmlinux",
+ "vmlinuz",
+ "bzImage",
+ "zImage",
+ ".rhkmvtag", /* wish RedHat had told me before they did this */
+ NULL /* marks the end of the list! */
+};
diff --git a/mdk-stage1/insmod-modutils/util/arch64.c b/mdk-stage1/insmod-modutils/util/arch64.c
new file mode 100644
index 000000000..4d5ace223
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/arch64.c
@@ -0,0 +1,35 @@
+/* Misc utility functions.
+ Copyright 1996, 1997 Linux International.
+ Written by Keith Owens <kaos@ocs.com.au>
+
+ 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. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/utsname.h>
+#include "util.h"
+
+/*======================================================================*/
+
+/* Indicate if the current machine uses 64 bit architecture */
+int arch64(void)
+{
+ struct utsname u;
+ return(!uname(&u) && strstr(u.machine, "64"));
+}
diff --git a/mdk-stage1/insmod-modutils/util/config.c b/mdk-stage1/insmod-modutils/util/config.c
new file mode 100644
index 000000000..a860920f6
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/config.c
@@ -0,0 +1,1591 @@
+/*
+ * Handle the configuration, including /etc/modules.conf
+ *
+ * Copyright 1994, 1995, 1996, 1997:
+ * Jacques Gelinas <jack@solucorp.qc.ca>
+ * Björn Ekwall <bj0rn@blox.se> February 1999
+ * Keith Owens <kaos@ocs.com.au> October 1999
+ *
+ * "kernelversion" idea from the Debian release via:
+ * Wichert Akkerman <wakkerma@cs.leidenuniv.nl>
+ *
+ * Björn, inspired by Richard Henderson <rth@twiddle.net>, cleaned up
+ * the wildcard handling and started using ftw in March 1999
+ * Cleanup of hardcoded arrays: Björn Ekwall <bj0rn@blox.se> March 1999
+ * Many additional keywords: Björn Ekwall <bj0rn@blox.se> (C) March 1999
+ * Standardize on /etc/modules.conf Keith Owens <kaos@ocs.com.au> October 1999
+ *
+ * Alpha typecast:Michal Jaegermann <michal@ellpspace.math.ualberta.ca>
+ *
+ * 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.
+ */
+
+/*
+ * Specification: /etc/modules.conf / format
+ * Modules may be located at different places in the filesystem.
+ *
+ * The file /etc/modules.conf contains different definitions to
+ * control the manipulation of modules.
+ *
+ * Standard Unix style comments and continuation line are supported.
+ * Comments begin with a # and continue until the end of the line.
+ * A line continues on the next one if the last non-white character
+ * is a \.
+ */
+/* #Specification: /etc/modules.conf / format / official name */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <limits.h>
+#include <sys/param.h>
+#include <errno.h>
+
+#include "util.h"
+#include "config.h"
+#include "alias.h"
+
+int flag_autoclean; /* set/used by modprobe and insmod */
+
+struct utsname uts_info;
+
+struct PATH_TYPE *modpath;
+int nmodpath = 0;
+static int maxpath = 0;
+
+struct EXEC_TYPE *execs;
+int nexecs = 0;
+static int maxexecs = 0;
+
+OPT_LIST *opt_list;
+static int n_opt_list;
+
+OPT_LIST *abovelist;
+static int n_abovelist;
+
+OPT_LIST *belowlist;
+static int n_belowlist;
+
+OPT_LIST *prunelist;
+static int n_prunelist;
+
+OPT_LIST *probe_list;
+static int n_probe_list;
+
+OPT_LIST *probeall_list;
+static int n_probeall_list;
+
+OPT_LIST *aliases;
+static int n_aliases;
+
+char *persistdir = "/var/lib/modules/persist";
+
+const char symprefix[] = SYMPREFIX;
+
+char *insmod_opt = NULL;
+char *config_file = NULL; /* Which file was actually used */
+time_t config_mtime;
+int root_check_off = CONFIG_ROOT_CHECK_OFF; /* Default is modules must be owned by root */
+static char *config_version; /* Hack for config_add */
+int quick = 0; /* Option -A */
+
+/* The initialization order must match the gen_file_enum order in config.h */
+struct gen_files gen_file[] = {
+ {"generic_string", NULL, 0},
+ {"pcimap", NULL, 0},
+ {"isapnpmap", NULL, 0},
+ {"usbmap", NULL, 0},
+ {"parportmap", NULL, 0},
+ {"dep", NULL, 0},
+};
+
+const int gen_file_count = sizeof(gen_file)/sizeof(gen_file[0]);
+
+int flag_verbose;
+
+unsigned long safemode;
+
+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.xxx files need updating,
+ * based on the timestamps of the modules and the config file.
+ */
+static int check_update (const char *file, const struct stat *sb)
+{
+ int len = strlen(file);
+ int i;
+
+ if (!S_ISREG(sb->st_mode))
+ return 0;
+ for (i = 0; i < gen_file_count; ++i) {
+ if (sb->st_mtime > gen_file[i].mtime)
+ break;
+ }
+ if (i == gen_file_count)
+ return 0; /* All generated files are up to date */
+
+ if (len > 2 && !strcmp(file + len - 2, ".o"))
+ return 1;
+ else if (len > 4 && !strcmp(file + len - 4, ".mod"))
+ return 1;
+#ifdef CONFIG_USE_ZLIB
+ else if (len > 5 && !strcmp(file + len - 5, ".o.gz"))
+ return 1;
+#endif
+ return 0;
+}
+
+static int need_update (const char *force_ver, const char *base_dir)
+{
+ struct stat tmp;
+ char dep[PATH_MAX];
+ int i;
+ uname (&uts_info);
+ if (!force_ver)
+ force_ver = uts_info.release;
+
+ if (strlen (force_ver) > 50)
+ /* That's just silly. */
+ return 1;
+
+ for (i = 0; i < gen_file_count; ++i) {
+ if (stat(gen_file[i].name, &tmp))
+ return 1; /* No dependency file yet, so we need to build it. */
+ gen_file[i].mtime = tmp.st_mtime;
+ }
+
+ if (stat ("/etc/modules.conf", &tmp) &&
+ stat ("/etc/conf.modules", &tmp))
+ return 1;
+
+ for (i = 0; i < gen_file_count; ++i) {
+ if (tmp.st_mtime > gen_file[i].mtime)
+ return 1; /* Config file is newer. */
+ }
+
+ snprintf (dep, sizeof(dep), "%s/lib/modules/%s", base_dir, force_ver);
+ return xftw (dep, check_update);
+}
+
+
+/*
+ * Strip white char at the end of a string.
+ * Return the address of the last non white char + 1 (point on the '\0').
+ */
+static char *strip_end(char *str)
+{
+ int len = strlen(str);
+
+ for (str += len - 1; len > 0 && (isspace(*str)); --len, --str)
+ *str = '\0';
+ return str + 1;
+}
+
+/*
+ * Read a line of a configuration file and process continuation lines.
+ * Return buf, or NULL if EOF.
+ * Blank at the end of line are always stripped.
+ * Everything on a line following comchar is a comment.
+ *
+ * Continuation character is \
+ * Comment character is #
+ */
+char *fgets_strip(char *buf, int sizebuf, FILE * fin, int *lineno)
+{
+ int nocomment = 1; /* No comments found ? */
+ int contline = 0;
+ char *start = buf;
+ char *ret = NULL;
+ char comchar = '#';
+ char contchar = '\\';
+
+ *buf = '\0';
+
+ while (fgets(buf, sizebuf, fin) != NULL) {
+ char *end = strip_end(buf);
+ char *pt = strchr(buf, comchar);
+
+ if (pt != NULL) {
+ nocomment = 0;
+ *pt = '\0';
+ end = strip_end(buf);
+ }
+
+ if (lineno != NULL)
+ (*lineno)++;
+ ret = start;
+ if (contline) {
+ char *pt = buf;
+
+ while (isspace(*pt))
+ pt++;
+ if (pt > buf + 1) {
+ strcpy(buf + 1, pt); /* safe, backward copy */
+ buf[0] = ' ';
+ end -= (int) (pt - buf) - 1;
+ } else if (pt == buf + 1) {
+ buf[0] = ' ';
+ }
+ }
+ if (end > buf && *(end - 1) == contchar) {
+ if (end == buf + 1 || *(end - 2) != contchar) {
+ /* Continuation */
+ contline = 1;
+ end--;
+ *end = '\0';
+ buf = end;
+ } else {
+ *(end - 1) = '\0';
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static char *next_word(char *pt)
+{
+ char *match;
+ char *pt2;
+
+ /* find end of word */
+ for (pt2 = pt; *pt2 && !(isspace(*pt2)); ++pt2) {
+ if ((match = strchr("\"'`", *pt2)) != NULL) {
+ for (++pt2; *pt2 && *pt2 != *match; ++pt2) {
+ if (*pt2 == '\\' && *(pt2 + 1) == *match)
+ ++pt2;
+ }
+ }
+ }
+
+ /* skip leading whitespace before next word */
+ if (*pt2) {
+ *pt2++ = '\0'; /* terminate last word */
+ while (*pt2 && isspace(*pt2))
+ ++pt2;
+ }
+ return pt2;
+}
+
+static GLOB_LIST *addlist(GLOB_LIST *orig, GLOB_LIST *add)
+{
+ if (!orig)
+ return add;
+ /* else */
+ orig->pathv = (char **)xrealloc(orig->pathv,
+ (orig->pathc + add->pathc + 1) *
+ sizeof(char *));
+ memcpy(orig->pathv + orig->pathc, add->pathv,
+ add->pathc * sizeof(char *));
+ orig->pathc += add->pathc;
+ orig->pathv[orig->pathc] = NULL;
+ /*
+ free(add->pathv);
+ free(add);
+ */
+ return orig;
+}
+
+static void decode_list(int *n, OPT_LIST **list, char *arg, int adding,
+ char *version, int opts)
+{
+ GLOB_LIST *pg;
+ GLOB_LIST *prevlist = NULL;
+ int i, autoclean = 1;
+ int where = *n;
+ char *arg2 = next_word(arg);
+
+ if (opts && !strcmp (arg, "-k")) {
+ if (!*arg2)
+ error("Missing module argument after -k\n");
+ arg = arg2;
+ arg2 = next_word(arg);
+ autoclean = 0;
+ }
+
+ for (i = 0; i < *n; ++i) {
+ if (strcmp((*list)[i].name, arg) == 0) {
+ if (adding)
+ prevlist = (*list)[i].opts;
+ else
+ free((*list)[i].opts);
+ (*list)[i].opts = NULL;
+ where = i;
+ break;
+ }
+ }
+ if (where == *n) {
+ (*list) = (OPT_LIST *)xrealloc((*list),
+ (*n + 2) * sizeof(OPT_LIST));
+ (*list)[*n].name = xstrdup(arg);
+ (*list)[*n].autoclean = autoclean;
+ *n += 1;
+ memset(&(*list)[*n], 0, sizeof(OPT_LIST));
+ } else if (!autoclean)
+ (*list)[where].autoclean = 0;
+ pg = (GLOB_LIST *)xmalloc(sizeof(GLOB_LIST));
+ meta_expand(arg2, pg, NULL, version, ME_ALL);
+ (*list)[where].opts = addlist(prevlist, pg);
+}
+
+static void decode_exec(char *arg, int type)
+{
+ char *arg2;
+
+ execs[nexecs].when = type;
+ arg2 = next_word(arg);
+ execs[nexecs].module = xstrdup(arg);
+ execs[nexecs].cmd = xstrdup(arg2);
+ if (++nexecs >= maxexecs) {
+ maxexecs += 10;
+ execs = (struct EXEC_TYPE *)xrealloc(execs,
+ maxexecs * sizeof(struct EXEC_TYPE));
+ }
+}
+
+static int build_list(char **in, OPT_LIST **out, char *version, int opts)
+{
+ GLOB_LIST *pg;
+ int i;
+
+ for (i = 0; in[i]; ++i) {
+ char *p = xstrdup(in[i]);
+ char *pt = next_word(p);
+ char *pn = p;
+
+ *out = (OPT_LIST *)xrealloc(*out, (i + 2) * sizeof(OPT_LIST));
+ (*out)[i].autoclean = 1;
+ if (opts && !strcmp (p, "-k")) {
+ pn = pt;
+ pt = next_word(pn);
+ (*out)[i].autoclean = 0;
+ }
+ pg = (GLOB_LIST *)xmalloc(sizeof(GLOB_LIST));
+ meta_expand(pt, pg, NULL, version, ME_ALL);
+ (*out)[i].name = xstrdup(pn);
+ (*out)[i].opts = pg;
+ free(p);
+ }
+ memset(&(*out)[i], 0, sizeof(OPT_LIST));
+
+ return i;
+}
+
+/* Environment variables can override defaults, testing only */
+static void gen_file_env(struct gen_files *gf)
+{
+ if (!safemode) {
+ char *e = xmalloc(strlen(gf->base)+5), *p1 = gf->base, *p2 = e;
+ while ((*p2++ = toupper(*p1++))) ;
+ strcpy(p2-1, "PATH"); /* safe, xmalloc */
+ if ((p2 = getenv(e)) != NULL) {
+ free(gf->name);
+ gf->name = xstrdup(p2);
+ }
+ free(e);
+ }
+}
+
+/* Read a config option for a generated filename */
+static int gen_file_conf(struct gen_files *gf, int assgn, const char *parm, const char *arg)
+{
+
+ int l = strlen(gf->base);
+ if (assgn &&
+ strncmp(parm, gf->base, l) == 0 &&
+ strcmp(parm+l, "file") == 0 &&
+ !gf->name) {
+ gf->name = xstrdup(arg);
+ return(0);
+ }
+ return(1);
+}
+
+/* Check we have a name for a generated file */
+static int gen_file_check(struct gen_files *gf, GLOB_LIST *g,
+ char *base_dir, char *version)
+{
+ char tmp[PATH_MAX];
+ int ret = 0;
+ if (!gf->name) {
+ /*
+ * Specification: config file / no xxxfile parameter
+ * The default value for generated filename xxx is:
+ *
+ * xxxfile=/lib/modules/`uname -r`/modules.xxx
+ *
+ * If the config file exists but lacks an xxxfile
+ * specification, the default value is used since
+ * the system can't work without one.
+ */
+ snprintf(tmp, sizeof(tmp), "%s/lib/modules/%s/modules.%s",
+ base_dir, version, gf->base);
+ gf->name = xstrdup(tmp);
+ } else { /* xxxfile defined in modules.conf */
+ /*
+ * If we have a xxxfile definition in the configuration file
+ * we must resolve any shell meta-chars in its value.
+ */
+ if (meta_expand(gf->name, g, base_dir, version, ME_ALL))
+ ret = -1;
+ else if (!g->pathv || g->pathv[0] == NULL)
+ ret = -1;
+ else {
+ free(gf->name);
+ gf->name = xstrdup(g->pathv[0]);
+ }
+ }
+ return(ret);
+}
+
+/*
+ * Read the configuration file.
+ * If parameter "all" == 0 then ignore everything except path info
+ * Return -1 if any error.
+ * Error messages generated.
+ */
+static int do_read(int all, char *force_ver, char *base_dir, char *conf_file, int depth)
+{
+ #define MAX_LEVEL 20
+ FILE *fin;
+ GLOB_LIST g;
+ int i;
+ int assgn;
+ int drop_default_paths = 1;
+ int lineno = 0;
+ int ret = 0;
+ int state[MAX_LEVEL + 1]; /* nested "if" */
+ int level = 0;
+ char buf[3000];
+ char tmpline[100];
+ char **pathp;
+ char *envpath;
+ char *version;
+ char *type;
+ char **glb;
+ char old_name[] = "/etc/conf.modules";
+ int conf_file_specified = 0;
+
+ /*
+ * The configuration file is optional.
+ * No error is printed if it is missing.
+ * If it is missing the following content is assumed.
+ *
+ * path[boot]=/lib/modules/boot
+ *
+ * path[toplevel]=/lib/modules/`uname -r`
+ *
+ * path[toplevel]=/lib/modules/`kernelversion`
+ * (where kernelversion gives the major kernel version: "2.0", "2.2"...)
+ *
+ * path[toplevel]=/lib/modules/default
+ *
+ * path[kernel]=/lib/modules/kernel
+ * path[fs]=/lib/modules/fs
+ * path[net]=/lib/modules/net
+ * path[scsi]=/lib/modules/scsi
+ * path[block]=/lib/modules/block
+ * path[cdrom]=/lib/modules/cdrom
+ * path[ipv4]=/lib/modules/ipv4
+ * path[ipv6]=/lib/modules/ipv6
+ * path[sound]=/lib/modules/sound
+ * path[fc4]=/lib/modules/fc4
+ * path[video]=/lib/modules/video
+ * path[misc]=/lib/modules/misc
+ * path[pcmcia]=/lib/modules/pcmcia
+ * path[atm]=/lib/modules/atm
+ * path[usb]=/lib/modules/usb
+ * path[ide]=/lib/modules/ide
+ * path[ieee1394]=/lib/modules/ieee1394
+ * path[mtd]=/lib/modules/mtd
+ *
+ * The idea is that modprobe will look first if the
+ * modules are compiled for the current release of the kernel.
+ * If not found, it will look for modules that fit for the
+ * general kernelversion (2.0, 2.2 and so on).
+ * If still not found, it will look into the default release.
+ * And if still not found, it will look in the other directories.
+ *
+ * The strategy should be like this:
+ * When you install a new linux kernel, the modules should go
+ * into a directory related to the release (version) of the kernel.
+ * Then you can do a symlink "default" to this directory.
+ *
+ * Each time you compile a new kernel, the make modules_install
+ * will create a new directory, but it won't change thee default.
+ *
+ * When you get a module unrelated to the kernel distribution
+ * you can place it in one of the last three directory types.
+ *
+ * This is the default strategy. Of course you can overide
+ * this in /etc/modules.conf.
+ *
+ * 2.3.15 added a new file tree walk algorithm which made it possible to
+ * point at a top level directory and get the same behaviour as earlier
+ * versions of modutils. 2.3.16 takes this one stage further, it
+ * removes all the individual directory names from most of the scans,
+ * only pointing at the top level directory. The only exception is the
+ * last ditch scan, scanning all of /lib/modules would be a bad idea(TM)
+ * so the last ditch scan still runs individual directory names under
+ * /lib/modules.
+ *
+ * Additional syntax:
+ *
+ * [add] above module module1 ...
+ * Specify additional modules to pull in on top of a module
+ *
+ * [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.
+ *
+ * [add] probeall name module1 ...
+ * When "name" is requested, modprobe tries to install all
+ * modules in the list.
+ * If any module is installed, the command has succeeded.
+ *
+ * [add] options module option_list
+ *
+ * For all of the above, the optional "add" prefix is used to
+ * add to a list instead of replacing the contents.
+ *
+ * include FILE_TO_INCLUDE
+ * This does what you expect. No limitation on include levels.
+ *
+ * persistdir=persist_directory
+ * Name the directory to save persistent data from modules.
+ *
+ * In the following WORD is a sequence if non-white characters.
+ * If ' " or ` is found in the string, all characters up to the
+ * matching ' " or ` will also be included, even whitespace.
+ * Every WORD will then be expanded w.r.t. meta-characters.
+ * If the expanded result gives more than one word, then only
+ * the first word of the result will be used.
+ *
+ *
+ * define CODE WORD
+ * Do a putenv("CODE=WORD")
+ *
+ * EXPRESSION below can be:
+ * WORD compare_op WORD
+ * where compare_op is one of == != < <= >= >
+ * The string values of the WORDs are compared
+ * or
+ * -n WORD compare_op WORD
+ * where compare_op is one of == != < <= >= >
+ * The numeric values of the WORDs are compared
+ * or
+ * WORD
+ * if the expansion of WORD fails, or if the
+ * expansion is "0" (zero), "false" or "" (empty)
+ * then the expansion has the value FALSE.
+ * Otherwise the expansion has the value TRUE
+ * or
+ * -f FILENAME
+ * Test if the file FILENAME exists
+ * or
+ * -k
+ * Test if "autoclean" (i.e. called from the kernel)
+ * or
+ * ! EXPRESSION
+ * A negated expression is also an expression
+ *
+ * if EXPRESSION
+ * any config line
+ * ...
+ * elseif EXPRESSION
+ * any config line
+ * ...
+ * else
+ * any config line
+ * ...
+ * endif
+ *
+ * The else and elseif keywords are optional.
+ * "if"-statements nest up to 20 levels.
+ */
+
+ state[0] = 1;
+
+ if (force_ver)
+ version = force_ver;
+ else
+ version = uts_info.release;
+
+ config_version = xstrdup(version);
+
+ /* Only read the default entries on the first file */
+ if (depth == 0) {
+ maxpath = 100;
+ modpath = (struct PATH_TYPE *)xmalloc(maxpath * sizeof(struct PATH_TYPE));
+ nmodpath = 0;
+
+ maxexecs = 10;
+ execs = (struct EXEC_TYPE *)xmalloc(maxexecs * sizeof(struct EXEC_TYPE));
+ nexecs = 0;
+
+ /*
+ * Build predef options
+ */
+ if (all && optlist[0])
+ n_opt_list = build_list(optlist, &opt_list, version, 1);
+
+ /*
+ * Build predef above
+ */
+ if (all && above[0])
+ n_abovelist = build_list(above, &abovelist, version, 0);
+
+ /*
+ * Build predef below
+ */
+ if (all && below[0])
+ 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])
+ n_aliases = build_list(aliaslist, &aliases, version, 0);
+
+ /* Order and priority is now: (MODPATH + modules.conf) || (predefs + modules.conf) */
+ if ((envpath = getenv("MODPATH")) != NULL && !safemode) {
+ size_t len;
+ char *p;
+ char *path;
+
+ /* Make a copy so's we can mung it with strtok. */
+ len = strlen(envpath) + 1;
+ p = alloca(len);
+ memcpy(p, envpath, len);
+ path = alloca(PATH_MAX);
+
+ for (p = strtok(p, ":"); p != NULL; p = strtok(NULL, ":")) {
+ len = snprintf(path, PATH_MAX, p, version);
+ modpath[nmodpath].path = xstrdup(path);
+ if ((type = strrchr(path, '/')) != NULL)
+ type += 1;
+ else
+ type = "misc";
+ modpath[nmodpath].type = xstrdup(type);
+ if (++nmodpath >= maxpath) {
+ maxpath += 100;
+ modpath = (struct PATH_TYPE *)xrealloc(modpath,
+ maxpath * sizeof(struct PATH_TYPE));
+ }
+
+ }
+ } else {
+ /*
+ * Build the default "path[type]" configuration
+ */
+ int n;
+ char *k;
+
+ /* The first entry in the path list */
+ modpath[nmodpath].type = xstrdup("boot");
+ snprintf(tmpline, sizeof(tmpline), "%s/lib/modules/boot", base_dir);
+ modpath[nmodpath].path = xstrdup(tmpline);
+ ++nmodpath;
+
+ /* The second entry in the path list, `uname -r` */
+ modpath[nmodpath].type = xstrdup("toplevel");
+ snprintf(tmpline, sizeof(tmpline), "%s/lib/modules/%s", base_dir, version);
+ modpath[nmodpath].path = xstrdup(tmpline);
+ ++nmodpath;
+
+ /* The third entry in the path list, `kernelversion` */
+ modpath[nmodpath].type = xstrdup("toplevel");
+ for (n = 0, k = version; *k; ++k) {
+ if (*k == '.' && ++n == 2)
+ break;
+ }
+ snprintf(tmpline, sizeof(tmpline), "%s/lib/modules/%.*s", base_dir,
+ (/* typecast for Alpha */ int)(k - version), version);
+ modpath[nmodpath].path = xstrdup(tmpline);
+ ++nmodpath;
+
+ /* The rest of the entries in the path list */
+ for (pathp = tbpath; *pathp; ++pathp) {
+ char **type;
+
+ for (type = tbtype; *type; ++type) {
+ char path[PATH_MAX];
+
+ snprintf(path, sizeof(path), "%s%s/%s", base_dir, *pathp, *type);
+ if (meta_expand(path, &g, NULL, version, ME_ALL))
+ return -1;
+
+ for (glb = g.pathv; glb && *glb; ++glb) {
+ modpath[nmodpath].type = xstrdup(*type);
+ modpath[nmodpath].path = *glb;
+ if (++nmodpath >= maxpath) {
+ maxpath += 100;
+ modpath = (struct PATH_TYPE *)xrealloc(modpath,
+ maxpath * sizeof(struct PATH_TYPE));
+ }
+ }
+ }
+ }
+ }
+
+ /* Environment overrides for testing only, undocumented */
+ for (i = 0; i < gen_file_count; ++i)
+ gen_file_env(gen_file+i);
+
+ } /* End of depth == 0 */
+
+ if (conf_file ||
+ ((conf_file = getenv("MODULECONFIG")) != NULL && *conf_file && !safemode)) {
+ if (!(fin = fopen(conf_file, "r"))) {
+ error("Can't open %s", conf_file);
+ return -1;
+ }
+ conf_file_specified = 1;
+ } else {
+ if (!(fin = fopen((conf_file = ETC_MODULES_CONF), "r"))) {
+ /* Fall back to non-standard name */
+ if ((fin = fopen((conf_file = old_name), "r"))) {
+ fprintf(stderr,
+ "Warning: modutils is reading from %s because\n"
+ " %s does not exist. The use of %s is\n"
+ " deprecated, please rename %s to %s\n"
+ " as soon as possible. Command\n"
+ " mv %s %s\n",
+ old_name, ETC_MODULES_CONF,
+ old_name, old_name, ETC_MODULES_CONF,
+ old_name, ETC_MODULES_CONF);
+ }
+ /* So what... use the default configuration */
+ }
+ }
+
+ if (fin) {
+ struct stat statbuf1, statbuf2;
+ if (fstat(fileno(fin), &statbuf1) == 0)
+ config_mtime = statbuf1.st_mtime;
+ config_file = xstrdup(conf_file); /* Save name actually used */
+ if (!conf_file_specified &&
+ stat(ETC_MODULES_CONF, &statbuf1) == 0 &&
+ stat(old_name, &statbuf2) == 0) {
+ /* Both /etc files exist */
+ if (statbuf1.st_dev == statbuf2.st_dev &&
+ statbuf1.st_ino == statbuf2.st_ino) {
+ if (lstat(ETC_MODULES_CONF, &statbuf1) == 0 &&
+ S_ISLNK(statbuf1.st_mode))
+ fprintf(stderr,
+ "Warning: You do not need a link from %s to\n"
+ " %s. The use of %s is deprecated,\n"
+ " please remove %s and rename %s\n"
+ " to %s as soon as possible. Commands.\n"
+ " rm %s\n"
+ " mv %s %s\n",
+ ETC_MODULES_CONF, old_name,
+ old_name, ETC_MODULES_CONF, old_name, ETC_MODULES_CONF,
+ ETC_MODULES_CONF,
+ old_name, ETC_MODULES_CONF);
+ else {
+#ifndef NO_WARN_ON_OLD_LINK
+ fprintf(stderr,
+ "Warning: You do not need a link from %s to\n"
+ " %s. The use of %s is deprecated,\n"
+ " please remove %s as soon as possible. Command\n"
+ " rm %s\n",
+ old_name, ETC_MODULES_CONF,
+ old_name, old_name,
+ old_name);
+#endif
+ }
+ }
+ else
+ fprintf(stderr,
+ "Warning: modutils is reading from %s and\n"
+ " ignoring %s. The use of %s is deprecated,\n"
+ " please remove %s as soon as possible. Command\n"
+ " rm %s\n",
+ ETC_MODULES_CONF, old_name,
+ old_name, old_name,
+ old_name);
+ }
+ }
+
+ /*
+ * Finally, decode the file
+ */
+ while (fin && fgets_strip(buf, sizeof(buf) - 1, fin, &lineno) != NULL) {
+ char *arg2;
+ char *parm = buf;
+ char *arg;
+ int one_err = 0;
+ int adding;
+
+ while (isspace(*parm))
+ parm++;
+
+ if (strncmp(parm, "add", 3) == 0) {
+ adding = 1;
+ parm += 3;
+ while (isspace(*parm))
+ parm++;
+ } else
+ adding = 0;
+
+ arg = parm;
+
+ if (*parm == '\0')
+ continue;
+
+ one_err = 1;
+
+ while (*arg > ' ' && *arg != '=')
+ arg++;
+
+ if (*arg == '=')
+ assgn = 1;
+ else
+ assgn = 0;
+ *arg++ = '\0';
+ while (isspace(*arg))
+ arg++;
+
+ /*
+ * endif
+ */
+ if (!assgn && strcmp(parm, "endif") == 0) {
+ if (level > 0)
+ --level;
+ else {
+ error("unmatched endif in line %d", lineno);
+ return -1;
+ }
+ continue;
+ }
+
+ /*
+ * else
+ */
+ if (!assgn && strcmp(parm, "else") == 0) {
+ if (level <= 0) {
+ error("else without if in line %d", lineno);
+ return -1;
+ }
+ state[level] = !state[level];
+ continue;
+ }
+
+ /*
+ * elseif
+ */
+ if (!assgn && strcmp(parm, "elseif") == 0) {
+ if (level <= 0) {
+ error("elseif without if in line %d", lineno);
+ return -1;
+ }
+ if (state[level] != 0) {
+ /*
+ * We have already found a TRUE
+ * if statement in this "chain".
+ * That's what "2" means.
+ */
+ state[level] = 2;
+ continue;
+ }
+ /* else: No TRUE if has been found, cheat */
+ /*
+ * The "if" handling increments level,
+ * but this is the _same_ level as before.
+ * So, compensate for it.
+ */
+ --level;
+ parm = "if";
+ /* Fallthru to "if" */
+ }
+
+ /*
+ * if
+ */
+ if (strcmp(parm, "if") == 0) {
+ char *cmp;
+ int not = 0;
+ int numeric = 0;
+
+ if (level >= MAX_LEVEL) {
+ error("Too many nested if's in line %d\n", lineno);
+ return -1;
+ }
+ state[++level] = 0; /* default false */
+
+ if (*arg == '!') {
+ not = 1;
+ arg = next_word(arg);
+ }
+
+ if (strncmp(arg, "-k", 2) == 0) {
+ state[level] = flag_autoclean;
+ continue;
+ }
+
+ if (strncmp(arg, "-f", 2) == 0) {
+ char *file = next_word(arg);
+ meta_expand(file, &g, NULL, version, ME_ALL);
+ if (access(g.pathc ? g.pathv[0] : file, R_OK) == 0)
+ state[level] = !not;
+ else
+ state[level] = not;
+ continue;
+ }
+
+ if (strncmp(arg, "-n", 2) == 0) {
+ numeric = 1;
+ arg = next_word(arg);
+ }
+
+
+ cmp = next_word(arg);
+ if (*cmp) {
+ GLOB_LIST g2;
+ long n1 = 0;
+ long n2 = 0;
+ char *w1 = "";
+ char *w2 = "";
+
+ arg2 = next_word(cmp);
+
+ meta_expand(arg, &g, NULL, version, ME_ALL);
+ if (g.pathc && g.pathv[0])
+ w1 = g.pathv[0];
+
+ meta_expand(arg2, &g2, NULL, version, ME_ALL);
+ if (g2.pathc && g2.pathv[0])
+ w2 = g2.pathv[0];
+
+ if (numeric) {
+ n1 = strtol(w1, NULL, 0);
+ n2 = strtol(w2, NULL, 0);
+ }
+
+ if (strcmp(cmp, "==") == 0 ||
+ strcmp(cmp, "=") == 0) {
+ if (numeric)
+ state[level] = (n1 == n2);
+ else
+ state[level] = strcmp(w1, w2) == 0;
+ } else if (strcmp(cmp, "!=") == 0) {
+ if (numeric)
+ state[level] = (n1 != n2);
+ else
+ state[level] = strcmp(w1, w2) != 0;
+ } else if (strcmp(cmp, ">=") == 0) {
+ if (numeric)
+ state[level] = (n1 >= n2);
+ else
+ state[level] = strcmp(w1, w2) >= 0;
+ } else if (strcmp(cmp, "<=") == 0) {
+ if (numeric)
+ state[level] = (n1 <= n2);
+ else
+ state[level] = strcmp(w1, w2) <= 0;
+ } else if (strcmp(cmp, ">") == 0) {
+ if (numeric)
+ state[level] = (n1 > n2);
+ else
+ state[level] = strcmp(w1, w2) > 0;
+ } else if (strcmp(cmp, "<") == 0) {
+ if (numeric)
+ state[level] = (n1 < n2);
+ else
+ state[level] = strcmp(w1, w2) < 0;
+ }
+ } else { /* Check defined value, if any */
+ /* undef or defined as
+ * "" or "0" or "false" => false
+ * defined => true
+ */
+ if (!meta_expand(arg, &g, NULL, version, ME_ALL) &&
+ g.pathc > 0 &&
+ strcmp(g.pathv[0], "0") != 0 &&
+ strcmp(g.pathv[0], "false") != 0 &&
+ strlen(g.pathv[0]) != 0)
+ state[level] = 1; /* true */
+ }
+ if (not)
+ state[level] = !state[level];
+
+ continue;
+ }
+
+ /*
+ * Should we bother?
+ */
+ if (state[level] != 1)
+ continue;
+
+ /*
+ * define
+ */
+ if (!assgn && strcmp(parm, "define") == 0) {
+ char env[PATH_MAX];
+
+ arg2 = next_word(arg);
+ meta_expand(arg2, &g, NULL, version, ME_ALL);
+ snprintf(env, sizeof(env), "%s=%s", arg, (g.pathc ? g.pathv[0] : ""));
+ putenv(env);
+ one_err = 0;
+ }
+
+ /*
+ * include
+ */
+ if (!assgn && strcmp(parm, "include") == 0) {
+ meta_expand(arg, &g, NULL, version, ME_ALL);
+
+ if (!do_read(all, version, base_dir, g.pathc ? g.pathv[0] : arg, depth+1))
+ one_err = 0;
+ else
+ error("include %s failed\n", arg);
+ }
+
+ /*
+ * above
+ */
+ else if (all && !assgn && strcmp(parm, "above") == 0) {
+ decode_list(&n_abovelist, &abovelist, arg, adding, version, 0);
+ one_err = 0;
+ }
+
+ /*
+ * below
+ */
+ else if (all && !assgn && strcmp(parm, "below") == 0) {
+ decode_list(&n_belowlist, &belowlist, arg, adding, version, 0);
+ one_err = 0;
+ }
+
+ /*
+ * 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) {
+ decode_list(&n_probe_list, &probe_list, arg, adding, version, 0);
+ one_err = 0;
+ }
+
+ /*
+ * probeall
+ */
+ else if (all && !assgn && strcmp(parm, "probeall") == 0) {
+ decode_list(&n_probeall_list, &probeall_list, arg, adding, version, 0);
+ one_err = 0;
+ }
+
+ /*
+ * options
+ */
+ else if (all && !assgn && strcmp(parm, "options") == 0) {
+ decode_list(&n_opt_list, &opt_list, arg, adding, version, 1);
+ one_err = 0;
+ }
+
+ /*
+ * alias
+ */
+ else if (all && !assgn && strcmp(parm, "alias") == 0) {
+ /*
+ * Replace any previous (default) definitions
+ * for the same module
+ */
+ decode_list(&n_aliases, &aliases, arg, 0, version, 0);
+ one_err = 0;
+ }
+
+ /*
+ * Specification: /etc/modules.conf
+ * The format of the commands in /etc/modules.conf are:
+ *
+ * pre-install module command
+ * install module command
+ * post-install module command
+ * pre-remove module command
+ * remove module command
+ * post-remove module command
+ *
+ * The different words are separated by tabs or spaces.
+ */
+ /*
+ * pre-install
+ */
+ else if (all && !assgn && (strcmp(parm, "pre-install") == 0)) {
+ decode_exec(arg, EXEC_PRE_INSTALL);
+ one_err = 0;
+ }
+
+ /*
+ * install
+ */
+ else if (all && !assgn && (strcmp(parm, "install") == 0)) {
+ decode_exec(arg, EXEC_INSTALL);
+ one_err = 0;
+ }
+
+ /*
+ * post-install
+ */
+ else if (all && !assgn && (strcmp(parm, "post-install") == 0)) {
+ decode_exec(arg, EXEC_POST_INSTALL);
+ one_err = 0;
+ }
+
+ /*
+ * pre-remove
+ */
+ else if (all && !assgn && (strcmp(parm, "pre-remove") == 0)) {
+ decode_exec(arg, EXEC_PRE_REMOVE);
+ one_err = 0;
+ }
+
+ /*
+ * remove
+ */
+ else if (all && !assgn && (strcmp(parm, "remove") == 0)) {
+ decode_exec(arg, EXEC_REMOVE);
+ one_err = 0;
+ }
+
+ /*
+ * post-remove
+ */
+ else if (all && !assgn && (strcmp(parm, "post-remove") == 0)) {
+ decode_exec(arg, EXEC_POST_REMOVE);
+ one_err = 0;
+ }
+
+ /*
+ * insmod_opt=
+ */
+ else if (assgn && (strcmp(parm, "insmod_opt") == 0)) {
+ insmod_opt = xstrdup(arg);
+ one_err = 0;
+ }
+
+ /*
+ * keep
+ */
+ else if (!assgn && (strcmp(parm, "keep") == 0)) {
+ drop_default_paths = 0;
+ one_err = 0;
+ }
+
+ /*
+ * path...=
+ */
+ else if (assgn && strncmp(parm, "path", 4) == 0) {
+ /*
+ * Specification: config file / path parameter
+ * The path parameter specifies a directory to
+ * search for modules.
+ * This parameter may be repeated multiple times.
+ *
+ * Note that the actual path may be defined using
+ * wildcards and other shell meta-chars, such as "*?`".
+ * For example:
+ * path[misc]=/lib/modules/1.1.5?/misc
+ *
+ * Optionally the path keyword carries a tag.
+ * This tells us a little more about the purpose of
+ * this directory and allows some automated operations.
+ * A path is marked with a tag by adding the tag,
+ * enclosed in square brackets, to the path keyword:
+ * #
+ * path[boot]=/lib/modules/boot
+ * #
+ * This case identifies the path a of directory
+ * holding modules loadable a boot time.
+ */
+
+ if (drop_default_paths) {
+ int n;
+
+ /*
+ * Specification: config file / path / default
+ *
+ * Whenever there is a path[] specification
+ * in the config file, all the default
+ * path are reset.
+ *
+ * If one instead wants to _add_ to the default
+ * set of paths, one has to have the option
+ * keep
+ * before the first path[]-specification line
+ * in the configuration file.
+ */
+ drop_default_paths = 0;
+ for (n = 0; n < nmodpath; n++) {
+ free(modpath[n].path);
+ free(modpath[n].type);
+ }
+ nmodpath = 0;
+ }
+
+ /*
+ * Get (the optional) tag
+ * If the tag is missing, the word "misc"
+ * is assumed.
+ */
+ type = "misc";
+
+ if (parm[4] == '[') {
+ char *pt_type = parm + 5;
+
+ while (*pt_type != '\0' && *pt_type != ']')
+ pt_type++;
+
+ if (*pt_type == ']' && pt_type[1] == '\0') {
+ *pt_type = '\0';
+ type = parm + 5;
+ } /* else CHECKME */
+ }
+
+ /*
+ * Handle the actual path description
+ */
+ if (meta_expand(arg, &g, base_dir, version, ME_ALL))
+ return -1;
+ for (glb = g.pathv; glb && *glb; ++glb) {
+ modpath[nmodpath].type = xstrdup(type);
+ modpath[nmodpath].path = *glb;
+ if (++nmodpath >= maxpath) {
+ maxpath += 100;
+ modpath = (struct PATH_TYPE *)xrealloc(modpath,
+ maxpath * sizeof(struct PATH_TYPE));
+ }
+ }
+ one_err = 0;
+ }
+
+ /*
+ * persistdir
+ */
+ else if (assgn && strcmp(parm, "persistdir") == 0) {
+ meta_expand(arg, &g, NULL, version, ME_ALL);
+ persistdir = xstrdup(g.pathc ? g.pathv[0] : arg);
+ one_err = 0;
+ }
+
+ /* Names for generated files in config file */
+ for (i = 0; one_err && i < gen_file_count; ++i)
+ one_err = gen_file_conf(gen_file+i, assgn, parm, arg);
+
+ /*
+ * any errors so far?
+ */
+ if (all == 0)
+ one_err = 0;
+ else if (one_err) {
+ error("Invalid line %d in %s\n\t%s",
+ lineno, conf_file, buf);
+ ret = -1;
+ }
+ }
+ if (fin)
+ fclose(fin);
+
+ if (level) {
+ error("missing endif at %s EOF", conf_file);
+ ret = -1;
+ }
+
+ if (ret)
+ return ret;
+ /* else */
+
+ /* Check we have names for generated files */
+ for (i = 0; !ret && i < gen_file_count; ++i)
+ ret = gen_file_check(gen_file+i, &g, base_dir, version);
+
+ return ret;
+}
+
+int config_read(int all, char *force_ver, char *base_dir, char *conf_file)
+{
+ int r;
+ if (modpath != NULL)
+ return 0; /* already initialized */
+
+ if (uname(&uts_info) < 0) {
+ error("Failed to find kernel name information");
+ return -1;
+ }
+
+ r = do_read(all, force_ver, base_dir, conf_file, 0);
+
+ if (quick && !r && !need_update (force_ver, base_dir))
+ exit (0);
+
+ return r;
+}
+
+/****************************************************************************/
+/*
+ * FIXME: Far too much global state. KAO.
+ */
+static int found;
+static int favail;
+static int one_only;
+static int meta_expand_type;
+char **list;
+static const char *filter_by_file;
+static char *filter_by_dir;
+
+/*
+ * Add a file name if it exist
+ */
+static int config_add(const char *file, const struct stat *sb)
+{
+ int i;
+ int npaths = 0;
+ char **paths = NULL;
+
+ if (meta_expand_type) {
+ GLOB_LIST g;
+ char **p;
+ char full[PATH_MAX];
+
+ snprintf(full, sizeof(full), "%s/%s", file, filter_by_file);
+
+ if (filter_by_dir && !strstr(full, filter_by_dir))
+ return 0;
+
+ if (meta_expand(full, &g, NULL, config_version, meta_expand_type))
+ return 1;
+ for (p = g.pathv; p && *p; ++p) {
+ paths = (char **)xrealloc(paths,
+ (npaths + 1) * sizeof(char *));
+ paths[npaths++] = *p;
+ }
+ } else { /* normal path match or match with "*" */
+ if (!S_ISREG(sb->st_mode))
+ return 0;
+
+ if (strcmp(filter_by_file, "*")) {
+ char *p;
+
+ if ((p = strrchr(file, '/')) == NULL)
+ p = (char *)file;
+ else
+ p += 1;
+
+ if (strcmp(p, filter_by_file))
+ return 0;
+ }
+ if (filter_by_dir && !strstr(file, filter_by_dir))
+ return 0;
+ paths = (char **)xmalloc(sizeof(char **));
+ *paths = xstrdup(file);
+ npaths = 1;
+ }
+
+ for (i = 0; i < npaths; ++i) {
+ struct stat sbuf;
+
+ if (S_ISDIR(sb->st_mode)) {
+ if (stat(paths[i], &sbuf) == 0)
+ sb = &sbuf;
+ }
+ if (S_ISREG(sb->st_mode) && sb->st_mode & S_IRUSR) {
+ int j;
+ char **this;
+
+ if (!root_check_off) {
+ if (sb->st_uid != 0) {
+ error("%s is not owned by root", paths[i]);
+ continue;
+ }
+ }
+
+ /* avoid duplicates */
+ for (j = 0, this = list; j < found; ++j, ++this) {
+ if (strcmp(*this, paths[i]) == 0) {
+ free(paths[i]);
+ goto next;
+ }
+ }
+
+ list[found] = paths[i];
+ if (++found >= favail)
+ list = (char **)xrealloc(list,
+ (favail += 100) * sizeof(char *));
+
+ if (one_only) {
+ for (j = i + 1; j < npaths; ++j)
+ free(paths[j]);
+ free(paths);
+ return 1; /* finish xftw */
+ }
+ }
+ next:
+ }
+
+ if (npaths > 0)
+ free(paths);
+
+ return 0;
+}
+
+/*
+ * Find modules matching the name "match" in directory of type "type"
+ * (type == NULL matches all)
+ *
+ * Return a pointer to the list of modules found (or NULL if error).
+ * Update the counter (sent as parameter).
+ */
+GLOB_LIST *config_lstmod(const char *match, const char *type, int first_only)
+{
+ /*
+ * Note:
+ * There are _no_ wildcards remaining in the path descriptions!
+ */
+ struct stat sb;
+ int i;
+ int ret = 0;
+ char *path = NULL;
+ char this[PATH_MAX];
+
+ if (!match)
+ match = "*";
+ one_only = first_only;
+ found = 0;
+ filter_by_file = match;
+ filter_by_dir = NULL;
+ if (type) {
+ char tmpdir[PATH_MAX];
+ snprintf(tmpdir, sizeof(tmpdir), "/%s/", type);
+ filter_by_dir = xstrdup(tmpdir);
+ }
+ /* In safe mode, the module name is always handled as is, without meta
+ * expansion. It might have come from an end user via kmod and must
+ * not be trusted. Even in unsafe mode, only apply globbing to the
+ * module name, not command expansion. We trust config file input so
+ * applying command expansion is safe, we do not trust command line input.
+ * This assumes that the only time the user can specify -C config file
+ * is when they run under their own authority. In particular all
+ * mechanisms that call modprobe as root on behalf of the user must
+ * run in safe mode, without letting the user supply a config filename.
+ */
+ meta_expand_type = 0;
+ if (strpbrk(match, SHELL_META) && strcmp(match, "*") && !safemode)
+ meta_expand_type = ME_GLOB|ME_BUILTIN_COMMAND;
+
+ list = (char **)xmalloc((favail = 100) * sizeof(char *));
+
+ for (i = 0; i < nmodpath; i++) {
+ path = modpath[i].path;
+ /* Special case: insmod: handle single, non-wildcard match */
+ if (first_only && strpbrk(match, SHELL_META) == NULL) {
+ /* Fix for "2.1.121 syntax */
+ snprintf(this, sizeof(this), "%s/%s/%s", path,
+ modpath[i].type, match);
+ if (stat(this, &sb) == 0 &&
+ config_add(this, &sb))
+ break;
+ /* End fix for "2.1.121 syntax */
+
+ snprintf(this, sizeof(this), "%s/%s", path, match);
+ if (stat(this, &sb) == 0 &&
+ config_add(this, &sb))
+ break;
+ }
+
+ /* Start looking */
+ if ((ret = xftw(path, config_add))) {
+ break;
+ }
+ }
+ if (ret >= 0) {
+ GLOB_LIST *g = (GLOB_LIST *)xmalloc(sizeof(GLOB_LIST));
+ g->pathc = found;
+ g->pathv = list;
+ free(filter_by_dir);
+ return g;
+ }
+ free(list);
+ free(filter_by_dir);
+ return NULL;
+}
+
+/* Given a bare module name, poke through the module path to find the file. */
+char *search_module_path(const char *base)
+{
+ GLOB_LIST *g;
+
+ if (config_read(0, NULL, "", NULL) < 0)
+ return NULL;
+ /* else */
+ g = config_lstmod(base, NULL, 1);
+ if (g == NULL || g->pathc == 0) {
+ char base_o[PATH_MAX];
+
+ snprintf(base_o, sizeof(base_o), "%s.o", base);
+ g = config_lstmod(base_o, NULL, 1);
+#ifdef CONFIG_USE_ZLIB
+ if (g == NULL || g->pathc == 0) {
+ snprintf(base_o, sizeof(base_o), "%s.o.gz", base);
+ g = config_lstmod(base_o, NULL, 1);
+ }
+#endif
+ }
+ if (g == NULL || g->pathc == 0)
+ return NULL;
+ /* else */
+ return g->pathv[0];
+}
diff --git a/mdk-stage1/insmod-modutils/util/gzfiles.c b/mdk-stage1/insmod-modutils/util/gzfiles.c
new file mode 100644
index 000000000..8d02253bb
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/gzfiles.c
@@ -0,0 +1,74 @@
+/*
+ * This simple library intends to make it transparent to read gzipped and/or
+ * standard files. This is simple enough to fit modutils' needs, but may be
+ * easily adapted to anyone's needs. It's completely free, do what you want
+ * with it . - Willy Tarreau <willy@meta-x.org> - 2000/05/05 -
+ */
+
+#ifdef CONFIG_USE_ZLIB
+
+#include <stdio.h>
+#include <zlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/* redefinition of gz_stream which isn't exported by zlib */
+typedef struct gz_stream {
+ z_stream stream;
+ int z_err; /* error code for last stream operation */
+ int z_eof; /* set if end of input file */
+ FILE *file; /* .gz file */
+ Byte *inbuf; /* input buffer */
+ Byte *outbuf; /* output buffer */
+ uLong crc; /* crc32 of uncompressed data */
+ char *msg; /* error message */
+ char *path; /* path name for debugging only */
+ int transparent; /* 1 if input file is not a .gz file */
+ char mode; /* 'w' or 'r' */
+ long startpos; /* start of compressed data in file (header skipped) */
+} gz_stream;
+
+/* maximum number of simultaneous open files, also greater file descriptor number */
+#define MAXFD 64
+
+/* this static list is assumed to be filled with NULLs at runtime */
+static gzFile gzf_fds[MAXFD];
+
+/* returns the filedesc of the opened file. */
+int gzf_open(const char *name, int mode) {
+ int fd;
+ gzFile g;
+
+ if ((g=gzopen(name, "rb")) != NULL) {
+ fd=fileno(((gz_stream*)g)->file);
+ gzf_fds[fd]=g;
+ }
+ else if ((fd=open(name, mode)) != -1) {
+ gzf_fds[fd]=NULL; /* NULL means not GZ mode */
+ }
+ return fd;
+}
+
+off_t gzf_lseek(int fd, off_t offset, int whence) {
+ if (fd<0 || fd>=MAXFD || gzf_fds[fd]==NULL)
+ return lseek(fd, offset, whence);
+ else
+ return gzseek(gzf_fds[fd], offset, whence);
+}
+
+int gzf_read(int fd, void *buf, size_t count) {
+ if (fd<0 || fd>=MAXFD || gzf_fds[fd]==NULL)
+ return read(fd, buf, count);
+ else
+ return gzread(gzf_fds[fd], buf, count);
+}
+
+void gzf_close(int fd) {
+ if (fd<0 || fd>=MAXFD || gzf_fds[fd]==NULL)
+ close(fd);
+ else
+ gzclose(gzf_fds[fd]);
+}
+#endif
+
diff --git a/mdk-stage1/insmod-modutils/util/logger.c b/mdk-stage1/insmod-modutils/util/logger.c
new file mode 100644
index 000000000..3b790df5a
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/logger.c
@@ -0,0 +1,163 @@
+/* Error logging facilities.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ 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
+ */
+
+#ident "$Id$"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <syslog.h>
+
+#include "util.h"
+
+/*======================================================================*/
+
+int errors;
+const char *error_file;
+int log;
+
+#define STOREMSG
+#ifdef STOREMSG
+struct cbuf {
+ struct cbuf *next;
+ int type;
+ char *msg;
+} *head, *tail;
+
+static void savemsg(int type, char *msg)
+{
+ struct cbuf *me = (struct cbuf *)xmalloc(sizeof(struct cbuf));
+ char *s = xstrdup(msg);
+
+ me->next = NULL;
+ me->type = type;
+ me->msg = s;
+
+ if (tail)
+ tail->next = me;
+ else
+ head = me;
+ tail = me;
+}
+
+#endif /* STOREMSG */
+
+static void dumpmsg(void)
+{
+ for (;head; head = head->next)
+ syslog(head->type, "%s", head->msg);
+}
+
+void setsyslog(const char *program)
+{
+ openlog(program, LOG_CONS, LOG_DAEMON);
+#ifdef STOREMSG
+ atexit(dumpmsg);
+#endif
+ log = 1;
+}
+
+
+
+#ifdef _STANDALONE_
+static int silent;
+
+const char *program_name;
+
+void error(const char *fmt,...)
+{
+ va_list args;
+
+ if (silent)
+ ;
+ else if (log) {
+ char buf[1024];
+ int n;
+
+ if (error_file)
+ n = snprintf(buf, sizeof(buf), "%s: ", error_file);
+ else
+ n = 0;
+ va_start(args, fmt);
+ vsnprintf(buf + n, sizeof(buf) - n, fmt, args);
+ va_end(args);
+#ifdef STOREMSG
+ savemsg(LOG_ERR, buf);
+#else
+ syslog(LOG_ERR, "%s", buf);
+#endif
+ } else {
+ if (error_file)
+ fprintf(stderr, "%s: ", error_file);
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ putc('\n', stderr);
+ }
+
+ errors++;
+}
+
+void lprintf(const char *fmt,...)
+{
+ va_list args;
+
+ if (silent);
+ else if (log) {
+ char buf[1024];
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+#ifdef STOREMSG
+ savemsg(LOG_INFO, buf);
+#else
+ syslog(LOG_INFO, "%s", buf);
+#endif
+ } else {
+ va_start(args, fmt);
+ vfprintf(stdout, fmt, args);
+ va_end(args);
+ putchar('\n');
+ }
+}
+
+#else /* _STANDALONE_ */
+#include "../../log.h"
+void error(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ vlog_message(s, p);
+ va_end(p);
+}
+
+void lprintf(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ vlog_message(s, p);
+ va_end(p);
+}
+#endif
diff --git a/mdk-stage1/insmod-modutils/util/meta_expand.c b/mdk-stage1/insmod-modutils/util/meta_expand.c
new file mode 100644
index 000000000..41fb4024c
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/meta_expand.c
@@ -0,0 +1,339 @@
+/*
+ * Handle expansion of meta charaters
+ *
+ * Copyright 1999 Björn Ekwall <bj0rn@blox.se>
+ *
+ * "kernelversion" idea from the Debian release via:
+ * Wichert Akkerman <wakkerma@cs.leidenuniv.nl>
+ *
+ * Use wordexp(): idea from Tim Waugh <tim@cyberelk.demon.co.uk>
+ *
+ * Alpha typecast: Michal Jaegermann <michal@ellpspace.math.ualberta.ca>
+ *
+ * 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.
+ */
+
+#ifdef HAVE_WORDEXP
+#undef HAVE_WORDEXP
+#define HAVE_WORDEXP 0
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <ctype.h>
+#if HAVE_WORDEXP
+#include <wordexp.h>
+#elif HAVE_GLOB
+#include <glob.h>
+#endif
+#include "util.h"
+
+/*
+ * Split into words delimited by whitespace,
+ * handle remaining quotes though...
+ * If strip_quotes != 0 then strip one level of quotes from the line.
+ */
+static void split_line(GLOB_LIST *g, char *line, int strip_quotes)
+{
+ int len;
+ char *d;
+ char *e;
+ char *p;
+ char tmpline[PATH_MAX];
+
+ for (p = line; *p; p = e) {
+ /* Skip leading whitespace */
+ while (*p && isspace(*p))
+ ++p;
+
+ /* find end of word */
+ d = tmpline;
+ for (e = p; *e && !(isspace(*e)); ++e) {
+ char match;
+
+ /* Quote handling */
+ switch (*e) {
+ case '\\':
+ if (!strip_quotes)
+ *d++ = *e;
+ break;
+
+ case '"':
+ case '\'':
+ match = *e;
+ if (!strip_quotes)
+ *d++ = *e;
+ for (++e; *e && *e != match; ++e) {
+ *d++ = *e;
+ if (*e == '\\' && *(e + 1) == match)
+ *d++ = *++e;
+ }
+ if (!strip_quotes)
+ *d++ = *e;
+ break;
+
+ default:
+ *d++ = *e;
+ break;
+ }
+ }
+
+ if ((len = (int)(d - tmpline)) > 0) {
+ char *str = xmalloc(len + 1);
+ strncpy(str, tmpline, len);
+ str[len] = '\0';
+ g->pathv = (char **)xrealloc(g->pathv,
+ (g->pathc + 2) * sizeof(char *));
+ g->pathv[g->pathc++] = str;
+ }
+ }
+
+ if (g->pathc)
+ g->pathv[g->pathc] = NULL;
+}
+
+static int glob_it(char *pt, GLOB_LIST *g)
+{
+#if HAVE_WORDEXP
+ wordexp_t w;
+
+ memset(&w, 0, sizeof(w));
+ if (wordexp(pt, &w, WRDE_UNDEF)) {
+ /*
+ error("wordexp %s failed", pt);
+ */
+ return -1;
+ }
+ /* else */
+ g->pathc = w.we_wordc;
+ g->pathv = w.we_wordv;
+
+ return 0;
+#elif HAVE_GLOB /* but not wordexp */
+ glob_t w;
+
+ memset(&w, 0, sizeof(w));
+ if (glob(pt, GLOB_NOSORT, NULL, &w)) {
+ /*
+ error("glob %s failed", pt);
+ */
+ return -1;
+ }
+ /* else */
+ if (w.gl_pathc && strpbrk(w.gl_pathv[0], SHELL_META)) {
+ globfree(&w);
+ return -1;
+ }
+ g->pathc = w.gl_pathc;
+ g->pathv = w.gl_pathv;
+
+ return 0;
+#else /* Neither wordexp nor glob */
+ return -1;
+#endif
+}
+
+/*
+ * Expand the string (including meta-character) to a list of matches
+ *
+ * Return 0 if OK else -1
+ */
+int meta_expand(char *pt, GLOB_LIST *g, char *base_dir, char *version, int type)
+{
+ FILE *fin;
+ int len = 0;
+ char *line = NULL;
+ char *p, *p1;
+ char tmpline[PATH_MAX + 1];
+ char wrk[sizeof(tmpline)];
+ char tmpcmd[2*sizeof(tmpline)+20]; /* room for /bin/echo "text" */
+
+ g->pathc = 0;
+ g->pathv = NULL;
+
+ /*
+ * Take care of version dependent expansions
+ * Needed for forced version handling
+ */
+ if ((p = strchr(pt, '`')) != NULL && (type & ME_BUILTIN_COMMAND)) {
+ do {
+ char *s;
+
+ for (s = p + 1; isspace(*s); ++s)
+ ;
+
+ if (strncmp(s, "uname -r", 8) == 0) {
+ while (*s && (*s != '`'))
+ ++s;
+ if (*s == '`') {
+ *p = '\0';
+ snprintf(wrk, sizeof(wrk), "%s%s%s",
+ pt,
+ version,
+ s + 1);
+ *p = '`';
+ }
+ strcpy(tmpline, wrk); /* safe, same size */
+ pt = tmpline;
+ } else if (strncmp(s, "kernelversion", 13) == 0) {
+ while (*s && (*s != '`'))
+ ++s;
+ if (*s == '`') {
+ int n;
+ char *k;
+
+ *p = '\0';
+ for (n = 0, k = version; *k; ++k) {
+ if (*k == '.' && ++n == 2)
+ break;
+ }
+ snprintf(wrk, sizeof(wrk), "%s%.*s%s",
+ pt,
+ /* typecast for Alpha */
+ (int)(k - version),
+ version,
+ s + 1);
+ *p = '`';
+ strcpy(tmpline, wrk); /* safe, same size */
+ pt = tmpline;
+ }
+ } else
+ break;
+ } while ((p = strchr(pt, '`')) != NULL);
+ }
+
+ /*
+ * Any remaining meta-chars?
+ */
+ if (strpbrk(pt, SHELL_META) == NULL) {
+ /*
+ * No meta-chars.
+ * Split into words, delimited by whitespace.
+ */
+ snprintf(wrk, sizeof(wrk), "%s%s", (base_dir ? base_dir : ""), pt);
+ strcpy(tmpline, wrk); /* safe, same size */
+ if ((p = strtok(tmpline, " \t\n")) != NULL) {
+ while (p) {
+ g->pathv = (char **)xrealloc(g->pathv,
+ (g->pathc + 2) * sizeof(char *));
+ g->pathv[g->pathc++] = xstrdup(p);
+ p = strtok(NULL, " \t\n");
+ }
+ }
+ if (g->pathc)
+ g->pathv[g->pathc] = NULL;
+ return 0;
+ }
+ /* else */
+ /*
+ * Handle remaining meta-chars
+ */
+
+ /*
+ * Just plain quotes?
+ */
+ if (strpbrk(pt, "&();|<>$`!{}[]~=+:?*") == NULL &&
+ (p = strpbrk(pt, "\"'\\"))) {
+ split_line(g, pt, 1);
+ return 0;
+ }
+
+ if (strpbrk(pt, "&();|<>$`\"'\\!{}~+:[]~?*") == NULL) {
+ /* Only "=" remaining, should be module options */
+ split_line(g, pt, 0);
+ return 0;
+ }
+
+ /*
+ * If there are meta-characters and
+ * if they are only shell glob meta-characters: do globbing
+ */
+#if HAVE_WORDEXP
+ if (strpbrk(pt, "&();|<>`\"'\\!{}~=+:") == NULL &&
+ strpbrk(pt, "$[]~?*"))
+#else
+ if (strpbrk(pt, "&();|<>$`\"'\\!{}~=+:") == NULL &&
+ strpbrk(pt, "[]~?*"))
+#endif
+ if ((type & ME_GLOB) && glob_it(pt, g) == 0)
+ return 0;
+
+ if (strpbrk(pt, "&();|<>$`\"'\\!{}~+:[]~?*") == NULL) {
+ /* Only "=" remaining, should be module options */
+ split_line(g, pt, 0);
+ return 0;
+ }
+
+ /*
+ * Last resort: Use "echo".
+ * DANGER: Applying shell expansion to user supplied input is a
+ * major security risk. Modutils code should only do meta
+ * expansion via shell commands for trusted data. Basically
+ * this means only for data in the config file. Even that
+ * assumes that the user cannot run modprobe as root with
+ * their own config file. Programs (including the kernel)
+ * that invoke modprobe as root with user supplied input must
+ * pass exactly one user supplied parameter and must set
+ * safe mode.
+ */
+ if (!(type & ME_SHELL_COMMAND))
+ return 0;
+ snprintf(wrk, sizeof(wrk), "%s%s", (base_dir ? base_dir : ""), pt);
+ strcpy(tmpline, wrk); /* safe, same size */
+ snprintf(tmpcmd, sizeof(tmpcmd), "/bin/echo \"");
+ for (p = tmpline, p1 = tmpcmd + strlen(tmpcmd); *p; ++p, ++p1) {
+ if (*p == '"' || *p == '\\')
+ *p1++ = '\\';
+ *p1 = *p;
+ }
+ *p1++ = '"';
+ *p1++ = '\0';
+ if (p1 - tmpcmd > sizeof(tmpcmd)) {
+ error("tmpcmd overflow, should never happen");
+ exit(1);
+ }
+ if ((fin = popen(tmpcmd, "r")) == NULL) {
+ error("Can't execute: %s", tmpcmd);
+ return -1;
+ }
+ /* else */
+
+ /*
+ * Collect the result
+ */
+ while (fgets(tmpcmd, PATH_MAX, fin) != NULL) {
+ int l = strlen(tmpcmd);
+
+ line = (char *)xrealloc(line, len + l + 1);
+ line[len] = '\0';
+ strcat(line + len, tmpcmd); /* safe, realloc */
+ len += l;
+ }
+ pclose(fin);
+
+ if (line) {
+ /* shell used to strip one set of quotes. Paranoia code in
+ * 2.3.20 stops that strip so we do it ourselves.
+ */
+ split_line(g, line, 1);
+ free(line);
+ }
+
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/util/modstat.c b/mdk-stage1/insmod-modutils/util/modstat.c
new file mode 100644
index 000000000..ad82306c0
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/modstat.c
@@ -0,0 +1,419 @@
+/*
+ * Get kernel symbol table(s) and other relevant module info.
+ *
+ * Add module_name_list and l_module_name_list.
+ * Keith Owens <kaos@ocs.com.au> November 1999.
+ * Björn Ekwall <bj0rn@blox.se> in February 1999 (C)
+ * Initial work contributed by Richard Henderson <rth@tamu.edu>
+ *
+ * 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.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "util.h"
+#include "module.h"
+#include "obj.h"
+#include "modstat.h"
+
+struct module_stat *module_stat;
+size_t n_module_stat;
+char *module_name_list;
+size_t l_module_name_list;
+struct module_symbol *ksyms;
+size_t nksyms;
+int k_new_syscalls;
+
+static void *old_kernsym;
+
+/************************************************************************/
+static void drop(void)
+{
+ /*
+ * Clean the slate for multiple runs
+ */
+ if (module_stat) {
+ struct module_stat *m;
+ int i;
+
+ for (i = 0, m = module_stat; i < n_module_stat; ++i, ++m) {
+ if (m->syms)
+ free(m->syms);
+ if (m->refs)
+ free(m->refs);
+ }
+ free(module_stat);
+ module_stat = NULL;
+ n_module_stat = 0;
+ }
+ if (module_name_list) {
+ free(module_name_list);
+ module_name_list = NULL;
+ l_module_name_list = 0;
+ }
+ if (ksyms) {
+ free(ksyms);
+ ksyms = NULL;
+ nksyms = 0;
+ }
+ if (old_kernsym) {
+ free(old_kernsym);
+ old_kernsym = NULL;
+ }
+}
+
+static int new_get_kernel_info(int type)
+{
+ struct module_stat *modules;
+ struct module_stat *m;
+ struct module_symbol *syms;
+ struct module_symbol *s;
+ size_t ret;
+ size_t bufsize;
+ size_t nmod;
+ size_t nsyms;
+ size_t i;
+ size_t j;
+ char *module_names;
+ char *mn;
+
+ drop();
+
+ /*
+ * Collect the loaded modules
+ */
+ module_names = xmalloc(bufsize = 256);
+ while (query_module(NULL, QM_MODULES, module_names, bufsize, &ret)) {
+ if (errno != ENOSPC) {
+ error("QM_MODULES: %m\n");
+ return 0;
+ }
+ module_names = xrealloc(module_names, bufsize = ret);
+ }
+ module_name_list = module_names;
+ l_module_name_list = bufsize;
+ n_module_stat = nmod = ret;
+ module_stat = modules = xmalloc(nmod * sizeof(struct module_stat));
+ memset(modules, 0, nmod * sizeof(struct module_stat));
+
+ /* Collect the info from the modules */
+ for (i = 0, mn = module_names, m = modules;
+ i < nmod;
+ ++i, ++m, mn += strlen(mn) + 1) {
+ struct module_info info;
+
+ m->name = mn;
+ if (query_module(mn, QM_INFO, &info, sizeof(info), &ret)) {
+ if (errno == ENOENT) {
+ /* The module was removed out from underneath us. */
+ m->flags = NEW_MOD_DELETED;
+ continue;
+ }
+ /* else oops */
+ error("module %s: QM_INFO: %m", mn);
+ return 0;
+ }
+
+ m->addr = info.addr;
+
+ if (type & K_INFO) {
+ m->size = info.size;
+ m->flags = info.flags;
+ m->usecount = info.usecount;
+ m->modstruct = info.addr;
+ }
+
+ if (type & K_REFS) {
+ int mm;
+ char *mrefs;
+ char *mr;
+
+ mrefs = xmalloc(bufsize = 64);
+ while (query_module(mn, QM_REFS, mrefs, bufsize, &ret)) {
+ if (errno != ENOSPC) {
+ error("QM_REFS: %m");
+ return 1;
+ }
+ mrefs = xrealloc(mrefs, bufsize = ret);
+ }
+ for (j = 0, mr = mrefs;
+ j < ret;
+ ++j, mr += strlen(mr) + 1) {
+ for (mm = 0; mm < i; ++mm) {
+ if (strcmp(mr, module_stat[mm].name) == 0) {
+ m->nrefs += 1;
+ m->refs = xrealloc(m->refs, m->nrefs * sizeof(struct module_stat **));
+ m->refs[m->nrefs - 1] = module_stat + mm;
+ break;
+ }
+ }
+ }
+ free(mrefs);
+ }
+
+ if (type & K_SYMBOLS) { /* Want info about symbols */
+ syms = xmalloc(bufsize = 1024);
+ while (query_module(mn, QM_SYMBOLS, syms, bufsize, &ret)) {
+ if (errno == ENOSPC) {
+ syms = xrealloc(syms, bufsize = ret);
+ continue;
+ }
+ if (errno == ENOENT) {
+ /*
+ * The module was removed out
+ * from underneath us.
+ */
+ m->flags = NEW_MOD_DELETED;
+ free(syms);
+ goto next;
+ } else {
+ error("module %s: QM_SYMBOLS: %m", mn);
+ return 0;
+ }
+ }
+ nsyms = ret;
+
+ m->nsyms = nsyms;
+ m->syms = syms;
+
+ /* Convert string offsets to string pointers */
+ for (j = 0, s = syms; j < nsyms; ++j, ++s)
+ s->name += (unsigned long) syms;
+ }
+ next:
+ }
+
+ if (type & K_SYMBOLS) { /* Want info about symbols */
+ /* Collect the kernel's symbols. */
+ syms = xmalloc(bufsize = 16 * 1024);
+ while (query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)) {
+ if (errno != ENOSPC) {
+ error("kernel: QM_SYMBOLS: %m");
+ return 0;
+ }
+ syms = xrealloc(syms, bufsize = ret);
+ }
+ nksyms = nsyms = ret;
+ ksyms = syms;
+
+ /* Convert string offsets to string pointers */
+ for (j = 0, s = syms; j < nsyms; ++j, ++s)
+ s->name += (unsigned long) syms;
+ }
+
+ return 1;
+}
+
+#ifdef COMPAT_2_0
+/************************************************************************/
+
+#define mscan(offs,siz,ptr) \
+ if (lseek(kmem_fd, (off_t)(offs), SEEK_SET) == -1 || \
+ read(kmem_fd, (ptr), (siz)) != (siz)) { \
+ if (kmem_fd != -1) \
+ close(kmem_fd); \
+ error("kmem: %m"); \
+ return 0; \
+ }
+
+#define OLD_MOD_RUNNING 1
+#define OLD_MOD_DELETED 2
+#define OLD_MOD_VISITED 0x20000000
+
+/* Fetch all the symbols and divvy them up as appropriate for the modules. */
+static int old_get_kernel_info(int type)
+{
+ struct old_kernel_sym *kernsym;
+ struct old_kernel_sym *k;
+ struct module_stat *module;
+ struct module_stat *mod;
+ struct module_symbol *s = NULL;
+ int kmem_fd = -1;
+ int nkernsym;
+ int nmod;
+ int nm;
+ int nms;
+ int i;
+
+ drop();
+ module_name_list = xmalloc(1);
+ *module_name_list = '\0';
+
+ if ((nkernsym = get_kernel_syms(NULL)) < 0) {
+ error("get_kernel_syms: %m");
+ return 0;
+ }
+ kernsym = k = xmalloc(nkernsym * sizeof(struct old_kernel_sym));
+ old_kernsym = kernsym;
+ if (get_kernel_syms(kernsym) != nkernsym) {
+ error("inconsistency with get_kernel_syms -- is someone else "
+ "playing with modules?");
+ free(kernsym);
+ return 0;
+ }
+
+ /* Number of modules */
+ for (k = kernsym, nmod = 0, i = 0; i < nkernsym; ++i, ++k) {
+ if (k->name[0] == '#') {
+ if (k->name[1]) {
+ ++nmod;
+ i = strlen(k->name+1) + 1;
+ module_name_list =
+ xrealloc(module_name_list,
+ l_module_name_list + i);
+ strcpy(module_name_list+l_module_name_list, /* safe, xrealloc */
+ k->name+1);
+ l_module_name_list += i; /* NUL separated strings */
+ }
+ else
+ break;
+ }
+ }
+ module_stat = mod = module = xmalloc(nmod * sizeof(struct module_stat));
+ memset(module, 0, nmod * sizeof(struct module_stat));
+ n_module_stat = nmod;
+
+ /*
+ * Will we need kernel internal info?
+ */
+ if ((type & K_INFO) || (type & K_REFS)) {
+ if ((kmem_fd = open("/dev/kmem", O_RDONLY)) < 0) {
+ perror("ksyms: open /dev/kmem");
+ return 0;
+ }
+ }
+
+ /*
+ * Collect the module information.
+ */
+ for (k = kernsym, nm = 0, i = 0; i < nkernsym; ++i, ++k) {
+ if (k->name[0] == '#') {
+ struct old_kernel_sym *p;
+ struct old_module info;
+
+ if (k->name[1] == '\0')
+ break; /* kernel resident symbols follow */
+ /* else normal module */
+
+ module = mod++;
+ ++nm;
+ module->name = k->name + 1;
+ module->modstruct = k->value;
+
+ if ((type & K_INFO) || (type & K_REFS)) {
+ long tmp;
+ /*
+ * k->value is the address of the
+ * struct old_module
+ * in the kernel (for use via /dev/kmem)
+ */
+ mscan(k->value, sizeof(info), &info);
+ module->addr = info.addr;
+ module->size = info.size * getpagesize();
+
+ mscan(info.addr, sizeof(long), &tmp);
+ module->flags = info.state &
+ (OLD_MOD_RUNNING | OLD_MOD_DELETED);
+ module->flags |= NEW_MOD_USED_ONCE; /* Cheat */
+ if (tmp & OLD_MOD_AUTOCLEAN)
+ module->flags |= NEW_MOD_AUTOCLEAN;
+ if (tmp & OLD_MOD_VISITED)
+ module->flags |= NEW_MOD_VISITED;
+
+ module->usecount = tmp & ~(OLD_MOD_AUTOCLEAN | OLD_MOD_VISITED);
+ }
+
+ if ((type & K_REFS) && info.ref) {
+ struct old_module_ref mr;
+ int j;
+ unsigned long ref = info.ref;
+
+ do {
+ mscan(ref, sizeof(struct old_module_ref), &mr);
+ for (j = 0; j < nm -1; ++j) {
+ if (mr.module == module_stat[j].modstruct) {
+ module->nrefs += 1;
+ module->refs = xrealloc(module->refs, module->nrefs * sizeof(struct module_stat **));
+ module->refs[module->nrefs - 1] = module_stat + j;
+ break;
+ }
+ }
+ } while ((ref = mr.next) != 0);
+ }
+
+ if (!(type & K_SYMBOLS))
+ continue;
+ /*
+ * Find out how many symbols this module has.
+ */
+ for (nms = 0, p = k+1; p->name[0] != '#'; ++p)
+ ++nms;
+ s = xmalloc(nms * sizeof(struct module_symbol));
+ module->syms = s;
+ module->nsyms = nms;
+ } else if (type & K_SYMBOLS) { /* Want info about symbols */
+ s->name = (unsigned long) k->name;
+ s->value = k->value;
+ ++s;
+ }
+ }
+ if ((type & K_INFO) || (type & K_REFS)) {
+ if (kmem_fd != -1)
+ close(kmem_fd);
+ }
+
+ /*
+ * Kernel resident symbols follows
+ */
+ if (type & K_SYMBOLS) { /* Want info about symbols */
+ if (k->name[0] == '#')
+ ++k;
+ nksyms = nkernsym - (k - kernsym);
+ if (nksyms) {
+ ksyms = s = xmalloc(nksyms * sizeof(struct module_symbol));
+ for (i = 0; i < nksyms; ++i, ++k) {
+ if (k->name[0] != '#') {
+ s->name = (unsigned long) k->name;
+ s->value = k->value;
+ ++s;
+ }
+ }
+ nksyms = s - ksyms;
+ } else
+ ksyms = NULL;
+ }
+
+ return 1;
+}
+#endif /* COMPAT_2_0 */
+
+int get_kernel_info(int type)
+{
+ k_new_syscalls = !query_module(NULL, 0, NULL, 0, NULL);
+
+#ifdef COMPAT_2_0
+ if (!k_new_syscalls)
+ return old_get_kernel_info(type);
+#endif /* COMPAT_2_0 */
+
+ return new_get_kernel_info(type);
+}
diff --git a/mdk-stage1/insmod-modutils/util/snap_shot.c b/mdk-stage1/insmod-modutils/util/snap_shot.c
new file mode 100644
index 000000000..ae0cc7c79
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/snap_shot.c
@@ -0,0 +1,154 @@
+/* Take a snap shot of ksyms and modules for Oops debugging
+ Copyright 1999 Linux International.
+
+ Contributed by Keith Owens <kaos@ocs.com.au>
+
+ 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
+ */
+
+#ident "$Id$"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "module.h"
+#include "obj.h"
+#include "modstat.h"
+#include "util.h"
+
+static char snap_dir[] = "/var/log/ksymoops";
+
+/* If snap_dir exists, take a snap shot of ksyms and modules to snap_dir.
+ * Prefix the files with the equivalent of
+ * date +%Y%m%d%T%M%S | sed -e 's/://g'
+ */
+void snap_shot(const char *module_names, int n_module_names)
+{
+ char file[] = "ccyymmddhhmmss.modules", buffer[4096];
+ static char *infile[] = { "/proc/ksyms", "/proc/modules" };
+ static char *suffix[] = { "ksyms", "modules" };
+ struct tm *local;
+ time_t t;
+ int i, l;
+ FILE *in, *out;
+
+ if (module_names) {
+ /* Only snap shot if the list of modules has changed.
+ * Otherwise auto cleanup takes a snap shot every time
+ * and ends up with a large snap shot directory.
+ */
+ char *new_module_names;
+ size_t n_new_module_names;
+ get_kernel_info(0);
+ new_module_names = module_name_list;
+ n_new_module_names = n_module_stat;
+ if (n_module_names && n_new_module_names == n_module_names) {
+ while (n_module_names) {
+ if (strcmp(module_names, new_module_names))
+ break; /* difference detected */
+ i = strlen(module_names) + 1;
+ module_names += i;
+ new_module_names += i;
+ --n_module_names;
+ }
+ }
+ if (!n_module_names)
+ return; /* no difference, no need for snap shot */
+ }
+
+ if (chdir(snap_dir))
+ return;
+ t = time(NULL);
+ local = localtime(&t);
+ for (i = 0; i < sizeof(infile)/sizeof(infile[0]); ++i) {
+ snprintf(file, sizeof(file), "%04d%02d%02d%02d%02d%02d.%s",
+ local->tm_year+1900,
+ local->tm_mon + 1,
+ local->tm_mday,
+ local->tm_hour,
+ local->tm_min,
+ local->tm_sec,
+ suffix[i]);
+ out = fopen(file, "w");
+ if (!out) {
+ error("cannot create %s/%s %m", snap_dir, file);
+ return;
+ }
+ in = fopen(infile[i], "r");
+ if (!in) {
+ error("cannot open %s %m", infile[i]);
+ return;
+ }
+ while ((l = fread(buffer, 1, sizeof(buffer), in)) > 0) {
+ if (fwrite(buffer, l, 1, out) != 1) {
+ error("unable to write to %s %m", file);
+ fclose(in);
+ fclose(out);
+ return;
+ }
+ }
+ if (ferror(in))
+ error("unable to read from %s %m", infile[i]);
+ fclose(in);
+ fclose(out);
+ }
+}
+
+/* If snap_dir exists, log a message to snap_dir. The log file is called the
+ * equivalent of date +%Y%m%d | sed -e 's/://g'. Each line is prefixed with
+ * timestamp down to seconds and followed by a newline.
+ */
+void snap_shot_log(const char *fmt,...)
+{
+ char date[] = "ccyymmdd", file[] = "ccyymmdd.log", stamp[] = "ccyymmdd hhmmss";
+ struct tm *local;
+ time_t t;
+ FILE *log;
+ va_list args;
+ int save_errno = errno;
+
+ if (chdir(snap_dir))
+ return;
+ t = time(NULL);
+ local = localtime(&t);
+ snprintf(date, sizeof(date), "%04d%02d%02d",
+ local->tm_year+1900,
+ local->tm_mon + 1,
+ local->tm_mday);
+ snprintf(file, sizeof(file), "%s.log", date);
+ log = fopen(file, "a");
+ if (!log) {
+ error("cannot create %s/%s %m", snap_dir, file);
+ return;
+ }
+ snprintf(stamp, sizeof(stamp), "%s %02d%02d%02d",
+ date,
+ local->tm_hour,
+ local->tm_min,
+ local->tm_sec);
+ fprintf(log, "%s ", stamp);
+ va_start(args, fmt);
+ errno = save_errno; /* fmt may use %m */
+ vfprintf(log, fmt, args);
+ va_end(args);
+ fprintf(log, "\n");
+ fclose(log);
+}
diff --git a/mdk-stage1/insmod-modutils/util/sys_cm.c b/mdk-stage1/insmod-modutils/util/sys_cm.c
new file mode 100644
index 000000000..851fb709e
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/sys_cm.c
@@ -0,0 +1,88 @@
+/* Functions for the Linux module syscall interface.
+ Copyright 1996, 1997 Linux International.
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ 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. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "module.h"
+
+/* Kernel headers before 2.1.mumble need this on the Alpha to get
+ _syscall* defined. */
+#define __LIBRARY__
+
+#include <asm/unistd.h>
+
+
+/*======================================================================*/
+
+#if defined(__i386__) || defined(__m68k__) || defined(__arm__)
+
+#define __NR__create_module __NR_create_module
+static inline _syscall2(long, _create_module, const char *, name, size_t, size)
+
+unsigned long create_module(const char *name, size_t size)
+{
+ /* Why all this fuss?
+
+ In linux 2.1, the address returned by create module point in
+ kernel space which is now mapped at the top of user space (at
+ 0xc0000000 on i386). This looks like a negative number for a
+ long. The normal syscall macro of linux 2.0 (and all libc compile
+ with linux 2.0 or below) consider that the return value is a
+ negative number and consider it is an error number (A kernel
+ convention, return value are positive or negative, indicating the
+ error number).
+
+ By checking the value of errno, we know if we have been fooled by
+ the syscall2 macro and we fix it. */
+
+ long ret = _create_module(name, size);
+ if (ret == -1 && errno > 125)
+ {
+ ret = -errno;
+ errno = 0;
+ }
+ return ret;
+}
+
+#elif defined(__alpha__)
+
+/* Alpha doesn't have the same problem, exactly, but a bug in older
+ kernels fails to clear the error flag. Clear it here explicitly. */
+
+#define __NR__create_module __NR_create_module
+static inline _syscall4(unsigned long, _create_module, const char *, name,
+ size_t, size, size_t, dummy, size_t, err);
+
+unsigned long create_module(const char *name, size_t size)
+{
+ return _create_module(name, size, 0, 0);
+}
+
+#else
+
+/* Sparc, MIPS, (and Alpha, but that's another problem) don't mistake
+ return values for errors due to the nature of the system call. */
+
+_syscall2(unsigned long, create_module, const char *, name, size_t, size)
+
+#endif
diff --git a/mdk-stage1/insmod-modutils/util/sys_dm.c b/mdk-stage1/insmod-modutils/util/sys_dm.c
new file mode 100644
index 000000000..a166a30f4
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/sys_dm.c
@@ -0,0 +1,37 @@
+/* Functions for the Linux module syscall interface.
+ Copyright 1996, 1997 Linux International.
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ 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. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "module.h"
+
+/* Kernel headers before 2.1.mumble need this on the Alpha to get
+ _syscall* defined. */
+#define __LIBRARY__
+
+#include <asm/unistd.h>
+
+
+/*======================================================================*/
+
+_syscall1(int, delete_module, const char *, name)
diff --git a/mdk-stage1/insmod-modutils/util/sys_gks.c b/mdk-stage1/insmod-modutils/util/sys_gks.c
new file mode 100644
index 000000000..f71772c71
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/sys_gks.c
@@ -0,0 +1,37 @@
+/* Functions for the Linux module syscall interface.
+ Copyright 1996, 1997 Linux International.
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ 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. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "module.h"
+
+/* Kernel headers before 2.1.mumble need this on the Alpha to get
+ _syscall* defined. */
+#define __LIBRARY__
+
+#include <asm/unistd.h>
+
+
+/*======================================================================*/
+
+_syscall1(int, get_kernel_syms, struct old_kernel_sym *, ksyms)
diff --git a/mdk-stage1/insmod-modutils/util/sys_nim.c b/mdk-stage1/insmod-modutils/util/sys_nim.c
new file mode 100644
index 000000000..bbe42135c
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/sys_nim.c
@@ -0,0 +1,53 @@
+/* Functions for the Linux module syscall interface.
+ Copyright 1996, 1997 Linux International.
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ 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. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "module.h"
+
+/* Kernel headers before 2.1.mumble need this on the Alpha to get
+ _syscall* defined. */
+#define __LIBRARY__
+
+#include <asm/unistd.h>
+
+
+/*======================================================================*/
+
+#ifndef CONFIG_USE_SYSCALL
+
+extern int init_module(const char *name, const struct module *info);
+
+int
+sys_init_module(const char *name, const struct module *info)
+{
+ return init_module(name, info);
+}
+
+#else
+
+#define __NR_sys_init_module __NR_init_module
+_syscall2(int, sys_init_module, const char *, name,
+ const struct module *, info)
+
+#endif
diff --git a/mdk-stage1/insmod-modutils/util/sys_oim.c b/mdk-stage1/insmod-modutils/util/sys_oim.c
new file mode 100644
index 000000000..73ac6be52
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/sys_oim.c
@@ -0,0 +1,40 @@
+/* Functions for the Linux module syscall interface.
+ Copyright 1996, 1997 Linux International.
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ 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. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "module.h"
+
+/* Kernel headers before 2.1.mumble need this on the Alpha to get
+ _syscall* defined. */
+#define __LIBRARY__
+
+#include <asm/unistd.h>
+
+
+/*======================================================================*/
+
+#define __NR_old_sys_init_module __NR_init_module
+_syscall5(int, old_sys_init_module, const char *, name, char *, code,
+ unsigned, codesize, struct old_mod_routines *, routines,
+ struct old_symbol_table *, symtab)
diff --git a/mdk-stage1/insmod-modutils/util/sys_qm.c b/mdk-stage1/insmod-modutils/util/sys_qm.c
new file mode 100644
index 000000000..119a219a2
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/sys_qm.c
@@ -0,0 +1,56 @@
+/* Functions for the Linux module syscall interface.
+ Copyright 1996, 1997 Linux International.
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ 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. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "module.h"
+
+/* Kernel headers before 2.1.mumble need this on the Alpha to get
+ _syscall* defined. */
+#define __LIBRARY__
+
+#include <asm/unistd.h>
+
+
+/*======================================================================*/
+
+/* I am fucking tired of the "this doesn't build on 2.0.x" questions.
+ But if you ask, we still officially require 2.1.x to build. */
+#if !defined(__NR_query_module)
+# if defined(__i386__)
+# define __NR_query_module 167
+# elif defined(__alpha__)
+# define __NR_query_module 347
+# elif defined(__sparc__)
+# define __NR_query_module 184
+# elif defined(__mc68000__)
+# define __NR_query_module 167
+# elif defined(__arm__)
+# define __NR_query_module (__NR_SYSCALL_BASE + 167)
+# elif defined(__mips__)
+# define __NR_query_module 4187
+# endif
+#endif
+
+_syscall5(int, query_module, const char *, name, int, which,
+ void *, buf, size_t, bufsize, size_t *, ret);
diff --git a/mdk-stage1/insmod-modutils/util/xftw.c b/mdk-stage1/insmod-modutils/util/xftw.c
new file mode 100644
index 000000000..fe764a63c
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/xftw.c
@@ -0,0 +1,422 @@
+/*
+ * modutils specific implementation of ftw().
+ *
+ * Copyright 2000:
+ * Keith Owens <kaos@ocs.com.au> 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/<version> 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 <dirent.h>
+#include <errno.h>
+#include <limits.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#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); /* safe, xmalloc */
+ if (*directory && entry)
+ strcat(name, "/"); /* safe, xmalloc */
+ if (entry)
+ strcat(name, entry); /* safe, xmalloc */
+ 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);
+}
diff --git a/mdk-stage1/insmod-modutils/util/xmalloc.c b/mdk-stage1/insmod-modutils/util/xmalloc.c
new file mode 100644
index 000000000..9113d47fe
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/xmalloc.c
@@ -0,0 +1,39 @@
+/* Misc utility functions.
+ Copyright 1996, 1997 Linux International.
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ 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. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include "util.h"
+
+
+/*======================================================================*/
+
+void *
+xmalloc(size_t size)
+{
+ void *ptr = malloc(size);
+ if (!ptr)
+ {
+ error("Out of memory");
+ exit(1);
+ }
+ return ptr;
+}
diff --git a/mdk-stage1/insmod-modutils/util/xrealloc.c b/mdk-stage1/insmod-modutils/util/xrealloc.c
new file mode 100644
index 000000000..d287486f7
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/xrealloc.c
@@ -0,0 +1,39 @@
+/* Misc utility functions.
+ Copyright 1996, 1997 Linux International.
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ 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. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include "util.h"
+
+
+/*======================================================================*/
+
+void *
+xrealloc(void *old, size_t size)
+{
+ void *ptr = realloc(old, size);
+ if (!ptr)
+ {
+ error("Out of memory");
+ exit(1);
+ }
+ return ptr;
+}
diff --git a/mdk-stage1/insmod-modutils/util/xstrcat.c b/mdk-stage1/insmod-modutils/util/xstrcat.c
new file mode 100644
index 000000000..abb075c83
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/xstrcat.c
@@ -0,0 +1,40 @@
+/* Misc utility functions.
+ Copyright 2000 Keith Owens <kaos@ocs.com.au>
+
+ 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. */
+
+#ident "$Id"
+
+#include <stdlib.h>
+#include <string.h>
+#include "util.h"
+
+
+/*======================================================================*/
+
+char *
+xstrcat(char *dest, const char *src, size_t size)
+{
+ int ldest = strlen(dest);
+ int lsrc = strlen(src);
+ if ((size - ldest - 1) < lsrc) {
+ error("xstrcat: destination overflow");
+ exit(1);
+ }
+ memcpy(dest+ldest, src, lsrc+1);
+ return(dest);
+}
diff --git a/mdk-stage1/insmod-modutils/util/xstrdup.c b/mdk-stage1/insmod-modutils/util/xstrdup.c
new file mode 100644
index 000000000..11b289eb0
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/xstrdup.c
@@ -0,0 +1,41 @@
+/* Misc utility functions.
+ Copyright 1996, 1997 Linux International.
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ 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. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "util.h"
+
+
+/*======================================================================*/
+
+char *
+xstrdup(const char *s)
+{
+ char *n = strdup(s);
+ if (!n)
+ {
+ error("Out of memory");
+ exit(1);
+ }
+ return n;
+}
diff --git a/mdk-stage1/insmod-modutils/util/xsystem.c b/mdk-stage1/insmod-modutils/util/xsystem.c
new file mode 100644
index 000000000..edb995268
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/xsystem.c
@@ -0,0 +1,51 @@
+/* Misc utility functions.
+ Copyright 2000 Keith Owens <kaos@ocs.com.au>
+
+ 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. */
+
+#ident "$Id"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+
+
+/*======================================================================*/
+
+/* Clone of the system() function From Steven's Advanced Programming in a Unix
+ * Environment. Modified to use *argv[] and execvp to avoid shell expansion
+ * problems, modutils runs as root so system() is unsafe.
+ */
+
+int
+xsystem(const char *file, char *const argv[])
+{
+ pid_t pid;
+ int status;
+ if ((pid = fork()) < 0)
+ return(-1);
+ if (pid == 0) {
+ execvp(file, argv);
+ _exit(127);
+ }
+ while (waitpid(pid, &status, 0) < 0) {
+ if (errno != EINTR)
+ return(-1);
+ }
+ return(status);
+}