summaryrefslogtreecommitdiffstats
path: root/mdk-stage1
diff options
context:
space:
mode:
Diffstat (limited to 'mdk-stage1')
-rw-r--r--mdk-stage1/insmod-busybox/Config.h222
-rw-r--r--mdk-stage1/insmod-busybox/Makefile37
-rw-r--r--mdk-stage1/insmod-busybox/README8
-rw-r--r--mdk-stage1/insmod-busybox/busybox.h468
-rw-r--r--mdk-stage1/insmod-busybox/insmod-frontend.c24
-rw-r--r--mdk-stage1/insmod-busybox/insmod.c2995
-rw-r--r--mdk-stage1/insmod-busybox/loop.h5
-rw-r--r--mdk-stage1/insmod-busybox/messages.c90
-rw-r--r--mdk-stage1/insmod-busybox/utility.c1744
9 files changed, 5593 insertions, 0 deletions
diff --git a/mdk-stage1/insmod-busybox/Config.h b/mdk-stage1/insmod-busybox/Config.h
new file mode 100644
index 000000000..eb274fc17
--- /dev/null
+++ b/mdk-stage1/insmod-busybox/Config.h
@@ -0,0 +1,222 @@
+/* vi: set sw=4 ts=4: */
+// This file defines the feature set to be compiled into busybox.
+// When you turn things off here, they won't be compiled in at all.
+//
+//// This file is parsed by sed. You MUST use single line comments.
+// i.e. //#define BB_BLAH
+//
+//
+// BusyBox Applications
+#define BB_INSMOD
+// End of Applications List
+//
+//
+//
+// ---------------------------------------------------------
+// This is where feature definitions go. Generally speaking,
+// turning this stuff off makes things a bit smaller (and less
+// pretty/useful).
+//
+//
+//
+// Turn this on to use Erik's very cool devps, and devmtab kernel drivers,
+// thereby eliminating the need for the /proc filesystem and thereby saving
+// lots and lots memory for more important things. You can not use this and
+// USE_PROCFS at the same time... NOTE: If you enable this feature, you
+// _must_ have patched the kernel to include the devps patch that is included
+// in the busybox/kernel-patches directory. You will also need to create some
+// device special files in /dev on your embedded system:
+// mknod /dev/mtab c 10 22
+// mknod /dev/ps c 10 21
+// I emailed Linus and this patch will not be going into the stock kernel.
+//#define BB_FEATURE_USE_DEVPS_PATCH
+//
+// enable features that use the /proc filesystem (apps that
+// break without this will tell you on compile)...
+// You can't use this and BB_FEATURE_USE_DEVPS_PATCH
+// at the same time...
+#define BB_FEATURE_USE_PROCFS
+//
+// This compiles out everything but the most
+// trivial --help usage information (i.e. reduces binary size)
+//#define BB_FEATURE_TRIVIAL_HELP
+//
+// Use termios to manipulate the screen ('more' is prettier with this on)
+#define BB_FEATURE_USE_TERMIOS
+//
+// calculate terminal & column widths (for more and ls)
+#define BB_FEATURE_AUTOWIDTH
+//
+// show username/groupnames (bypasses libc6 NSS) for ls
+#define BB_FEATURE_LS_USERNAME
+//
+// show file timestamps in ls
+#define BB_FEATURE_LS_TIMESTAMPS
+//
+// enable ls -p and -F
+#define BB_FEATURE_LS_FILETYPES
+//
+// sort the file names (still a bit buggy)
+#define BB_FEATURE_LS_SORTFILES
+//
+// enable ls -R
+#define BB_FEATURE_LS_RECURSIVE
+//
+// enable ls -L
+#define BB_FEATURE_LS_FOLLOWLINKS
+//
+// Change ping implementation -- simplified, featureless, but really small.
+//#define BB_FEATURE_SIMPLE_PING
+//
+// Make init use a simplified /etc/inittab file (recommended).
+#define BB_FEATURE_USE_INITTAB
+//
+//Enable init being called as /linuxrc
+#define BB_FEATURE_LINUXRC
+//
+//Have init enable core dumping for child processes (for debugging only)
+//#define BB_FEATURE_INIT_COREDUMPS
+//
+// Allow init to permenently chroot, and umount the old root fs
+// just like an initrd does. Requires a kernel patch by Werner Almesberger.
+// ftp://icaftp.epfl.ch/pub/people/almesber/misc/umount-root-*.tar.gz
+//#define BB_FEATURE_INIT_CHROOT
+//
+//Make sure nothing is printed to the console on boot
+#define BB_FEATURE_EXTRA_QUIET
+//
+//Should syslogd also provide klogd support?
+#define BB_FEATURE_KLOGD
+//
+// enable syslogd -R remotehost
+#define BB_FEATURE_REMOTE_LOG
+//
+//Simple tail implementation (2.34k vs 3k for the full one).
+//Both provide 'tail -f' support (only one file at a time.)
+#define BB_FEATURE_SIMPLE_TAIL
+//
+// Enable support for loop devices in mount
+#define BB_FEATURE_MOUNT_LOOP
+//
+// Enable support for a real /etc/mtab file instead of /proc/mounts
+//#define BB_FEATURE_MOUNT_MTAB_SUPPORT
+//
+// Enable support for mounting remote NFS volumes
+#define BB_FEATURE_NFSMOUNT
+//
+// Enable support forced filesystem unmounting
+// (i.e. in case of an unreachable NFS system).
+#define BB_FEATURE_MOUNT_FORCE
+//
+// Enable support for creation of tar files.
+#define BB_FEATURE_TAR_CREATE
+//
+// Enable support for "--exclude" for excluding files
+#define BB_FEATURE_TAR_EXCLUDE
+//
+// Enable support for s///p pattern matching
+#define BB_FEATURE_SED_PATTERN_SPACE
+//
+//// Enable reverse sort
+#define BB_FEATURE_SORT_REVERSE
+//
+// Enable command line editing in the shell
+#define BB_FEATURE_SH_COMMAND_EDITING
+//
+//Allow the shell to invoke all the compiled in BusyBox commands as if they
+//were shell builtins. Nice for staticly linking an emergency rescue shell
+//among other thing.
+#define BB_FEATURE_SH_STANDALONE_SHELL
+//
+// Enable tab completion in the shell (not yet
+// working very well -- so don't turn this on)
+//#define BB_FEATURE_SH_TAB_COMPLETION
+//
+//Turn on extra fbset options
+//#define BB_FEATURE_FBSET_FANCY
+//
+//Turn on fbset readmode support
+//#define BB_FEATURE_FBSET_READMODE
+//
+// You must enable one or both of these features
+// Support installing modules from pre 2.1 kernels
+//#define BB_FEATURE_INSMOD_OLD_KERNEL
+// Support installing modules from kernel versions after 2.1.18
+#define BB_FEATURE_INSMOD_NEW_KERNEL
+//
+// Support module version checking
+//#define BB_FEATURE_INSMOD_VERSION_CHECKING
+//
+// Support for Minix filesystem, version 2
+//#define BB_FEATURE_MINIX2
+//
+//
+// Enable busybox --install [-s]
+// to create links (or symlinks) for all the commands that are
+// compiled into the binary. (needs /proc filesystem)
+// #define BB_FEATURE_INSTALLER
+//
+// Clean up all memory before exiting -- usually not needed
+// as the OS can clean up... Don't enable this unless you
+// have a really good reason for cleaning things up manually.
+//#define BB_FEATURE_CLEAN_UP
+//
+// End of Features List
+//
+//
+//
+//
+//
+//
+//---------------------------------------------------
+// Nothing beyond this point should ever be touched by
+// mere mortals so leave this stuff alone.
+//
+#ifdef BB_FEATURE_MOUNT_MTAB_SUPPORT
+#define BB_MTAB
+#endif
+//
+#if defined BB_FEATURE_SH_COMMAND_EDITING && defined BB_SH
+#define BB_CMDEDIT
+#endif
+//
+#ifdef BB_KILLALL
+#ifndef BB_KILL
+#define BB_KILL
+#endif
+#endif
+//
+#ifdef BB_FEATURE_LINUXRC
+#ifndef BB_INIT
+#define BB_INIT
+#endif
+#define BB_LINUXRC
+#endif
+//
+#ifdef BB_GZIP
+#ifndef BB_GUNZIP
+#define BB_GUNZIP
+#endif
+#endif
+//
+#if defined BB_MOUNT && defined BB_FEATURE_NFSMOUNT
+#define BB_NFSMOUNT
+#endif
+//
+#if defined BB_FEATURE_SH_COMMAND_EDITING
+#ifndef BB_FEATURE_USE_TERMIOS
+#define BB_FEATURE_USE_TERMIOS
+#endif
+#endif
+//
+#if defined BB_FEATURE_AUTOWIDTH
+#ifndef BB_FEATURE_USE_TERMIOS
+#define BB_FEATURE_USE_TERMIOS
+#endif
+#endif
+//
+#if defined BB_INSMOD
+#ifndef BB_FEATURE_INSMOD_OLD_KERNEL
+#define BB_FEATURE_INSMOD_NEW_KERNEL
+#endif
+#endif
diff --git a/mdk-stage1/insmod-busybox/Makefile b/mdk-stage1/insmod-busybox/Makefile
new file mode 100644
index 000000000..6ced68861
--- /dev/null
+++ b/mdk-stage1/insmod-busybox/Makefile
@@ -0,0 +1,37 @@
+ #******************************************************************************
+ #
+ # insmod from busybox (i386 only)
+ #
+ # $Id$
+ #
+ # Copyright (C) 1999,2000 by Lineo, inc.
+ #
+ #*****************************************************************************
+
+
+all: insmod libinsmod.a
+
+clean:
+ rm -f *.o insmod
+
+FLAGS = -c -Wall -Os -fomit-frame-pointer -D_GNU_SOURCE -DBB_VER='"0.47"' -DBB_BT='"2000.12.06-14:02+0000"'
+
+insmod: insmod-frontend.o insmod.o utility-standalone.o
+ gcc -o $@ $^
+
+libinsmod.a: insmod.o utility.o
+ ar cru $@ $^
+ ranlib $@
+
+insmod-frontend.o: insmod-frontend.c busybox.h
+ gcc $(FLAGS) insmod-frontend.c
+
+utility.o: utility.c busybox.h
+ gcc $(FLAGS) utility.c
+
+utility-standalone.o: utility.c busybox.h
+ gcc $(FLAGS) -o $@ -D_STANDALONE_ utility.c
+
+insmod.o: insmod.c busybox.h
+ gcc $(FLAGS) insmod.c
+
diff --git a/mdk-stage1/insmod-busybox/README b/mdk-stage1/insmod-busybox/README
new file mode 100644
index 000000000..06695074a
--- /dev/null
+++ b/mdk-stage1/insmod-busybox/README
@@ -0,0 +1,8 @@
+This insmod code comes from busybox-0.47
+
+ftp://ftp.lineo.com/pub/busybox
+
+It is cool but works only for ix86 architecture.
+
+
+gc
diff --git a/mdk-stage1/insmod-busybox/busybox.h b/mdk-stage1/insmod-busybox/busybox.h
new file mode 100644
index 000000000..69f455435
--- /dev/null
+++ b/mdk-stage1/insmod-busybox/busybox.h
@@ -0,0 +1,468 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Busybox main internal header file
+ *
+ *
+ * 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
+ *
+ * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
+ * Permission has been granted to redistribute this code under the GPL.
+ *
+ */
+#ifndef _BB_INTERNAL_H_
+#define _BB_INTERNAL_H_ 1
+
+#include "Config.h"
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <mntent.h>
+#include <regex.h>
+/* for the _syscall() macros */
+#include <sys/syscall.h>
+#include <linux/unistd.h>
+
+
+/* Some useful definitions */
+#define FALSE ((int) 1)
+#define TRUE ((int) 0)
+
+/* for mtab.c */
+#define MTAB_GETMOUNTPT '1'
+#define MTAB_GETDEVICE '2'
+
+#define BUF_SIZE 8192
+#define EXPAND_ALLOC 1024
+
+
+#define isBlank(ch) (((ch) == ' ') || ((ch) == '\t'))
+#define isDecimal(ch) (((ch) >= '0') && ((ch) <= '9'))
+#define isOctal(ch) (((ch) >= '0') && ((ch) <= '7'))
+#define isWildCard(ch) (((ch) == '*') || ((ch) == '?') || ((ch) == '['))
+
+/* Macros for min/max. */
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef MAX
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
+
+/* I don't like nested includes, but the string and io functions are used
+ * too often
+ */
+#include <stdio.h>
+#if !defined(NO_STRING_H) || defined(STDC_HEADERS)
+# include <string.h>
+# if !defined(STDC_HEADERS) && !defined(NO_MEMORY_H) && !defined(__GNUC__)
+# include <memory.h>
+# endif
+# define memzero(s, n) memset ((void *)(s), 0, (n))
+#else
+# include <strings.h>
+# define strchr index
+# define strrchr rindex
+# define memcpy(d, s, n) bcopy((s), (d), (n))
+# define memcmp(s1, s2, n) bcmp((s1), (s2), (n))
+# define memzero(s, n) bzero((s), (n))
+#endif
+
+
+enum Location {
+ _BB_DIR_ROOT = 0,
+ _BB_DIR_BIN,
+ _BB_DIR_SBIN,
+ _BB_DIR_USR_BIN,
+ _BB_DIR_USR_SBIN
+};
+
+struct BB_applet {
+ const char* name;
+ int (*main)(int argc, char** argv);
+ enum Location location;
+ const char* usage;
+};
+/* From busybox.c */
+extern const struct BB_applet applets[];
+
+extern int ar_main(int argc, char **argv);
+extern int basename_main(int argc, char **argv);
+extern int bogomips_main(int argc, char **argv);
+extern int busybox_main(int argc, char** argv);
+extern int cat_main(int argc, char** argv);
+extern int chmod_chown_chgrp_main(int argc, char** argv);
+extern int chroot_main(int argc, char** argv);
+extern int chvt_main(int argc, char** argv);
+extern int clear_main(int argc, char** argv);
+extern int cp_mv_main(int argc, char** argv);
+extern int cut_main(int argc, char** argv);
+extern int date_main(int argc, char** argv);
+extern int dc_main(int argc, char** argv);
+extern int dd_main(int argc, char** argv);
+extern int dirname_main(int argc, char** argv);
+extern int deallocvt_main(int argc, char** argv);
+extern int df_main(int argc, char** argv);
+extern int dmesg_main(int argc, char** argv);
+extern int dos2unix_main(int argc, char** argv);
+extern int du_main(int argc, char** argv);
+extern int dumpkmap_main(int argc, char** argv);
+extern int dutmp_main(int argc, char** argv);
+extern int echo_main(int argc, char** argv);
+extern int expr_main(int argc, char** argv);
+extern int false_main(int argc, char** argv);
+extern int fbset_main(int argc, char** argv);
+extern int fdisk_main(int argc, char** argv);
+extern int fdflush_main(int argc, char **argv);
+extern int fsck_minix_main(int argc, char **argv);
+extern int find_main(int argc, char** argv);
+extern int free_main(int argc, char** argv);
+extern int freeramdisk_main(int argc, char** argv);
+extern int getopt_main(int argc, char** argv);
+extern int grep_main(int argc, char** argv);
+extern int gunzip_main (int argc, char** argv);
+extern int gzip_main(int argc, char** argv);
+extern int halt_main(int argc, char** argv);
+extern int head_main(int argc, char** argv);
+extern int hostid_main(int argc, char** argv);
+extern int hostname_main(int argc, char** argv);
+extern int id_main(int argc, char** argv);
+extern int init_main(int argc, char** argv);
+extern int insmod_main(int argc, char** argv);
+extern int kill_main(int argc, char** argv);
+extern int length_main(int argc, char** argv);
+extern int ln_main(int argc, char** argv);
+extern int loadacm_main(int argc, char** argv);
+extern int loadfont_main(int argc, char** argv);
+extern int loadkmap_main(int argc, char** argv);
+extern int losetup_main(int argc, char** argv);
+extern int logger_main(int argc, char **argv);
+extern int logname_main(int argc, char **argv);
+extern int ls_main(int argc, char** argv);
+extern int lsmod_main(int argc, char** argv);
+extern int makedevs_main(int argc, char** argv);
+extern int md5sum_main(int argc, char** argv);
+extern int mkdir_main(int argc, char** argv);
+extern int mkfifo_main(int argc, char **argv);
+extern int mkfs_minix_main(int argc, char **argv);
+extern int mknod_main(int argc, char** argv);
+extern int mkswap_main(int argc, char** argv);
+extern int mktemp_main(int argc, char **argv);
+extern int nc_main(int argc, char** argv);
+extern int more_main(int argc, char** argv);
+extern int mount_main(int argc, char** argv);
+extern int mt_main(int argc, char** argv);
+extern int nslookup_main(int argc, char **argv);
+extern int ping_main(int argc, char **argv);
+extern int poweroff_main(int argc, char **argv);
+extern int printf_main(int argc, char** argv);
+extern int ps_main(int argc, char** argv);
+extern int pwd_main(int argc, char** argv);
+extern int rdate_main(int argc, char** argv);
+extern int reboot_main(int argc, char** argv);
+extern int renice_main(int argc, char** argv);
+extern int reset_main(int argc, char** argv);
+extern int rm_main(int argc, char** argv);
+extern int rmdir_main(int argc, char **argv);
+extern int rmmod_main(int argc, char** argv);
+extern int sed_main(int argc, char** argv);
+extern int sfdisk_main(int argc, char** argv);
+extern int setkeycodes_main(int argc, char** argv);
+extern int shell_main(int argc, char** argv);
+extern int sleep_main(int argc, char** argv);
+extern int sort_main(int argc, char** argv);
+extern int swap_on_off_main(int argc, char** argv);
+extern int sync_main(int argc, char** argv);
+extern int syslogd_main(int argc, char **argv);
+extern int tail_main(int argc, char** argv);
+extern int tar_main(int argc, char** argv);
+extern int tee_main(int argc, char** argv);
+extern int test_main(int argc, char** argv);
+extern int telnet_main(int argc, char** argv);
+extern int touch_main(int argc, char** argv);
+extern int tr_main(int argc, char** argv);
+extern int true_main(int argc, char** argv);
+extern int tput_main(int argc, char** argv);
+extern int tryopen_main(int argc, char** argv);
+extern int tty_main(int argc, char** argv);
+extern int umount_main(int argc, char** argv);
+extern int uname_main(int argc, char** argv);
+extern int uniq_main(int argc, char** argv);
+extern int unix2dos_main(int argc, char** argv);
+extern int unrpm_main(int argc, char** argv);
+extern int update_main(int argc, char** argv);
+extern int uptime_main(int argc, char** argv);
+extern int usleep_main(int argc, char** argv);
+extern int uuencode_main(int argc, char** argv);
+extern int uudecode_main(int argc, char** argv);
+extern int wc_main(int argc, char** argv);
+extern int wget_main(int argc, char** argv);
+extern int which_main(int argc, char** argv);
+extern int whoami_main(int argc, char** argv);
+extern int xargs_main(int argc, char** argv);
+extern int yes_main(int argc, char** argv);
+
+extern const char ar_usage[];
+extern const char basename_usage[];
+extern const char cat_usage[];
+extern const char chgrp_usage[];
+extern const char chmod_usage[];
+extern const char chown_usage[];
+extern const char chroot_usage[];
+extern const char chvt_usage[];
+extern const char clear_usage[];
+extern const char cp_usage[];
+extern const char cut_usage[];
+extern const char date_usage[];
+extern const char dc_usage[];
+extern const char dd_usage[];
+extern const char deallocvt_usage[];
+extern const char df_usage[];
+extern const char dirname_usage[];
+extern const char dmesg_usage[];
+extern const char dos2unix_usage[];
+extern const char du_usage[];
+extern const char dumpkmap_usage[];
+extern const char dutmp_usage[];
+extern const char echo_usage[];
+extern const char expr_usage[];
+extern const char false_usage[];
+extern const char fdflush_usage[];
+extern const char find_usage[];
+extern const char free_usage[];
+extern const char freeramdisk_usage[];
+extern const char fsck_minix_usage[];
+extern const char grep_usage[];
+extern const char gunzip_usage[];
+extern const char gzip_usage[];
+extern const char halt_usage[];
+extern const char head_usage[];
+extern const char hostid_usage[];
+extern const char hostname_usage[];
+extern const char id_usage[];
+extern const char insmod_usage[];
+extern const char kill_usage[];
+extern const char killall_usage[];
+extern const char length_usage[];
+extern const char ln_usage[];
+extern const char loadacm_usage[];
+extern const char loadfont_usage[];
+extern const char loadkmap_usage[];
+extern const char logger_usage[];
+extern const char logname_usage[];
+extern const char ls_usage[];
+extern const char lsmod_usage[];
+extern const char makedevs_usage[];
+extern const char md5sum_usage[];
+extern const char mkdir_usage[];
+extern const char mkfifo_usage[];
+extern const char mkfs_minix_usage[];
+extern const char mknod_usage[];
+extern const char mkswap_usage[];
+extern const char mktemp_usage[];
+extern const char more_usage[];
+extern const char mount_usage[];
+extern const char mt_usage[];
+extern const char mv_usage[];
+extern const char nc_usage[];
+extern const char nslookup_usage[];
+extern const char ping_usage[];
+extern const char poweroff_usage[];
+extern const char printf_usage[];
+extern const char ps_usage[];
+extern const char pwd_usage[];
+extern const char rdate_usage[];
+extern const char reboot_usage[];
+extern const char renice_usage[];
+extern const char reset_usage[];
+extern const char rm_usage[];
+extern const char rmdir_usage[];
+extern const char rmmod_usage[];
+extern const char sed_usage[];
+extern const char setkeycodes_usage[];
+extern const char shell_usage[];
+extern const char sleep_usage[];
+extern const char sort_usage[];
+extern const char swapoff_usage[];
+extern const char swapon_usage[];
+extern const char sync_usage[];
+extern const char syslogd_usage[];
+extern const char tail_usage[];
+extern const char tar_usage[];
+extern const char tee_usage[];
+extern const char telnet_usage[];
+extern const char test_usage[];
+extern const char touch_usage[];
+extern const char tr_usage[];
+extern const char true_usage[];
+extern const char tty_usage[];
+extern const char umount_usage[];
+extern const char uname_usage[];
+extern const char uniq_usage[];
+extern const char unix2dos_usage[];
+extern const char unrpm_usage[];
+extern const char update_usage[];
+extern const char uptime_usage[];
+extern const char usleep_usage[];
+extern const char uudecode_usage[];
+extern const char uuencode_usage[];
+extern const char wc_usage[];
+extern const char wget_usage[];
+extern const char which_usage[];
+extern const char whoami_usage[];
+extern const char xargs_usage[];
+extern const char yes_usage[];
+
+extern const char *applet_name;
+
+extern void usage(const char *usage) __attribute__ ((noreturn));
+extern void errorMsg(const char *s, ...) __attribute__ ((format (printf, 1, 2)));
+extern void fatalError(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2)));
+
+const char *modeString(int mode);
+const char *timeString(time_t timeVal);
+int isDirectory(const char *name, const int followLinks, struct stat *statBuf);
+int isDevice(const char *name);
+
+typedef struct ino_dev_hash_bucket_struct {
+ struct ino_dev_hash_bucket_struct *next;
+ ino_t ino;
+ dev_t dev;
+ char name[1];
+} ino_dev_hashtable_bucket_t;
+int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name);
+void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name);
+void reset_ino_dev_hashtable(void);
+
+int copyFile(const char *srcName, const char *destName,
+ int setModes, int followLinks, int forceFlag);
+int copySubFile(int srcFd, int dstFd, size_t remaining);
+char *buildName(const char *dirName, const char *fileName);
+int makeString(int argc, const char **argv, char *buf, int bufLen);
+char *getChunk(int size);
+char *chunkstrdup(const char *str);
+void freeChunks(void);
+int fullWrite(int fd, const char *buf, int len);
+int fullRead(int fd, char *buf, int len);
+int recursiveAction(const char *fileName, int recurse, int followLinks, int depthFirst,
+ int (*fileAction) (const char *fileName, struct stat* statbuf, void* userData),
+ int (*dirAction) (const char *fileName, struct stat* statbuf, void* userData),
+ void* userData);
+
+extern int createPath (const char *name, int mode);
+extern int parse_mode( const char* s, mode_t* theMode);
+
+extern int get_kernel_revision(void);
+
+extern int get_console_fd(char* tty_name);
+extern struct mntent *findMountPoint(const char *name, const char *table);
+extern void write_mtab(char* blockDevice, char* directory,
+ char* filesystemType, long flags, char* string_flags);
+extern void erase_mtab(const char * name);
+extern void mtab_read(void);
+extern char *mtab_first(void **iter);
+extern char *mtab_next(void **iter);
+extern char *mtab_getinfo(const char *match, const char which);
+extern int check_wildcard_match(const char* text, const char* pattern);
+extern long getNum (const char *cp);
+extern pid_t* findPidByName( char* pidName);
+extern int find_real_root_device_name(char* name);
+extern char *get_line_from_file(FILE *file);
+extern void print_file(FILE *file);
+extern int print_file_by_name(char *filename);
+extern char process_escape_sequence(char **ptr);
+extern char *get_last_path_component(char *path);
+extern void xregcomp(regex_t *preg, const char *regex, int cflags);
+
+#ifndef DMALLOC
+extern void *xmalloc (size_t size);
+extern void *xrealloc(void *old, size_t size);
+extern void *xcalloc(size_t nmemb, size_t size);
+extern char *xstrdup (const char *s);
+#endif
+extern char *xstrndup (const char *s, int n);
+
+
+/* These parse entries in /etc/passwd and /etc/group. This is desirable
+ * for BusyBox since we want to avoid using the glibc NSS stuff, which
+ * increases target size and is often not needed embedded systems. */
+extern long my_getpwnam(char *name);
+extern long my_getgrnam(char *name);
+extern void my_getpwuid(char *name, long uid);
+extern void my_getgrgid(char *group, long gid);
+extern long my_getpwnamegid(char *name);
+
+extern int device_open(char *device, int mode);
+
+#if defined BB_FEATURE_MOUNT_LOOP
+extern int del_loop(const char *device);
+extern int set_loop(const char *device, const char *file, int offset, int *loopro);
+extern char *find_unused_loop_device (void);
+#endif
+
+
+#if (__GLIBC__ < 2) && (defined BB_SYSLOGD || defined BB_INIT)
+extern int vdprintf(int d, const char *format, va_list ap);
+#endif
+
+#if defined BB_NFSMOUNT
+int nfsmount(const char *spec, const char *node, int *flags,
+ char **extra_opts, char **mount_opts, int running_bg);
+#endif
+
+#ifndef RB_POWER_OFF
+/* Stop system and switch power off if possible. */
+#define RB_POWER_OFF 0x4321fedc
+#endif
+
+/* Include our own copy of struct sysinfo to avoid binary compatability
+ * problems with Linux 2.4, which changed things. Grumble, grumble. */
+struct sysinfo {
+ long uptime; /* Seconds since boot */
+ unsigned long loads[3]; /* 1, 5, and 15 minute load averages */
+ unsigned long totalram; /* Total usable main memory size */
+ unsigned long freeram; /* Available memory size */
+ unsigned long sharedram; /* Amount of shared memory */
+ unsigned long bufferram; /* Memory used by buffers */
+ unsigned long totalswap; /* Total swap space size */
+ unsigned long freeswap; /* swap space still available */
+ unsigned short procs; /* Number of current processes */
+ unsigned long totalhigh; /* Total high memory size */
+ unsigned long freehigh; /* Available high memory size */
+ unsigned int mem_unit; /* Memory unit size in bytes */
+ char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */
+};
+extern int sysinfo (struct sysinfo* info);
+
+/* Bit map related macros -- libc5 doens't provide these... sigh. */
+#ifndef setbit
+#define NBBY CHAR_BIT
+#define setbit(a,i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
+#define clrbit(a,i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
+#define isset(a,i) ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
+#define isclr(a,i) (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
+#endif
+
+#endif /* _BB_INTERNAL_H_ */
diff --git a/mdk-stage1/insmod-busybox/insmod-frontend.c b/mdk-stage1/insmod-busybox/insmod-frontend.c
new file mode 100644
index 000000000..3e5d6b3d7
--- /dev/null
+++ b/mdk-stage1/insmod-busybox/insmod-frontend.c
@@ -0,0 +1,24 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 MandrakeSoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+
+
+int insmod_main( int argc, char **argv);
+
+int main( int argc, char **argv)
+{
+ printf("Using insmod provided by busybox.\n");
+ return insmod_main(argc, argv);
+}
diff --git a/mdk-stage1/insmod-busybox/insmod.c b/mdk-stage1/insmod-busybox/insmod.c
new file mode 100644
index 000000000..d998e8860
--- /dev/null
+++ b/mdk-stage1/insmod-busybox/insmod.c
@@ -0,0 +1,2995 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini insmod implementation for busybox
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc.
+ * Written by Erik Andersen <andersen@lineo.com>
+ * and Ron Alder <alder@lineo.com>
+ *
+ * Modified by Bryan Rittmeyer <bryan@ixiacom.com> to support SH4
+ * and (theoretically) SH3. Note that there is still no true
+ * multiple architecture support. You just get SH3|SH4|i386, despite
+ * the mention of ARM and m68k--which may or may not work (but
+ * almost certainly do not, due to at least MATCH_MACHINE). I have
+ * only tested SH4 in little endian mode.
+ *
+ * Based almost entirely on the Linux modutils-2.3.11 implementation.
+ * Copyright 1996, 1997 Linux International.
+ * New implementation contributed by Richard Henderson <rth@tamu.edu>
+ * Based on original work by Bjorn Ekwall <bj0rn@blox.se>
+ * Restructured (and partly rewritten) by:
+ * Björn Ekwall <bj0rn@blox.se> February 1999
+ *
+ * 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 "busybox.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <assert.h>
+#include <getopt.h>
+#include <sys/utsname.h>
+
+//----------------------------------------------------------------------------
+//--------modutils module.h, lines 45-242
+//----------------------------------------------------------------------------
+
+/* Definitions for the Linux module syscall interface.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+
+#ifndef MODUTILS_MODULE_H
+#define MODUTILS_MODULE_H 1
+
+#ident "$Id$"
+
+/* This file contains the structures used by the 2.0 and 2.1 kernels.
+ We do not use the kernel headers directly because we do not wish
+ to be dependant on a particular kernel version to compile insmod. */
+
+
+/*======================================================================*/
+/* The structures used by Linux 2.0. */
+
+/* The symbol format used by get_kernel_syms(2). */
+struct old_kernel_sym
+{
+ unsigned long value;
+ char name[60];
+};
+
+struct old_module_ref
+{
+ unsigned long module; /* kernel addresses */
+ unsigned long next;
+};
+
+struct old_module_symbol
+{
+ unsigned long addr;
+ unsigned long name;
+};
+
+struct old_symbol_table
+{
+ int size; /* total, including string table!!! */
+ int n_symbols;
+ int n_refs;
+ struct old_module_symbol symbol[0]; /* actual size defined by n_symbols */
+ struct old_module_ref ref[0]; /* actual size defined by n_refs */
+};
+
+struct old_mod_routines
+{
+ unsigned long init;
+ unsigned long cleanup;
+};
+
+struct old_module
+{
+ unsigned long next;
+ unsigned long ref; /* the list of modules that refer to me */
+ unsigned long symtab;
+ unsigned long name;
+ int size; /* size of module in pages */
+ unsigned long addr; /* address of module */
+ int state;
+ unsigned long cleanup; /* cleanup routine */
+};
+
+/* Sent to init_module(2) or'ed into the code size parameter. */
+#define OLD_MOD_AUTOCLEAN 0x40000000 /* big enough, but no sign problems... */
+
+int get_kernel_syms(struct old_kernel_sym *);
+int old_sys_init_module(const char *name, char *code, unsigned codesize,
+ struct old_mod_routines *, struct old_symbol_table *);
+
+/*======================================================================*/
+/* For sizeof() which are related to the module platform and not to the
+ environment isnmod is running in, use sizeof_xx instead of sizeof(xx). */
+
+#define tgt_sizeof_char sizeof(char)
+#define tgt_sizeof_short sizeof(short)
+#define tgt_sizeof_int sizeof(int)
+#define tgt_sizeof_long sizeof(long)
+#define tgt_sizeof_char_p sizeof(char *)
+#define tgt_sizeof_void_p sizeof(void *)
+#define tgt_long long
+
+#if defined(__sparc__) && !defined(__sparc_v9__) && defined(ARCH_sparc64)
+#undef tgt_sizeof_long
+#undef tgt_sizeof_char_p
+#undef tgt_sizeof_void_p
+#undef tgt_long
+#define tgt_sizeof_long 8
+#define tgt_sizeof_char_p 8
+#define tgt_sizeof_void_p 8
+#define tgt_long long long
+#endif
+
+/*======================================================================*/
+/* The structures used in Linux 2.1. */
+
+/* Note: new_module_symbol does not use tgt_long intentionally */
+struct new_module_symbol
+{
+ unsigned long value;
+ unsigned long name;
+};
+
+struct new_module_persist;
+
+struct new_module_ref
+{
+ unsigned tgt_long dep; /* kernel addresses */
+ unsigned tgt_long ref;
+ unsigned tgt_long next_ref;
+};
+
+struct new_module
+{
+ unsigned tgt_long size_of_struct; /* == sizeof(module) */
+ unsigned tgt_long next;
+ unsigned tgt_long name;
+ unsigned tgt_long size;
+
+ tgt_long usecount;
+ unsigned tgt_long flags; /* AUTOCLEAN et al */
+
+ unsigned nsyms;
+ unsigned ndeps;
+
+ unsigned tgt_long syms;
+ unsigned tgt_long deps;
+ unsigned tgt_long refs;
+ unsigned tgt_long init;
+ unsigned tgt_long cleanup;
+ unsigned tgt_long ex_table_start;
+ unsigned tgt_long ex_table_end;
+#ifdef __alpha__
+ unsigned tgt_long gp;
+#endif
+ /* Everything after here is extension. */
+ unsigned tgt_long persist_start;
+ unsigned tgt_long persist_end;
+ unsigned tgt_long can_unload;
+ unsigned tgt_long runsize;
+};
+
+struct new_module_info
+{
+ unsigned long addr;
+ unsigned long size;
+ unsigned long flags;
+ long usecount;
+};
+
+/* Bits of module.flags. */
+#define NEW_MOD_RUNNING 1
+#define NEW_MOD_DELETED 2
+#define NEW_MOD_AUTOCLEAN 4
+#define NEW_MOD_VISITED 8
+#define NEW_MOD_USED_ONCE 16
+
+int new_sys_init_module(const char *name, const struct new_module *);
+int query_module(const char *name, int which, void *buf, size_t bufsize,
+ size_t *ret);
+
+/* Values for query_module's which. */
+
+#define QM_MODULES 1
+#define QM_DEPS 2
+#define QM_REFS 3
+#define QM_SYMBOLS 4
+#define QM_INFO 5
+
+/*======================================================================*/
+/* The system calls unchanged between 2.0 and 2.1. */
+
+unsigned long create_module(const char *, size_t);
+int delete_module(const char *);
+
+
+#endif /* module.h */
+
+//----------------------------------------------------------------------------
+//--------end of modutils module.h
+//----------------------------------------------------------------------------
+
+
+
+//----------------------------------------------------------------------------
+//--------modutils obj.h, lines 253-462
+//----------------------------------------------------------------------------
+
+/* Elf object file loading and relocation routines.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+
+#ifndef MODUTILS_OBJ_H
+#define MODUTILS_OBJ_H 1
+
+#ident "$Id$"
+
+/* The relocatable object is manipulated using elfin types. */
+
+#include <stdio.h>
+#include <elf.h>
+
+
+/* Machine-specific elf macros for i386 et al. */
+
+/* the SH changes have only been tested on the SH4 in =little endian= mode */
+/* I'm not sure about big endian, so let's warn: */
+
+#if (defined(__SH4__) || defined(__SH3__)) && defined(__BIG_ENDIAN__)
+#error insmod.c may require changes for use on big endian SH4/SH3
+#endif
+
+/* it may or may not work on the SH1/SH2... So let's error on those
+ also */
+#if (defined(__sh__) && (!(defined(__SH3__) || defined(__SH4__))))
+#error insmod.c may require changes for non-SH3/SH4 use
+#endif
+
+#define ELFCLASSM ELFCLASS32
+#define ELFDATAM ELFDATA2LSB
+
+
+
+#if defined(__sh__)
+
+#define MATCH_MACHINE(x) (x == EM_SH)
+#define SHT_RELM SHT_RELA
+#define Elf32_RelM Elf32_Rela
+
+#else
+
+/* presumably we can use these for anything but the SH */
+/* this is the previous behavior, but it does result in
+ insmod.c being broken on anything except i386 */
+
+#define MATCH_MACHINE(x) (x == EM_386 || x == EM_486)
+#define SHT_RELM SHT_REL
+#define Elf32_RelM Elf32_Rel
+
+#endif
+
+#ifndef ElfW
+# if ELFCLASSM == ELFCLASS32
+# define ElfW(x) Elf32_ ## x
+# define ELFW(x) ELF32_ ## x
+# else
+# define ElfW(x) Elf64_ ## x
+# define ELFW(x) ELF64_ ## x
+# endif
+#endif
+
+/* For some reason this is missing from libc5. */
+#ifndef ELF32_ST_INFO
+# define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
+#endif
+
+#ifndef ELF64_ST_INFO
+# define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
+#endif
+
+struct obj_string_patch;
+struct obj_symbol_patch;
+
+struct obj_section
+{
+ ElfW(Shdr) header;
+ const char *name;
+ char *contents;
+ struct obj_section *load_next;
+ int idx;
+};
+
+struct obj_symbol
+{
+ struct obj_symbol *next; /* hash table link */
+ const char *name;
+ unsigned long value;
+ unsigned long size;
+ int secidx; /* the defining section index/module */
+ int info;
+ int ksymidx; /* for export to the kernel symtab */
+ int referenced; /* actually used in the link */
+};
+
+/* Hardcode the hash table size. We shouldn't be needing so many
+ symbols that we begin to degrade performance, and we get a big win
+ by giving the compiler a constant divisor. */
+
+#define HASH_BUCKETS 521
+
+struct obj_file
+{
+ ElfW(Ehdr) header;
+ ElfW(Addr) baseaddr;
+ struct obj_section **sections;
+ struct obj_section *load_order;
+ struct obj_section **load_order_search_start;
+ struct obj_string_patch *string_patches;
+ struct obj_symbol_patch *symbol_patches;
+ int (*symbol_cmp)(const char *, const char *);
+ unsigned long (*symbol_hash)(const char *);
+ unsigned long local_symtab_size;
+ struct obj_symbol **local_symtab;
+ struct obj_symbol *symtab[HASH_BUCKETS];
+};
+
+enum obj_reloc
+{
+ obj_reloc_ok,
+ obj_reloc_overflow,
+ obj_reloc_dangerous,
+ obj_reloc_unhandled
+};
+
+struct obj_string_patch
+{
+ struct obj_string_patch *next;
+ int reloc_secidx;
+ ElfW(Addr) reloc_offset;
+ ElfW(Addr) string_offset;
+};
+
+struct obj_symbol_patch
+{
+ struct obj_symbol_patch *next;
+ int reloc_secidx;
+ ElfW(Addr) reloc_offset;
+ struct obj_symbol *sym;
+};
+
+
+/* Generic object manipulation routines. */
+
+unsigned long obj_elf_hash(const char *);
+
+unsigned long obj_elf_hash_n(const char *, unsigned long len);
+
+struct obj_symbol *obj_add_symbol (struct obj_file *f, const char *name,
+ unsigned long symidx, int info, int secidx,
+ ElfW(Addr) value, unsigned long size);
+
+struct obj_symbol *obj_find_symbol (struct obj_file *f,
+ const char *name);
+
+ElfW(Addr) obj_symbol_final_value(struct obj_file *f,
+ struct obj_symbol *sym);
+
+void obj_set_symbol_compare(struct obj_file *f,
+ int (*cmp)(const char *, const char *),
+ unsigned long (*hash)(const char *));
+
+struct obj_section *obj_find_section (struct obj_file *f,
+ const char *name);
+
+void obj_insert_section_load_order (struct obj_file *f,
+ struct obj_section *sec);
+
+struct obj_section *obj_create_alloced_section (struct obj_file *f,
+ const char *name,
+ unsigned long align,
+ unsigned long size);
+
+struct obj_section *obj_create_alloced_section_first (struct obj_file *f,
+ const char *name,
+ unsigned long align,
+ unsigned long size);
+
+void *obj_extend_section (struct obj_section *sec, unsigned long more);
+
+int obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
+ const char *string);
+
+int obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
+ struct obj_symbol *sym);
+
+int obj_check_undefineds(struct obj_file *f);
+
+void obj_allocate_commons(struct obj_file *f);
+
+unsigned long obj_load_size (struct obj_file *f);
+
+int obj_relocate (struct obj_file *f, ElfW(Addr) base);
+
+struct obj_file *obj_load(FILE *f);
+
+int obj_create_image (struct obj_file *f, char *image);
+
+/* Architecture specific manipulation routines. */
+
+struct obj_file *arch_new_file (void);
+
+struct obj_section *arch_new_section (void);
+
+struct obj_symbol *arch_new_symbol (void);
+
+enum obj_reloc arch_apply_relocation (struct obj_file *f,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ ElfW(RelM) *rel, ElfW(Addr) value);
+
+int arch_create_got (struct obj_file *f);
+
+struct new_module;
+int arch_init_module (struct obj_file *f, struct new_module *);
+
+#endif /* obj.h */
+//----------------------------------------------------------------------------
+//--------end of modutils obj.h
+//----------------------------------------------------------------------------
+
+
+
+
+
+#define _PATH_MODULES "/lib/modules"
+#define STRVERSIONLEN 32
+
+#if !defined(BB_FEATURE_INSMOD_NEW_KERNEL) && !defined(BB_FEATURE_INSMOD_OLD_KERNEL)
+#error "Must have ether BB_FEATURE_INSMOD_NEW_KERNEL or BB_FEATURE_INSMOD_OLD_KERNEL defined"
+#endif
+
+/*======================================================================*/
+
+int flag_force_load = 0;
+int flag_autoclean = 0;
+int flag_export = 1;
+
+
+/*======================================================================*/
+
+/* previously, these were named i386_* but since we could be
+ compiling for the sh, I've renamed them to the more general
+ arch_* These structures are the same between the x86 and SH,
+ and we can't support anything else right now anyway. In the
+ future maybe they should be #if defined'd */
+
+struct arch_got_entry {
+ int offset;
+ unsigned offset_done:1;
+ unsigned reloc_done:1;
+};
+
+struct arch_file {
+ struct obj_file root;
+ struct obj_section *got;
+};
+
+struct arch_symbol {
+ struct obj_symbol root;
+ struct arch_got_entry gotent;
+};
+
+
+struct external_module {
+ const char *name;
+ ElfW(Addr) addr;
+ int used;
+ size_t nsyms;
+ struct new_module_symbol *syms;
+};
+
+struct new_module_symbol *ksyms;
+size_t nksyms;
+
+struct external_module *ext_modules;
+int n_ext_modules;
+int n_ext_modules_used;
+
+
+
+/* Some firendly syscalls to cheer everyone's day... */
+#define __NR_new_sys_init_module __NR_init_module
+_syscall2(int, new_sys_init_module, const char *, name,
+ const struct new_module *, info)
+#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)
+#ifndef BB_RMMOD
+_syscall1(int, delete_module, const char *, name)
+#else
+extern int delete_module(const char *);
+#endif
+
+/* This is kind of troublesome. See, we don't actually support
+ the m68k or the arm the same way we support i386 and (now)
+ sh. In doing my SH patch, I just assumed that whatever works
+ for i386 also works for m68k and arm since currently insmod.c
+ does nothing special for them. If this isn't true, the below
+ line is rather misleading IMHO, and someone should either
+ change it or add more proper architecture-dependent support
+ for these boys.
+
+ -- Bryan Rittmeyer <bryan@ixiacom.com> */
+
+#if defined(__i386__) || defined(__m68k__) || defined(__arm__)
+/* Jump through hoops to fixup error return codes */
+#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)
+{
+ long ret = _create_module(name, size);
+
+ if (ret == -1 && errno > 125) {
+ ret = -errno;
+ errno = 0;
+ }
+ return ret;
+}
+#else
+_syscall2(unsigned long, create_module, const char *, name, size_t, size)
+#endif
+static char m_filename[BUFSIZ + 1] = "\0";
+static char m_fullName[BUFSIZ + 1] = "\0";
+
+/*======================================================================*/
+
+
+static int findNamedModule(const char *fileName, struct stat *statbuf,
+ void *userDate)
+{
+ char *fullName = (char *) userDate;
+
+
+ if (fullName[0] == '\0')
+ return (FALSE);
+ else {
+ char *tmp = strrchr(fileName, '/');
+
+ if (tmp == NULL)
+ tmp = (char *) fileName;
+ else
+ tmp++;
+ if (check_wildcard_match(tmp, fullName) == TRUE) {
+ /* Stop searching if we find a match */
+ memcpy(m_filename, fileName, strlen(fileName)+1);
+ return (FALSE);
+ }
+ }
+ return (TRUE);
+}
+
+
+/*======================================================================*/
+
+struct obj_file *arch_new_file(void)
+{
+ struct arch_file *f;
+ f = xmalloc(sizeof(*f));
+ f->got = NULL;
+ return &f->root;
+}
+
+struct obj_section *arch_new_section(void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *arch_new_symbol(void)
+{
+ struct arch_symbol *sym;
+ sym = xmalloc(sizeof(*sym));
+ memset(&sym->gotent, 0, sizeof(sym->gotent));
+ return &sym->root;
+}
+
+enum obj_reloc
+arch_apply_relocation(struct obj_file *f,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+#if defined(__sh__)
+ Elf32_Rela * rel, Elf32_Addr v)
+#else
+ Elf32_Rel * rel, Elf32_Addr v)
+#endif
+{
+ struct arch_file *ifile = (struct arch_file *) f;
+ struct arch_symbol *isym = (struct arch_symbol *) sym;
+
+ Elf32_Addr *loc = (Elf32_Addr *) (targsec->contents + rel->r_offset);
+ Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset;
+ Elf32_Addr got = ifile->got ? ifile->got->header.sh_addr : 0;
+
+ enum obj_reloc ret = obj_reloc_ok;
+
+ switch (ELF32_R_TYPE(rel->r_info)) {
+
+/* even though these constants seem to be the same for
+ the i386 and the sh, we "#if define" them for clarity
+ and in case that ever changes */
+#if defined(__sh__)
+ case R_SH_NONE:
+#else
+ case R_386_NONE:
+#endif
+ break;
+
+#if defined(__sh__)
+ case R_SH_DIR32:
+#else
+ case R_386_32:
+#endif
+ *loc += v;
+ break;
+
+#if defined(__sh__)
+ case R_SH_REL32:
+#else
+ case R_386_PLT32:
+ case R_386_PC32:
+#endif
+ *loc += v - dot;
+ break;
+
+#if defined(__sh__)
+ case R_SH_PLT32:
+ *loc = v - dot;
+ break;
+#endif
+
+
+#if defined(__sh__)
+ case R_SH_GLOB_DAT:
+ case R_SH_JMP_SLOT:
+ *loc = v;
+ break;
+#else
+ case R_386_GLOB_DAT:
+ case R_386_JMP_SLOT:
+ *loc = v;
+ break;
+#endif
+
+#if defined(__sh__)
+ case R_SH_RELATIVE:
+ *loc += f->baseaddr + rel->r_addend;
+ break;
+#else
+ case R_386_RELATIVE:
+ *loc += f->baseaddr;
+ break;
+#endif
+
+#if defined(__sh__)
+ case R_SH_GOTPC:
+ assert(got != 0);
+ *loc += got - dot + rel->r_addend;;
+ break;
+#else
+ case R_386_GOTPC:
+ assert(got != 0);
+ *loc += got - dot;
+ break;
+#endif
+
+#if defined(__sh__)
+ case R_SH_GOT32:
+ assert(isym != NULL);
+ if (!isym->gotent.reloc_done) {
+ isym->gotent.reloc_done = 1;
+ *(Elf32_Addr *) (ifile->got->contents + isym->gotent.offset) =
+ v;
+ }
+ *loc += isym->gotent.offset + rel->r_addend;
+ break;
+#else
+ case R_386_GOT32:
+ assert(isym != NULL);
+ if (!isym->gotent.reloc_done) {
+ isym->gotent.reloc_done = 1;
+ *(Elf32_Addr *) (ifile->got->contents + isym->gotent.offset) =
+ v;
+ }
+ *loc += isym->gotent.offset;
+ break;
+#endif
+
+#if defined(__sh__)
+ case R_SH_GOTOFF:
+#else
+ case R_386_GOTOFF:
+#endif
+ assert(got != 0);
+ *loc += v - got;
+ break;
+
+ default:
+ ret = obj_reloc_unhandled;
+ break;
+ }
+
+ return ret;
+}
+
+int arch_create_got(struct obj_file *f)
+{
+ struct arch_file *ifile = (struct arch_file *) f;
+ int i, n, offset = 0, gotneeded = 0;
+
+ n = ifile->root.header.e_shnum;
+ for (i = 0; i < n; ++i) {
+ struct obj_section *relsec, *symsec, *strsec;
+#if defined(__sh__)
+ Elf32_Rela *rel, *relend;
+#else
+ Elf32_Rel *rel, *relend;
+#endif
+ Elf32_Sym *symtab;
+ const char *strtab;
+
+ relsec = ifile->root.sections[i];
+ if (relsec->header.sh_type != SHT_REL)
+ continue;
+
+ symsec = ifile->root.sections[relsec->header.sh_link];
+ strsec = ifile->root.sections[symsec->header.sh_link];
+
+
+#if defined(__sh__)
+ rel = (Elf32_Rela *) relsec->contents;
+ relend = rel + (relsec->header.sh_size / sizeof(Elf32_Rela));
+#else
+ rel = (Elf32_Rel *) relsec->contents;
+ relend = rel + (relsec->header.sh_size / sizeof(Elf32_Rel));
+#endif
+ symtab = (Elf32_Sym *) symsec->contents;
+ strtab = (const char *) strsec->contents;
+
+ for (; rel < relend; ++rel) {
+ Elf32_Sym *extsym;
+ struct arch_symbol *intsym;
+ const char *name;
+
+ switch (ELF32_R_TYPE(rel->r_info)) {
+#if defined(__sh__)
+ case R_SH_GOTPC:
+ case R_SH_GOTOFF:
+#else
+ case R_386_GOTPC:
+ case R_386_GOTOFF:
+#endif
+ gotneeded = 1;
+ default:
+ continue;
+
+#if defined(__sh__)
+ case R_SH_GOT32:
+#else
+ case R_386_GOT32:
+#endif
+ break;
+ }
+
+ extsym = &symtab[ELF32_R_SYM(rel->r_info)];
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ intsym =
+ (struct arch_symbol *) obj_find_symbol(&ifile->root, name);
+
+ if (!intsym->gotent.offset_done) {
+ intsym->gotent.offset_done = 1;
+ intsym->gotent.offset = offset;
+ offset += 4;
+ }
+ }
+ }
+
+ if (offset > 0 || gotneeded)
+ ifile->got =
+ obj_create_alloced_section(&ifile->root, ".got", 4, offset);
+
+ return 1;
+}
+
+int arch_init_module(struct obj_file *f, struct new_module *mod)
+{
+ return 1;
+}
+
+
+/*======================================================================*/
+
+/* Standard ELF hash function. */
+inline unsigned long obj_elf_hash_n(const char *name, unsigned long n)
+{
+ unsigned long h = 0;
+ unsigned long g;
+ unsigned char ch;
+
+ while (n > 0) {
+ ch = *name++;
+ h = (h << 4) + ch;
+ if ((g = (h & 0xf0000000)) != 0) {
+ h ^= g >> 24;
+ h &= ~g;
+ }
+ n--;
+ }
+ return h;
+}
+
+unsigned long obj_elf_hash(const char *name)
+{
+ return obj_elf_hash_n(name, strlen(name));
+}
+
+#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
+/* Get the kernel version in the canonical integer form. */
+
+static int get_kernel_version(char str[STRVERSIONLEN])
+{
+ struct utsname uts_info;
+ char *p, *q;
+ int a, b, c;
+
+ if (uname(&uts_info) < 0)
+ return -1;
+ strncpy(str, uts_info.release, STRVERSIONLEN);
+ p = uts_info.release;
+
+ a = strtoul(p, &p, 10);
+ if (*p != '.')
+ return -1;
+ b = strtoul(p + 1, &p, 10);
+ if (*p != '.')
+ return -1;
+ c = strtoul(p + 1, &q, 10);
+ if (p + 1 == q)
+ return -1;
+
+ return a << 16 | b << 8 | c;
+}
+
+/* String comparison for non-co-versioned kernel and module. */
+
+static int ncv_strcmp(const char *a, const char *b)
+{
+ size_t alen = strlen(a), blen = strlen(b);
+
+ if (blen == alen + 10 && b[alen] == '_' && b[alen + 1] == 'R')
+ return strncmp(a, b, alen);
+ else if (alen == blen + 10 && a[blen] == '_' && a[blen + 1] == 'R')
+ return strncmp(a, b, blen);
+ else
+ return strcmp(a, b);
+}
+
+/* String hashing for non-co-versioned kernel and module. Here
+ we are simply forced to drop the crc from the hash. */
+
+static unsigned long ncv_symbol_hash(const char *str)
+{
+ size_t len = strlen(str);
+ if (len > 10 && str[len - 10] == '_' && str[len - 9] == 'R')
+ len -= 10;
+ return obj_elf_hash_n(str, len);
+}
+
+void
+obj_set_symbol_compare(struct obj_file *f,
+ int (*cmp) (const char *, const char *),
+ unsigned long (*hash) (const char *))
+{
+ if (cmp)
+ f->symbol_cmp = cmp;
+ if (hash) {
+ struct obj_symbol *tmptab[HASH_BUCKETS], *sym, *next;
+ int i;
+
+ f->symbol_hash = hash;
+
+ memcpy(tmptab, f->symtab, sizeof(tmptab));
+ memset(f->symtab, 0, sizeof(f->symtab));
+
+ for (i = 0; i < HASH_BUCKETS; ++i)
+ for (sym = tmptab[i]; sym; sym = next) {
+ unsigned long h = hash(sym->name) % HASH_BUCKETS;
+ next = sym->next;
+ sym->next = f->symtab[h];
+ f->symtab[h] = sym;
+ }
+ }
+}
+
+#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */
+
+
+struct obj_symbol *obj_add_symbol(struct obj_file *f, const char *name,
+ unsigned long symidx, int info,
+ int secidx, ElfW(Addr) value,
+ unsigned long size)
+{
+ struct obj_symbol *sym;
+ unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS;
+ int n_type = ELFW(ST_TYPE) (info);
+ int n_binding = ELFW(ST_BIND) (info);
+
+ for (sym = f->symtab[hash]; sym; sym = sym->next)
+ if (f->symbol_cmp(sym->name, name) == 0) {
+ int o_secidx = sym->secidx;
+ int o_info = sym->info;
+ int o_type = ELFW(ST_TYPE) (o_info);
+ int o_binding = ELFW(ST_BIND) (o_info);
+
+ /* A redefinition! Is it legal? */
+
+ if (secidx == SHN_UNDEF)
+ return sym;
+ else if (o_secidx == SHN_UNDEF)
+ goto found;
+ else if (n_binding == STB_GLOBAL && o_binding == STB_LOCAL) {
+ /* Cope with local and global symbols of the same name
+ in the same object file, as might have been created
+ by ld -r. The only reason locals are now seen at this
+ level at all is so that we can do semi-sensible things
+ with parameters. */
+
+ struct obj_symbol *nsym, **p;
+
+ nsym = arch_new_symbol();
+ nsym->next = sym->next;
+ nsym->ksymidx = -1;
+
+ /* Excise the old (local) symbol from the hash chain. */
+ for (p = &f->symtab[hash]; *p != sym; p = &(*p)->next)
+ continue;
+ *p = sym = nsym;
+ goto found;
+ } else if (n_binding == STB_LOCAL) {
+ /* Another symbol of the same name has already been defined.
+ Just add this to the local table. */
+ sym = arch_new_symbol();
+ sym->next = NULL;
+ sym->ksymidx = -1;
+ f->local_symtab[symidx] = sym;
+ goto found;
+ } else if (n_binding == STB_WEAK)
+ return sym;
+ else if (o_binding == STB_WEAK)
+ goto found;
+ /* Don't unify COMMON symbols with object types the programmer
+ doesn't expect. */
+ else if (secidx == SHN_COMMON
+ && (o_type == STT_NOTYPE || o_type == STT_OBJECT))
+ return sym;
+ else if (o_secidx == SHN_COMMON
+ && (n_type == STT_NOTYPE || n_type == STT_OBJECT))
+ goto found;
+ else {
+ /* Don't report an error if the symbol is coming from
+ the kernel or some external module. */
+ if (secidx <= SHN_HIRESERVE)
+ errorMsg("%s multiply defined\n", name);
+ return sym;
+ }
+ }
+
+ /* Completely new symbol. */
+ sym = arch_new_symbol();
+ sym->next = f->symtab[hash];
+ f->symtab[hash] = sym;
+ sym->ksymidx = -1;
+
+ if (ELFW(ST_BIND) (info) == STB_LOCAL)
+ f->local_symtab[symidx] = sym;
+
+ found:
+ sym->name = name;
+ sym->value = value;
+ sym->size = size;
+ sym->secidx = secidx;
+ sym->info = info;
+
+ return sym;
+}
+
+struct obj_symbol *obj_find_symbol(struct obj_file *f, const char *name)
+{
+ struct obj_symbol *sym;
+ unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS;
+
+ for (sym = f->symtab[hash]; sym; sym = sym->next)
+ if (f->symbol_cmp(sym->name, name) == 0)
+ return sym;
+
+ return NULL;
+}
+
+ElfW(Addr)
+ obj_symbol_final_value(struct obj_file * f, struct obj_symbol * sym)
+{
+ if (sym) {
+ if (sym->secidx >= SHN_LORESERVE)
+ return sym->value;
+
+ return sym->value + f->sections[sym->secidx]->header.sh_addr;
+ } else {
+ /* As a special case, a NULL sym has value zero. */
+ return 0;
+ }
+}
+
+struct obj_section *obj_find_section(struct obj_file *f, const char *name)
+{
+ int i, n = f->header.e_shnum;
+
+ for (i = 0; i < n; ++i)
+ if (strcmp(f->sections[i]->name, name) == 0)
+ return f->sections[i];
+
+ return NULL;
+}
+
+static int obj_load_order_prio(struct obj_section *a)
+{
+ unsigned long af, ac;
+
+ af = a->header.sh_flags;
+
+ ac = 0;
+ if (a->name[0] != '.' || strlen(a->name) != 10 ||
+ strcmp(a->name + 5, ".init"))
+ ac |= 32;
+ if (af & SHF_ALLOC)
+ ac |= 16;
+ if (!(af & SHF_WRITE))
+ ac |= 8;
+ if (af & SHF_EXECINSTR)
+ ac |= 4;
+ if (a->header.sh_type != SHT_NOBITS)
+ ac |= 2;
+
+ return ac;
+}
+
+void
+obj_insert_section_load_order(struct obj_file *f, struct obj_section *sec)
+{
+ struct obj_section **p;
+ int prio = obj_load_order_prio(sec);
+ for (p = f->load_order_search_start; *p; p = &(*p)->load_next)
+ if (obj_load_order_prio(*p) < prio)
+ break;
+ sec->load_next = *p;
+ *p = sec;
+}
+
+struct obj_section *obj_create_alloced_section(struct obj_file *f,
+ const char *name,
+ unsigned long align,
+ unsigned long size)
+{
+ int newidx = f->header.e_shnum++;
+ struct obj_section *sec;
+
+ f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec));
+ f->sections[newidx] = sec = arch_new_section();
+
+ memset(sec, 0, sizeof(*sec));
+ sec->header.sh_type = SHT_PROGBITS;
+ sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
+ sec->header.sh_size = size;
+ sec->header.sh_addralign = align;
+ sec->name = name;
+ sec->idx = newidx;
+ if (size)
+ sec->contents = xmalloc(size);
+
+ obj_insert_section_load_order(f, sec);
+
+ return sec;
+}
+
+struct obj_section *obj_create_alloced_section_first(struct obj_file *f,
+ const char *name,
+ unsigned long align,
+ unsigned long size)
+{
+ int newidx = f->header.e_shnum++;
+ struct obj_section *sec;
+
+ f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec));
+ f->sections[newidx] = sec = arch_new_section();
+
+ memset(sec, 0, sizeof(*sec));
+ sec->header.sh_type = SHT_PROGBITS;
+ sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
+ sec->header.sh_size = size;
+ sec->header.sh_addralign = align;
+ sec->name = name;
+ sec->idx = newidx;
+ if (size)
+ sec->contents = xmalloc(size);
+
+ sec->load_next = f->load_order;
+ f->load_order = sec;
+ if (f->load_order_search_start == &f->load_order)
+ f->load_order_search_start = &sec->load_next;
+
+ return sec;
+}
+
+void *obj_extend_section(struct obj_section *sec, unsigned long more)
+{
+ unsigned long oldsize = sec->header.sh_size;
+ sec->contents = xrealloc(sec->contents, sec->header.sh_size += more);
+ return sec->contents + oldsize;
+}
+
+
+
+/* Conditionally add the symbols from the given symbol set to the
+ new module. */
+
+static int
+add_symbols_from(
+ struct obj_file *f,
+ int idx, struct new_module_symbol *syms, size_t nsyms)
+{
+ struct new_module_symbol *s;
+ size_t i;
+ int used = 0;
+
+ for (i = 0, s = syms; i < nsyms; ++i, ++s) {
+
+ /* Only add symbols that are already marked external. If we
+ override locals we may cause problems for argument initialization.
+ We will also create a false dependency on the module. */
+ struct obj_symbol *sym;
+
+ sym = obj_find_symbol(f, (char *) s->name);
+ if (sym && !ELFW(ST_BIND) (sym->info) == STB_LOCAL) {
+ sym = obj_add_symbol(f, (char *) s->name, -1,
+ ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE),
+ idx, s->value, 0);
+ /* Did our symbol just get installed? If so, mark the
+ module as "used". */
+ if (sym->secidx == idx)
+ used = 1;
+ }
+ }
+
+ return used;
+}
+
+static void add_kernel_symbols(struct obj_file *f)
+{
+ struct external_module *m;
+ int i, nused = 0;
+
+ /* Add module symbols first. */
+
+ for (i = 0, m = ext_modules; i < n_ext_modules; ++i, ++m)
+ if (m->nsyms
+ && add_symbols_from(f, SHN_HIRESERVE + 2 + i, m->syms,
+ m->nsyms)) m->used = 1, ++nused;
+
+ n_ext_modules_used = nused;
+
+ /* And finally the symbols from the kernel proper. */
+
+ if (nksyms)
+ add_symbols_from(f, SHN_HIRESERVE + 1, ksyms, nksyms);
+}
+
+static char *get_modinfo_value(struct obj_file *f, const char *key)
+{
+ struct obj_section *sec;
+ char *p, *v, *n, *ep;
+ size_t klen = strlen(key);
+
+ sec = obj_find_section(f, ".modinfo");
+ if (sec == NULL)
+ return NULL;
+ p = sec->contents;
+ ep = p + sec->header.sh_size;
+ while (p < ep) {
+ v = strchr(p, '=');
+ n = strchr(p, '\0');
+ if (v) {
+ if (p + klen == v && strncmp(p, key, klen) == 0)
+ return v + 1;
+ } else {
+ if (p + klen == n && strcmp(p, key) == 0)
+ return n;
+ }
+ p = n + 1;
+ }
+
+ return NULL;
+}
+
+
+/*======================================================================*/
+/* Functions relating to module loading in pre 2.1 kernels. */
+
+static int
+old_process_module_arguments(struct obj_file *f, int argc, char **argv)
+{
+ while (argc > 0) {
+ char *p, *q;
+ struct obj_symbol *sym;
+ int *loc;
+
+ p = *argv;
+ if ((q = strchr(p, '=')) == NULL) {
+ argc--;
+ continue;
+ }
+ *q++ = '\0';
+
+ sym = obj_find_symbol(f, p);
+
+ /* Also check that the parameter was not resolved from the kernel. */
+ if (sym == NULL || sym->secidx > SHN_HIRESERVE) {
+ errorMsg("symbol for parameter %s not found\n", p);
+ return 0;
+ }
+
+ loc = (int *) (f->sections[sym->secidx]->contents + sym->value);
+
+ /* Do C quoting if we begin with a ". */
+ if (*q == '"') {
+ char *r, *str;
+
+ str = alloca(strlen(q));
+ for (r = str, q++; *q != '"'; ++q, ++r) {
+ if (*q == '\0') {
+ errorMsg("improperly terminated string argument for %s\n", p);
+ return 0;
+ } else if (*q == '\\')
+ switch (*++q) {
+ case 'a':
+ *r = '\a';
+ break;
+ case 'b':
+ *r = '\b';
+ break;
+ case 'e':
+ *r = '\033';
+ break;
+ case 'f':
+ *r = '\f';
+ break;
+ case 'n':
+ *r = '\n';
+ break;
+ case 'r':
+ *r = '\r';
+ break;
+ case 't':
+ *r = '\t';
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ int c = *q - '0';
+ if (q[1] >= '0' && q[1] <= '7') {
+ c = (c * 8) + *++q - '0';
+ if (q[1] >= '0' && q[1] <= '7')
+ c = (c * 8) + *++q - '0';
+ }
+ *r = c;
+ }
+ break;
+
+ default:
+ *r = *q;
+ break;
+ } else
+ *r = *q;
+ }
+ *r = '\0';
+ obj_string_patch(f, sym->secidx, sym->value, str);
+ } else if (*q >= '0' && *q <= '9') {
+ do
+ *loc++ = strtoul(q, &q, 0);
+ while (*q++ == ',');
+ } else {
+ char *contents = f->sections[sym->secidx]->contents;
+ char *loc = contents + sym->value;
+ char *r; /* To search for commas */
+
+ /* Break the string with comas */
+ while ((r = strchr(q, ',')) != (char *) NULL) {
+ *r++ = '\0';
+ obj_string_patch(f, sym->secidx, loc - contents, q);
+ loc += sizeof(char *);
+ q = r;
+ }
+
+ /* last part */
+ obj_string_patch(f, sym->secidx, loc - contents, q);
+ }
+
+ argc--, argv++;
+ }
+
+ return 1;
+}
+
+#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
+static int old_is_module_checksummed(struct obj_file *f)
+{
+ return obj_find_symbol(f, "Using_Versions") != NULL;
+}
+/* Get the module's kernel version in the canonical integer form. */
+
+static int
+old_get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
+{
+ struct obj_symbol *sym;
+ char *p, *q;
+ int a, b, c;
+
+ sym = obj_find_symbol(f, "kernel_version");
+ if (sym == NULL)
+ return -1;
+
+ p = f->sections[sym->secidx]->contents + sym->value;
+ strncpy(str, p, STRVERSIONLEN);
+
+ a = strtoul(p, &p, 10);
+ if (*p != '.')
+ return -1;
+ b = strtoul(p + 1, &p, 10);
+ if (*p != '.')
+ return -1;
+ c = strtoul(p + 1, &q, 10);
+ if (p + 1 == q)
+ return -1;
+
+ return a << 16 | b << 8 | c;
+}
+
+#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */
+
+#ifdef BB_FEATURE_INSMOD_OLD_KERNEL
+
+/* Fetch all the symbols and divvy them up as appropriate for the modules. */
+
+static int old_get_kernel_symbols(const char *m_name)
+{
+ struct old_kernel_sym *ks, *k;
+ struct new_module_symbol *s;
+ struct external_module *mod;
+ int nks, nms, nmod, i;
+
+ nks = get_kernel_syms(NULL);
+ if (nks < 0) {
+ errorMsg("get_kernel_syms: %s: %s", m_name, strerror(errno));
+ return 0;
+ }
+
+ ks = k = xmalloc(nks * sizeof(*ks));
+
+ if (get_kernel_syms(ks) != nks) {
+ perror("inconsistency with get_kernel_syms -- is someone else "
+ "playing with modules?");
+ free(ks);
+ return 0;
+ }
+
+ /* Collect the module information. */
+
+ mod = NULL;
+ nmod = -1;
+
+ while (k->name[0] == '#' && k->name[1]) {
+ struct old_kernel_sym *k2;
+ struct new_module_symbol *s;
+
+ /* Find out how many symbols this module has. */
+ for (k2 = k + 1; k2->name[0] != '#'; ++k2)
+ continue;
+ nms = k2 - k - 1;
+
+ mod = xrealloc(mod, (++nmod + 1) * sizeof(*mod));
+ mod[nmod].name = k->name + 1;
+ mod[nmod].addr = k->value;
+ mod[nmod].used = 0;
+ mod[nmod].nsyms = nms;
+ mod[nmod].syms = s = (nms ? xmalloc(nms * sizeof(*s)) : NULL);
+
+ for (i = 0, ++k; i < nms; ++i, ++s, ++k) {
+ s->name = (unsigned long) k->name;
+ s->value = k->value;
+ }
+
+ k = k2;
+ }
+
+ ext_modules = mod;
+ n_ext_modules = nmod + 1;
+
+ /* Now collect the symbols for the kernel proper. */
+
+ if (k->name[0] == '#')
+ ++k;
+
+ nksyms = nms = nks - (k - ks);
+ ksyms = s = (nms ? xmalloc(nms * sizeof(*s)) : NULL);
+
+ for (i = 0; i < nms; ++i, ++s, ++k) {
+ s->name = (unsigned long) k->name;
+ s->value = k->value;
+ }
+
+ return 1;
+}
+
+/* Return the kernel symbol checksum version, or zero if not used. */
+
+static int old_is_kernel_checksummed(void)
+{
+ /* Using_Versions is the first symbol. */
+ if (nksyms > 0
+ && strcmp((char *) ksyms[0].name,
+ "Using_Versions") == 0) return ksyms[0].value;
+ else
+ return 0;
+}
+
+
+static int old_create_mod_use_count(struct obj_file *f)
+{
+ struct obj_section *sec;
+
+ sec = obj_create_alloced_section_first(f, ".moduse", sizeof(long),
+ sizeof(long));
+
+ obj_add_symbol(f, "mod_use_count_", -1,
+ ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0,
+ sizeof(long));
+
+ return 1;
+}
+
+static int
+old_init_module(const char *m_name, struct obj_file *f,
+ unsigned long m_size)
+{
+ char *image;
+ struct old_mod_routines routines;
+ struct old_symbol_table *symtab;
+ int ret;
+
+ /* Create the symbol table */
+ {
+ int nsyms = 0, strsize = 0, total;
+
+ /* Size things first... */
+ if (flag_export) {
+ int i;
+ for (i = 0; i < HASH_BUCKETS; ++i) {
+ struct obj_symbol *sym;
+ for (sym = f->symtab[i]; sym; sym = sym->next)
+ if (ELFW(ST_BIND) (sym->info) != STB_LOCAL
+ && sym->secidx <= SHN_HIRESERVE)
+ {
+ sym->ksymidx = nsyms++;
+ strsize += strlen(sym->name) + 1;
+ }
+ }
+ }
+
+ total = (sizeof(struct old_symbol_table)
+ + nsyms * sizeof(struct old_module_symbol)
+ + n_ext_modules_used * sizeof(struct old_module_ref)
+ + strsize);
+ symtab = xmalloc(total);
+ symtab->size = total;
+ symtab->n_symbols = nsyms;
+ symtab->n_refs = n_ext_modules_used;
+
+ if (flag_export && nsyms) {
+ struct old_module_symbol *ksym;
+ char *str;
+ int i;
+
+ ksym = symtab->symbol;
+ str = ((char *) ksym + nsyms * sizeof(struct old_module_symbol)
+ + n_ext_modules_used * sizeof(struct old_module_ref));
+
+ for (i = 0; i < HASH_BUCKETS; ++i) {
+ struct obj_symbol *sym;
+ for (sym = f->symtab[i]; sym; sym = sym->next)
+ if (sym->ksymidx >= 0) {
+ ksym->addr = obj_symbol_final_value(f, sym);
+ ksym->name =
+ (unsigned long) str - (unsigned long) symtab;
+
+ str = stpcpy(str, sym->name) + 1;
+ ksym++;
+ }
+ }
+ }
+
+ if (n_ext_modules_used) {
+ struct old_module_ref *ref;
+ int i;
+
+ ref = (struct old_module_ref *)
+ ((char *) symtab->symbol + nsyms * sizeof(struct old_module_symbol));
+
+ for (i = 0; i < n_ext_modules; ++i)
+ if (ext_modules[i].used)
+ ref++->module = ext_modules[i].addr;
+ }
+ }
+
+ /* Fill in routines. */
+
+ routines.init =
+ obj_symbol_final_value(f, obj_find_symbol(f, "init_module"));
+ routines.cleanup =
+ obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module"));
+
+ /* Whew! All of the initialization is complete. Collect the final
+ module image and give it to the kernel. */
+
+ image = xmalloc(m_size);
+ obj_create_image(f, image);
+
+ /* image holds the complete relocated module, accounting correctly for
+ mod_use_count. However the old module kernel support assume that
+ it is receiving something which does not contain mod_use_count. */
+ ret = old_sys_init_module(m_name, image + sizeof(long),
+ m_size | (flag_autoclean ? OLD_MOD_AUTOCLEAN
+ : 0), &routines, symtab);
+ if (ret)
+ errorMsg("init_module: %s: %s", m_name, strerror(errno));
+
+ free(image);
+ free(symtab);
+
+ return ret == 0;
+}
+
+#else
+
+#define old_create_mod_use_count(x) TRUE
+#define old_init_module(x, y, z) TRUE
+
+#endif /* BB_FEATURE_INSMOD_OLD_KERNEL */
+
+
+
+/*======================================================================*/
+/* Functions relating to module loading after 2.1.18. */
+
+static int
+new_process_module_arguments(struct obj_file *f, int argc, char **argv)
+{
+ while (argc > 0) {
+ char *p, *q, *key;
+ struct obj_symbol *sym;
+ char *contents, *loc;
+ int min, max, n;
+
+ p = *argv;
+ if ((q = strchr(p, '=')) == NULL) {
+ argc--;
+ continue;
+ }
+
+ key = alloca(q - p + 6);
+ memcpy(key, "parm_", 5);
+ memcpy(key + 5, p, q - p);
+ key[q - p + 5] = 0;
+
+ p = get_modinfo_value(f, key);
+ key += 5;
+ if (p == NULL) {
+ errorMsg("invalid parameter %s\n", key);
+ return 0;
+ }
+
+ sym = obj_find_symbol(f, key);
+
+ /* Also check that the parameter was not resolved from the kernel. */
+ if (sym == NULL || sym->secidx > SHN_HIRESERVE) {
+ errorMsg("symbol for parameter %s not found\n", key);
+ return 0;
+ }
+
+ if (isdigit(*p)) {
+ min = strtoul(p, &p, 10);
+ if (*p == '-')
+ max = strtoul(p + 1, &p, 10);
+ else
+ max = min;
+ } else
+ min = max = 1;
+
+ contents = f->sections[sym->secidx]->contents;
+ loc = contents + sym->value;
+ n = (*++q != '\0');
+
+ while (1) {
+ if ((*p == 's') || (*p == 'c')) {
+ char *str;
+
+ /* Do C quoting if we begin with a ", else slurp the lot. */
+ if (*q == '"') {
+ char *r;
+
+ str = alloca(strlen(q));
+ for (r = str, q++; *q != '"'; ++q, ++r) {
+ if (*q == '\0') {
+ errorMsg("improperly terminated string argument for %s\n",
+ key);
+ return 0;
+ } else if (*q == '\\')
+ switch (*++q) {
+ case 'a':
+ *r = '\a';
+ break;
+ case 'b':
+ *r = '\b';
+ break;
+ case 'e':
+ *r = '\033';
+ break;
+ case 'f':
+ *r = '\f';
+ break;
+ case 'n':
+ *r = '\n';
+ break;
+ case 'r':
+ *r = '\r';
+ break;
+ case 't':
+ *r = '\t';
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ int c = *q - '0';
+ if (q[1] >= '0' && q[1] <= '7') {
+ c = (c * 8) + *++q - '0';
+ if (q[1] >= '0' && q[1] <= '7')
+ c = (c * 8) + *++q - '0';
+ }
+ *r = c;
+ }
+ break;
+
+ default:
+ *r = *q;
+ break;
+ } else
+ *r = *q;
+ }
+ *r = '\0';
+ ++q;
+ } else {
+ char *r;
+
+ /* In this case, the string is not quoted. We will break
+ it using the coma (like for ints). If the user wants to
+ include comas in a string, he just has to quote it */
+
+ /* Search the next coma */
+ r = strchr(q, ',');
+
+ /* Found ? */
+ if (r != (char *) NULL) {
+ /* Recopy the current field */
+ str = alloca(r - q + 1);
+ memcpy(str, q, r - q);
+
+ /* I don't know if it is usefull, as the previous case
+ doesn't null terminate the string ??? */
+ str[r - q] = '\0';
+
+ /* Keep next fields */
+ q = r;
+ } else {
+ /* last string */
+ str = q;
+ q = "";
+ }
+ }
+
+ if (*p == 's') {
+ /* Normal string */
+ obj_string_patch(f, sym->secidx, loc - contents, str);
+ loc += tgt_sizeof_char_p;
+ } else {
+ /* Array of chars (in fact, matrix !) */
+ unsigned long charssize; /* size of each member */
+
+ /* Get the size of each member */
+ /* Probably we should do that outside the loop ? */
+ if (!isdigit(*(p + 1))) {
+ errorMsg("parameter type 'c' for %s must be followed by"
+ " the maximum size\n", key);
+ return 0;
+ }
+ charssize = strtoul(p + 1, (char **) NULL, 10);
+
+ /* Check length */
+ if (strlen(str) >= charssize) {
+ errorMsg("string too long for %s (max %ld)\n", key,
+ charssize - 1);
+ return 0;
+ }
+
+ /* Copy to location */
+ strcpy((char *) loc, str);
+ loc += charssize;
+ }
+ } else {
+ long v = strtoul(q, &q, 0);
+ switch (*p) {
+ case 'b':
+ *loc++ = v;
+ break;
+ case 'h':
+ *(short *) loc = v;
+ loc += tgt_sizeof_short;
+ break;
+ case 'i':
+ *(int *) loc = v;
+ loc += tgt_sizeof_int;
+ break;
+ case 'l':
+ *(long *) loc = v;
+ loc += tgt_sizeof_long;
+ break;
+
+ default:
+ errorMsg("unknown parameter type '%c' for %s\n", *p, key);
+ return 0;
+ }
+ }
+
+ retry_end_of_value:
+ switch (*q) {
+ case '\0':
+ goto end_of_arg;
+
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ ++q;
+ goto retry_end_of_value;
+
+ case ',':
+ if (++n > max) {
+ errorMsg("too many values for %s (max %d)\n", key, max);
+ return 0;
+ }
+ ++q;
+ break;
+
+ default:
+ errorMsg("invalid argument syntax for %s\n", key);
+ return 0;
+ }
+ }
+
+ end_of_arg:
+ if (n < min) {
+ errorMsg("too few values for %s (min %d)\n", key, min);
+ return 0;
+ }
+
+ argc--, argv++;
+ }
+
+ return 1;
+}
+
+#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
+static int new_is_module_checksummed(struct obj_file *f)
+{
+ const char *p = get_modinfo_value(f, "using_checksums");
+ if (p)
+ return atoi(p);
+ else
+ return 0;
+}
+
+/* Get the module's kernel version in the canonical integer form. */
+
+static int
+new_get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
+{
+ char *p, *q;
+ int a, b, c;
+
+ p = get_modinfo_value(f, "kernel_version");
+ if (p == NULL)
+ return -1;
+ strncpy(str, p, STRVERSIONLEN);
+
+ a = strtoul(p, &p, 10);
+ if (*p != '.')
+ return -1;
+ b = strtoul(p + 1, &p, 10);
+ if (*p != '.')
+ return -1;
+ c = strtoul(p + 1, &q, 10);
+ if (p + 1 == q)
+ return -1;
+
+ return a << 16 | b << 8 | c;
+}
+
+#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */
+
+
+#ifdef BB_FEATURE_INSMOD_NEW_KERNEL
+
+/* Fetch the loaded modules, and all currently exported symbols. */
+
+static int new_get_kernel_symbols(void)
+{
+ char *module_names, *mn;
+ struct external_module *modules, *m;
+ struct new_module_symbol *syms, *s;
+ size_t ret, bufsize, nmod, nsyms, i, j;
+
+ /* Collect the loaded modules. */
+
+ module_names = xmalloc(bufsize = 256);
+ retry_modules_load:
+ if (query_module(NULL, QM_MODULES, module_names, bufsize, &ret)) {
+ if (errno == ENOSPC) {
+ module_names = xrealloc(module_names, bufsize = ret);
+ goto retry_modules_load;
+ }
+ errorMsg("QM_MODULES: %s", strerror(errno));
+ return 0;
+ }
+
+ n_ext_modules = nmod = ret;
+ ext_modules = modules = xmalloc(nmod * sizeof(*modules));
+ memset(modules, 0, nmod * sizeof(*modules));
+
+ /* Collect the modules' symbols. */
+
+ for (i = 0, mn = module_names, m = modules;
+ i < nmod; ++i, ++m, mn += strlen(mn) + 1) {
+ struct new_module_info info;
+
+ if (query_module(mn, QM_INFO, &info, sizeof(info), &ret)) {
+ if (errno == ENOENT) {
+ /* The module was removed out from underneath us. */
+ continue;
+ }
+ errorMsg("query_module: QM_INFO: %s: %s", mn, strerror(errno));
+ return 0;
+ }
+
+ syms = xmalloc(bufsize = 1024);
+ retry_mod_sym_load:
+ if (query_module(mn, QM_SYMBOLS, syms, bufsize, &ret)) {
+ switch (errno) {
+ case ENOSPC:
+ syms = xrealloc(syms, bufsize = ret);
+ goto retry_mod_sym_load;
+ case ENOENT:
+ /* The module was removed out from underneath us. */
+ continue;
+ default:
+ errorMsg("query_module: QM_SYMBOLS: %s: %s", mn, strerror(errno));
+ return 0;
+ }
+ }
+ nsyms = ret;
+
+ m->name = mn;
+ m->addr = info.addr;
+ m->nsyms = nsyms;
+ m->syms = syms;
+
+ for (j = 0, s = syms; j < nsyms; ++j, ++s) {
+ s->name += (unsigned long) syms;
+ }
+ }
+
+ /* Collect the kernel's symbols. */
+
+ syms = xmalloc(bufsize = 16 * 1024);
+ retry_kern_sym_load:
+ if (query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)) {
+ if (errno == ENOSPC) {
+ syms = xrealloc(syms, bufsize = ret);
+ goto retry_kern_sym_load;
+ }
+ errorMsg("kernel: QM_SYMBOLS: %s", strerror(errno));
+ return 0;
+ }
+ nksyms = nsyms = ret;
+ ksyms = syms;
+
+ for (j = 0, s = syms; j < nsyms; ++j, ++s) {
+ s->name += (unsigned long) syms;
+ }
+ return 1;
+}
+
+
+/* Return the kernel symbol checksum version, or zero if not used. */
+
+static int new_is_kernel_checksummed(void)
+{
+ struct new_module_symbol *s;
+ size_t i;
+
+ /* Using_Versions is not the first symbol, but it should be in there. */
+
+ for (i = 0, s = ksyms; i < nksyms; ++i, ++s)
+ if (strcmp((char *) s->name, "Using_Versions") == 0)
+ return s->value;
+
+ return 0;
+}
+
+
+static int new_create_this_module(struct obj_file *f, const char *m_name)
+{
+ struct obj_section *sec;
+
+ sec = obj_create_alloced_section_first(f, ".this", tgt_sizeof_long,
+ sizeof(struct new_module));
+ memset(sec->contents, 0, sizeof(struct new_module));
+
+ obj_add_symbol(f, "__this_module", -1,
+ ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0,
+ sizeof(struct new_module));
+
+ obj_string_patch(f, sec->idx, offsetof(struct new_module, name),
+ m_name);
+
+ return 1;
+}
+
+
+static int new_create_module_ksymtab(struct obj_file *f)
+{
+ struct obj_section *sec;
+ int i;
+
+ /* We must always add the module references. */
+
+ if (n_ext_modules_used) {
+ struct new_module_ref *dep;
+ struct obj_symbol *tm;
+
+ sec = obj_create_alloced_section(f, ".kmodtab", tgt_sizeof_void_p,
+ (sizeof(struct new_module_ref)
+ * n_ext_modules_used));
+ if (!sec)
+ return 0;
+
+ tm = obj_find_symbol(f, "__this_module");
+ dep = (struct new_module_ref *) sec->contents;
+ for (i = 0; i < n_ext_modules; ++i)
+ if (ext_modules[i].used) {
+ dep->dep = ext_modules[i].addr;
+ obj_symbol_patch(f, sec->idx,
+ (char *) &dep->ref - sec->contents, tm);
+ dep->next_ref = 0;
+ ++dep;
+ }
+ }
+
+ if (flag_export && !obj_find_section(f, "__ksymtab")) {
+ size_t nsyms;
+ int *loaded;
+
+ sec =
+ obj_create_alloced_section(f, "__ksymtab", tgt_sizeof_void_p,
+ 0);
+
+ /* We don't want to export symbols residing in sections that
+ aren't loaded. There are a number of these created so that
+ we make sure certain module options don't appear twice. */
+
+ loaded = alloca(sizeof(int) * (i = f->header.e_shnum));
+ while (--i >= 0)
+ loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0;
+
+ for (nsyms = i = 0; i < HASH_BUCKETS; ++i) {
+ struct obj_symbol *sym;
+ for (sym = f->symtab[i]; sym; sym = sym->next)
+ if (ELFW(ST_BIND) (sym->info) != STB_LOCAL
+ && sym->secidx <= SHN_HIRESERVE
+ && (sym->secidx >= SHN_LORESERVE
+ || loaded[sym->secidx])) {
+ ElfW(Addr) ofs = nsyms * 2 * tgt_sizeof_void_p;
+
+ obj_symbol_patch(f, sec->idx, ofs, sym);
+ obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p,
+ sym->name);
+
+ nsyms++;
+ }
+ }
+
+ obj_extend_section(sec, nsyms * 2 * tgt_sizeof_char_p);
+ }
+
+ return 1;
+}
+
+
+static int
+new_init_module(const char *m_name, struct obj_file *f,
+ unsigned long m_size)
+{
+ struct new_module *module;
+ struct obj_section *sec;
+ void *image;
+ int ret;
+ tgt_long m_addr;
+
+ sec = obj_find_section(f, ".this");
+ module = (struct new_module *) sec->contents;
+ m_addr = sec->header.sh_addr;
+
+ module->size_of_struct = sizeof(*module);
+ module->size = m_size;
+ module->flags = flag_autoclean ? NEW_MOD_AUTOCLEAN : 0;
+
+ sec = obj_find_section(f, "__ksymtab");
+ if (sec && sec->header.sh_size) {
+ module->syms = sec->header.sh_addr;
+ module->nsyms = sec->header.sh_size / (2 * tgt_sizeof_char_p);
+ }
+
+ if (n_ext_modules_used) {
+ sec = obj_find_section(f, ".kmodtab");
+ module->deps = sec->header.sh_addr;
+ module->ndeps = n_ext_modules_used;
+ }
+
+ module->init =
+ obj_symbol_final_value(f, obj_find_symbol(f, "init_module"));
+ module->cleanup =
+ obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module"));
+
+ sec = obj_find_section(f, "__ex_table");
+ if (sec) {
+ module->ex_table_start = sec->header.sh_addr;
+ module->ex_table_end = sec->header.sh_addr + sec->header.sh_size;
+ }
+
+ sec = obj_find_section(f, ".text.init");
+ if (sec) {
+ module->runsize = sec->header.sh_addr - m_addr;
+ }
+ sec = obj_find_section(f, ".data.init");
+ if (sec) {
+ if (!module->runsize ||
+ module->runsize > sec->header.sh_addr - m_addr)
+ module->runsize = sec->header.sh_addr - m_addr;
+ }
+
+ if (!arch_init_module(f, module))
+ return 0;
+
+ /* Whew! All of the initialization is complete. Collect the final
+ module image and give it to the kernel. */
+
+ image = xmalloc(m_size);
+ obj_create_image(f, image);
+
+ ret = new_sys_init_module(m_name, (struct new_module *) image);
+ if (ret)
+ errorMsg("init_module: %s: %s", m_name, strerror(errno));
+
+ free(image);
+
+ return ret == 0;
+}
+
+#else
+
+#define new_init_module(x, y, z) TRUE
+#define new_create_this_module(x, y) 0
+#define new_create_module_ksymtab(x)
+
+#endif /* BB_FEATURE_INSMOD_OLD_KERNEL */
+
+
+/*======================================================================*/
+
+int
+obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
+ const char *string)
+{
+ struct obj_string_patch *p;
+ struct obj_section *strsec;
+ size_t len = strlen(string) + 1;
+ char *loc;
+
+ p = xmalloc(sizeof(*p));
+ p->next = f->string_patches;
+ p->reloc_secidx = secidx;
+ p->reloc_offset = offset;
+ f->string_patches = p;
+
+ strsec = obj_find_section(f, ".kstrtab");
+ if (strsec == NULL) {
+ strsec = obj_create_alloced_section(f, ".kstrtab", 1, len);
+ p->string_offset = 0;
+ loc = strsec->contents;
+ } else {
+ p->string_offset = strsec->header.sh_size;
+ loc = obj_extend_section(strsec, len);
+ }
+ memcpy(loc, string, len);
+
+ return 1;
+}
+
+int
+obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
+ struct obj_symbol *sym)
+{
+ struct obj_symbol_patch *p;
+
+ p = xmalloc(sizeof(*p));
+ p->next = f->symbol_patches;
+ p->reloc_secidx = secidx;
+ p->reloc_offset = offset;
+ p->sym = sym;
+ f->symbol_patches = p;
+
+ return 1;
+}
+
+int obj_check_undefineds(struct obj_file *f)
+{
+ unsigned long i;
+ int ret = 1;
+
+ for (i = 0; i < HASH_BUCKETS; ++i) {
+ struct obj_symbol *sym;
+ for (sym = f->symtab[i]; sym; sym = sym->next)
+ if (sym->secidx == SHN_UNDEF) {
+ if (ELFW(ST_BIND) (sym->info) == STB_WEAK) {
+ sym->secidx = SHN_ABS;
+ sym->value = 0;
+ } else {
+ errorMsg("unresolved symbol %s\n", sym->name);
+ ret = 0;
+ }
+ }
+ }
+
+ return ret;
+}
+
+void obj_allocate_commons(struct obj_file *f)
+{
+ struct common_entry {
+ struct common_entry *next;
+ struct obj_symbol *sym;
+ } *common_head = NULL;
+
+ unsigned long i;
+
+ for (i = 0; i < HASH_BUCKETS; ++i) {
+ struct obj_symbol *sym;
+ for (sym = f->symtab[i]; sym; sym = sym->next)
+ if (sym->secidx == SHN_COMMON) {
+ /* Collect all COMMON symbols and sort them by size so as to
+ minimize space wasted by alignment requirements. */
+ {
+ struct common_entry **p, *n;
+ for (p = &common_head; *p; p = &(*p)->next)
+ if (sym->size <= (*p)->sym->size)
+ break;
+
+ n = alloca(sizeof(*n));
+ n->next = *p;
+ n->sym = sym;
+ *p = n;
+ }
+ }
+ }
+
+ for (i = 1; i < f->local_symtab_size; ++i) {
+ struct obj_symbol *sym = f->local_symtab[i];
+ if (sym && sym->secidx == SHN_COMMON) {
+ struct common_entry **p, *n;
+ for (p = &common_head; *p; p = &(*p)->next)
+ if (sym == (*p)->sym)
+ break;
+ else if (sym->size < (*p)->sym->size) {
+ n = alloca(sizeof(*n));
+ n->next = *p;
+ n->sym = sym;
+ *p = n;
+ break;
+ }
+ }
+ }
+
+ if (common_head) {
+ /* Find the bss section. */
+ for (i = 0; i < f->header.e_shnum; ++i)
+ if (f->sections[i]->header.sh_type == SHT_NOBITS)
+ break;
+
+ /* If for some reason there hadn't been one, create one. */
+ if (i == f->header.e_shnum) {
+ struct obj_section *sec;
+
+ f->sections = xrealloc(f->sections, (i + 1) * sizeof(sec));
+ f->sections[i] = sec = arch_new_section();
+ f->header.e_shnum = i + 1;
+
+ memset(sec, 0, sizeof(*sec));
+ sec->header.sh_type = SHT_PROGBITS;
+ sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
+ sec->name = ".bss";
+ sec->idx = i;
+ }
+
+ /* Allocate the COMMONS. */
+ {
+ ElfW(Addr) bss_size = f->sections[i]->header.sh_size;
+ ElfW(Addr) max_align = f->sections[i]->header.sh_addralign;
+ struct common_entry *c;
+
+ for (c = common_head; c; c = c->next) {
+ ElfW(Addr) align = c->sym->value;
+
+ if (align > max_align)
+ max_align = align;
+ if (bss_size & (align - 1))
+ bss_size = (bss_size | (align - 1)) + 1;
+
+ c->sym->secidx = i;
+ c->sym->value = bss_size;
+
+ bss_size += c->sym->size;
+ }
+
+ f->sections[i]->header.sh_size = bss_size;
+ f->sections[i]->header.sh_addralign = max_align;
+ }
+ }
+
+ /* For the sake of patch relocation and parameter initialization,
+ allocate zeroed data for NOBITS sections now. Note that after
+ this we cannot assume NOBITS are really empty. */
+ for (i = 0; i < f->header.e_shnum; ++i) {
+ struct obj_section *s = f->sections[i];
+ if (s->header.sh_type == SHT_NOBITS) {
+ s->contents = memset(xmalloc(s->header.sh_size),
+ 0, s->header.sh_size);
+ s->header.sh_type = SHT_PROGBITS;
+ }
+ }
+}
+
+unsigned long obj_load_size(struct obj_file *f)
+{
+ unsigned long dot = 0;
+ struct obj_section *sec;
+
+ /* Finalize the positions of the sections relative to one another. */
+
+ for (sec = f->load_order; sec; sec = sec->load_next) {
+ ElfW(Addr) align;
+
+ align = sec->header.sh_addralign;
+ if (align && (dot & (align - 1)))
+ dot = (dot | (align - 1)) + 1;
+
+ sec->header.sh_addr = dot;
+ dot += sec->header.sh_size;
+ }
+
+ return dot;
+}
+
+int obj_relocate(struct obj_file *f, ElfW(Addr) base)
+{
+ int i, n = f->header.e_shnum;
+ int ret = 1;
+
+ /* Finalize the addresses of the sections. */
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+
+ /* And iterate over all of the relocations. */
+
+ for (i = 0; i < n; ++i) {
+ struct obj_section *relsec, *symsec, *targsec, *strsec;
+ ElfW(RelM) * rel, *relend;
+ ElfW(Sym) * symtab;
+ const char *strtab;
+
+ relsec = f->sections[i];
+ if (relsec->header.sh_type != SHT_RELM)
+ continue;
+
+ symsec = f->sections[relsec->header.sh_link];
+ targsec = f->sections[relsec->header.sh_info];
+ strsec = f->sections[symsec->header.sh_link];
+
+ rel = (ElfW(RelM) *) relsec->contents;
+ relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM)));
+ symtab = (ElfW(Sym) *) symsec->contents;
+ strtab = (const char *) strsec->contents;
+
+ for (; rel < relend; ++rel) {
+ ElfW(Addr) value = 0;
+ struct obj_symbol *intsym = NULL;
+ unsigned long symndx;
+ ElfW(Sym) * extsym = 0;
+ const char *errmsg;
+
+ /* Attempt to find a value to use for this relocation. */
+
+ symndx = ELFW(R_SYM) (rel->r_info);
+ if (symndx) {
+ /* Note we've already checked for undefined symbols. */
+
+ extsym = &symtab[symndx];
+ if (ELFW(ST_BIND) (extsym->st_info) == STB_LOCAL) {
+ /* Local symbols we look up in the local table to be sure
+ we get the one that is really intended. */
+ intsym = f->local_symtab[symndx];
+ } else {
+ /* Others we look up in the hash table. */
+ const char *name;
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ intsym = obj_find_symbol(f, name);
+ }
+
+ value = obj_symbol_final_value(f, intsym);
+ intsym->referenced = 1;
+ }
+#if SHT_RELM == SHT_RELA
+#if defined(__alpha__) && defined(AXP_BROKEN_GAS)
+ /* Work around a nasty GAS bug, that is fixed as of 2.7.0.9. */
+ if (!extsym || !extsym->st_name ||
+ ELFW(ST_BIND) (extsym->st_info) != STB_LOCAL)
+#endif
+ value += rel->r_addend;
+#endif
+
+ /* Do it! */
+ switch (arch_apply_relocation
+ (f, targsec, symsec, intsym, rel, value)) {
+ case obj_reloc_ok:
+ break;
+
+ case obj_reloc_overflow:
+ errmsg = "Relocation overflow";
+ goto bad_reloc;
+ case obj_reloc_dangerous:
+ errmsg = "Dangerous relocation";
+ goto bad_reloc;
+ case obj_reloc_unhandled:
+ errmsg = "Unhandled relocation";
+ bad_reloc:
+ if (extsym) {
+ errorMsg("%s of type %ld for %s\n", errmsg,
+ (long) ELFW(R_TYPE) (rel->r_info),
+ strtab + extsym->st_name);
+ } else {
+ errorMsg("%s of type %ld\n", errmsg,
+ (long) ELFW(R_TYPE) (rel->r_info));
+ }
+ ret = 0;
+ break;
+ }
+ }
+ }
+
+ /* Finally, take care of the patches. */
+
+ if (f->string_patches) {
+ struct obj_string_patch *p;
+ struct obj_section *strsec;
+ ElfW(Addr) strsec_base;
+ strsec = obj_find_section(f, ".kstrtab");
+ strsec_base = strsec->header.sh_addr;
+
+ for (p = f->string_patches; p; p = p->next) {
+ struct obj_section *targsec = f->sections[p->reloc_secidx];
+ *(ElfW(Addr) *) (targsec->contents + p->reloc_offset)
+ = strsec_base + p->string_offset;
+ }
+ }
+
+ if (f->symbol_patches) {
+ struct obj_symbol_patch *p;
+
+ for (p = f->symbol_patches; p; p = p->next) {
+ struct obj_section *targsec = f->sections[p->reloc_secidx];
+ *(ElfW(Addr) *) (targsec->contents + p->reloc_offset)
+ = obj_symbol_final_value(f, p->sym);
+ }
+ }
+
+ return ret;
+}
+
+int obj_create_image(struct obj_file *f, char *image)
+{
+ struct obj_section *sec;
+ ElfW(Addr) base = f->baseaddr;
+
+ for (sec = f->load_order; sec; sec = sec->load_next) {
+ char *secimg;
+
+ if (sec->header.sh_size == 0)
+ continue;
+
+ secimg = image + (sec->header.sh_addr - base);
+
+ /* Note that we allocated data for NOBITS sections earlier. */
+ memcpy(secimg, sec->contents, sec->header.sh_size);
+ }
+
+ return 1;
+}
+
+/*======================================================================*/
+
+struct obj_file *obj_load(FILE * fp)
+{
+ struct obj_file *f;
+ ElfW(Shdr) * section_headers;
+ int shnum, i;
+ char *shstrtab;
+
+ /* Read the file header. */
+
+ f = arch_new_file();
+ memset(f, 0, sizeof(*f));
+ f->symbol_cmp = strcmp;
+ f->symbol_hash = obj_elf_hash;
+ f->load_order_search_start = &f->load_order;
+
+ fseek(fp, 0, SEEK_SET);
+ if (fread(&f->header, sizeof(f->header), 1, fp) != 1) {
+ errorMsg("error reading ELF header: %s", strerror(errno));
+ return NULL;
+ }
+
+ if (f->header.e_ident[EI_MAG0] != ELFMAG0
+ || f->header.e_ident[EI_MAG1] != ELFMAG1
+ || f->header.e_ident[EI_MAG2] != ELFMAG2
+ || f->header.e_ident[EI_MAG3] != ELFMAG3) {
+ errorMsg("not an ELF file\n");
+ return NULL;
+ }
+ if (f->header.e_ident[EI_CLASS] != ELFCLASSM
+ || f->header.e_ident[EI_DATA] != ELFDATAM
+ || f->header.e_ident[EI_VERSION] != EV_CURRENT
+ || !MATCH_MACHINE(f->header.e_machine)) {
+ errorMsg("ELF file not for this architecture\n");
+ return NULL;
+ }
+ if (f->header.e_type != ET_REL) {
+ errorMsg("ELF file not a relocatable object\n");
+ return NULL;
+ }
+
+ /* Read the section headers. */
+
+ if (f->header.e_shentsize != sizeof(ElfW(Shdr))) {
+ errorMsg("section header size mismatch: %lu != %lu\n",
+ (unsigned long) f->header.e_shentsize,
+ (unsigned long) sizeof(ElfW(Shdr)));
+ return NULL;
+ }
+
+ shnum = f->header.e_shnum;
+ f->sections = xmalloc(sizeof(struct obj_section *) * shnum);
+ memset(f->sections, 0, sizeof(struct obj_section *) * shnum);
+
+ section_headers = alloca(sizeof(ElfW(Shdr)) * shnum);
+ fseek(fp, f->header.e_shoff, SEEK_SET);
+ if (fread(section_headers, sizeof(ElfW(Shdr)), shnum, fp) != shnum) {
+ errorMsg("error reading ELF section headers: %s", strerror(errno));
+ return NULL;
+ }
+
+ /* Read the section data. */
+
+ for (i = 0; i < shnum; ++i) {
+ struct obj_section *sec;
+
+ f->sections[i] = sec = arch_new_section();
+ memset(sec, 0, sizeof(*sec));
+
+ sec->header = section_headers[i];
+ sec->idx = i;
+
+ switch (sec->header.sh_type) {
+ case SHT_NULL:
+ case SHT_NOTE:
+ case SHT_NOBITS:
+ /* ignore */
+ break;
+
+ case SHT_PROGBITS:
+ case SHT_SYMTAB:
+ case SHT_STRTAB:
+ case SHT_RELM:
+ if (sec->header.sh_size > 0) {
+ sec->contents = xmalloc(sec->header.sh_size);
+ fseek(fp, sec->header.sh_offset, SEEK_SET);
+ if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) {
+ errorMsg("error reading ELF section data: %s", strerror(errno));
+ return NULL;
+ }
+ } else {
+ sec->contents = NULL;
+ }
+ break;
+
+#if SHT_RELM == SHT_REL
+ case SHT_RELA:
+ errorMsg("RELA relocations not supported on this architecture\n");
+ return NULL;
+#else
+ case SHT_REL:
+ errorMsg("REL relocations not supported on this architecture\n");
+ return NULL;
+#endif
+
+ default:
+ if (sec->header.sh_type >= SHT_LOPROC) {
+ /* Assume processor specific section types are debug
+ info and can safely be ignored. If this is ever not
+ the case (Hello MIPS?), don't put ifdefs here but
+ create an arch_load_proc_section(). */
+ break;
+ }
+
+ errorMsg("can't handle sections of type %ld\n",
+ (long) sec->header.sh_type);
+ return NULL;
+ }
+ }
+
+ /* Do what sort of interpretation as needed by each section. */
+
+ shstrtab = f->sections[f->header.e_shstrndx]->contents;
+
+ for (i = 0; i < shnum; ++i) {
+ struct obj_section *sec = f->sections[i];
+ sec->name = shstrtab + sec->header.sh_name;
+ }
+
+ for (i = 0; i < shnum; ++i) {
+ struct obj_section *sec = f->sections[i];
+
+ if (sec->header.sh_flags & SHF_ALLOC)
+ obj_insert_section_load_order(f, sec);
+
+ switch (sec->header.sh_type) {
+ case SHT_SYMTAB:
+ {
+ unsigned long nsym, j;
+ char *strtab;
+ ElfW(Sym) * sym;
+
+ if (sec->header.sh_entsize != sizeof(ElfW(Sym))) {
+ errorMsg("symbol size mismatch: %lu != %lu\n",
+ (unsigned long) sec->header.sh_entsize,
+ (unsigned long) sizeof(ElfW(Sym)));
+ return NULL;
+ }
+
+ nsym = sec->header.sh_size / sizeof(ElfW(Sym));
+ strtab = f->sections[sec->header.sh_link]->contents;
+ sym = (ElfW(Sym) *) sec->contents;
+
+ /* Allocate space for a table of local symbols. */
+ j = f->local_symtab_size = sec->header.sh_info;
+ f->local_symtab = xmalloc(j *=
+ sizeof(struct obj_symbol *));
+ memset(f->local_symtab, 0, j);
+
+ /* Insert all symbols into the hash table. */
+ for (j = 1, ++sym; j < nsym; ++j, ++sym) {
+ const char *name;
+ if (sym->st_name)
+ name = strtab + sym->st_name;
+ else
+ name = f->sections[sym->st_shndx]->name;
+
+ obj_add_symbol(f, name, j, sym->st_info, sym->st_shndx,
+ sym->st_value, sym->st_size);
+ }
+ }
+ break;
+
+ case SHT_RELM:
+ if (sec->header.sh_entsize != sizeof(ElfW(RelM))) {
+ errorMsg("relocation entry size mismatch: %lu != %lu\n",
+ (unsigned long) sec->header.sh_entsize,
+ (unsigned long) sizeof(ElfW(RelM)));
+ return NULL;
+ }
+ break;
+ }
+ }
+
+ return f;
+}
+
+static void hide_special_symbols(struct obj_file *f)
+{
+ static const char *const specials[] = {
+ "cleanup_module",
+ "init_module",
+ "kernel_version",
+ NULL
+ };
+
+ struct obj_symbol *sym;
+ const char *const *p;
+
+ for (p = specials; *p; ++p)
+ if ((sym = obj_find_symbol(f, *p)) != NULL)
+ sym->info =
+ ELFW(ST_INFO) (STB_LOCAL, ELFW(ST_TYPE) (sym->info));
+}
+
+
+void my_usage(void)
+{
+ printf("Usage.\n");
+ exit(0);
+}
+
+extern int insmod_main( int argc, char **argv)
+{
+ int k_crcs;
+ int k_new_syscalls;
+ int len;
+ char *tmp;
+ unsigned long m_size;
+ ElfW(Addr) m_addr;
+ FILE *fp;
+ struct obj_file *f;
+ char m_name[BUFSIZ + 1] = "\0";
+ int exit_status = FALSE;
+ int m_has_modinfo;
+#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
+ int k_version;
+ char k_strversion[STRVERSIONLEN];
+ char m_strversion[STRVERSIONLEN];
+ int m_version;
+ int m_crcs;
+#endif
+
+
+ if (argc <= 1)
+ my_usage();
+
+ /* Parse any options */
+ while (--argc > 0 && **(++argv) == '-') {
+ while (*(++(*argv))) {
+ switch (**argv) {
+ case 'f': /* force loading */
+ flag_force_load = 1;
+ break;
+ case 'k': /* module loaded by kerneld, auto-cleanable */
+ flag_autoclean = 1;
+ break;
+ case 'x': /* do not export externs */
+ flag_export = 0;
+ break;
+ default:
+ my_usage();
+ }
+ }
+ }
+
+ if (argc <= 0)
+ my_usage();
+ /* Grab the module name */
+ if ((tmp = strrchr(*argv, '/')) != NULL) {
+ tmp++;
+ } else {
+ tmp = *argv;
+ }
+ len = strlen(tmp);
+
+ if (len > 2 && tmp[len - 2] == '.' && tmp[len - 1] == 'o')
+ len -= 2;
+ memcpy(m_name, tmp, len);
+ strcpy(m_fullName, m_name);
+ strcat(m_fullName, ".o");
+
+ /* Get a filedesc for the module */
+ if ((fp = fopen(*argv, "r")) == NULL) {
+ /* Hmpf. Could not open it. Search through _PATH_MODULES to find a module named m_name */
+ if (recursiveAction(_PATH_MODULES, TRUE, FALSE, FALSE,
+ findNamedModule, 0, m_fullName) == FALSE)
+ {
+ if (m_filename[0] == '\0'
+ || ((fp = fopen(m_filename, "r")) == NULL))
+ {
+ errorMsg("No module named '%s' found in '%s'\n", m_fullName, _PATH_MODULES);
+ return -1;
+ }
+ } else
+ fatalError("No module named '%s' found in '%s'\n", m_fullName, _PATH_MODULES);
+ } else
+ memcpy(m_filename, *argv, strlen(*argv));
+
+
+ if ((f = obj_load(fp)) == NULL) {
+ perror("Could not load the module\n");
+ return -1;
+ }
+
+ if (get_modinfo_value(f, "kernel_version") == NULL)
+ m_has_modinfo = 0;
+ else
+ m_has_modinfo = 1;
+
+#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
+ /* Version correspondence? */
+
+ k_version = get_kernel_version(k_strversion);
+ if (m_has_modinfo) {
+ m_version = new_get_module_version(f, m_strversion);
+ } else {
+ m_version = old_get_module_version(f, m_strversion);
+ if (m_version == -1) {
+ errorMsg("couldn't find the kernel version the module was "
+ "compiled for\n");
+ goto out;
+ }
+ }
+
+ if (strncmp(k_strversion, m_strversion, STRVERSIONLEN) != 0) {
+ if (flag_force_load) {
+ errorMsg("Warning: kernel-module version mismatch\n"
+ "\t%s was compiled for kernel version %s\n"
+ "\twhile this kernel is version %s\n",
+ m_filename, m_strversion, k_strversion);
+ } else {
+ errorMsg("kernel-module version mismatch\n"
+ "\t%s was compiled for kernel version %s\n"
+ "\twhile this kernel is version %s.\n",
+ m_filename, m_strversion, k_strversion);
+ goto out;
+ }
+ }
+ k_crcs = 0;
+#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */
+
+ k_new_syscalls = !query_module(NULL, 0, NULL, 0, NULL);
+
+ if (k_new_syscalls) {
+#ifdef BB_FEATURE_INSMOD_NEW_KERNEL
+ if (!new_get_kernel_symbols())
+ goto out;
+ k_crcs = new_is_kernel_checksummed();
+#else
+ errorMsg("Not configured to support new kernels\n");
+ goto out;
+#endif
+ } else {
+#ifdef BB_FEATURE_INSMOD_OLD_KERNEL
+ if (!old_get_kernel_symbols(m_name))
+ goto out;
+ k_crcs = old_is_kernel_checksummed();
+#else
+ errorMsg("Not configured to support old kernels\n");
+ goto out;
+#endif
+ }
+
+#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
+ if (m_has_modinfo)
+ m_crcs = new_is_module_checksummed(f);
+ else
+ m_crcs = old_is_module_checksummed(f);
+
+ if (m_crcs != k_crcs)
+ obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash);
+#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */
+
+ /* Let the module know about the kernel symbols. */
+ add_kernel_symbols(f);
+
+ /* Allocate common symbols, symbol tables, and string tables. */
+
+ if (k_new_syscalls
+ ? !new_create_this_module(f, m_name)
+ : !old_create_mod_use_count(f))
+ {
+ goto out;
+ }
+
+ if (!obj_check_undefineds(f)) {
+ goto out;
+ }
+ obj_allocate_commons(f);
+
+ if (optind < argc) {
+ if (m_has_modinfo
+ ? !new_process_module_arguments(f, argc - optind, argv + optind)
+ : !old_process_module_arguments(f, argc - optind, argv + optind))
+ {
+ goto out;
+ }
+ }
+
+ arch_create_got(f);
+ hide_special_symbols(f);
+
+ if (k_new_syscalls)
+ new_create_module_ksymtab(f);
+
+ /* Find current size of the module */
+ m_size = obj_load_size(f);
+
+
+ errno = 0;
+ m_addr = create_module(m_name, m_size);
+ switch (errno) {
+ case 0:
+ break;
+ case EEXIST:
+ errorMsg("A module named %s already exists\n", m_name);
+ /* Considered as a success in stage1 */
+ fclose(fp);
+ return(TRUE);
+ case ENOMEM:
+ errorMsg("Can't allocate kernel memory for module; needed %lu bytes\n",
+ m_size);
+ goto out;
+ default:
+ errorMsg("create_module: %s: %s", m_name, strerror(errno));
+ goto out;
+ }
+
+ if (!obj_relocate(f, m_addr)) {
+ delete_module(m_name);
+ goto out;
+ }
+
+ if (k_new_syscalls
+ ? !new_init_module(m_name, f, m_size)
+ : !old_init_module(m_name, f, m_size))
+ {
+ delete_module(m_name);
+ goto out;
+ }
+
+ exit_status = TRUE;
+
+out:
+ fclose(fp);
+ return(exit_status);
+}
+
+
+int insmod_call(char * full_filename)
+{
+ int argc = 2;
+ char *argv[2];
+ argv[0] = "stage1";
+ argv[1] = full_filename;
+ return insmod_main(argc, argv);
+}
diff --git a/mdk-stage1/insmod-busybox/loop.h b/mdk-stage1/insmod-busybox/loop.h
new file mode 100644
index 000000000..cba8c6b2b
--- /dev/null
+++ b/mdk-stage1/insmod-busybox/loop.h
@@ -0,0 +1,5 @@
+#include <linux/posix_types.h>
+#undef dev_t
+#define dev_t __kernel_dev_t
+#include <linux/loop.h>
+#undef dev_t
diff --git a/mdk-stage1/insmod-busybox/messages.c b/mdk-stage1/insmod-busybox/messages.c
new file mode 100644
index 000000000..81fd9c75c
--- /dev/null
+++ b/mdk-stage1/insmod-busybox/messages.c
@@ -0,0 +1,90 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2000 by BitterSweet Enterprises, LLC.
+ * Written by Karl M. Hegbloom <karlheg@debian.org>
+ *
+ * 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
+ *
+ */
+
+/*
+ * Let's put all of these messages in one place, and link this in as
+ * a separate object module, so that there are not going to be
+ * multiple non-unique but very similar strings in the binary.
+ * Perhaps this will make it simpler to internationalize also, and
+ * may make the binary slightly smaller.
+ */
+
+// To use this header file, include something like this:
+//
+//#define BB_DECLARE_EXTERN
+//#define bb_need_memory_exhausted
+//#include "messages.c"
+//
+//Then just use the string memory_exhausted when it is needed.
+//
+
+#include "busybox.h"
+#ifndef _BB_MESSAGES_C
+#define _BB_MESSAGES_C
+
+#ifdef BB_DECLARE_EXTERN
+# define BB_DEF_MESSAGE(symbol, string_const) extern const char *symbol;
+#else
+# define BB_DEF_MESSAGE(symbol, string_const) const char *symbol = string_const;
+#endif
+
+
+#if defined bb_need_full_version || ! defined BB_DECLARE_EXTERN
+ BB_DEF_MESSAGE(full_version,
+ "BusyBox v" BB_VER " (" BB_BT ") multi-call binary -- GPL2")
+#endif
+#if defined bb_need_name_too_long || ! defined BB_DECLARE_EXTERN
+ BB_DEF_MESSAGE(name_too_long, "file name too long\n")
+#endif
+#if defined bb_need_omitting_directory || ! defined BB_DECLARE_EXTERN
+ BB_DEF_MESSAGE(omitting_directory, "%s: omitting directory\n")
+#endif
+#if defined bb_need_not_a_directory || ! defined BB_DECLARE_EXTERN
+ BB_DEF_MESSAGE(not_a_directory, "%s: not a directory\n")
+#endif
+#if defined bb_need_memory_exhausted || ! defined BB_DECLARE_EXTERN
+ BB_DEF_MESSAGE(memory_exhausted, "memory exhausted\n")
+#endif
+#if defined bb_need_invalid_date || ! defined BB_DECLARE_EXTERN
+ BB_DEF_MESSAGE(invalid_date, "invalid date `%s'\n")
+#endif
+#if defined bb_need_invalid_option || ! defined BB_DECLARE_EXTERN
+ BB_DEF_MESSAGE(invalid_option, "invalid option -- %c\n")
+#endif
+#if defined bb_need_io_error || ! defined BB_DECLARE_EXTERN
+ BB_DEF_MESSAGE(io_error, "%s: input/output error -- %s\n")
+#endif
+#if defined bb_need_help || ! defined BB_DECLARE_EXTERN
+ BB_DEF_MESSAGE(dash_dash_help, "--help")
+#endif
+#if defined bb_need_write_error || ! defined BB_DECLARE_EXTERN
+ BB_DEF_MESSAGE(write_error, "Write Error\n")
+#endif
+#if defined bb_need_too_few_args || ! defined BB_DECLARE_EXTERN
+ BB_DEF_MESSAGE(too_few_args, "too few arguments\n")
+#endif
+#if defined bb_need_name_longer_then_foo || ! defined BB_DECLARE_EXTERN
+ BB_DEF_MESSAGE(name_longer_then_foo, "Names longer then %d chars not supported.\n")
+#endif
+
+
+#endif /* _BB_MESSAGES_C */
+
diff --git a/mdk-stage1/insmod-busybox/utility.c b/mdk-stage1/insmod-busybox/utility.c
new file mode 100644
index 000000000..35c169538
--- /dev/null
+++ b/mdk-stage1/insmod-busybox/utility.c
@@ -0,0 +1,1744 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) tons of folks. Tracking down who wrote what
+ * isn't something I'm going to worry about... If you wrote something
+ * here, please feel free to acknowledge your work.
+ *
+ * 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
+ *
+ * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
+ * Permission has been granted to redistribute this code under the GPL.
+ *
+ */
+
+#include "busybox.h"
+#if defined (BB_CHMOD_CHOWN_CHGRP) \
+ || defined (BB_CP_MV) \
+ || defined (BB_FIND) \
+ || defined (BB_INSMOD) \
+ || defined (BB_LS) \
+ || defined (BB_RM) \
+ || defined (BB_TAR)
+/* same conditions as recursiveAction */
+#define bb_need_name_too_long
+#endif
+#define bb_need_memory_exhausted
+#define bb_need_full_version
+#define BB_DECLARE_EXTERN
+#include "messages.c"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <time.h>
+#include <utime.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/ioctl.h>
+#include <sys/utsname.h> /* for uname(2) */
+
+/* Busybox mount uses either /proc/filesystems or /dev/mtab to get the
+ * list of available filesystems used for the -t auto option */
+#if defined BB_FEATURE_USE_PROCFS && defined BB_FEATURE_USE_DEVPS_PATCH
+//#error Sorry, but busybox can't use both /proc and /dev/ps at the same time -- Pick one and try again.
+#error "Sorry, but busybox can't use both /proc and /dev/ps at the same time -- Pick one and try again."
+#endif
+
+
+#if defined BB_MOUNT || defined BB_UMOUNT || defined BB_DF
+# if defined BB_MTAB
+const char mtab_file[] = "/etc/mtab";
+# else
+# if defined BB_FEATURE_USE_PROCFS
+const char mtab_file[] = "/proc/mounts";
+# else
+# if defined BB_FEATURE_USE_DEVPS_PATCH
+const char mtab_file[] = "/dev/mtab";
+# else
+# error With (BB_MOUNT||BB_UMOUNT||BB_DF) defined, you must define either BB_MTAB or ( BB_FEATURE_USE_PROCFS | BB_FEATURE_USE_DEVPS_PATCH)
+# endif
+# endif
+# endif
+#endif
+
+#ifdef _STANDALONE_
+extern void errorMsg(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ fflush(stdout);
+ fprintf(stderr, "busybox: ");
+ vfprintf(stderr, s, p);
+ va_end(p);
+ fflush(stderr);
+}
+
+extern void fatalError(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ fflush(stdout);
+ fprintf(stderr, "busybox: ");
+ vfprintf(stderr, s, p);
+ va_end(p);
+ fflush(stderr);
+ exit(FALSE);
+}
+#else /* _STANDALONE_ */
+#include "../log.h"
+extern void errorMsg(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ vlog_message_nobs(s, p);
+ va_end(p);
+}
+
+extern void fatalError(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ vlog_message_nobs(s, p);
+ va_end(p);
+ while (1);
+}
+#endif /* _STANDALONE_ */
+
+
+#if defined BB_INIT
+/* Returns kernel version encoded as major*65536 + minor*256 + patch,
+ * so, for example, to check if the kernel is greater than 2.2.11:
+ * if (get_kernel_revision() <= 2*65536+2*256+11) { <stuff> }
+ */
+extern int get_kernel_revision(void)
+{
+ struct utsname name;
+ int major = 0, minor = 0, patch = 0;
+
+ if (uname(&name) == -1) {
+ perror("cannot get system information");
+ return (0);
+ }
+ sscanf(name.version, "%d.%d.%d", &major, &minor, &patch);
+ return major * 65536 + minor * 256 + patch;
+}
+#endif /* BB_INIT */
+
+
+
+#if defined BB_FREE || defined BB_INIT || defined BB_UNAME || defined BB_UPTIME
+_syscall1(int, sysinfo, struct sysinfo *, info);
+#endif /* BB_INIT */
+
+#if defined BB_MOUNT || defined BB_UMOUNT
+
+#ifndef __NR_umount2
+#define __NR_umount2 52
+#endif
+
+/* Include our own version of <sys/mount.h>, since libc5 doesn't
+ * know about umount2 */
+extern _syscall1(int, umount, const char *, special_file);
+extern _syscall2(int, umount2, const char *, special_file, int, flags);
+extern _syscall5(int, mount, const char *, special_file, const char *, dir,
+ const char *, fstype, unsigned long int, rwflag, const void *, data);
+#endif
+
+#if defined BB_INSMOD || defined BB_LSMOD
+#ifndef __NR_query_module
+#define __NR_query_module 167
+#endif
+_syscall5(int, query_module, const char *, name, int, which,
+ void *, buf, size_t, bufsize, size_t*, ret);
+#endif
+
+
+#if defined (BB_CP_MV) || defined (BB_DU)
+
+#define HASH_SIZE 311 /* Should be prime */
+#define hash_inode(i) ((i) % HASH_SIZE)
+
+static ino_dev_hashtable_bucket_t *ino_dev_hashtable[HASH_SIZE];
+
+/*
+ * Return 1 if statbuf->st_ino && statbuf->st_dev are recorded in
+ * `ino_dev_hashtable', else return 0
+ *
+ * If NAME is a non-NULL pointer to a character pointer, and there is
+ * a match, then set *NAME to the value of the name slot in that
+ * bucket.
+ */
+int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name)
+{
+ ino_dev_hashtable_bucket_t *bucket;
+
+ bucket = ino_dev_hashtable[hash_inode(statbuf->st_ino)];
+ while (bucket != NULL) {
+ if ((bucket->ino == statbuf->st_ino) &&
+ (bucket->dev == statbuf->st_dev))
+ {
+ if (name) *name = bucket->name;
+ return 1;
+ }
+ bucket = bucket->next;
+ }
+ return 0;
+}
+
+/* Add statbuf to statbuf hash table */
+void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name)
+{
+ int i;
+ size_t s;
+ ino_dev_hashtable_bucket_t *bucket;
+
+ i = hash_inode(statbuf->st_ino);
+ s = name ? strlen(name) : 0;
+ bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + s);
+ bucket->ino = statbuf->st_ino;
+ bucket->dev = statbuf->st_dev;
+ if (name)
+ strcpy(bucket->name, name);
+ else
+ bucket->name[0] = '\0';
+ bucket->next = ino_dev_hashtable[i];
+ ino_dev_hashtable[i] = bucket;
+}
+
+/* Clear statbuf hash table */
+void reset_ino_dev_hashtable(void)
+{
+ int i;
+ ino_dev_hashtable_bucket_t *bucket;
+
+ for (i = 0; i < HASH_SIZE; i++) {
+ while (ino_dev_hashtable[i] != NULL) {
+ bucket = ino_dev_hashtable[i]->next;
+ free(ino_dev_hashtable[i]);
+ ino_dev_hashtable[i] = bucket;
+ }
+ }
+}
+
+#endif /* BB_CP_MV || BB_DU */
+
+#if defined (BB_CP_MV) || defined (BB_DU) || defined (BB_LN) || defined (BB_AR)
+/*
+ * Return TRUE if a fileName is a directory.
+ * Nonexistant files return FALSE.
+ */
+int isDirectory(const char *fileName, const int followLinks, struct stat *statBuf)
+{
+ int status;
+ int didMalloc = 0;
+
+ if (statBuf == NULL) {
+ statBuf = (struct stat *)xmalloc(sizeof(struct stat));
+ ++didMalloc;
+ }
+
+ if (followLinks == TRUE)
+ status = stat(fileName, statBuf);
+ else
+ status = lstat(fileName, statBuf);
+
+ if (status < 0 || !(S_ISDIR(statBuf->st_mode))) {
+ status = FALSE;
+ }
+ else status = TRUE;
+
+ if (didMalloc) {
+ free(statBuf);
+ statBuf = NULL;
+ }
+ return status;
+}
+#endif
+
+#if defined (BB_AR) || defined BB_CP_MV
+/*
+ * Copy readSize bytes between two file descriptors
+ */
+int copySubFile(int srcFd, int dstFd, size_t remaining)
+{
+ size_t size;
+ char buffer[BUFSIZ];
+
+ while (remaining > 0) {
+ if (remaining > BUFSIZ)
+ size = BUFSIZ;
+ else
+ size = remaining;
+ if (fullWrite(dstFd, buffer, fullRead(srcFd, buffer, size)) < size)
+ return(FALSE);
+ remaining -= size;
+ }
+ return (TRUE);
+}
+#endif
+
+
+#if defined (BB_CP_MV)
+/*
+ * Copy one file to another, while possibly preserving its modes, times, and
+ * modes. Returns TRUE if successful, or FALSE on a failure with an error
+ * message output. (Failure is not indicated if attributes cannot be set.)
+ * -Erik Andersen
+ */
+int
+copyFile(const char *srcName, const char *destName,
+ int setModes, int followLinks, int forceFlag)
+{
+ int rfd;
+ int wfd;
+ int status;
+ struct stat srcStatBuf;
+ struct stat dstStatBuf;
+ struct utimbuf times;
+
+ if (followLinks == TRUE)
+ status = stat(srcName, &srcStatBuf);
+ else
+ status = lstat(srcName, &srcStatBuf);
+
+ if (status < 0) {
+ perror(srcName);
+ return FALSE;
+ }
+
+ if (followLinks == TRUE)
+ status = stat(destName, &dstStatBuf);
+ else
+ status = lstat(destName, &dstStatBuf);
+
+ if (status < 0 || forceFlag==TRUE) {
+ unlink(destName);
+ dstStatBuf.st_ino = -1;
+ dstStatBuf.st_dev = -1;
+ }
+
+ if ((srcStatBuf.st_dev == dstStatBuf.st_dev) &&
+ (srcStatBuf.st_ino == dstStatBuf.st_ino)) {
+ errorMsg("Copying file \"%s\" to itself\n", srcName);
+ return FALSE;
+ }
+
+ if (S_ISDIR(srcStatBuf.st_mode)) {
+ //fprintf(stderr, "copying directory %s to %s\n", srcName, destName);
+ /* Make sure the directory is writable */
+ status = mkdir(destName, 0777777 ^ umask(0));
+ if (status < 0 && errno != EEXIST) {
+ perror(destName);
+ return FALSE;
+ }
+ } else if (S_ISLNK(srcStatBuf.st_mode)) {
+ char link_val[BUFSIZ + 1];
+ int link_size;
+
+ //fprintf(stderr, "copying link %s to %s\n", srcName, destName);
+ /* Warning: This could possibly truncate silently, to BUFSIZ chars */
+ link_size = readlink(srcName, &link_val[0], BUFSIZ);
+ if (link_size < 0) {
+ perror(srcName);
+ return FALSE;
+ }
+ link_val[link_size] = '\0';
+ status = symlink(link_val, destName);
+ if (status < 0) {
+ perror(destName);
+ return FALSE;
+ }
+#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
+ if (setModes == TRUE) {
+ /* Try to set owner, but fail silently like GNU cp */
+ lchown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid);
+ }
+#endif
+ return TRUE;
+ } else if (S_ISFIFO(srcStatBuf.st_mode)) {
+ //fprintf(stderr, "copying fifo %s to %s\n", srcName, destName);
+ if (mkfifo(destName, 0644) < 0) {
+ perror(destName);
+ return FALSE;
+ }
+ } else if (S_ISBLK(srcStatBuf.st_mode) || S_ISCHR(srcStatBuf.st_mode)
+ || S_ISSOCK(srcStatBuf.st_mode)) {
+ //fprintf(stderr, "copying soc, blk, or chr %s to %s\n", srcName, destName);
+ if (mknod(destName, srcStatBuf.st_mode, srcStatBuf.st_rdev) < 0) {
+ perror(destName);
+ return FALSE;
+ }
+ } else if (S_ISREG(srcStatBuf.st_mode)) {
+ //fprintf(stderr, "copying regular file %s to %s\n", srcName, destName);
+ rfd = open(srcName, O_RDONLY);
+ if (rfd < 0) {
+ perror(srcName);
+ return FALSE;
+ }
+
+ wfd = open(destName, O_WRONLY | O_CREAT | O_TRUNC,
+ srcStatBuf.st_mode);
+ if (wfd < 0) {
+ perror(destName);
+ close(rfd);
+ return FALSE;
+ }
+
+ if (copySubFile(rfd, wfd, srcStatBuf.st_size)==FALSE)
+ goto error_exit;
+
+ close(rfd);
+ if (close(wfd) < 0) {
+ return FALSE;
+ }
+ }
+
+ if (setModes == TRUE) {
+ /* This is fine, since symlinks never get here */
+ if (chown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid) < 0) {
+ perror(destName);
+ exit FALSE;
+ }
+ if (chmod(destName, srcStatBuf.st_mode) < 0) {
+ perror(destName);
+ exit FALSE;
+ }
+ times.actime = srcStatBuf.st_atime;
+ times.modtime = srcStatBuf.st_mtime;
+ if (utime(destName, &times) < 0) {
+ perror(destName);
+ exit FALSE;
+ }
+ }
+
+ return TRUE;
+
+ error_exit:
+ perror(destName);
+ close(rfd);
+ close(wfd);
+
+ return FALSE;
+}
+#endif /* BB_CP_MV */
+
+
+
+#if defined BB_TAR || defined BB_LS ||defined BB_AR
+
+#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
+#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
+
+/* The special bits. If set, display SMODE0/1 instead of MODE0/1 */
+static const mode_t SBIT[] = {
+ 0, 0, S_ISUID,
+ 0, 0, S_ISGID,
+ 0, 0, S_ISVTX
+};
+
+/* The 9 mode bits to test */
+static const mode_t MBIT[] = {
+ S_IRUSR, S_IWUSR, S_IXUSR,
+ S_IRGRP, S_IWGRP, S_IXGRP,
+ S_IROTH, S_IWOTH, S_IXOTH
+};
+
+#define MODE1 "rwxrwxrwx"
+#define MODE0 "---------"
+#define SMODE1 "..s..s..t"
+#define SMODE0 "..S..S..T"
+
+/*
+ * Return the standard ls-like mode string from a file mode.
+ * This is static and so is overwritten on each call.
+ */
+const char *modeString(int mode)
+{
+ static char buf[12];
+
+ int i;
+
+ buf[0] = TYPECHAR(mode);
+ for (i = 0; i < 9; i++) {
+ if (mode & SBIT[i])
+ buf[i + 1] = (mode & MBIT[i]) ? SMODE1[i] : SMODE0[i];
+ else
+ buf[i + 1] = (mode & MBIT[i]) ? MODE1[i] : MODE0[i];
+ }
+ return buf;
+}
+#endif /* BB_TAR || BB_LS */
+
+
+#if defined BB_TAR || defined BB_AR
+/*
+ * Return the standard ls-like time string from a time_t
+ * This is static and so is overwritten on each call.
+ */
+const char *timeString(time_t timeVal)
+{
+ time_t now;
+ char *str;
+ static char buf[26];
+
+ time(&now);
+
+ str = ctime(&timeVal);
+
+ strcpy(buf, &str[4]);
+ buf[12] = '\0';
+
+ if ((timeVal > now) || (timeVal < now - 365 * 24 * 60 * 60L)) {
+ strcpy(&buf[7], &str[20]);
+ buf[11] = '\0';
+ }
+
+ return buf;
+}
+#endif /* BB_TAR || BB_AR */
+
+#if defined BB_TAR || defined BB_CP_MV || defined BB_AR
+/*
+ * Write all of the supplied buffer out to a file.
+ * This does multiple writes as necessary.
+ * Returns the amount written, or -1 on an error.
+ */
+int fullWrite(int fd, const char *buf, int len)
+{
+ int cc;
+ int total;
+
+ total = 0;
+
+ while (len > 0) {
+ cc = write(fd, buf, len);
+
+ if (cc < 0)
+ return -1;
+
+ buf += cc;
+ total += cc;
+ len -= cc;
+ }
+
+ return total;
+}
+#endif /* BB_TAR || BB_CP_MV || BB_AR */
+
+
+#if defined BB_TAR || defined BB_TAIL || defined BB_AR || defined BB_SH || defined BB_CP_MV
+/*
+ * Read all of the supplied buffer from a file.
+ * This does multiple reads as necessary.
+ * Returns the amount read, or -1 on an error.
+ * A short read is returned on an end of file.
+ */
+int fullRead(int fd, char *buf, int len)
+{
+ int cc;
+ int total;
+
+ total = 0;
+
+ while (len > 0) {
+ cc = read(fd, buf, len);
+
+ if (cc < 0)
+ return -1;
+
+ if (cc == 0)
+ break;
+
+ buf += cc;
+ total += cc;
+ len -= cc;
+ }
+
+ return total;
+}
+#endif /* BB_TAR || BB_TAIL || BB_AR || BB_SH */
+
+
+#if defined (BB_CHMOD_CHOWN_CHGRP) \
+ || defined (BB_CP_MV) \
+ || defined (BB_FIND) \
+ || defined (BB_INSMOD) \
+ || defined (BB_LS) \
+ || defined (BB_RM) \
+ || defined (BB_TAR)
+
+/*
+ * Walk down all the directories under the specified
+ * location, and do something (something specified
+ * by the fileAction and dirAction function pointers).
+ *
+ * Unfortunatly, while nftw(3) could replace this and reduce
+ * code size a bit, nftw() wasn't supported before GNU libc 2.1,
+ * and so isn't sufficiently portable to take over since glibc2.1
+ * is so stinking huge.
+ */
+int recursiveAction(const char *fileName,
+ int recurse, int followLinks, int depthFirst,
+ int (*fileAction) (const char *fileName,
+ struct stat * statbuf,
+ void* userData),
+ int (*dirAction) (const char *fileName,
+ struct stat * statbuf,
+ void* userData),
+ void* userData)
+{
+ int status;
+ struct stat statbuf;
+ struct dirent *next;
+
+ if (followLinks == TRUE)
+ status = stat(fileName, &statbuf);
+ else
+ status = lstat(fileName, &statbuf);
+
+ if (status < 0) {
+#ifdef BB_DEBUG_PRINT_SCAFFOLD
+ fprintf(stderr,
+ "status=%d followLinks=%d TRUE=%d\n",
+ status, followLinks, TRUE);
+#endif
+ perror(fileName);
+ return FALSE;
+ }
+
+ if ((followLinks == FALSE) && (S_ISLNK(statbuf.st_mode))) {
+ if (fileAction == NULL)
+ return TRUE;
+ else
+ return fileAction(fileName, &statbuf, userData);
+ }
+
+ if (recurse == FALSE) {
+ if (S_ISDIR(statbuf.st_mode)) {
+ if (dirAction != NULL)
+ return (dirAction(fileName, &statbuf, userData));
+ else
+ return TRUE;
+ }
+ }
+
+ if (S_ISDIR(statbuf.st_mode)) {
+ DIR *dir;
+
+ dir = opendir(fileName);
+ if (!dir) {
+ perror(fileName);
+ return FALSE;
+ }
+ if (dirAction != NULL && depthFirst == FALSE) {
+ status = dirAction(fileName, &statbuf, userData);
+ if (status == FALSE) {
+ perror(fileName);
+ return FALSE;
+ }
+ }
+ while ((next = readdir(dir)) != NULL) {
+ char nextFile[BUFSIZ + 1];
+
+ if ((strcmp(next->d_name, "..") == 0)
+ || (strcmp(next->d_name, ".") == 0)) {
+ continue;
+ }
+ if (strlen(fileName) + strlen(next->d_name) + 1 > BUFSIZ) {
+ errorMsg("name_too_long");
+ return FALSE;
+ }
+ memset(nextFile, 0, sizeof(nextFile));
+ sprintf(nextFile, "%s/%s", fileName, next->d_name);
+ status =
+ recursiveAction(nextFile, TRUE, followLinks, depthFirst,
+ fileAction, dirAction, userData);
+ if (status == FALSE) {
+ closedir(dir);
+ return FALSE;
+ }
+ }
+ status = closedir(dir);
+ if (status < 0) {
+ perror(fileName);
+ return FALSE;
+ }
+ if (dirAction != NULL && depthFirst == TRUE) {
+ status = dirAction(fileName, &statbuf, userData);
+ if (status == FALSE) {
+ perror(fileName);
+ return FALSE;
+ }
+ }
+ } else {
+ if (fileAction == NULL)
+ return TRUE;
+ else
+ return fileAction(fileName, &statbuf, userData);
+ }
+ return TRUE;
+}
+
+#endif /* BB_CHMOD_CHOWN_CHGRP || BB_CP_MV || BB_FIND || BB_LS || BB_INSMOD */
+
+
+
+#if defined (BB_TAR) || defined (BB_MKDIR) || defined (BB_AR)
+/*
+ * Attempt to create the directories along the specified path, except for
+ * the final component. The mode is given for the final directory only,
+ * while all previous ones get default protections. Errors are not reported
+ * here, as failures to restore files can be reported later.
+ */
+extern int createPath(const char *name, int mode)
+{
+ char *cp;
+ char *cpOld;
+ char buf[BUFSIZ + 1];
+ int retVal = 0;
+
+ strcpy(buf, name);
+ for (cp = buf; *cp == '/'; cp++);
+ cp = strchr(cp, '/');
+ while (cp) {
+ cpOld = cp;
+ cp = strchr(cp + 1, '/');
+ *cpOld = '\0';
+ retVal = mkdir(buf, cp ? 0777 : mode);
+ if (retVal != 0 && errno != EEXIST) {
+ perror(buf);
+ return FALSE;
+ }
+ *cpOld = '/';
+ }
+ return TRUE;
+}
+#endif /* BB_TAR || BB_MKDIR */
+
+
+
+#if defined (BB_CHMOD_CHOWN_CHGRP) || defined (BB_MKDIR) \
+ || defined (BB_MKFIFO) || defined (BB_MKNOD) || defined (BB_AR)
+/* [ugoa]{+|-|=}[rwxst] */
+
+
+
+extern int parse_mode(const char *s, mode_t * theMode)
+{
+ mode_t andMode =
+
+ S_ISVTX | S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
+ mode_t orMode = 0;
+ mode_t mode = 0;
+ mode_t groups = 0;
+ char type;
+ char c;
+
+ if (s==NULL)
+ return (FALSE);
+
+ do {
+ for (;;) {
+ switch (c = *s++) {
+ case '\0':
+ return -1;
+ case 'u':
+ groups |= S_ISUID | S_IRWXU;
+ continue;
+ case 'g':
+ groups |= S_ISGID | S_IRWXG;
+ continue;
+ case 'o':
+ groups |= S_IRWXO;
+ continue;
+ case 'a':
+ groups |= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
+ continue;
+ case '+':
+ case '=':
+ case '-':
+ type = c;
+ if (groups == 0) /* The default is "all" */
+ groups |=
+ S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
+ break;
+ default:
+ if (isdigit(c) && c >= '0' && c <= '7' &&
+ mode == 0 && groups == 0) {
+ *theMode = strtol(--s, NULL, 8);
+ return (TRUE);
+ } else
+ return (FALSE);
+ }
+ break;
+ }
+
+ while ((c = *s++) != '\0') {
+ switch (c) {
+ case ',':
+ break;
+ case 'r':
+ mode |= S_IRUSR | S_IRGRP | S_IROTH;
+ continue;
+ case 'w':
+ mode |= S_IWUSR | S_IWGRP | S_IWOTH;
+ continue;
+ case 'x':
+ mode |= S_IXUSR | S_IXGRP | S_IXOTH;
+ continue;
+ case 's':
+ mode |= S_IXGRP | S_ISUID | S_ISGID;
+ continue;
+ case 't':
+ mode |= 0;
+ continue;
+ default:
+ *theMode &= andMode;
+ *theMode |= orMode;
+ return (TRUE);
+ }
+ break;
+ }
+ switch (type) {
+ case '=':
+ andMode &= ~(groups);
+ /* fall through */
+ case '+':
+ orMode |= mode & groups;
+ break;
+ case '-':
+ andMode &= ~(mode & groups);
+ orMode &= andMode;
+ break;
+ }
+ } while (c == ',');
+ *theMode &= andMode;
+ *theMode |= orMode;
+ return (TRUE);
+}
+
+
+#endif
+/* BB_CHMOD_CHOWN_CHGRP || BB_MKDIR || BB_MKFIFO || BB_MKNOD */
+
+
+
+
+
+#if defined BB_CHMOD_CHOWN_CHGRP || defined BB_PS || defined BB_LS \
+ || defined BB_TAR || defined BB_ID || defined BB_LOGGER \
+ || defined BB_LOGNAME || defined BB_WHOAMI
+
+/* This parses entries in /etc/passwd and /etc/group. This is desirable
+ * for BusyBox, since we want to avoid using the glibc NSS stuff, which
+ * increases target size and is often not needed or wanted for embedded
+ * systems.
+ *
+ * /etc/passwd entries look like this:
+ * root:x:0:0:root:/root:/bin/bash
+ * and /etc/group entries look like this:
+ * root:x:0:
+ *
+ * This uses buf as storage to hold things.
+ *
+ */
+unsigned long my_getid(const char *filename, char *name, long id, long *gid)
+{
+ FILE *file;
+ char *rname, *start, *end, buf[128];
+ long rid;
+ long rgid = 0;
+
+ file = fopen(filename, "r");
+ if (file == NULL) {
+ /* Do not complain. It is ok for /etc/passwd and
+ * friends to be missing... */
+ return (-1);
+ }
+
+ while (fgets(buf, 128, file) != NULL) {
+ if (buf[0] == '#')
+ continue;
+
+ /* username/group name */
+ start = buf;
+ end = strchr(start, ':');
+ if (end == NULL)
+ continue;
+ *end = '\0';
+ rname = start;
+
+ /* password */
+ start = end + 1;
+ end = strchr(start, ':');
+ if (end == NULL)
+ continue;
+
+ /* uid in passwd, gid in group */
+ start = end + 1;
+ rid = (unsigned long) strtol(start, &end, 10);
+ if (end == start)
+ continue;
+
+ /* gid in passwd */
+ start = end + 1;
+ rgid = (unsigned long) strtol(start, &end, 10);
+
+ if (name) {
+ if (0 == strcmp(rname, name)) {
+ if (gid) *gid = rgid;
+ fclose(file);
+ return (rid);
+ }
+ }
+ if (id != -1 && id == rid) {
+ strncpy(name, rname, 8);
+ if (gid) *gid = rgid;
+ fclose(file);
+ return (TRUE);
+ }
+ }
+ fclose(file);
+ return (-1);
+}
+
+/* returns a uid given a username */
+long my_getpwnam(char *name)
+{
+ return my_getid("/etc/passwd", name, -1, NULL);
+}
+
+/* returns a gid given a group name */
+long my_getgrnam(char *name)
+{
+ return my_getid("/etc/group", name, -1, NULL);
+}
+
+/* gets a username given a uid */
+void my_getpwuid(char *name, long uid)
+{
+ my_getid("/etc/passwd", name, uid, NULL);
+}
+
+/* gets a groupname given a gid */
+void my_getgrgid(char *group, long gid)
+{
+ my_getid("/etc/group", group, gid, NULL);
+}
+
+/* gets a gid given a user name */
+long my_getpwnamegid(char *name)
+{
+ long gid;
+ my_getid("/etc/passwd", name, -1, &gid);
+ return gid;
+}
+
+#endif
+ /* BB_CHMOD_CHOWN_CHGRP || BB_PS || BB_LS || BB_TAR \
+ || BB_ID || BB_LOGGER || BB_LOGNAME || BB_WHOAMI */
+
+
+#if (defined BB_CHVT) || (defined BB_DEALLOCVT) || (defined BB_SETKEYCODES)
+
+/* From <linux/kd.h> */
+#define KDGKBTYPE 0x4B33 /* get keyboard type */
+#define KB_84 0x01
+#define KB_101 0x02 /* this is what we always answer */
+
+int is_a_console(int fd)
+{
+ char arg;
+
+ arg = 0;
+ return (ioctl(fd, KDGKBTYPE, &arg) == 0
+ && ((arg == KB_101) || (arg == KB_84)));
+}
+
+static int open_a_console(char *fnam)
+{
+ int fd;
+
+ /* try read-only */
+ fd = open(fnam, O_RDWR);
+
+ /* if failed, try read-only */
+ if (fd < 0 && errno == EACCES)
+ fd = open(fnam, O_RDONLY);
+
+ /* if failed, try write-only */
+ if (fd < 0 && errno == EACCES)
+ fd = open(fnam, O_WRONLY);
+
+ /* if failed, fail */
+ if (fd < 0)
+ return -1;
+
+ /* if not a console, fail */
+ if (!is_a_console(fd)) {
+ close(fd);
+ return -1;
+ }
+
+ /* success */
+ return fd;
+}
+
+/*
+ * Get an fd for use with kbd/console ioctls.
+ * We try several things because opening /dev/console will fail
+ * if someone else used X (which does a chown on /dev/console).
+ *
+ * if tty_name is non-NULL, try this one instead.
+ */
+
+int get_console_fd(char *tty_name)
+{
+ int fd;
+
+ if (tty_name) {
+ if (-1 == (fd = open_a_console(tty_name)))
+ return -1;
+ else
+ return fd;
+ }
+
+ fd = open_a_console("/dev/tty");
+ if (fd >= 0)
+ return fd;
+
+ fd = open_a_console("/dev/tty0");
+ if (fd >= 0)
+ return fd;
+
+ fd = open_a_console("/dev/console");
+ if (fd >= 0)
+ return fd;
+
+ for (fd = 0; fd < 3; fd++)
+ if (is_a_console(fd))
+ return fd;
+
+ errorMsg("Couldnt get a file descriptor referring to the console\n");
+ return -1; /* total failure */
+}
+
+
+#endif /* BB_CHVT || BB_DEALLOCVT || BB_SETKEYCODES */
+
+
+#if defined BB_FIND || defined BB_INSMOD
+/*
+ * Routine to see if a text string is matched by a wildcard pattern.
+ * Returns TRUE if the text is matched, or FALSE if it is not matched
+ * or if the pattern is invalid.
+ * * matches zero or more characters
+ * ? matches a single character
+ * [abc] matches 'a', 'b' or 'c'
+ * \c quotes character c
+ * Adapted from code written by Ingo Wilken, and
+ * then taken from sash, Copyright (c) 1999 by David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ * Permission to distribute this code under the GPL has been granted.
+ */
+extern int check_wildcard_match(const char *text, const char *pattern)
+{
+ const char *retryPat;
+ const char *retryText;
+ int ch;
+ int found;
+ int len;
+
+ retryPat = NULL;
+ retryText = NULL;
+
+ while (*text || *pattern) {
+ ch = *pattern++;
+
+ switch (ch) {
+ case '*':
+ retryPat = pattern;
+ retryText = text;
+ break;
+
+ case '[':
+ found = FALSE;
+
+ while ((ch = *pattern++) != ']') {
+ if (ch == '\\')
+ ch = *pattern++;
+
+ if (ch == '\0')
+ return FALSE;
+
+ if (*text == ch)
+ found = TRUE;
+ }
+ len=strlen(text);
+ if (found == FALSE && len!=0) {
+ return FALSE;
+ }
+ if (found == TRUE) {
+ if (strlen(pattern)==0 && len==1) {
+ return TRUE;
+ }
+ if (len!=0) {
+ text++;
+ continue;
+ }
+ }
+
+ /* fall into next case */
+
+ case '?':
+ if (*text++ == '\0')
+ return FALSE;
+
+ break;
+
+ case '\\':
+ ch = *pattern++;
+
+ if (ch == '\0')
+ return FALSE;
+
+ /* fall into next case */
+
+ default:
+ if (*text == ch) {
+ if (*text)
+ text++;
+ break;
+ }
+
+ if (*text) {
+ pattern = retryPat;
+ text = ++retryText;
+ break;
+ }
+
+ return FALSE;
+ }
+
+ if (pattern == NULL)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+#endif /* BB_FIND || BB_INSMOD */
+
+
+
+
+#if defined BB_DF || defined BB_MTAB
+/*
+ * Given a block device, find the mount table entry if that block device
+ * is mounted.
+ *
+ * Given any other file (or directory), find the mount table entry for its
+ * filesystem.
+ */
+extern struct mntent *findMountPoint(const char *name, const char *table)
+{
+ struct stat s;
+ dev_t mountDevice;
+ FILE *mountTable;
+ struct mntent *mountEntry;
+
+ if (stat(name, &s) != 0)
+ return 0;
+
+ if ((s.st_mode & S_IFMT) == S_IFBLK)
+ mountDevice = s.st_rdev;
+ else
+ mountDevice = s.st_dev;
+
+
+ if ((mountTable = setmntent(table, "r")) == 0)
+ return 0;
+
+ while ((mountEntry = getmntent(mountTable)) != 0) {
+ if (strcmp(name, mountEntry->mnt_dir) == 0
+ || strcmp(name, mountEntry->mnt_fsname) == 0) /* String match. */
+ break;
+ if (stat(mountEntry->mnt_fsname, &s) == 0 && s.st_rdev == mountDevice) /* Match the device. */
+ break;
+ if (stat(mountEntry->mnt_dir, &s) == 0 && s.st_dev == mountDevice) /* Match the directory's mount point. */
+ break;
+ }
+ endmntent(mountTable);
+ return mountEntry;
+}
+#endif /* BB_DF || BB_MTAB */
+
+
+
+#if defined BB_DD || defined BB_TAIL
+/*
+ * Read a number with a possible multiplier.
+ * Returns -1 if the number format is illegal.
+ */
+extern long getNum(const char *cp)
+{
+ long value;
+
+ if (!isDecimal(*cp))
+ return -1;
+
+ value = 0;
+
+ while (isDecimal(*cp))
+ value = value * 10 + *cp++ - '0';
+
+ switch (*cp++) {
+ case 'M':
+ case 'm': /* `tail' uses it traditionally */
+ value *= 1048576;
+ break;
+
+ case 'k':
+ value *= 1024;
+ break;
+
+ case 'b':
+ value *= 512;
+ break;
+
+ case 'w':
+ value *= 2;
+ break;
+
+ case '\0':
+ return value;
+
+ default:
+ return -1;
+ }
+
+ if (*cp)
+ return -1;
+
+ return value;
+}
+#endif /* BB_DD || BB_TAIL */
+
+
+#if defined BB_INIT || defined BB_SYSLOGD
+/* try to open up the specified device */
+extern int device_open(char *device, int mode)
+{
+ int m, f, fd = -1;
+
+ m = mode | O_NONBLOCK;
+
+ /* Retry up to 5 times */
+ for (f = 0; f < 5; f++)
+ if ((fd = open(device, m, 0600)) >= 0)
+ break;
+ if (fd < 0)
+ return fd;
+ /* Reset original flags. */
+ if (m != mode)
+ fcntl(fd, F_SETFL, mode);
+ return fd;
+}
+#endif /* BB_INIT BB_SYSLOGD */
+
+
+#if defined BB_KILLALL || ( defined BB_FEATURE_LINUXRC && ( defined BB_HALT || defined BB_REBOOT || defined BB_POWEROFF ))
+#ifdef BB_FEATURE_USE_DEVPS_PATCH
+#include <linux/devps.h> /* For Erik's nifty devps device driver */
+#endif
+
+#if defined BB_FEATURE_USE_DEVPS_PATCH
+/* findPidByName()
+ *
+ * This finds the pid of the specified process,
+ * by using the /dev/ps device driver.
+ *
+ * Returns a list of all matching PIDs
+ */
+extern pid_t* findPidByName( char* pidName)
+{
+ int fd, i, j;
+ char device[] = "/dev/ps";
+ pid_t num_pids;
+ pid_t* pid_array = NULL;
+ pid_t* pidList=NULL;
+
+ /* open device */
+ fd = open(device, O_RDONLY);
+ if (fd < 0)
+ fatalError( "open failed for `%s': %s\n", device, strerror (errno));
+
+ /* Find out how many processes there are */
+ if (ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids)<0)
+ fatalError( "\nDEVPS_GET_PID_LIST: %s\n", strerror (errno));
+
+ /* Allocate some memory -- grab a few extras just in case
+ * some new processes start up while we wait. The kernel will
+ * just ignore any extras if we give it too many, and will trunc.
+ * the list if we give it too few. */
+ pid_array = (pid_t*) xcalloc( num_pids+10, sizeof(pid_t));
+ pid_array[0] = num_pids+10;
+
+ /* Now grab the pid list */
+ if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0)
+ fatalError( "\nDEVPS_GET_PID_LIST: %s\n", strerror (errno));
+
+ /* Now search for a match */
+ for (i=1, j=0; i<pid_array[0] ; i++) {
+ char* p;
+ struct pid_info info;
+
+ info.pid = pid_array[i];
+ if (ioctl (fd, DEVPS_GET_PID_INFO, &info)<0)
+ fatalError( "\nDEVPS_GET_PID_INFO: %s\n", strerror (errno));
+
+ /* Make sure we only match on the process name */
+ p=info.command_line+1;
+ while ((*p != 0) && !isspace(*(p)) && (*(p-1) != '\\')) {
+ (p)++;
+ }
+ if (isspace(*(p)))
+ *p='\0';
+
+ if ((strstr(info.command_line, pidName) != NULL)
+ && (strlen(pidName) == strlen(info.command_line))) {
+ pidList=xrealloc( pidList, sizeof(pid_t) * (j+2));
+ pidList[j++]=info.pid;
+ }
+ }
+ if (pidList)
+ pidList[j]=0;
+
+ /* Free memory */
+ free( pid_array);
+
+ /* close device */
+ if (close (fd) != 0)
+ fatalError( "close failed for `%s': %s\n",device, strerror (errno));
+
+ return pidList;
+}
+#else /* BB_FEATURE_USE_DEVPS_PATCH */
+#if ! defined BB_FEATURE_USE_PROCFS
+#error Sorry, I depend on the /proc filesystem right now.
+#endif
+
+/* findPidByName()
+ *
+ * This finds the pid of the specified process.
+ * Currently, it's implemented by rummaging through
+ * the proc filesystem.
+ *
+ * Returns a list of all matching PIDs
+ */
+extern pid_t* findPidByName( char* pidName)
+{
+ DIR *dir;
+ struct dirent *next;
+ pid_t* pidList=NULL;
+ int i=0;
+
+ dir = opendir("/proc");
+ if (!dir)
+ fatalError( "Cannot open /proc: %s\n", strerror (errno));
+
+ while ((next = readdir(dir)) != NULL) {
+ FILE *status;
+ char filename[256];
+ char buffer[256];
+
+ /* If it isn't a number, we don't want it */
+ if (!isdigit(*next->d_name))
+ continue;
+
+ sprintf(filename, "/proc/%s/cmdline", next->d_name);
+ status = fopen(filename, "r");
+ if (!status) {
+ continue;
+ }
+ fgets(buffer, 256, status);
+ fclose(status);
+
+ if (strstr(get_last_path_component(buffer), pidName) != NULL) {
+ pidList=xrealloc( pidList, sizeof(pid_t) * (i+2));
+ pidList[i++]=strtol(next->d_name, NULL, 0);
+ }
+ }
+
+ if (pidList)
+ pidList[i]=0;
+ return pidList;
+}
+#endif /* BB_FEATURE_USE_DEVPS_PATCH */
+#endif /* BB_KILLALL || ( BB_FEATURE_LINUXRC && ( BB_HALT || BB_REBOOT || BB_POWEROFF )) */
+
+#ifndef DMALLOC
+/* this should really be farmed out to libbusybox.a */
+extern void *xmalloc(size_t size)
+{
+ void *ptr = malloc(size);
+
+ if (!ptr)
+ fatalError("memory_exhausted");
+ return ptr;
+}
+
+extern void *xrealloc(void *old, size_t size)
+{
+ void *ptr = realloc(old, size);
+ if (!ptr)
+ fatalError("memory_exhausted");
+ return ptr;
+}
+
+extern void *xcalloc(size_t nmemb, size_t size)
+{
+ void *ptr = calloc(nmemb, size);
+ if (!ptr)
+ fatalError("memory_exhausted");
+ return ptr;
+}
+#endif
+
+#if defined BB_FEATURE_NFSMOUNT || defined BB_SH || defined BB_LS
+# ifndef DMALLOC
+extern char * xstrdup (const char *s) {
+ char *t;
+
+ if (s == NULL)
+ return NULL;
+
+ t = strdup (s);
+
+ if (t == NULL)
+ fatalError("memory_exhausted");
+
+ return t;
+}
+# endif
+#endif
+
+#if defined BB_FEATURE_NFSMOUNT
+extern char * xstrndup (const char *s, int n) {
+ char *t;
+
+ if (s == NULL)
+ fatalError("xstrndup bug");
+
+ t = xmalloc(n+1);
+ strncpy(t,s,n);
+ t[n] = 0;
+
+ return t;
+}
+#endif
+
+
+#if (__GLIBC__ < 2) && (defined BB_SYSLOGD || defined BB_INIT)
+extern int vdprintf(int d, const char *format, va_list ap)
+{
+ char buf[BUF_SIZE];
+ int len;
+
+ len = vsprintf(buf, format, ap);
+ return write(d, buf, len);
+}
+#endif /* BB_SYSLOGD */
+
+
+#if defined BB_FEATURE_MOUNT_LOOP
+#include <fcntl.h>
+#include "loop.h" /* Pull in loop device support */
+
+extern int del_loop(const char *device)
+{
+ int fd;
+
+ if ((fd = open(device, O_RDONLY)) < 0) {
+ perror(device);
+ return (FALSE);
+ }
+ if (ioctl(fd, LOOP_CLR_FD, 0) < 0) {
+ perror("ioctl: LOOP_CLR_FD");
+ return (FALSE);
+ }
+ close(fd);
+ return (TRUE);
+}
+
+extern int set_loop(const char *device, const char *file, int offset,
+ int *loopro)
+{
+ struct loop_info loopinfo;
+ int fd, ffd, mode;
+
+ mode = *loopro ? O_RDONLY : O_RDWR;
+ if ((ffd = open(file, mode)) < 0 && !*loopro
+ && (errno != EROFS || (ffd = open(file, mode = O_RDONLY)) < 0)) {
+ perror(file);
+ return 1;
+ }
+ if ((fd = open(device, mode)) < 0) {
+ close(ffd);
+ perror(device);
+ return 1;
+ }
+ *loopro = (mode == O_RDONLY);
+
+ memset(&loopinfo, 0, sizeof(loopinfo));
+ strncpy(loopinfo.lo_name, file, LO_NAME_SIZE);
+ loopinfo.lo_name[LO_NAME_SIZE - 1] = 0;
+
+ loopinfo.lo_offset = offset;
+
+ loopinfo.lo_encrypt_key_size = 0;
+ if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
+ perror("ioctl: LOOP_SET_FD");
+ close(fd);
+ close(ffd);
+ return 1;
+ }
+ if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) {
+ (void) ioctl(fd, LOOP_CLR_FD, 0);
+ perror("ioctl: LOOP_SET_STATUS");
+ close(fd);
+ close(ffd);
+ return 1;
+ }
+ close(fd);
+ close(ffd);
+ return 0;
+}
+
+extern char *find_unused_loop_device(void)
+{
+ char dev[20];
+ int i, fd;
+ struct stat statbuf;
+ struct loop_info loopinfo;
+
+ for (i = 0; i <= 7; i++) {
+ sprintf(dev, "/dev/loop%d", i);
+ if (stat(dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) {
+ if ((fd = open(dev, O_RDONLY)) >= 0) {
+ if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) == -1) {
+ if (errno == ENXIO) { /* probably free */
+ close(fd);
+ return strdup(dev);
+ }
+ }
+ close(fd);
+ }
+ }
+ }
+ return NULL;
+}
+#endif /* BB_FEATURE_MOUNT_LOOP */
+
+#if defined BB_MOUNT || defined BB_DF || ( defined BB_UMOUNT && ! defined BB_MTAB)
+extern int find_real_root_device_name(char* name)
+{
+ DIR *dir;
+ struct dirent *entry;
+ struct stat statBuf, rootStat;
+ char fileName[BUFSIZ];
+
+ if (stat("/", &rootStat) != 0) {
+ errorMsg("could not stat '/'\n");
+ return( FALSE);
+ }
+
+ dir = opendir("/dev");
+ if (!dir) {
+ errorMsg("could not open '/dev'\n");
+ return( FALSE);
+ }
+
+ while((entry = readdir(dir)) != NULL) {
+
+ /* Must skip ".." since that is "/", and so we
+ * would get a false positive on ".." */
+ if (strcmp(entry->d_name, "..") == 0)
+ continue;
+
+ snprintf( fileName, strlen(name)+1, "/dev/%s", entry->d_name);
+
+ if (stat(fileName, &statBuf) != 0)
+ continue;
+ /* Some char devices have the same dev_t as block
+ * devices, so make sure this is a block device */
+ if (! S_ISBLK(statBuf.st_mode))
+ continue;
+ if (statBuf.st_rdev == rootStat.st_rdev) {
+ strcpy(name, fileName);
+ return ( TRUE);
+ }
+ }
+
+ return( FALSE);
+}
+#endif
+
+
+/* get_line_from_file() - This function reads an entire line from a text file
+ * up to a newline. It returns a malloc'ed char * which must be stored and
+ * free'ed by the caller. */
+extern char *get_line_from_file(FILE *file)
+{
+ static const int GROWBY = 80; /* how large we will grow strings by */
+
+ int ch;
+ int idx = 0;
+ char *linebuf = NULL;
+ int linebufsz = 0;
+
+ while (1) {
+ ch = fgetc(file);
+ if (ch == EOF)
+ break;
+ /* grow the line buffer as necessary */
+ while (idx > linebufsz-2)
+ linebuf = xrealloc(linebuf, linebufsz += GROWBY);
+ linebuf[idx++] = (char)ch;
+ if ((char)ch == '\n')
+ break;
+ }
+
+ if (idx == 0)
+ return NULL;
+
+ linebuf[idx] = 0;
+ return linebuf;
+}
+
+#if defined BB_CAT
+extern void print_file(FILE *file)
+{
+ int c;
+
+ while ((c = getc(file)) != EOF)
+ putc(c, stdout);
+ fclose(file);
+ fflush(stdout);
+}
+
+extern int print_file_by_name(char *filename)
+{
+ FILE *file;
+ file = fopen(filename, "r");
+ if (file == NULL) {
+ return FALSE;
+ }
+ print_file(file);
+ return TRUE;
+}
+#endif /* BB_CAT || BB_LSMOD */
+
+#if defined BB_ECHO || defined BB_TR
+char process_escape_sequence(char **ptr)
+{
+ char c;
+
+ switch (c = *(*ptr)++) {
+ case 'a':
+ c = '\a';
+ break;
+ case 'b':
+ c = '\b';
+ break;
+ case 'f':
+ c = '\f';
+ break;
+ case 'n':
+ c = '\n';
+ break;
+ case 't':
+ c = '\t';
+ break;
+ case 'v':
+ c = '\v';
+ break;
+ case '\\':
+ c = '\\';
+ break;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ c -= '0';
+ if ('0' <= **ptr && **ptr <= '7') {
+ c = c * 8 + (*(*ptr)++ - '0');
+ if ('0' <= **ptr && **ptr <= '7')
+ c = c * 8 + (*(*ptr)++ - '0');
+ }
+ break;
+ default:
+ (*ptr)--;
+ c = '\\';
+ break;
+ }
+ return c;
+}
+#endif
+
+#if defined BB_BASENAME || defined BB_LN || defined BB_SH
+char *get_last_path_component(char *path)
+{
+ char *s=path+strlen(path)-1;
+
+ /* strip trailing slashes */
+ while (s && *s == '/') {
+ *s-- = '\0';
+ }
+
+ /* find last component */
+ s = strrchr(path, '/');
+ if (s==NULL) return path;
+ else return s+1;
+}
+#endif
+
+#if defined BB_GREP || defined BB_SED
+void xregcomp(regex_t *preg, const char *regex, int cflags)
+{
+ int ret;
+ if ((ret = regcomp(preg, regex, cflags)) != 0) {
+ int errmsgsz = regerror(ret, preg, NULL, 0);
+ char *errmsg = xmalloc(errmsgsz);
+ regerror(ret, preg, errmsg, errmsgsz);
+ fatalError("bb_regcomp: %s\n", errmsg);
+ }
+}
+#endif
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/