diff options
Diffstat (limited to 'mdk-stage1')
-rw-r--r-- | mdk-stage1/insmod-busybox/Config.h | 222 | ||||
-rw-r--r-- | mdk-stage1/insmod-busybox/Makefile | 37 | ||||
-rw-r--r-- | mdk-stage1/insmod-busybox/README | 8 | ||||
-rw-r--r-- | mdk-stage1/insmod-busybox/busybox.h | 468 | ||||
-rw-r--r-- | mdk-stage1/insmod-busybox/insmod-frontend.c | 24 | ||||
-rw-r--r-- | mdk-stage1/insmod-busybox/insmod.c | 2995 | ||||
-rw-r--r-- | mdk-stage1/insmod-busybox/loop.h | 5 | ||||
-rw-r--r-- | mdk-stage1/insmod-busybox/messages.c | 90 | ||||
-rw-r--r-- | mdk-stage1/insmod-busybox/utility.c | 1744 |
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, ×) < 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: +*/ |