From 31d44a623579fbca300f20bc751c7278c4375980 Mon Sep 17 00:00:00 2001 From: Guillaume Cottenceau Date: Thu, 22 Feb 2001 17:21:43 +0000 Subject: use modutils for non Intel arch's --- mdk-stage1/insmod-modutils/util/Makefile | 39 + mdk-stage1/insmod-modutils/util/alias.h | 244 ++++ mdk-stage1/insmod-modutils/util/arch64.c | 35 + mdk-stage1/insmod-modutils/util/config.c | 1591 +++++++++++++++++++++++++ mdk-stage1/insmod-modutils/util/gzfiles.c | 74 ++ mdk-stage1/insmod-modutils/util/logger.c | 163 +++ mdk-stage1/insmod-modutils/util/meta_expand.c | 339 ++++++ mdk-stage1/insmod-modutils/util/modstat.c | 419 +++++++ mdk-stage1/insmod-modutils/util/snap_shot.c | 154 +++ mdk-stage1/insmod-modutils/util/sys_cm.c | 88 ++ mdk-stage1/insmod-modutils/util/sys_dm.c | 37 + mdk-stage1/insmod-modutils/util/sys_gks.c | 37 + mdk-stage1/insmod-modutils/util/sys_nim.c | 53 + mdk-stage1/insmod-modutils/util/sys_oim.c | 40 + mdk-stage1/insmod-modutils/util/sys_qm.c | 56 + mdk-stage1/insmod-modutils/util/xftw.c | 422 +++++++ mdk-stage1/insmod-modutils/util/xmalloc.c | 39 + mdk-stage1/insmod-modutils/util/xrealloc.c | 39 + mdk-stage1/insmod-modutils/util/xstrcat.c | 40 + mdk-stage1/insmod-modutils/util/xstrdup.c | 41 + mdk-stage1/insmod-modutils/util/xsystem.c | 51 + 21 files changed, 4001 insertions(+) create mode 100644 mdk-stage1/insmod-modutils/util/Makefile create mode 100644 mdk-stage1/insmod-modutils/util/alias.h create mode 100644 mdk-stage1/insmod-modutils/util/arch64.c create mode 100644 mdk-stage1/insmod-modutils/util/config.c create mode 100644 mdk-stage1/insmod-modutils/util/gzfiles.c create mode 100644 mdk-stage1/insmod-modutils/util/logger.c create mode 100644 mdk-stage1/insmod-modutils/util/meta_expand.c create mode 100644 mdk-stage1/insmod-modutils/util/modstat.c create mode 100644 mdk-stage1/insmod-modutils/util/snap_shot.c create mode 100644 mdk-stage1/insmod-modutils/util/sys_cm.c create mode 100644 mdk-stage1/insmod-modutils/util/sys_dm.c create mode 100644 mdk-stage1/insmod-modutils/util/sys_gks.c create mode 100644 mdk-stage1/insmod-modutils/util/sys_nim.c create mode 100644 mdk-stage1/insmod-modutils/util/sys_oim.c create mode 100644 mdk-stage1/insmod-modutils/util/sys_qm.c create mode 100644 mdk-stage1/insmod-modutils/util/xftw.c create mode 100644 mdk-stage1/insmod-modutils/util/xmalloc.c create mode 100644 mdk-stage1/insmod-modutils/util/xrealloc.c create mode 100644 mdk-stage1/insmod-modutils/util/xstrcat.c create mode 100644 mdk-stage1/insmod-modutils/util/xstrdup.c create mode 100644 mdk-stage1/insmod-modutils/util/xsystem.c (limited to 'mdk-stage1/insmod-modutils/util') 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 */ + "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 */ + + "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 */ + "char-major-10-157 applicom", /* from David Woodhouse */ + "char-major-10-175 agpgart", /* /dev/agpgart GART AGP mapping access */ + "char-major-10-184 microcode", /* Tigran Aivazian */ + + "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 */ + "char-major-99 ppdev", + "char-major-107 3dfx", /* from Tigran Aivazian */ + "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 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 + + 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 +#include +#include +#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 + * Björn Ekwall February 1999 + * Keith Owens October 1999 + * + * "kernelversion" idea from the Debian release via: + * Wichert Akkerman + * + * Björn, inspired by Richard Henderson , cleaned up + * the wildcard handling and started using ftw in March 1999 + * Cleanup of hardcoded arrays: Björn Ekwall March 1999 + * Many additional keywords: Björn Ekwall (C) March 1999 + * Standardize on /etc/modules.conf Keith Owens October 1999 + * + * Alpha typecast:Michal Jaegermann + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 - 2000/05/05 - + */ + +#ifdef CONFIG_USE_ZLIB + +#include +#include +#include +#include +#include + +/* 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 + + 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 +#include +#include +#include +#include + +#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 + * + * "kernelversion" idea from the Debian release via: + * Wichert Akkerman + * + * Use wordexp(): idea from Tim Waugh + * + * Alpha typecast: Michal Jaegermann + * + * 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 +#include +#include +#include +#include +#if HAVE_WORDEXP +#include +#elif HAVE_GLOB +#include +#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 November 1999. + * Björn Ekwall in February 1999 (C) + * Initial work contributed by Richard Henderson + * + * 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 +#include +#include +#include +#include +#include +#include +#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 + + 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 +#include +#include +#include +#include +#include + +#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 + + 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 +#include + +#include "module.h" + +/* Kernel headers before 2.1.mumble need this on the Alpha to get + _syscall* defined. */ +#define __LIBRARY__ + +#include + + +/*======================================================================*/ + +#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 + + 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 +#include + +#include "module.h" + +/* Kernel headers before 2.1.mumble need this on the Alpha to get + _syscall* defined. */ +#define __LIBRARY__ + +#include + + +/*======================================================================*/ + +_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 + + 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 +#include + +#include "module.h" + +/* Kernel headers before 2.1.mumble need this on the Alpha to get + _syscall* defined. */ +#define __LIBRARY__ + +#include + + +/*======================================================================*/ + +_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 + + 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 +#include + +#include "module.h" + +/* Kernel headers before 2.1.mumble need this on the Alpha to get + _syscall* defined. */ +#define __LIBRARY__ + +#include + + +/*======================================================================*/ + +#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 + + 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 +#include + +#include "module.h" + +/* Kernel headers before 2.1.mumble need this on the Alpha to get + _syscall* defined. */ +#define __LIBRARY__ + +#include + + +/*======================================================================*/ + +#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 + + 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 +#include + +#include "module.h" + +/* Kernel headers before 2.1.mumble need this on the Alpha to get + _syscall* defined. */ +#define __LIBRARY__ + +#include + + +/*======================================================================*/ + +/* 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 August 2000 + * + * This file is part of the Linux modutils. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + modutils requires special processing during the file tree walk + of /lib/modules/ and any paths that the user specifies. + The standard ftw() does a blind walk of all paths and can end + up following the build symlink down the kernel source tree. + Although nftw() has the option to get more control such as not + automatically following symbolic links, even that is not enough + for modutils. The requirements are: + + Paths must be directories or symlinks to directories. + + Each directory is read and sorted into alphabetical order + before processing. + + A directory is type 1 iff it was specified on a path statement + (either explicit or default) and the directory contains a + subdirectory with one of the known names and the directory name + does not end with "/kernel". Otherwise it is type 2. + + In a type 1 directory, walk the kernel subdirectory if it exists, + then the old known names in their historical order then any + remaining directory entries in alphabetical order and finally any + non-directory entries in alphabetical order. + + Entries in a type 1 directory are filtered against the "prune" + list. A type 1 directory can contain additional files which + are not modules nor symlinks to modules. The prune list skips + known additional files, if a distribution wants to store + additional text files in the top level directory they should be + added to the prune list. + + A type 2 directory must contain only modules or symlinks to + modules. They are processed in alphabetical order, without + pruning. Symlinks to directories are an error in type 2 + directories. + + The user function is not called for type 1 directories, nor for + pruned entries. It is called for type 2 directories and their + contents. It is also called for any files left in a type 1 + directory after pruning and processing type 2 subdirectories. + The user function never sees symlinks, they are resolved before + calling the function. + + Why have different directory types? The original file tree + walk was not well defined. Some users specified each directory + individually, others just pointed at the top level directory. + Either version worked until the "build" symlink was added. Now + users who specify the top level directory end up running the + entire kernel source tree looking for modules, not nice. We + cannot just ignore symlinks because pcmcia uses symlinks to + modules for backwards compatibility. + + Type 1 is when a user specifies the top level directory which needs + special processing, type 2 is individual subdirectories. But the + only way to tell the difference is by looking at the contents. The + "/kernel" directory introduced in 2.3.12 either contains nothing + (old make modules_install) or contains all the kernel modules using + the same tree structure as the source. Because "/kernel" can + contain old names but is really a type 2 directory, it is detected + as a special case. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "config.h" + +extern char *tbpath[]; + +extern OPT_LIST *prune_list; +extern int n_prune_list; + +extern char *tbtype[]; + +struct xftw_dirent { + struct stat statbuf; + char *name; + char *fullname; +}; + +#define XFTW_MAXDEPTH 64 /* Maximum directory depth handled */ + +typedef struct { + struct xftw_dirent *contents; + int size; + int used; +} xftw_tree_t; + +static xftw_tree_t tree[XFTW_MAXDEPTH]; + +/* Free all data for one tree level */ +static void xftw_free_tree(int depth) +{ + int i; + xftw_tree_t *t = tree+depth; + for (i = 0; i < t->size; ++i) { + free(t->contents[i].name); + free(t->contents[i].fullname); + } + free(t->contents); + t->contents = NULL; + t->size = 0; + t->used = 0; +} + +/* Increment dirents used at this depth, resizing if necessary */ +static void xftw_add_dirent(int depth) +{ + xftw_tree_t *t = tree+depth; + int i, size = t->size; + if (++t->used < size) + return; + size += 10; /* arbitrary increment */ + t->contents = xrealloc(t->contents, size*sizeof(*(t->contents))); + for (i = t->size; i < size; ++i) { + memset(&(t->contents[i].statbuf), 0, sizeof(t->contents[i].statbuf)); + t->contents[i].name = NULL; + t->contents[i].fullname = NULL; + } + t->size = size; +} + +/* Concatenate directory name and entry name into one string. + * Note: caller must free result or leak. + */ +static char *xftw_dir_name(const char *directory, const char *entry) +{ + int i = strlen(directory); + char *name; + if (entry) + i += strlen(entry); + i += 2; + name = xmalloc(i); + strcpy(name, directory); /* 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 + + 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 +#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 + + 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 +#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 + + 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 +#include +#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 + + 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 +#include +#include +#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 + + 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 +#include +#include +#include + + +/*======================================================================*/ + +/* 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); +} -- cgit v1.2.1