diff options
author | Erik Andersen <andersen@codepoet.org> | 2000-01-04 01:10:25 +0000 |
---|---|---|
committer | Erik Andersen <andersen@codepoet.org> | 2000-01-04 01:10:25 +0000 |
commit | 7dc160721ee3ceb76240a43d1454b45aaa9dbee4 (patch) | |
tree | 7532471be456e2c9f11eab88cb34f1e38abd184f | |
parent | 9c88cac5cbfb2ff70f800ee5bb3289e925aaa65f (diff) | |
download | busybox-7dc160721ee3ceb76240a43d1454b45aaa9dbee4.tar.gz |
Bunches of fixes. Typos, bugs, etc.
Added 'gunzip -t'. inittab support _almost_ works (but it isn't
ready for prime time useage yet).
-Erik
-rw-r--r-- | Changelog | 19 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | applets/busybox.c | 6 | ||||
-rw-r--r-- | archival/gunzip.c | 32 | ||||
-rw-r--r-- | archival/tar.c | 121 | ||||
-rw-r--r-- | busybox.c | 6 | ||||
-rw-r--r-- | busybox.def.h | 6 | ||||
-rw-r--r-- | busybox_functions.h | 11 | ||||
-rw-r--r-- | coreutils/cp.c | 2 | ||||
-rw-r--r-- | cp.c | 2 | ||||
-rw-r--r-- | editors/sed.c | 2 | ||||
-rw-r--r-- | gunzip.c | 32 | ||||
-rw-r--r-- | init.c | 483 | ||||
-rw-r--r-- | init/init.c | 483 | ||||
-rw-r--r-- | internal.h | 3 | ||||
-rw-r--r-- | kill.c | 3 | ||||
-rw-r--r-- | procps/kill.c | 3 | ||||
-rw-r--r-- | sed.c | 2 | ||||
-rw-r--r-- | tar.c | 121 | ||||
-rw-r--r-- | utility.c | 16 |
20 files changed, 779 insertions, 576 deletions
@@ -1,11 +1,11 @@ 0.40 * Added the -s option to du -beppu * Fixed an embarrasing segfault in head -beppu - * Fixed an bug in syslogd causing it to stop logging after 20 minutes. -erik + * Fixed an bug in syslogd causing it to stop after 20 minutes. -erik * New Apps: lsmod, rmmod -erik * New Apps: fbset contributed by Randolph Chung <tausq@debian.org>. - * Fixed the embarrasing failure of the -p opition in the logger app. -erik - * Re-worked the whole source tree a bit so it will compile under glibc 2.0.7 + * Fixed the embarrasing failure of 'logger -p'. -erik + * Re-worked the source tree a bit so it will compile under glibc 2.0.7 with the 2.0.x Linux kernel. * Added 'grep -q' thanks to a patch from "Konstantin Boldyshev" <konst@voshod.com>. @@ -13,15 +13,24 @@ * Fixed a bug where tar would set, and then clear SGID and SUID bits. * Fixed a bug where tar would not set the user and group on device special files. - * cp and mv were quite broken when moving directories. I have rewritten + * cp and mv were very broken when moving directories. I have rewritten them so they should now work as expected. * New app: loadacm contributed by Peter Novodvorsky <petya@logic.ru> - for loading application character maps for working with Unicode fonts. + for loading application character maps for Unicode fonts. * sed now supports addresses (numeric or regexp, with negation) and has an append command, thanks to Marco Pantaleoni <panta@prosa.it> * Fixed dmesg. It wasn't parsing its options (-n or -s) properly. * Some cosmetic fixes to ls output formatting to make it behave more like GNU ls. + * Fixed a bug where tar would not restore the time to files. + * Fixed a major security problem with tar -- it changed ownership + of any file pointed to by a symlink to 777 (like say libc....) + Ouch!!! + * Fixed a stupid segfault in kill. + * Several fixes from Friedrich Vedder <fwv@myrtle.lahn.de>: + - Added gunzip -t, removed gunzip.c dead code, + - fixed several typos + - Glibc 2.0.7 and libc5 compile fixes -Erik Andersen @@ -22,7 +22,7 @@ BUILDTIME=$(shell date "+%Y%m%d-%H%M") # Comment out the following to make a debuggable build # Leave this off for production use. -DODEBUG=false +DODEBUG=true # If you want a static binary, turn this on. I can't think # of many situations where anybody would ever want it static, # but... diff --git a/applets/busybox.c b/applets/busybox.c index 403b14008..a35306915 100644 --- a/applets/busybox.c +++ b/applets/busybox.c @@ -102,6 +102,9 @@ static const struct Applet applets[] = { #ifdef BB_LN //bin {"ln", ln_main}, #endif +#ifdef BB_LOADACM //usr/bin + {"loadacm", loadacm_main}, +#endif #ifdef BB_LOADFONT //usr/bin {"loadfont", loadfont_main}, #endif @@ -232,9 +235,6 @@ static const struct Applet applets[] = { #ifdef BB_GZIP //bin {"gzip", gzip_main}, #endif -#ifdef BB_LOADACM //usr/bin - {"loadacm", loadacm_main}, -#endif {0} }; diff --git a/archival/gunzip.c b/archival/gunzip.c index 61391a33f..84f5d02b7 100644 --- a/archival/gunzip.c +++ b/archival/gunzip.c @@ -8,7 +8,8 @@ static const char gunzip_usage[] = "gunzip [OPTION]... FILE\n\n" "Uncompress FILE (or standard input if FILE is '-').\n\n" "Options:\n" - "\t-c\tWrite output to standard output\n"; + "\t-c\tWrite output to standard output\n" + "\t-t\tTest compressed file integrity\n"; /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface * Copyright (C) 1992-1993 Jean-loup Gailly @@ -653,7 +654,7 @@ DECLARE(uch, window, 2L*WSIZE); /* local variables */ -int force = 0; /* don't ask questions, compress links (-f) */ +int test_mode = 0; /* check file integrity option */ int foreground; /* set if program run in foreground */ int maxbits = BITS; /* max bits per code for LZW */ int method = DEFLATED;/* compression method */ @@ -714,6 +715,10 @@ int gunzip_main (int argc, char** argv) case 'c': to_stdout = 1; break; + case 't': + test_mode = 1; + break; + default: usage(gunzip_usage); } @@ -786,6 +791,9 @@ int gunzip_main (int argc, char** argv) /* Actually do the compression/decompression. */ unzip(inFileNum, outFileNum); + } else if (test_mode) { + /* Actually do the compression/decompression. */ + unzip(inFileNum, 2); } else { char* pos; @@ -857,17 +865,8 @@ local int get_method(in) uch flags; /* compression flags */ char magic[2]; /* magic header */ - /* If --force and --stdout, zcat == cat, so do not complain about - * premature end of file: use try_byte instead of get_byte. - */ - if (force) { - magic[0] = (char)try_byte(); - magic[1] = (char)try_byte(); - /* If try_byte returned EOF, magic[1] == 0xff */ - } else { - magic[0] = (char)get_byte(); - magic[1] = (char)get_byte(); - } + magic[0] = (char)get_byte(); + magic[1] = (char)get_byte(); method = -1; /* unknown yet */ part_nb++; /* number of parts in gzip file */ header_bytes = 0; @@ -1188,7 +1187,8 @@ void flush_outbuf() { if (outcnt == 0) return; - write_buf(ofd, (char *)outbuf, outcnt); + if (!test_mode) + write_buf(ofd, (char *)outbuf, outcnt); bytes_out += (ulg)outcnt; outcnt = 0; } @@ -1202,8 +1202,8 @@ void flush_window() if (outcnt == 0) return; updcrc(window, outcnt); - write_buf(ofd, (char *)window, outcnt); - + if (!test_mode) + write_buf(ofd, (char *)window, outcnt); bytes_out += (ulg)outcnt; outcnt = 0; } diff --git a/archival/tar.c b/archival/tar.c index 7167d95cd..a53370e85 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -37,6 +37,7 @@ #include <fcntl.h> #include <signal.h> #include <time.h> +#include <utime.h> #include <sys/types.h> #include <sys/sysmacros.h> @@ -106,8 +107,12 @@ static int warnedRoot; static int eofFlag; static long dataCc; static int outFd; -static char outName[TAR_NAME_SIZE]; +static const char *outName; +static int mode; +static int uid; +static int gid; +static time_t mtime; /* * Static data associated with the tar file. @@ -364,8 +369,9 @@ static void readTarFile (int fileCount, char **fileTable) * message is required on errors. */ if (tostdoutFlag == FALSE) { - if (outFd >= 0) - (void) close (outFd); + if (outFd >= 0) { + close (outFd); + } } } @@ -378,29 +384,25 @@ static void readTarFile (int fileCount, char **fileTable) static void readHeader (const TarHeader * hp, int fileCount, char **fileTable) { - int mode; - int uid; - int gid; int checkSum; - unsigned int major; - unsigned int minor; - long size; - time_t mtime; - const char *name; int cc; int hardLink; int softLink; int devFileFlag; + unsigned int major; + unsigned int minor; + long size; + struct utimbuf utb; /* * If the block is completely empty, then this is the end of the * archive file. If the name is null, then just skip this header. */ - name = hp->name; + outName = hp->name; - if (*name == '\0') { + if (*outName == '\0') { for (cc = TAR_BLOCK_SIZE; cc > 0; cc--) { - if (*name++) + if (*outName++) return; } @@ -447,16 +449,16 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable) /* * Check for a directory. */ - if (name[strlen (name) - 1] == '/') + if (outName[strlen (outName) - 1] == '/') mode |= S_IFDIR; /* * Check for absolute paths in the file. * If we find any, then warn the user and make them relative. */ - if (*name == '/') { - while (*name == '/') - name++; + if (*outName == '/') { + while (*outName == '/') + outName++; if (warnedRoot==FALSE) { fprintf (stderr, @@ -470,7 +472,7 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable) * See if we want this file to be restored. * If not, then set up to skip it. */ - if (wantFileName (name, fileCount, fileTable) == FALSE) { + if (wantFileName (outName, fileCount, fileTable) == FALSE) { if ( !hardLink && !softLink && (S_ISREG (mode) || S_ISCHR (mode) || S_ISBLK (mode) || S_ISSOCK(mode) || S_ISFIFO(mode) ) ) { inHeader = (size == 0)? TRUE : FALSE; @@ -494,7 +496,7 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable) else printf ("%9ld %s ", size, timeString (mtime)); } - printf ("%s", name); + printf ("%s", outName); if (hardLink) printf (" (link to \"%s\")", hp->linkName); @@ -515,22 +517,35 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable) * We really want to extract the file. */ if (verboseFlag==TRUE) - printf ("x %s\n", name); + printf ("x %s\n", outName); if (hardLink) { - if (link (hp->linkName, name) < 0) - perror (name); - chown(name, uid, gid); - chmod(name, mode); + if (link (hp->linkName, outName) < 0) + perror (outName); + /* Set the file time */ + utb.actime = mtime; + utb.modtime = mtime; + utime (outName, &utb); + /* Set the file permissions */ + chown(outName, uid, gid); + chmod(outName, mode); return; } if (softLink) { #ifdef S_ISLNK - if (symlink (hp->linkName, name) < 0) - perror (name); - chown(name, uid, gid); - chmod(name, mode); + if (symlink (hp->linkName, outName) < 0) + perror (outName); + /* Try to change ownership of the symlink. + * If libs doesn't support that, don't bother. + * Changing the pointed-to file is the Wrong Thing(tm). + */ +#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) + lchown(outName, uid, gid); +#endif + + /* Do not change permissions or date on symlink, + * since it changes the pointed to file instead. duh. */ #else fprintf (stderr, "Cannot create symbolic links\n"); #endif @@ -545,10 +560,14 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable) * If the file is a directory, then just create the path. */ if (S_ISDIR (mode)) { - createPath (name, mode); - chown(name, uid, gid); - chmod(name, mode); - + createPath (outName, mode); + /* Set the file time */ + utb.actime = mtime; + utb.modtime = mtime; + utime (outName, &utb); + /* Set the file permissions */ + chown(outName, uid, gid); + chmod(outName, mode); return; } @@ -556,7 +575,7 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable) * There is a file to write. * First create the path to it if necessary with default permissions. */ - createPath (name, 0777); + createPath (outName, 0777); inHeader = (size == 0)? TRUE : FALSE; dataCc = size; @@ -569,21 +588,26 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable) else { if ( S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode) ) { devFileFlag = TRUE; - outFd = mknod (name, mode, makedev(major, minor) ); + outFd = mknod (outName, mode, makedev(major, minor) ); } else if (S_ISFIFO(mode) ) { devFileFlag = TRUE; - outFd = mkfifo(name, mode); + outFd = mkfifo(outName, mode); } else { - outFd = open (name, O_WRONLY | O_CREAT | O_TRUNC, mode); + outFd = open (outName, O_WRONLY | O_CREAT | O_TRUNC, mode); } if (outFd < 0) { - perror (name); + perror (outName); skipFileFlag = TRUE; return; } - chown(name, uid, gid); - chmod(name, mode); + /* Set the file time */ + utb.actime = mtime; + utb.modtime = mtime; + utime (outName, &utb); + /* Set the file permissions */ + chown(outName, uid, gid); + chmod(outName, mode); } @@ -591,7 +615,7 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable) * If the file is empty, then that's all we need to do. */ if (size == 0 && (tostdoutFlag == FALSE) && (devFileFlag == FALSE)) { - (void) close (outFd); + close (outFd); outFd = -1; } } @@ -625,7 +649,7 @@ static void readData (const char *cp, int count) if (fullWrite (outFd, cp, count) < 0) { perror (outName); if (tostdoutFlag == FALSE) { - (void) close (outFd); + close (outFd); outFd = -1; } skipFileFlag = TRUE; @@ -633,13 +657,21 @@ static void readData (const char *cp, int count) } /* - * If the write failed, close the file and disable further - * writes to this file. + * Check if we are done writing to the file now. */ if (dataCc <= 0 && tostdoutFlag == FALSE) { + struct utimbuf utb; if (close (outFd)) perror (outName); + /* Set the file time */ + utb.actime = mtime; + utb.modtime = mtime; + utime (outName, &utb); + /* Set the file permissions */ + chown(outName, uid, gid); + chmod(outName, mode); + outFd = -1; } } @@ -720,7 +752,6 @@ static void writeTarFile (int fileCount, char **fileTable) static void saveFile (const char *fileName, int seeLinks) { int status; - int mode; struct stat statbuf; if (verboseFlag==TRUE) @@ -102,6 +102,9 @@ static const struct Applet applets[] = { #ifdef BB_LN //bin {"ln", ln_main}, #endif +#ifdef BB_LOADACM //usr/bin + {"loadacm", loadacm_main}, +#endif #ifdef BB_LOADFONT //usr/bin {"loadfont", loadfont_main}, #endif @@ -232,9 +235,6 @@ static const struct Applet applets[] = { #ifdef BB_GZIP //bin {"gzip", gzip_main}, #endif -#ifdef BB_LOADACM //usr/bin - {"loadacm", loadacm_main}, -#endif {0} }; diff --git a/busybox.def.h b/busybox.def.h index 3982a1c83..503410f1a 100644 --- a/busybox.def.h +++ b/busybox.def.h @@ -36,7 +36,7 @@ //#define BB_LOADACM //#define BB_LOADFONT //#define BB_LOADKMAP -#define BB_LOGGER +//#define BB_LOGGER #define BB_LS #define BB_LSMOD //#define BB_MAKEDEVS @@ -68,7 +68,7 @@ #define BB_SORT #define BB_SWAPONOFF #define BB_SYNC -#define BB_SYSLOGD +//#define BB_SYSLOGD #define BB_TAIL #define BB_TAR #define BB_TEE @@ -90,8 +90,6 @@ // pretty/useful). // // -// enable a second console on TTY2 in init -#define BB_FEATURE_INIT_SECOND_CONSOLE // enable features that use the /proc filesystem #define BB_FEATURE_USE_PROCFS //Enable init being called as /linuxrc diff --git a/busybox_functions.h b/busybox_functions.h deleted file mode 100644 index 61fc48438..000000000 --- a/busybox_functions.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __BUSYBOX_FUNCTIONS_H__ -#define __BUSYBOX_FUNCTIONS_H__ - -int -mkswap(char *device_name, int pages, int check); -/* pages = 0 for autodetection */ - -int -fdflush(char *filename); - -#endif /* __BUSYBOX_FUNCTIONS_H__ */ diff --git a/coreutils/cp.c b/coreutils/cp.c index 83460190a..4af73c274 100644 --- a/coreutils/cp.c +++ b/coreutils/cp.c @@ -33,7 +33,7 @@ static const char cp_usage[] = "cp [OPTION]... SOURCE DEST\n" "\n" "\t-a\tsame as -dpR\n" "\t-d\tpreserve links\n" - "\t-p\tpreserve file attributes if possable\n" + "\t-p\tpreserve file attributes if possible\n" "\t-R\tcopy directories recursively\n"; @@ -33,7 +33,7 @@ static const char cp_usage[] = "cp [OPTION]... SOURCE DEST\n" "\n" "\t-a\tsame as -dpR\n" "\t-d\tpreserve links\n" - "\t-p\tpreserve file attributes if possable\n" + "\t-p\tpreserve file attributes if possible\n" "\t-R\tcopy directories recursively\n"; diff --git a/editors/sed.c b/editors/sed.c index 8e5f695c4..25777243d 100644 --- a/editors/sed.c +++ b/editors/sed.c @@ -46,7 +46,7 @@ static const char sed_usage[] = "\t /REGEXP/ Match specified regexp\n" "\t (! inverts the meaning of the match)\n\n" "\tand COMMAND can be:\n" - "\t s/regexp/replacement/[gp]\n" + "\t s/regexp/replacement/[igp]\n" "\t which attempt to match regexp against the pattern space\n" "\t and if successful replaces the matched portion with replacement.\n\n" "\t aTEXT\n" @@ -8,7 +8,8 @@ static const char gunzip_usage[] = "gunzip [OPTION]... FILE\n\n" "Uncompress FILE (or standard input if FILE is '-').\n\n" "Options:\n" - "\t-c\tWrite output to standard output\n"; + "\t-c\tWrite output to standard output\n" + "\t-t\tTest compressed file integrity\n"; /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface * Copyright (C) 1992-1993 Jean-loup Gailly @@ -653,7 +654,7 @@ DECLARE(uch, window, 2L*WSIZE); /* local variables */ -int force = 0; /* don't ask questions, compress links (-f) */ +int test_mode = 0; /* check file integrity option */ int foreground; /* set if program run in foreground */ int maxbits = BITS; /* max bits per code for LZW */ int method = DEFLATED;/* compression method */ @@ -714,6 +715,10 @@ int gunzip_main (int argc, char** argv) case 'c': to_stdout = 1; break; + case 't': + test_mode = 1; + break; + default: usage(gunzip_usage); } @@ -786,6 +791,9 @@ int gunzip_main (int argc, char** argv) /* Actually do the compression/decompression. */ unzip(inFileNum, outFileNum); + } else if (test_mode) { + /* Actually do the compression/decompression. */ + unzip(inFileNum, 2); } else { char* pos; @@ -857,17 +865,8 @@ local int get_method(in) uch flags; /* compression flags */ char magic[2]; /* magic header */ - /* If --force and --stdout, zcat == cat, so do not complain about - * premature end of file: use try_byte instead of get_byte. - */ - if (force) { - magic[0] = (char)try_byte(); - magic[1] = (char)try_byte(); - /* If try_byte returned EOF, magic[1] == 0xff */ - } else { - magic[0] = (char)get_byte(); - magic[1] = (char)get_byte(); - } + magic[0] = (char)get_byte(); + magic[1] = (char)get_byte(); method = -1; /* unknown yet */ part_nb++; /* number of parts in gzip file */ header_bytes = 0; @@ -1188,7 +1187,8 @@ void flush_outbuf() { if (outcnt == 0) return; - write_buf(ofd, (char *)outbuf, outcnt); + if (!test_mode) + write_buf(ofd, (char *)outbuf, outcnt); bytes_out += (ulg)outcnt; outcnt = 0; } @@ -1202,8 +1202,8 @@ void flush_window() if (outcnt == 0) return; updcrc(window, outcnt); - write_buf(ofd, (char *)window, outcnt); - + if (!test_mode) + write_buf(ofd, (char *)window, outcnt); bytes_out += (ulg)outcnt; outcnt = 0; } @@ -23,6 +23,7 @@ #include "internal.h" #include <stdio.h> +#include <string.h> #include <stdlib.h> #include <stdarg.h> #include <unistd.h> @@ -55,22 +56,57 @@ #endif -#define VT_PRIMARY "/dev/tty1" /* Primary virtual console */ -#define VT_SECONDARY "/dev/tty2" /* Virtual console */ -#define VT_LOG "/dev/tty3" /* Virtual console */ -#define SERIAL_CON0 "/dev/ttyS0" /* Primary serial console */ -#define SERIAL_CON1 "/dev/ttyS1" /* Serial console */ -#define GETTY "/sbin/getty" /* Default location of getty */ -#define SHELL "/bin/sh" /* Default shell */ -#define INITTAB "/etc/inittab" /* inittab file location */ -#ifndef BB_INIT_SCRIPT -#define BB_INIT_SCRIPT "/etc/init.d/rcS" /* Initscript. */ -#endif - -#if 1 +#define VT_PRIMARY "/dev/tty1" /* Primary virtual console */ +#define VT_SECONDARY "/dev/tty2" /* Virtual console */ +#define VT_LOG "/dev/tty3" /* Virtual console */ +#define SERIAL_CON0 "/dev/ttyS0" /* Primary serial console */ +#define SERIAL_CON1 "/dev/ttyS1" /* Serial console */ +#define SHELL "/bin/sh" /* Default shell */ +#define REBOOT "/sbin/reboot" /* Default ctrl-alt-del command */ +#define INITTAB "/etc/inittab" /* inittab file location */ +#define INIT_SCRIPT "/etc/init.d/rcS" /* Default sysinit script. */ #define LOG 0x1 #define CONSOLE 0x2 + +/* Allowed init action types */ +typedef enum { + SYSINIT=1, + CTRLALTDEL, + RESPAWN, + ASKFIRST, + WAIT, + ONCE +} initActionEnum; + +/* And now a list of the actions we support in the version of init */ +typedef struct initActionType{ + const char* name; + initActionEnum action; +} initActionType; + +static const struct initActionType actions[] = { + {"sysinit", SYSINIT}, + {"ctrlaltdel", CTRLALTDEL}, + {"respawn", RESPAWN}, + {"askfirst", ASKFIRST}, + {"wait", WAIT}, + {"once", ONCE}, + {0} +}; + +/* Set up a linked list of initactions, to be read from inittab */ +typedef struct initActionTag initAction; +struct initActionTag { + pid_t pid; + char process[256]; + char *console; + initAction *nextPtr; + initActionEnum action; +}; +initAction* initActionList = NULL; + + static char *console = _PATH_CONSOLE; static char *second_console = VT_SECONDARY; static char *log = VT_LOG; @@ -100,8 +136,9 @@ int device_open(char *device, int mode) * device may be bitwise-or'd from LOG | CONSOLE */ void message(int device, char *fmt, ...) { - int fd; va_list arguments; + int fd; + #ifdef BB_SYSLOGD /* Log the message to syslogd */ @@ -298,16 +335,18 @@ static int waitfor(int pid) } -static pid_t run(const char * const* command, +static pid_t run(char* command, char *terminal, int get_enter) { - int fd; + int i; pid_t pid; - const char * const* cmd = command+1; + char* tmpCmd; + char* cmd[255]; static const char press_enter[] = "\nPlease press Enter to activate this console. "; if ((pid = fork()) == 0) { + int fd; /* Clean up */ close(0); close(1); @@ -321,7 +360,7 @@ static pid_t run(const char * const* command, signal(SIGTERM, SIG_DFL); if ((fd = device_open(terminal, O_RDWR)) < 0) { - message(LOG, "Bummer, can't open %s\r\n", terminal); + message(LOG|CONSOLE, "Bummer, can't open %s\r\n", terminal); exit(-1); } dup(fd); @@ -340,21 +379,32 @@ static pid_t run(const char * const* command, */ char c; message(LOG, "Waiting for enter to start '%s' (pid %d, console %s)\r\n", - *cmd, getpid(), terminal ); - write(1, press_enter, sizeof(press_enter) - 1); - read(0, &c, 1); + command, getpid(), terminal ); + write(fileno(stdout), press_enter, sizeof(press_enter) - 1); + read(fileno(stdin), &c, 1); } + /* Convert command (char*) into cmd (char**, one word per string) */ + for (tmpCmd=command, i=0; (tmpCmd=strsep(&command, " \t")) != NULL;) { + if (*tmpCmd != '\0') { + cmd[i] = tmpCmd; + tmpCmd++; + i++; + } + } + cmd[i] = NULL; + /* Log the process name and args */ - message(LOG|CONSOLE, "Starting pid %d, console %s: '", getpid(), terminal); - while ( *cmd) message(LOG|CONSOLE, "%s ", *cmd++); - message(LOG|CONSOLE, "'\r\n"); - + message(LOG, "Starting pid %d, console %s: '%s'\r\n", + getpid(), terminal, cmd[0]); + /* Now run it. The new program will take over this PID, * so nothing further in init.c should be run. */ - execvp(*command, (char**)command+1); + execvp(cmd[0], cmd); - message(LOG, "Bummer, could not run '%s'\n", command); + /* We're still here? Some error happened. */ + message(LOG|CONSOLE, "Bummer, could not run '%s': %s\n", cmd[0], + strerror(errno)); exit(-1); } return pid; @@ -365,15 +415,13 @@ static pid_t run(const char * const* command, static void check_memory() { struct stat statbuf; - const char* const swap_on_cmd[] = - { "/bin/swapon", "swapon", "-a", 0}; if (mem_total() > 3500) return; if (stat("/etc/fstab", &statbuf) == 0) { /* Try to turn on swap */ - waitfor(run(swap_on_cmd, log, FALSE)); + waitfor(run("/bin/swapon swapon -a", log, FALSE)); if (mem_total() < 3500) goto goodnight; } else @@ -385,33 +433,28 @@ goodnight: while (1) sleep(1); } +#ifndef DEBUG_INIT static void shutdown_system(void) { - const char* const swap_off_cmd[] = { "swapoff", "swapoff", "-a", 0}; - const char* const umount_cmd[] = { "umount", "umount", "-a", 0}; - -#ifndef DEBUG_INIT /* Allow Ctrl-Alt-Del to reboot system. */ reboot(RB_ENABLE_CAD); -#endif message(CONSOLE, "\r\nThe system is going down NOW !!\r\n"); sync(); + /* Send signals to every process _except_ pid 1 */ message(CONSOLE, "Sending SIGHUP to all processes.\r\n"); -#ifndef DEBUG_INIT kill(-1, SIGHUP); -#endif sleep(2); sync(); + message(CONSOLE, "Sending SIGKILL to all processes.\r\n"); -#ifndef DEBUG_INIT kill(-1, SIGKILL); -#endif sleep(1); + message(CONSOLE, "Disabling swap.\r\n"); - waitfor(run( swap_off_cmd, console, FALSE)); + waitfor(run( "swapoff -a", console, FALSE)); message(CONSOLE, "Unmounting filesystems.\r\n"); - waitfor(run( umount_cmd, console, FALSE)); + waitfor(run( "umount -a", console, FALSE)); sync(); if (kernel_version > 0 && kernel_version <= 2 * 65536 + 2 * 256 + 11) { /* bdflush, kupdate not needed for kernels >2.2.11 */ @@ -427,14 +470,12 @@ static void halt_signal(int sig) message(CONSOLE, "The system is halted. Press CTRL-ALT-DEL or turn off power\r\n"); sync(); -#ifndef DEBUG_INIT #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) if (sig == SIGUSR2) reboot(RB_POWER_OFF); else #endif - reboot(RB_HALT_SYSTEM); -#endif + reboot(RB_HALT_SYSTEM); exit(0); } @@ -443,64 +484,157 @@ static void reboot_signal(int sig) shutdown_system(); message(CONSOLE, "Please stand by while rebooting the system.\r\n"); sync(); -#ifndef DEBUG_INIT reboot(RB_AUTOBOOT); -#endif exit(0); } +static void ctrl_alt_del_signal(int sig) +{ + initAction* a; + /* Run whatever we are supposed to run */ + for( a=initActionList ; a; a=a->nextPtr) { + if (a->action == CTRLALTDEL) { + waitfor(run(a->process, console, FALSE)); + } + } +} +#endif + +void new_initAction (const struct initActionType *a, + char* process, char* console) +{ + initAction* newAction; + newAction = calloc ((size_t)(1), sizeof(initAction)); + if (!newAction) { + fprintf(stderr, "Memory allocation failure\n"); + while (1) sleep(1); + } + newAction->nextPtr = initActionList; + initActionList = newAction; + strncpy( newAction->process, process, 255); + newAction->action = a->action; + newAction->console = console; + newAction->pid = 0; +} + +void delete_initAction (initAction *action) +{ + initAction *a, *b=NULL; + for( a=initActionList ; a; b=a, a=a->nextPtr) { + if (a == action && b != NULL) { + b->nextPtr=a->nextPtr; + free( a); + break; + } + } +} + +void parse_inittab(void) +{ + FILE* file; + char buf[256]; + char *p, *q, *r; + const struct initActionType *a = actions; + int foundIt; + + + file = fopen(INITTAB, "r"); + if (file == NULL) { + /* No inittab file -- set up some default behavior */ + + /* Askfirst shell on tty1 */ + new_initAction( &(actions[3]), SHELL, console ); + /* Askfirst shell on tty2 */ + if (second_console != NULL) + new_initAction( &(actions[3]), SHELL, second_console ); + /* Control-alt-del */ + new_initAction( &(actions[1]), REBOOT, console ); + /* sysinit */ + new_initAction( &(actions[0]), INIT_SCRIPT, console ); + + return; + } + + while ( fgets(buf, 255, file) != NULL) { + foundIt=FALSE; + for(p = buf; *p == ' ' || *p == '\t'; p++); + if (*p == '#' || *p == '\n') continue; + + /* Trim the trailing \n */ + q = strrchr( p, '\n'); + if (q != NULL) + *q='\0'; + + /* Skip past the ID field and the runlevel + * field (both are ignored) */ + p = strchr( p, ':'); + + /* Now peal off the process field from the end + * of the string */ + q = strrchr( p, ':'); + if ( q == NULL || *(q+1) == '\0' ) { + fprintf(stderr, "Bad inittab entry: %s\n", buf); + continue; + } else { + *q='\0'; + ++q; + } + + /* Now peal off the action field */ + r = strrchr( p, ':'); + if ( r == NULL || *(r+1) == '\0') { + fprintf(stderr, "Bad inittab entry: %s\n", buf); + continue; + } else { + ++r; + } + + /* Ok, now process it */ + a = actions; + while (a->name != 0) { + if (strcmp(a->name, r) == 0) { + new_initAction( a, q, NULL); + foundIt=TRUE; + } + a++; + } + if (foundIt==TRUE) + continue; + else { + /* Choke on an unknown action */ + fprintf(stderr, "Bad inittab entry: %s\n", buf); + } + } + return; +} + + extern int init_main(int argc, char **argv) { - int run_rc = FALSE; + initAction *a; + pid_t wpid; + int status; int single = FALSE; - int wait_for_enter_tty1 = TRUE; - int wait_for_enter_tty2 = TRUE; - pid_t pid1 = 0; - pid_t pid2 = 0; - struct stat statbuf; - char which_vt1[30]; - char which_vt2[30]; - const char* const rc_script_command[] = { BB_INIT_SCRIPT, BB_INIT_SCRIPT, 0}; - const char* const getty1_command[] = { GETTY, GETTY, "38400", which_vt1, 0}; - const char* const getty2_command[] = { GETTY, GETTY, "38400", which_vt2, 0}; - const char* const shell_command[] = { SHELL, "-" SHELL, 0}; - const char* const* tty1_command = shell_command; - const char* const* tty2_command = shell_command; -#ifdef BB_INIT_CMD_IF_RC_SCRIPT_EXITS - const char* const rc_exit_command[] = { "BB_INIT_CMD_IF_RC_SCRIPT_EXITS", - "BB_INIT_CMD_IF_RC_SCRIPT_EXITS", 0 }; -#endif -#ifdef DEBUG_INIT - char *hello_msg_format = - "init(%d) started: BusyBox v%s (%s) multi-call binary\r\n"; -#else - char *hello_msg_format = - "init started: BusyBox v%s (%s) multi-call binary\r\n"; -#endif - #ifndef DEBUG_INIT /* Expect to be PID 1 iff we are run as init (not linuxrc) */ if (getpid() != 1 && strstr(argv[0], "init")!=NULL ) { usage( "init\n\nInit is the parent of all processes.\n\n" "This version of init is designed to be run only by the kernel\n"); } -#endif - /* Set up sig handlers -- be sure to - * clear all of these in run() */ + /* Set up sig handlers -- be sure to clear all of these in run() */ signal(SIGUSR1, halt_signal); signal(SIGUSR2, reboot_signal); - signal(SIGINT, reboot_signal); + signal(SIGINT, ctrl_alt_del_signal); signal(SIGTERM, reboot_signal); /* Turn off rebooting via CTL-ALT-DEL -- we get a * SIGINT on CAD so we can shut things down gracefully... */ -#ifndef DEBUG_INIT reboot(RB_DISABLE_CAD); #endif - + /* Figure out where the default console should be */ console_init(); @@ -517,9 +651,13 @@ extern int init_main(int argc, char **argv) /* Hello world */ #ifndef DEBUG_INIT - message(CONSOLE|LOG, hello_msg_format, BB_VER, BB_BT); + message(CONSOLE|LOG, + "init started: BusyBox v%s (%s) multi-call binary\r\n", + BB_VER, BB_BT); #else - message(CONSOLE|LOG, hello_msg_format, getpid(), BB_VER, BB_BT); + message(CONSOLE|LOG, + "init(%d) started: BusyBox v%s (%s) multi-call binary\r\n", + getpid(), BB_VER, BB_BT); #endif @@ -537,150 +675,77 @@ extern int init_main(int argc, char **argv) if ( argc > 1 && (!strcmp(argv[1], "single") || !strcmp(argv[1], "-s") || !strcmp(argv[1], "1"))) { single = TRUE; - tty1_command = shell_command; - tty2_command = shell_command; + /* Ask first then start a shell on tty2 */ + if (second_console != NULL) + new_initAction( &(actions[3]), SHELL, second_console); + /* Ask first then start a shell on tty1 */ + new_initAction( &(actions[3]), SHELL, console); + } else { + /* Not in single user mode -- see what inittab says */ + parse_inittab(); } - /* Make sure an init script exists before trying to run it */ - if (single==FALSE && stat(BB_INIT_SCRIPT, &statbuf)==0) { - run_rc = TRUE; - wait_for_enter_tty1 = FALSE; - tty1_command = rc_script_command; + /* Now run everything that needs to be run */ + + /* First run sysinit */ + for( a=initActionList ; a; a=a->nextPtr) { + if (a->action == SYSINIT) { + waitfor(run(a->process, console, FALSE)); + /* Now remove the "sysinit" entry from the list */ + delete_initAction( a); + } } - - /* Make sure /sbin/getty exists before trying to run it */ - if (stat(GETTY, &statbuf)==0) { - char* where; - /* First do tty2 */ - wait_for_enter_tty2 = FALSE; - where = strrchr( second_console, '/'); - if ( where != NULL) { - where++; - strncpy( which_vt2, where, sizeof(which_vt2)); + /* Next run anything that wants to block */ + for( a=initActionList ; a; a=a->nextPtr) { + if (a->action == WAIT) { + waitfor(run(a->process, console, FALSE)); + /* Now remove the "wait" entry from the list */ + delete_initAction( a); } - tty2_command = getty2_command; - - /* Check on hooking a getty onto tty1 */ - if (run_rc == FALSE && single==FALSE) { - wait_for_enter_tty1 = FALSE; - where = strrchr( console, '/'); - if ( where != NULL) { - where++; - strncpy( which_vt1, where, sizeof(which_vt1)); - } - tty1_command = getty1_command; + } + /* Next run anything to be run only once */ + for( a=initActionList ; a; a=a->nextPtr) { + if (a->action == ONCE) { + run(a->process, console, FALSE); + /* Now remove the "once" entry from the list */ + delete_initAction( a); } } - - /* Ok, now launch the tty1_command and tty2_command */ + /* Now run the looping stuff */ for (;;) { - pid_t wpid; - int status; - - if (pid1 == 0 && tty1_command) { - pid1 = run(tty1_command, console, wait_for_enter_tty1); - } -#ifdef BB_FEATURE_INIT_SECOND_CONSOLE - if (pid2 == 0 && tty2_command && second_console) { - pid2 = run(tty2_command, second_console, wait_for_enter_tty2); + for( a=initActionList ; a; a=a->nextPtr) { + /* Only run stuff with pid==0. If they have + * a pid, that means they are still running */ + if (a->pid == 0) { + switch(a->action) { + case RESPAWN: + /* run the respawn stuff */ + a->pid = run(a->process, console, FALSE); + break; + case ASKFIRST: + /* run the askfirst stuff */ + a->pid = waitfor(run(a->process, console, TRUE)); + break; + /* silence the compiler's whining */ + default: + break; + } + } } -#endif + wpid = wait(&status); + /* Find out who died and clean up their corpse */ if (wpid > 0 ) { message(LOG, "pid %d exited, status=%x.\n", wpid, status); - } - /* Don't respawn init script if it exits */ - if (wpid == pid1) { - if (run_rc == FALSE) { - pid1 = 0; + for( a=initActionList ; a; a=a->nextPtr) { + if (a->pid==wpid) { + a->pid=0; + } } -#ifdef BB_INIT_CMD_IF_RC_SCRIPT_EXITS - else { - pid1 = 0; - run_rc=FALSE; - wait_for_enter_tty1=TRUE; - tty1_command=rc_exit_command; - } -#endif } -#ifdef BB_FEATURE_INIT_SECOND_CONSOLE - if (wpid == pid2) { - pid2 = 0; - } -#endif - sleep(1); - } -} - -#else - - -void parse_inittab(void) -{ - FILE* file; - char buf[256]; - char action[256]=""; - char process[256]=""; - char *p, *q; - - - if ((file = fopen(INITTAB, "r")) < 0) { - /* No inittab file -- set up some default behavior */ - - /* FIXME */ - return; - } - - while ( fgets(buf, 255, file) != NULL) { - for(p = buf; *p == ' ' || *p == '\t'; p++); - if (*p == '#' || *p == '\n') continue; - - /* Trim the trailing \n */ - q = strrchr( p, '\n'); - if (q != NULL) - *q='\0'; - - /* Skip past the ID field and the runlevel - * field (both are ignored) */ - p = strchr( p, ':'); - - /* Now peal off the process field from the end - * of the string */ - q = strrchr( p, ':'); - if ( q == NULL || q+1 == NULL) - goto choke; - *q='\0'; - strcpy( process, ++q); - fprintf(stderr, "process=%s\n", process); - - - /* Now peal off the action field */ - q = strrchr( p, ':'); - if ( q == NULL || q+1 == NULL) - goto choke; - strcpy( action, ++q); - fprintf(stderr, "action=%s\n", action); - - - /* Ok, now do the right thing */ + sleep(1); } - return; - -choke: - //message(CONSOLE, "Bad entry:"); - fprintf(stderr, "Bad inittab entry: %s", buf); - while (1) sleep(1); - -} - - -extern int init_main(int argc, char **argv) -{ - parse_inittab(); - exit( TRUE); } - -#endif diff --git a/init/init.c b/init/init.c index b71c9f74e..be04ec34f 100644 --- a/init/init.c +++ b/init/init.c @@ -23,6 +23,7 @@ #include "internal.h" #include <stdio.h> +#include <string.h> #include <stdlib.h> #include <stdarg.h> #include <unistd.h> @@ -55,22 +56,57 @@ #endif -#define VT_PRIMARY "/dev/tty1" /* Primary virtual console */ -#define VT_SECONDARY "/dev/tty2" /* Virtual console */ -#define VT_LOG "/dev/tty3" /* Virtual console */ -#define SERIAL_CON0 "/dev/ttyS0" /* Primary serial console */ -#define SERIAL_CON1 "/dev/ttyS1" /* Serial console */ -#define GETTY "/sbin/getty" /* Default location of getty */ -#define SHELL "/bin/sh" /* Default shell */ -#define INITTAB "/etc/inittab" /* inittab file location */ -#ifndef BB_INIT_SCRIPT -#define BB_INIT_SCRIPT "/etc/init.d/rcS" /* Initscript. */ -#endif - -#if 1 +#define VT_PRIMARY "/dev/tty1" /* Primary virtual console */ +#define VT_SECONDARY "/dev/tty2" /* Virtual console */ +#define VT_LOG "/dev/tty3" /* Virtual console */ +#define SERIAL_CON0 "/dev/ttyS0" /* Primary serial console */ +#define SERIAL_CON1 "/dev/ttyS1" /* Serial console */ +#define SHELL "/bin/sh" /* Default shell */ +#define REBOOT "/sbin/reboot" /* Default ctrl-alt-del command */ +#define INITTAB "/etc/inittab" /* inittab file location */ +#define INIT_SCRIPT "/etc/init.d/rcS" /* Default sysinit script. */ #define LOG 0x1 #define CONSOLE 0x2 + +/* Allowed init action types */ +typedef enum { + SYSINIT=1, + CTRLALTDEL, + RESPAWN, + ASKFIRST, + WAIT, + ONCE +} initActionEnum; + +/* And now a list of the actions we support in the version of init */ +typedef struct initActionType{ + const char* name; + initActionEnum action; +} initActionType; + +static const struct initActionType actions[] = { + {"sysinit", SYSINIT}, + {"ctrlaltdel", CTRLALTDEL}, + {"respawn", RESPAWN}, + {"askfirst", ASKFIRST}, + {"wait", WAIT}, + {"once", ONCE}, + {0} +}; + +/* Set up a linked list of initactions, to be read from inittab */ +typedef struct initActionTag initAction; +struct initActionTag { + pid_t pid; + char process[256]; + char *console; + initAction *nextPtr; + initActionEnum action; +}; +initAction* initActionList = NULL; + + static char *console = _PATH_CONSOLE; static char *second_console = VT_SECONDARY; static char *log = VT_LOG; @@ -100,8 +136,9 @@ int device_open(char *device, int mode) * device may be bitwise-or'd from LOG | CONSOLE */ void message(int device, char *fmt, ...) { - int fd; va_list arguments; + int fd; + #ifdef BB_SYSLOGD /* Log the message to syslogd */ @@ -298,16 +335,18 @@ static int waitfor(int pid) } -static pid_t run(const char * const* command, +static pid_t run(char* command, char *terminal, int get_enter) { - int fd; + int i; pid_t pid; - const char * const* cmd = command+1; + char* tmpCmd; + char* cmd[255]; static const char press_enter[] = "\nPlease press Enter to activate this console. "; if ((pid = fork()) == 0) { + int fd; /* Clean up */ close(0); close(1); @@ -321,7 +360,7 @@ static pid_t run(const char * const* command, signal(SIGTERM, SIG_DFL); if ((fd = device_open(terminal, O_RDWR)) < 0) { - message(LOG, "Bummer, can't open %s\r\n", terminal); + message(LOG|CONSOLE, "Bummer, can't open %s\r\n", terminal); exit(-1); } dup(fd); @@ -340,21 +379,32 @@ static pid_t run(const char * const* command, */ char c; message(LOG, "Waiting for enter to start '%s' (pid %d, console %s)\r\n", - *cmd, getpid(), terminal ); - write(1, press_enter, sizeof(press_enter) - 1); - read(0, &c, 1); + command, getpid(), terminal ); + write(fileno(stdout), press_enter, sizeof(press_enter) - 1); + read(fileno(stdin), &c, 1); } + /* Convert command (char*) into cmd (char**, one word per string) */ + for (tmpCmd=command, i=0; (tmpCmd=strsep(&command, " \t")) != NULL;) { + if (*tmpCmd != '\0') { + cmd[i] = tmpCmd; + tmpCmd++; + i++; + } + } + cmd[i] = NULL; + /* Log the process name and args */ - message(LOG|CONSOLE, "Starting pid %d, console %s: '", getpid(), terminal); - while ( *cmd) message(LOG|CONSOLE, "%s ", *cmd++); - message(LOG|CONSOLE, "'\r\n"); - + message(LOG, "Starting pid %d, console %s: '%s'\r\n", + getpid(), terminal, cmd[0]); + /* Now run it. The new program will take over this PID, * so nothing further in init.c should be run. */ - execvp(*command, (char**)command+1); + execvp(cmd[0], cmd); - message(LOG, "Bummer, could not run '%s'\n", command); + /* We're still here? Some error happened. */ + message(LOG|CONSOLE, "Bummer, could not run '%s': %s\n", cmd[0], + strerror(errno)); exit(-1); } return pid; @@ -365,15 +415,13 @@ static pid_t run(const char * const* command, static void check_memory() { struct stat statbuf; - const char* const swap_on_cmd[] = - { "/bin/swapon", "swapon", "-a", 0}; if (mem_total() > 3500) return; if (stat("/etc/fstab", &statbuf) == 0) { /* Try to turn on swap */ - waitfor(run(swap_on_cmd, log, FALSE)); + waitfor(run("/bin/swapon swapon -a", log, FALSE)); if (mem_total() < 3500) goto goodnight; } else @@ -385,33 +433,28 @@ goodnight: while (1) sleep(1); } +#ifndef DEBUG_INIT static void shutdown_system(void) { - const char* const swap_off_cmd[] = { "swapoff", "swapoff", "-a", 0}; - const char* const umount_cmd[] = { "umount", "umount", "-a", 0}; - -#ifndef DEBUG_INIT /* Allow Ctrl-Alt-Del to reboot system. */ reboot(RB_ENABLE_CAD); -#endif message(CONSOLE, "\r\nThe system is going down NOW !!\r\n"); sync(); + /* Send signals to every process _except_ pid 1 */ message(CONSOLE, "Sending SIGHUP to all processes.\r\n"); -#ifndef DEBUG_INIT kill(-1, SIGHUP); -#endif sleep(2); sync(); + message(CONSOLE, "Sending SIGKILL to all processes.\r\n"); -#ifndef DEBUG_INIT kill(-1, SIGKILL); -#endif sleep(1); + message(CONSOLE, "Disabling swap.\r\n"); - waitfor(run( swap_off_cmd, console, FALSE)); + waitfor(run( "swapoff -a", console, FALSE)); message(CONSOLE, "Unmounting filesystems.\r\n"); - waitfor(run( umount_cmd, console, FALSE)); + waitfor(run( "umount -a", console, FALSE)); sync(); if (kernel_version > 0 && kernel_version <= 2 * 65536 + 2 * 256 + 11) { /* bdflush, kupdate not needed for kernels >2.2.11 */ @@ -427,14 +470,12 @@ static void halt_signal(int sig) message(CONSOLE, "The system is halted. Press CTRL-ALT-DEL or turn off power\r\n"); sync(); -#ifndef DEBUG_INIT #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) if (sig == SIGUSR2) reboot(RB_POWER_OFF); else #endif - reboot(RB_HALT_SYSTEM); -#endif + reboot(RB_HALT_SYSTEM); exit(0); } @@ -443,64 +484,157 @@ static void reboot_signal(int sig) shutdown_system(); message(CONSOLE, "Please stand by while rebooting the system.\r\n"); sync(); -#ifndef DEBUG_INIT reboot(RB_AUTOBOOT); -#endif exit(0); } +static void ctrl_alt_del_signal(int sig) +{ + initAction* a; + /* Run whatever we are supposed to run */ + for( a=initActionList ; a; a=a->nextPtr) { + if (a->action == CTRLALTDEL) { + waitfor(run(a->process, console, FALSE)); + } + } +} +#endif + +void new_initAction (const struct initActionType *a, + char* process, char* console) +{ + initAction* newAction; + newAction = calloc ((size_t)(1), sizeof(initAction)); + if (!newAction) { + fprintf(stderr, "Memory allocation failure\n"); + while (1) sleep(1); + } + newAction->nextPtr = initActionList; + initActionList = newAction; + strncpy( newAction->process, process, 255); + newAction->action = a->action; + newAction->console = console; + newAction->pid = 0; +} + +void delete_initAction (initAction *action) +{ + initAction *a, *b=NULL; + for( a=initActionList ; a; b=a, a=a->nextPtr) { + if (a == action && b != NULL) { + b->nextPtr=a->nextPtr; + free( a); + break; + } + } +} + +void parse_inittab(void) +{ + FILE* file; + char buf[256]; + char *p, *q, *r; + const struct initActionType *a = actions; + int foundIt; + + + file = fopen(INITTAB, "r"); + if (file == NULL) { + /* No inittab file -- set up some default behavior */ + + /* Askfirst shell on tty1 */ + new_initAction( &(actions[3]), SHELL, console ); + /* Askfirst shell on tty2 */ + if (second_console != NULL) + new_initAction( &(actions[3]), SHELL, second_console ); + /* Control-alt-del */ + new_initAction( &(actions[1]), REBOOT, console ); + /* sysinit */ + new_initAction( &(actions[0]), INIT_SCRIPT, console ); + + return; + } + + while ( fgets(buf, 255, file) != NULL) { + foundIt=FALSE; + for(p = buf; *p == ' ' || *p == '\t'; p++); + if (*p == '#' || *p == '\n') continue; + + /* Trim the trailing \n */ + q = strrchr( p, '\n'); + if (q != NULL) + *q='\0'; + + /* Skip past the ID field and the runlevel + * field (both are ignored) */ + p = strchr( p, ':'); + + /* Now peal off the process field from the end + * of the string */ + q = strrchr( p, ':'); + if ( q == NULL || *(q+1) == '\0' ) { + fprintf(stderr, "Bad inittab entry: %s\n", buf); + continue; + } else { + *q='\0'; + ++q; + } + + /* Now peal off the action field */ + r = strrchr( p, ':'); + if ( r == NULL || *(r+1) == '\0') { + fprintf(stderr, "Bad inittab entry: %s\n", buf); + continue; + } else { + ++r; + } + + /* Ok, now process it */ + a = actions; + while (a->name != 0) { + if (strcmp(a->name, r) == 0) { + new_initAction( a, q, NULL); + foundIt=TRUE; + } + a++; + } + if (foundIt==TRUE) + continue; + else { + /* Choke on an unknown action */ + fprintf(stderr, "Bad inittab entry: %s\n", buf); + } + } + return; +} + + extern int init_main(int argc, char **argv) { - int run_rc = FALSE; + initAction *a; + pid_t wpid; + int status; int single = FALSE; - int wait_for_enter_tty1 = TRUE; - int wait_for_enter_tty2 = TRUE; - pid_t pid1 = 0; - pid_t pid2 = 0; - struct stat statbuf; - char which_vt1[30]; - char which_vt2[30]; - const char* const rc_script_command[] = { BB_INIT_SCRIPT, BB_INIT_SCRIPT, 0}; - const char* const getty1_command[] = { GETTY, GETTY, "38400", which_vt1, 0}; - const char* const getty2_command[] = { GETTY, GETTY, "38400", which_vt2, 0}; - const char* const shell_command[] = { SHELL, "-" SHELL, 0}; - const char* const* tty1_command = shell_command; - const char* const* tty2_command = shell_command; -#ifdef BB_INIT_CMD_IF_RC_SCRIPT_EXITS - const char* const rc_exit_command[] = { "BB_INIT_CMD_IF_RC_SCRIPT_EXITS", - "BB_INIT_CMD_IF_RC_SCRIPT_EXITS", 0 }; -#endif -#ifdef DEBUG_INIT - char *hello_msg_format = - "init(%d) started: BusyBox v%s (%s) multi-call binary\r\n"; -#else - char *hello_msg_format = - "init started: BusyBox v%s (%s) multi-call binary\r\n"; -#endif - #ifndef DEBUG_INIT /* Expect to be PID 1 iff we are run as init (not linuxrc) */ if (getpid() != 1 && strstr(argv[0], "init")!=NULL ) { usage( "init\n\nInit is the parent of all processes.\n\n" "This version of init is designed to be run only by the kernel\n"); } -#endif - /* Set up sig handlers -- be sure to - * clear all of these in run() */ + /* Set up sig handlers -- be sure to clear all of these in run() */ signal(SIGUSR1, halt_signal); signal(SIGUSR2, reboot_signal); - signal(SIGINT, reboot_signal); + signal(SIGINT, ctrl_alt_del_signal); signal(SIGTERM, reboot_signal); /* Turn off rebooting via CTL-ALT-DEL -- we get a * SIGINT on CAD so we can shut things down gracefully... */ -#ifndef DEBUG_INIT reboot(RB_DISABLE_CAD); #endif - + /* Figure out where the default console should be */ console_init(); @@ -517,9 +651,13 @@ extern int init_main(int argc, char **argv) /* Hello world */ #ifndef DEBUG_INIT - message(CONSOLE|LOG, hello_msg_format, BB_VER, BB_BT); + message(CONSOLE|LOG, + "init started: BusyBox v%s (%s) multi-call binary\r\n", + BB_VER, BB_BT); #else - message(CONSOLE|LOG, hello_msg_format, getpid(), BB_VER, BB_BT); + message(CONSOLE|LOG, + "init(%d) started: BusyBox v%s (%s) multi-call binary\r\n", + getpid(), BB_VER, BB_BT); #endif @@ -537,150 +675,77 @@ extern int init_main(int argc, char **argv) if ( argc > 1 && (!strcmp(argv[1], "single") || !strcmp(argv[1], "-s") || !strcmp(argv[1], "1"))) { single = TRUE; - tty1_command = shell_command; - tty2_command = shell_command; + /* Ask first then start a shell on tty2 */ + if (second_console != NULL) + new_initAction( &(actions[3]), SHELL, second_console); + /* Ask first then start a shell on tty1 */ + new_initAction( &(actions[3]), SHELL, console); + } else { + /* Not in single user mode -- see what inittab says */ + parse_inittab(); } - /* Make sure an init script exists before trying to run it */ - if (single==FALSE && stat(BB_INIT_SCRIPT, &statbuf)==0) { - run_rc = TRUE; - wait_for_enter_tty1 = FALSE; - tty1_command = rc_script_command; + /* Now run everything that needs to be run */ + + /* First run sysinit */ + for( a=initActionList ; a; a=a->nextPtr) { + if (a->action == SYSINIT) { + waitfor(run(a->process, console, FALSE)); + /* Now remove the "sysinit" entry from the list */ + delete_initAction( a); + } } - - /* Make sure /sbin/getty exists before trying to run it */ - if (stat(GETTY, &statbuf)==0) { - char* where; - /* First do tty2 */ - wait_for_enter_tty2 = FALSE; - where = strrchr( second_console, '/'); - if ( where != NULL) { - where++; - strncpy( which_vt2, where, sizeof(which_vt2)); + /* Next run anything that wants to block */ + for( a=initActionList ; a; a=a->nextPtr) { + if (a->action == WAIT) { + waitfor(run(a->process, console, FALSE)); + /* Now remove the "wait" entry from the list */ + delete_initAction( a); } - tty2_command = getty2_command; - - /* Check on hooking a getty onto tty1 */ - if (run_rc == FALSE && single==FALSE) { - wait_for_enter_tty1 = FALSE; - where = strrchr( console, '/'); - if ( where != NULL) { - where++; - strncpy( which_vt1, where, sizeof(which_vt1)); - } - tty1_command = getty1_command; + } + /* Next run anything to be run only once */ + for( a=initActionList ; a; a=a->nextPtr) { + if (a->action == ONCE) { + run(a->process, console, FALSE); + /* Now remove the "once" entry from the list */ + delete_initAction( a); } } - - /* Ok, now launch the tty1_command and tty2_command */ + /* Now run the looping stuff */ for (;;) { - pid_t wpid; - int status; - - if (pid1 == 0 && tty1_command) { - pid1 = run(tty1_command, console, wait_for_enter_tty1); - } -#ifdef BB_FEATURE_INIT_SECOND_CONSOLE - if (pid2 == 0 && tty2_command && second_console) { - pid2 = run(tty2_command, second_console, wait_for_enter_tty2); + for( a=initActionList ; a; a=a->nextPtr) { + /* Only run stuff with pid==0. If they have + * a pid, that means they are still running */ + if (a->pid == 0) { + switch(a->action) { + case RESPAWN: + /* run the respawn stuff */ + a->pid = run(a->process, console, FALSE); + break; + case ASKFIRST: + /* run the askfirst stuff */ + a->pid = waitfor(run(a->process, console, TRUE)); + break; + /* silence the compiler's whining */ + default: + break; + } + } } -#endif + wpid = wait(&status); + /* Find out who died and clean up their corpse */ if (wpid > 0 ) { message(LOG, "pid %d exited, status=%x.\n", wpid, status); - } - /* Don't respawn init script if it exits */ - if (wpid == pid1) { - if (run_rc == FALSE) { - pid1 = 0; + for( a=initActionList ; a; a=a->nextPtr) { + if (a->pid==wpid) { + a->pid=0; + } } -#ifdef BB_INIT_CMD_IF_RC_SCRIPT_EXITS - else { - pid1 = 0; - run_rc=FALSE; - wait_for_enter_tty1=TRUE; - tty1_command=rc_exit_command; - } -#endif } -#ifdef BB_FEATURE_INIT_SECOND_CONSOLE - if (wpid == pid2) { - pid2 = 0; - } -#endif - sleep(1); - } -} - -#else - - -void parse_inittab(void) -{ - FILE* file; - char buf[256]; - char action[256]=""; - char process[256]=""; - char *p, *q; - - - if ((file = fopen(INITTAB, "r")) < 0) { - /* No inittab file -- set up some default behavior */ - - /* FIXME */ - return; - } - - while ( fgets(buf, 255, file) != NULL) { - for(p = buf; *p == ' ' || *p == '\t'; p++); - if (*p == '#' || *p == '\n') continue; - - /* Trim the trailing \n */ - q = strrchr( p, '\n'); - if (q != NULL) - *q='\0'; - - /* Skip past the ID field and the runlevel - * field (both are ignored) */ - p = strchr( p, ':'); - - /* Now peal off the process field from the end - * of the string */ - q = strrchr( p, ':'); - if ( q == NULL || q+1 == NULL) - goto choke; - *q='\0'; - strcpy( process, ++q); - fprintf(stderr, "process=%s\n", process); - - - /* Now peal off the action field */ - q = strrchr( p, ':'); - if ( q == NULL || q+1 == NULL) - goto choke; - strcpy( action, ++q); - fprintf(stderr, "action=%s\n", action); - - - /* Ok, now do the right thing */ + sleep(1); } - return; - -choke: - //message(CONSOLE, "Bad entry:"); - fprintf(stderr, "Bad inittab entry: %s", buf); - while (1) sleep(1); - -} - - -extern int init_main(int argc, char **argv) -{ - parse_inittab(); - exit( TRUE); } - -#endif diff --git a/internal.h b/internal.h index 1e42982d3..6804e2da8 100644 --- a/internal.h +++ b/internal.h @@ -169,6 +169,9 @@ extern int check_wildcard_match(const char* text, const char* pattern); extern long getNum (const char *cp); extern pid_t findInitPid(); +#if (__GLIBC__ < 2) && defined BB_SYSLOGD +extern int vdprintf(int d, const char *format, va_list ap); +#endif #if defined BB_MTAB #define whine_if_fstab_is_missing() {} @@ -183,7 +183,7 @@ extern int kill_main (int argc, char **argv) do_it_now: - while (argc >= 1) { + while (--argc >= 0) { int pid; struct stat statbuf; char pidpath[20]="/proc/"; @@ -198,6 +198,7 @@ do_it_now: fprintf(stderr, "kill: (%d) - No such pid\n", pid); exit( FALSE); } + fprintf(stderr, "sig = %d\n", sig); if (kill (pid, sig) != 0) { perror (*argv); exit ( FALSE); diff --git a/procps/kill.c b/procps/kill.c index 0ba6d76ce..e72b73493 100644 --- a/procps/kill.c +++ b/procps/kill.c @@ -183,7 +183,7 @@ extern int kill_main (int argc, char **argv) do_it_now: - while (argc >= 1) { + while (--argc >= 0) { int pid; struct stat statbuf; char pidpath[20]="/proc/"; @@ -198,6 +198,7 @@ do_it_now: fprintf(stderr, "kill: (%d) - No such pid\n", pid); exit( FALSE); } + fprintf(stderr, "sig = %d\n", sig); if (kill (pid, sig) != 0) { perror (*argv); exit ( FALSE); @@ -46,7 +46,7 @@ static const char sed_usage[] = "\t /REGEXP/ Match specified regexp\n" "\t (! inverts the meaning of the match)\n\n" "\tand COMMAND can be:\n" - "\t s/regexp/replacement/[gp]\n" + "\t s/regexp/replacement/[igp]\n" "\t which attempt to match regexp against the pattern space\n" "\t and if successful replaces the matched portion with replacement.\n\n" "\t aTEXT\n" @@ -37,6 +37,7 @@ #include <fcntl.h> #include <signal.h> #include <time.h> +#include <utime.h> #include <sys/types.h> #include <sys/sysmacros.h> @@ -106,8 +107,12 @@ static int warnedRoot; static int eofFlag; static long dataCc; static int outFd; -static char outName[TAR_NAME_SIZE]; +static const char *outName; +static int mode; +static int uid; +static int gid; +static time_t mtime; /* * Static data associated with the tar file. @@ -364,8 +369,9 @@ static void readTarFile (int fileCount, char **fileTable) * message is required on errors. */ if (tostdoutFlag == FALSE) { - if (outFd >= 0) - (void) close (outFd); + if (outFd >= 0) { + close (outFd); + } } } @@ -378,29 +384,25 @@ static void readTarFile (int fileCount, char **fileTable) static void readHeader (const TarHeader * hp, int fileCount, char **fileTable) { - int mode; - int uid; - int gid; int checkSum; - unsigned int major; - unsigned int minor; - long size; - time_t mtime; - const char *name; int cc; int hardLink; int softLink; int devFileFlag; + unsigned int major; + unsigned int minor; + long size; + struct utimbuf utb; /* * If the block is completely empty, then this is the end of the * archive file. If the name is null, then just skip this header. */ - name = hp->name; + outName = hp->name; - if (*name == '\0') { + if (*outName == '\0') { for (cc = TAR_BLOCK_SIZE; cc > 0; cc--) { - if (*name++) + if (*outName++) return; } @@ -447,16 +449,16 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable) /* * Check for a directory. */ - if (name[strlen (name) - 1] == '/') + if (outName[strlen (outName) - 1] == '/') mode |= S_IFDIR; /* * Check for absolute paths in the file. * If we find any, then warn the user and make them relative. */ - if (*name == '/') { - while (*name == '/') - name++; + if (*outName == '/') { + while (*outName == '/') + outName++; if (warnedRoot==FALSE) { fprintf (stderr, @@ -470,7 +472,7 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable) * See if we want this file to be restored. * If not, then set up to skip it. */ - if (wantFileName (name, fileCount, fileTable) == FALSE) { + if (wantFileName (outName, fileCount, fileTable) == FALSE) { if ( !hardLink && !softLink && (S_ISREG (mode) || S_ISCHR (mode) || S_ISBLK (mode) || S_ISSOCK(mode) || S_ISFIFO(mode) ) ) { inHeader = (size == 0)? TRUE : FALSE; @@ -494,7 +496,7 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable) else printf ("%9ld %s ", size, timeString (mtime)); } - printf ("%s", name); + printf ("%s", outName); if (hardLink) printf (" (link to \"%s\")", hp->linkName); @@ -515,22 +517,35 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable) * We really want to extract the file. */ if (verboseFlag==TRUE) - printf ("x %s\n", name); + printf ("x %s\n", outName); if (hardLink) { - if (link (hp->linkName, name) < 0) - perror (name); - chown(name, uid, gid); - chmod(name, mode); + if (link (hp->linkName, outName) < 0) + perror (outName); + /* Set the file time */ + utb.actime = mtime; + utb.modtime = mtime; + utime (outName, &utb); + /* Set the file permissions */ + chown(outName, uid, gid); + chmod(outName, mode); return; } if (softLink) { #ifdef S_ISLNK - if (symlink (hp->linkName, name) < 0) - perror (name); - chown(name, uid, gid); - chmod(name, mode); + if (symlink (hp->linkName, outName) < 0) + perror (outName); + /* Try to change ownership of the symlink. + * If libs doesn't support that, don't bother. + * Changing the pointed-to file is the Wrong Thing(tm). + */ +#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) + lchown(outName, uid, gid); +#endif + + /* Do not change permissions or date on symlink, + * since it changes the pointed to file instead. duh. */ #else fprintf (stderr, "Cannot create symbolic links\n"); #endif @@ -545,10 +560,14 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable) * If the file is a directory, then just create the path. */ if (S_ISDIR (mode)) { - createPath (name, mode); - chown(name, uid, gid); - chmod(name, mode); - + createPath (outName, mode); + /* Set the file time */ + utb.actime = mtime; + utb.modtime = mtime; + utime (outName, &utb); + /* Set the file permissions */ + chown(outName, uid, gid); + chmod(outName, mode); return; } @@ -556,7 +575,7 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable) * There is a file to write. * First create the path to it if necessary with default permissions. */ - createPath (name, 0777); + createPath (outName, 0777); inHeader = (size == 0)? TRUE : FALSE; dataCc = size; @@ -569,21 +588,26 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable) else { if ( S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode) ) { devFileFlag = TRUE; - outFd = mknod (name, mode, makedev(major, minor) ); + outFd = mknod (outName, mode, makedev(major, minor) ); } else if (S_ISFIFO(mode) ) { devFileFlag = TRUE; - outFd = mkfifo(name, mode); + outFd = mkfifo(outName, mode); } else { - outFd = open (name, O_WRONLY | O_CREAT | O_TRUNC, mode); + outFd = open (outName, O_WRONLY | O_CREAT | O_TRUNC, mode); } if (outFd < 0) { - perror (name); + perror (outName); skipFileFlag = TRUE; return; } - chown(name, uid, gid); - chmod(name, mode); + /* Set the file time */ + utb.actime = mtime; + utb.modtime = mtime; + utime (outName, &utb); + /* Set the file permissions */ + chown(outName, uid, gid); + chmod(outName, mode); } @@ -591,7 +615,7 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable) * If the file is empty, then that's all we need to do. */ if (size == 0 && (tostdoutFlag == FALSE) && (devFileFlag == FALSE)) { - (void) close (outFd); + close (outFd); outFd = -1; } } @@ -625,7 +649,7 @@ static void readData (const char *cp, int count) if (fullWrite (outFd, cp, count) < 0) { perror (outName); if (tostdoutFlag == FALSE) { - (void) close (outFd); + close (outFd); outFd = -1; } skipFileFlag = TRUE; @@ -633,13 +657,21 @@ static void readData (const char *cp, int count) } /* - * If the write failed, close the file and disable further - * writes to this file. + * Check if we are done writing to the file now. */ if (dataCc <= 0 && tostdoutFlag == FALSE) { + struct utimbuf utb; if (close (outFd)) perror (outName); + /* Set the file time */ + utb.actime = mtime; + utb.modtime = mtime; + utime (outName, &utb); + /* Set the file permissions */ + chown(outName, uid, gid); + chmod(outName, mode); + outFd = -1; } } @@ -720,7 +752,6 @@ static void writeTarFile (int fileCount, char **fileTable) static void saveFile (const char *fileName, int seeLinks) { int status; - int mode; struct stat statbuf; if (verboseFlag==TRUE) @@ -379,7 +379,7 @@ int fullRead(int fd, char *buf, int len) #endif -#if defined (BB_CHOWN) || defined (BB_CP) || defined (BB_FIND) || defined (BB_LS) || defined (BB_INSMOD) +#if defined (BB_CHMOD_CHOWN_CHGRP) || defined (BB_CP) || defined (BB_FIND) || defined (BB_LS) || defined (BB_INSMOD) /* * Walk down all the directories under the specified * location, and do something (something specified @@ -969,7 +969,7 @@ check_wildcard_match(const char* text, const char* pattern) -#if defined BB_DF | defined BB_MTAB +#if defined BB_DF || defined BB_MTAB /* * Given a block device, find the mount table entry if that block device * is mounted. @@ -1008,7 +1008,6 @@ extern struct mntent *findMountPoint(const char *name, const char *table) endmntent(mountTable); return mountEntry; } - #endif @@ -1111,4 +1110,15 @@ findInitPid() } #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 + /* END CODE */ |