OSDN Git Service

Bunches of fixes. Typos, bugs, etc.
authorErik Andersen <andersen@codepoet.org>
Tue, 4 Jan 2000 01:10:25 +0000 (01:10 -0000)
committerErik Andersen <andersen@codepoet.org>
Tue, 4 Jan 2000 01:10:25 +0000 (01:10 -0000)
Added 'gunzip -t'.  inittab support _almost_ works (but it isn't
ready for prime time useage yet).
 -Erik

20 files changed:
Changelog
Makefile
applets/busybox.c
archival/gunzip.c
archival/tar.c
busybox.c
busybox.def.h
busybox_functions.h [deleted file]
coreutils/cp.c
cp.c
editors/sed.c
gunzip.c
init.c
init/init.c
internal.h
kill.c
procps/kill.c
sed.c
tar.c
utility.c

index 37570d2..54fd3ca 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -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>.
        * 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
index 73aa2fc..4215b29 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -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...
index 403b140..a353069 100644 (file)
@@ -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}
 };
 
index 61391a3..84f5d02 100644 (file)
@@ -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;
 }
index 7167d95..a53370e 100644 (file)
@@ -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)
index 403b140..a353069 100644 (file)
--- a/busybox.c
+++ b/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}
 };
 
index 3982a1c..503410f 100644 (file)
@@ -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 (file)
index 61fc484..0000000
+++ /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__ */
index 8346019..4af73c2 100644 (file)
@@ -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/cp.c b/cp.c
index 8346019..4af73c2 100644 (file)
--- a/cp.c
+++ b/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";
 
 
index 8e5f695..2577724 100644 (file)
@@ -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"
index 61391a3..84f5d02 100644 (file)
--- a/gunzip.c
+++ b/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/init.c b/init.c
index b71c9f7..be04ec3 100644 (file)
--- a/init.c
+++ b/init.c
@@ -23,6 +23,7 @@
 
 #include "internal.h"
 #include <stdio.h>
+#include <string.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <unistd.h>
 #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
index b71c9f7..be04ec3 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "internal.h"
 #include <stdio.h>
+#include <string.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <unistd.h>
 #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
index 1e42982..6804e2d 100644 (file)
@@ -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() {} 
diff --git a/kill.c b/kill.c
index 0ba6d76..e72b734 100644 (file)
--- a/kill.c
+++ b/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);
index 0ba6d76..e72b734 100644 (file)
@@ -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/sed.c b/sed.c
index 8e5f695..2577724 100644 (file)
--- a/sed.c
+++ b/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"
diff --git a/tar.c b/tar.c
index 7167d95..a53370e 100644 (file)
--- a/tar.c
+++ b/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)
index 2a840f7..c20025c 100644 (file)
--- a/utility.c
+++ b/utility.c
@@ -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 */