Bunches of fixes. Typos, bugs, etc.

Added 'gunzip -t'.  inittab support _almost_ works (but it isn't
ready for prime time useage yet).
 -Erik
This commit is contained in:
Erik Andersen 2000-01-04 01:10:25 +00:00
parent 9c88cac5cb
commit 7dc160721e
20 changed files with 781 additions and 578 deletions

View File

@ -1,11 +1,11 @@
0.40 0.40
* Added the -s option to du -beppu * Added the -s option to du -beppu
* Fixed an embarrasing segfault in head -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: lsmod, rmmod -erik
* New Apps: fbset contributed by Randolph Chung <tausq@debian.org>. * New Apps: fbset contributed by Randolph Chung <tausq@debian.org>.
* Fixed the embarrasing failure of the -p opition in the logger app. -erik * Fixed the embarrasing failure of 'logger -p'. -erik
* Re-worked the whole source tree a bit so it will compile under glibc 2.0.7 * Re-worked the source tree a bit so it will compile under glibc 2.0.7
with the 2.0.x Linux kernel. with the 2.0.x Linux kernel.
* Added 'grep -q' thanks to a patch from "Konstantin Boldyshev" * Added 'grep -q' thanks to a patch from "Konstantin Boldyshev"
<konst@voshod.com>. <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 set, and then clear SGID and SUID bits.
* Fixed a bug where tar would not set the user and group on device * Fixed a bug where tar would not set the user and group on device
special files. 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. them so they should now work as expected.
* New app: loadacm contributed by Peter Novodvorsky <petya@logic.ru> * 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 * sed now supports addresses (numeric or regexp, with negation) and
has an append command, thanks to Marco Pantaleoni <panta@prosa.it> has an append command, thanks to Marco Pantaleoni <panta@prosa.it>
* Fixed dmesg. It wasn't parsing its options (-n or -s) properly. * Fixed dmesg. It wasn't parsing its options (-n or -s) properly.
* Some cosmetic fixes to ls output formatting to make it behave more * Some cosmetic fixes to ls output formatting to make it behave more
like GNU ls. 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 -Erik Andersen

View File

@ -22,7 +22,7 @@ BUILDTIME=$(shell date "+%Y%m%d-%H%M")
# Comment out the following to make a debuggable build # Comment out the following to make a debuggable build
# Leave this off for production use. # Leave this off for production use.
DODEBUG=false DODEBUG=true
# If you want a static binary, turn this on. I can't think # If you want a static binary, turn this on. I can't think
# of many situations where anybody would ever want it static, # of many situations where anybody would ever want it static,
# but... # but...

View File

@ -102,6 +102,9 @@ static const struct Applet applets[] = {
#ifdef BB_LN //bin #ifdef BB_LN //bin
{"ln", ln_main}, {"ln", ln_main},
#endif #endif
#ifdef BB_LOADACM //usr/bin
{"loadacm", loadacm_main},
#endif
#ifdef BB_LOADFONT //usr/bin #ifdef BB_LOADFONT //usr/bin
{"loadfont", loadfont_main}, {"loadfont", loadfont_main},
#endif #endif
@ -232,9 +235,6 @@ static const struct Applet applets[] = {
#ifdef BB_GZIP //bin #ifdef BB_GZIP //bin
{"gzip", gzip_main}, {"gzip", gzip_main},
#endif #endif
#ifdef BB_LOADACM //usr/bin
{"loadacm", loadacm_main},
#endif
{0} {0}
}; };

View File

@ -8,7 +8,8 @@ static const char gunzip_usage[] =
"gunzip [OPTION]... FILE\n\n" "gunzip [OPTION]... FILE\n\n"
"Uncompress FILE (or standard input if FILE is '-').\n\n" "Uncompress FILE (or standard input if FILE is '-').\n\n"
"Options:\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 /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
* Copyright (C) 1992-1993 Jean-loup Gailly * Copyright (C) 1992-1993 Jean-loup Gailly
@ -653,7 +654,7 @@ DECLARE(uch, window, 2L*WSIZE);
/* local variables */ /* 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 foreground; /* set if program run in foreground */
int maxbits = BITS; /* max bits per code for LZW */ int maxbits = BITS; /* max bits per code for LZW */
int method = DEFLATED;/* compression method */ int method = DEFLATED;/* compression method */
@ -714,6 +715,10 @@ int gunzip_main (int argc, char** argv)
case 'c': case 'c':
to_stdout = 1; to_stdout = 1;
break; break;
case 't':
test_mode = 1;
break;
default: default:
usage(gunzip_usage); usage(gunzip_usage);
} }
@ -786,6 +791,9 @@ int gunzip_main (int argc, char** argv)
/* Actually do the compression/decompression. */ /* Actually do the compression/decompression. */
unzip(inFileNum, outFileNum); unzip(inFileNum, outFileNum);
} else if (test_mode) {
/* Actually do the compression/decompression. */
unzip(inFileNum, 2);
} else { } else {
char* pos; char* pos;
@ -857,17 +865,8 @@ local int get_method(in)
uch flags; /* compression flags */ uch flags; /* compression flags */
char magic[2]; /* magic header */ char magic[2]; /* magic header */
/* If --force and --stdout, zcat == cat, so do not complain about magic[0] = (char)get_byte();
* premature end of file: use try_byte instead of get_byte. magic[1] = (char)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();
}
method = -1; /* unknown yet */ method = -1; /* unknown yet */
part_nb++; /* number of parts in gzip file */ part_nb++; /* number of parts in gzip file */
header_bytes = 0; header_bytes = 0;
@ -1188,7 +1187,8 @@ void flush_outbuf()
{ {
if (outcnt == 0) return; if (outcnt == 0) return;
write_buf(ofd, (char *)outbuf, outcnt); if (!test_mode)
write_buf(ofd, (char *)outbuf, outcnt);
bytes_out += (ulg)outcnt; bytes_out += (ulg)outcnt;
outcnt = 0; outcnt = 0;
} }
@ -1202,8 +1202,8 @@ void flush_window()
if (outcnt == 0) return; if (outcnt == 0) return;
updcrc(window, outcnt); updcrc(window, outcnt);
write_buf(ofd, (char *)window, outcnt); if (!test_mode)
write_buf(ofd, (char *)window, outcnt);
bytes_out += (ulg)outcnt; bytes_out += (ulg)outcnt;
outcnt = 0; outcnt = 0;
} }

View File

@ -37,6 +37,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <signal.h> #include <signal.h>
#include <time.h> #include <time.h>
#include <utime.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/sysmacros.h> #include <sys/sysmacros.h>
@ -106,8 +107,12 @@ static int warnedRoot;
static int eofFlag; static int eofFlag;
static long dataCc; static long dataCc;
static int outFd; 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. * Static data associated with the tar file.
@ -364,8 +369,9 @@ static void readTarFile (int fileCount, char **fileTable)
* message is required on errors. * message is required on errors.
*/ */
if (tostdoutFlag == FALSE) { if (tostdoutFlag == FALSE) {
if (outFd >= 0) if (outFd >= 0) {
(void) close (outFd); close (outFd);
}
} }
} }
@ -378,29 +384,25 @@ static void readTarFile (int fileCount, char **fileTable)
static void static void
readHeader (const TarHeader * hp, int fileCount, char **fileTable) readHeader (const TarHeader * hp, int fileCount, char **fileTable)
{ {
int mode;
int uid;
int gid;
int checkSum; int checkSum;
unsigned int major;
unsigned int minor;
long size;
time_t mtime;
const char *name;
int cc; int cc;
int hardLink; int hardLink;
int softLink; int softLink;
int devFileFlag; 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 * 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. * 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--) { for (cc = TAR_BLOCK_SIZE; cc > 0; cc--) {
if (*name++) if (*outName++)
return; return;
} }
@ -447,16 +449,16 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable)
/* /*
* Check for a directory. * Check for a directory.
*/ */
if (name[strlen (name) - 1] == '/') if (outName[strlen (outName) - 1] == '/')
mode |= S_IFDIR; mode |= S_IFDIR;
/* /*
* Check for absolute paths in the file. * Check for absolute paths in the file.
* If we find any, then warn the user and make them relative. * If we find any, then warn the user and make them relative.
*/ */
if (*name == '/') { if (*outName == '/') {
while (*name == '/') while (*outName == '/')
name++; outName++;
if (warnedRoot==FALSE) { if (warnedRoot==FALSE) {
fprintf (stderr, fprintf (stderr,
@ -470,7 +472,7 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable)
* See if we want this file to be restored. * See if we want this file to be restored.
* If not, then set up to skip it. * 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) if ( !hardLink && !softLink && (S_ISREG (mode) || S_ISCHR (mode)
|| S_ISBLK (mode) || S_ISSOCK(mode) || S_ISFIFO(mode) ) ) { || S_ISBLK (mode) || S_ISSOCK(mode) || S_ISFIFO(mode) ) ) {
inHeader = (size == 0)? TRUE : FALSE; inHeader = (size == 0)? TRUE : FALSE;
@ -494,7 +496,7 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable)
else else
printf ("%9ld %s ", size, timeString (mtime)); printf ("%9ld %s ", size, timeString (mtime));
} }
printf ("%s", name); printf ("%s", outName);
if (hardLink) if (hardLink)
printf (" (link to \"%s\")", hp->linkName); 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. * We really want to extract the file.
*/ */
if (verboseFlag==TRUE) if (verboseFlag==TRUE)
printf ("x %s\n", name); printf ("x %s\n", outName);
if (hardLink) { if (hardLink) {
if (link (hp->linkName, name) < 0) if (link (hp->linkName, outName) < 0)
perror (name); perror (outName);
chown(name, uid, gid); /* Set the file time */
chmod(name, mode); utb.actime = mtime;
utb.modtime = mtime;
utime (outName, &utb);
/* Set the file permissions */
chown(outName, uid, gid);
chmod(outName, mode);
return; return;
} }
if (softLink) { if (softLink) {
#ifdef S_ISLNK #ifdef S_ISLNK
if (symlink (hp->linkName, name) < 0) if (symlink (hp->linkName, outName) < 0)
perror (name); perror (outName);
chown(name, uid, gid); /* Try to change ownership of the symlink.
chmod(name, mode); * 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 #else
fprintf (stderr, "Cannot create symbolic links\n"); fprintf (stderr, "Cannot create symbolic links\n");
#endif #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 the file is a directory, then just create the path.
*/ */
if (S_ISDIR (mode)) { if (S_ISDIR (mode)) {
createPath (name, mode); createPath (outName, mode);
chown(name, uid, gid); /* Set the file time */
chmod(name, mode); utb.actime = mtime;
utb.modtime = mtime;
utime (outName, &utb);
/* Set the file permissions */
chown(outName, uid, gid);
chmod(outName, mode);
return; return;
} }
@ -556,7 +575,7 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable)
* There is a file to write. * There is a file to write.
* First create the path to it if necessary with default permissions. * First create the path to it if necessary with default permissions.
*/ */
createPath (name, 0777); createPath (outName, 0777);
inHeader = (size == 0)? TRUE : FALSE; inHeader = (size == 0)? TRUE : FALSE;
dataCc = size; dataCc = size;
@ -569,21 +588,26 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable)
else { else {
if ( S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode) ) { if ( S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode) ) {
devFileFlag = TRUE; devFileFlag = TRUE;
outFd = mknod (name, mode, makedev(major, minor) ); outFd = mknod (outName, mode, makedev(major, minor) );
} }
else if (S_ISFIFO(mode) ) { else if (S_ISFIFO(mode) ) {
devFileFlag = TRUE; devFileFlag = TRUE;
outFd = mkfifo(name, mode); outFd = mkfifo(outName, mode);
} else { } else {
outFd = open (name, O_WRONLY | O_CREAT | O_TRUNC, mode); outFd = open (outName, O_WRONLY | O_CREAT | O_TRUNC, mode);
} }
if (outFd < 0) { if (outFd < 0) {
perror (name); perror (outName);
skipFileFlag = TRUE; skipFileFlag = TRUE;
return; return;
} }
chown(name, uid, gid); /* Set the file time */
chmod(name, mode); 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 the file is empty, then that's all we need to do.
*/ */
if (size == 0 && (tostdoutFlag == FALSE) && (devFileFlag == FALSE)) { if (size == 0 && (tostdoutFlag == FALSE) && (devFileFlag == FALSE)) {
(void) close (outFd); close (outFd);
outFd = -1; outFd = -1;
} }
} }
@ -625,7 +649,7 @@ static void readData (const char *cp, int count)
if (fullWrite (outFd, cp, count) < 0) { if (fullWrite (outFd, cp, count) < 0) {
perror (outName); perror (outName);
if (tostdoutFlag == FALSE) { if (tostdoutFlag == FALSE) {
(void) close (outFd); close (outFd);
outFd = -1; outFd = -1;
} }
skipFileFlag = TRUE; skipFileFlag = TRUE;
@ -633,13 +657,21 @@ static void readData (const char *cp, int count)
} }
/* /*
* If the write failed, close the file and disable further * Check if we are done writing to the file now.
* writes to this file.
*/ */
if (dataCc <= 0 && tostdoutFlag == FALSE) { if (dataCc <= 0 && tostdoutFlag == FALSE) {
struct utimbuf utb;
if (close (outFd)) if (close (outFd))
perror (outName); 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; outFd = -1;
} }
} }
@ -720,7 +752,6 @@ static void writeTarFile (int fileCount, char **fileTable)
static void saveFile (const char *fileName, int seeLinks) static void saveFile (const char *fileName, int seeLinks)
{ {
int status; int status;
int mode;
struct stat statbuf; struct stat statbuf;
if (verboseFlag==TRUE) if (verboseFlag==TRUE)

View File

@ -102,6 +102,9 @@ static const struct Applet applets[] = {
#ifdef BB_LN //bin #ifdef BB_LN //bin
{"ln", ln_main}, {"ln", ln_main},
#endif #endif
#ifdef BB_LOADACM //usr/bin
{"loadacm", loadacm_main},
#endif
#ifdef BB_LOADFONT //usr/bin #ifdef BB_LOADFONT //usr/bin
{"loadfont", loadfont_main}, {"loadfont", loadfont_main},
#endif #endif
@ -232,9 +235,6 @@ static const struct Applet applets[] = {
#ifdef BB_GZIP //bin #ifdef BB_GZIP //bin
{"gzip", gzip_main}, {"gzip", gzip_main},
#endif #endif
#ifdef BB_LOADACM //usr/bin
{"loadacm", loadacm_main},
#endif
{0} {0}
}; };

View File

@ -36,7 +36,7 @@
//#define BB_LOADACM //#define BB_LOADACM
//#define BB_LOADFONT //#define BB_LOADFONT
//#define BB_LOADKMAP //#define BB_LOADKMAP
#define BB_LOGGER //#define BB_LOGGER
#define BB_LS #define BB_LS
#define BB_LSMOD #define BB_LSMOD
//#define BB_MAKEDEVS //#define BB_MAKEDEVS
@ -68,7 +68,7 @@
#define BB_SORT #define BB_SORT
#define BB_SWAPONOFF #define BB_SWAPONOFF
#define BB_SYNC #define BB_SYNC
#define BB_SYSLOGD //#define BB_SYSLOGD
#define BB_TAIL #define BB_TAIL
#define BB_TAR #define BB_TAR
#define BB_TEE #define BB_TEE
@ -90,8 +90,6 @@
// pretty/useful). // pretty/useful).
// //
// //
// enable a second console on TTY2 in init
#define BB_FEATURE_INIT_SECOND_CONSOLE
// enable features that use the /proc filesystem // enable features that use the /proc filesystem
#define BB_FEATURE_USE_PROCFS #define BB_FEATURE_USE_PROCFS
//Enable init being called as /linuxrc //Enable init being called as /linuxrc

View File

@ -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__ */

View File

@ -33,7 +33,7 @@ static const char cp_usage[] = "cp [OPTION]... SOURCE DEST\n"
"\n" "\n"
"\t-a\tsame as -dpR\n" "\t-a\tsame as -dpR\n"
"\t-d\tpreserve links\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"; "\t-R\tcopy directories recursively\n";

2
cp.c
View File

@ -33,7 +33,7 @@ static const char cp_usage[] = "cp [OPTION]... SOURCE DEST\n"
"\n" "\n"
"\t-a\tsame as -dpR\n" "\t-a\tsame as -dpR\n"
"\t-d\tpreserve links\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"; "\t-R\tcopy directories recursively\n";

View File

@ -46,7 +46,7 @@ static const char sed_usage[] =
"\t /REGEXP/ Match specified regexp\n" "\t /REGEXP/ Match specified regexp\n"
"\t (! inverts the meaning of the match)\n\n" "\t (! inverts the meaning of the match)\n\n"
"\tand COMMAND can be:\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 which attempt to match regexp against the pattern space\n"
"\t and if successful replaces the matched portion with replacement.\n\n" "\t and if successful replaces the matched portion with replacement.\n\n"
"\t aTEXT\n" "\t aTEXT\n"

View File

@ -8,7 +8,8 @@ static const char gunzip_usage[] =
"gunzip [OPTION]... FILE\n\n" "gunzip [OPTION]... FILE\n\n"
"Uncompress FILE (or standard input if FILE is '-').\n\n" "Uncompress FILE (or standard input if FILE is '-').\n\n"
"Options:\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 /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
* Copyright (C) 1992-1993 Jean-loup Gailly * Copyright (C) 1992-1993 Jean-loup Gailly
@ -653,7 +654,7 @@ DECLARE(uch, window, 2L*WSIZE);
/* local variables */ /* 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 foreground; /* set if program run in foreground */
int maxbits = BITS; /* max bits per code for LZW */ int maxbits = BITS; /* max bits per code for LZW */
int method = DEFLATED;/* compression method */ int method = DEFLATED;/* compression method */
@ -714,6 +715,10 @@ int gunzip_main (int argc, char** argv)
case 'c': case 'c':
to_stdout = 1; to_stdout = 1;
break; break;
case 't':
test_mode = 1;
break;
default: default:
usage(gunzip_usage); usage(gunzip_usage);
} }
@ -786,6 +791,9 @@ int gunzip_main (int argc, char** argv)
/* Actually do the compression/decompression. */ /* Actually do the compression/decompression. */
unzip(inFileNum, outFileNum); unzip(inFileNum, outFileNum);
} else if (test_mode) {
/* Actually do the compression/decompression. */
unzip(inFileNum, 2);
} else { } else {
char* pos; char* pos;
@ -857,17 +865,8 @@ local int get_method(in)
uch flags; /* compression flags */ uch flags; /* compression flags */
char magic[2]; /* magic header */ char magic[2]; /* magic header */
/* If --force and --stdout, zcat == cat, so do not complain about magic[0] = (char)get_byte();
* premature end of file: use try_byte instead of get_byte. magic[1] = (char)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();
}
method = -1; /* unknown yet */ method = -1; /* unknown yet */
part_nb++; /* number of parts in gzip file */ part_nb++; /* number of parts in gzip file */
header_bytes = 0; header_bytes = 0;
@ -1188,7 +1187,8 @@ void flush_outbuf()
{ {
if (outcnt == 0) return; if (outcnt == 0) return;
write_buf(ofd, (char *)outbuf, outcnt); if (!test_mode)
write_buf(ofd, (char *)outbuf, outcnt);
bytes_out += (ulg)outcnt; bytes_out += (ulg)outcnt;
outcnt = 0; outcnt = 0;
} }
@ -1202,8 +1202,8 @@ void flush_window()
if (outcnt == 0) return; if (outcnt == 0) return;
updcrc(window, outcnt); updcrc(window, outcnt);
write_buf(ofd, (char *)window, outcnt); if (!test_mode)
write_buf(ofd, (char *)window, outcnt);
bytes_out += (ulg)outcnt; bytes_out += (ulg)outcnt;
outcnt = 0; outcnt = 0;
} }

485
init.c
View File

@ -23,6 +23,7 @@
#include "internal.h" #include "internal.h"
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <unistd.h> #include <unistd.h>
@ -55,22 +56,57 @@
#endif #endif
#define VT_PRIMARY "/dev/tty1" /* Primary virtual console */ #define VT_PRIMARY "/dev/tty1" /* Primary virtual console */
#define VT_SECONDARY "/dev/tty2" /* Virtual console */ #define VT_SECONDARY "/dev/tty2" /* Virtual console */
#define VT_LOG "/dev/tty3" /* Virtual console */ #define VT_LOG "/dev/tty3" /* Virtual console */
#define SERIAL_CON0 "/dev/ttyS0" /* Primary serial console */ #define SERIAL_CON0 "/dev/ttyS0" /* Primary serial console */
#define SERIAL_CON1 "/dev/ttyS1" /* Serial console */ #define SERIAL_CON1 "/dev/ttyS1" /* Serial console */
#define GETTY "/sbin/getty" /* Default location of getty */ #define SHELL "/bin/sh" /* Default shell */
#define SHELL "/bin/sh" /* Default shell */ #define REBOOT "/sbin/reboot" /* Default ctrl-alt-del command */
#define INITTAB "/etc/inittab" /* inittab file location */ #define INITTAB "/etc/inittab" /* inittab file location */
#ifndef BB_INIT_SCRIPT #define INIT_SCRIPT "/etc/init.d/rcS" /* Default sysinit script. */
#define BB_INIT_SCRIPT "/etc/init.d/rcS" /* Initscript. */
#endif
#if 1
#define LOG 0x1 #define LOG 0x1
#define CONSOLE 0x2 #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 *console = _PATH_CONSOLE;
static char *second_console = VT_SECONDARY; static char *second_console = VT_SECONDARY;
static char *log = VT_LOG; 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 */ * device may be bitwise-or'd from LOG | CONSOLE */
void message(int device, char *fmt, ...) void message(int device, char *fmt, ...)
{ {
int fd;
va_list arguments; va_list arguments;
int fd;
#ifdef BB_SYSLOGD #ifdef BB_SYSLOGD
/* Log the message to 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) char *terminal, int get_enter)
{ {
int fd; int i;
pid_t pid; pid_t pid;
const char * const* cmd = command+1; char* tmpCmd;
char* cmd[255];
static const char press_enter[] = static const char press_enter[] =
"\nPlease press Enter to activate this console. "; "\nPlease press Enter to activate this console. ";
if ((pid = fork()) == 0) { if ((pid = fork()) == 0) {
int fd;
/* Clean up */ /* Clean up */
close(0); close(0);
close(1); close(1);
@ -321,7 +360,7 @@ static pid_t run(const char * const* command,
signal(SIGTERM, SIG_DFL); signal(SIGTERM, SIG_DFL);
if ((fd = device_open(terminal, O_RDWR)) < 0) { 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); exit(-1);
} }
dup(fd); dup(fd);
@ -340,21 +379,32 @@ static pid_t run(const char * const* command,
*/ */
char c; char c;
message(LOG, "Waiting for enter to start '%s' (pid %d, console %s)\r\n", message(LOG, "Waiting for enter to start '%s' (pid %d, console %s)\r\n",
*cmd, getpid(), terminal ); command, getpid(), terminal );
write(1, press_enter, sizeof(press_enter) - 1); write(fileno(stdout), press_enter, sizeof(press_enter) - 1);
read(0, &c, 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 */ /* Log the process name and args */
message(LOG|CONSOLE, "Starting pid %d, console %s: '", getpid(), terminal); message(LOG, "Starting pid %d, console %s: '%s'\r\n",
while ( *cmd) message(LOG|CONSOLE, "%s ", *cmd++); getpid(), terminal, cmd[0]);
message(LOG|CONSOLE, "'\r\n");
/* Now run it. The new program will take over this PID, /* Now run it. The new program will take over this PID,
* so nothing further in init.c should be run. */ * 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); exit(-1);
} }
return pid; return pid;
@ -365,15 +415,13 @@ static pid_t run(const char * const* command,
static void check_memory() static void check_memory()
{ {
struct stat statbuf; struct stat statbuf;
const char* const swap_on_cmd[] =
{ "/bin/swapon", "swapon", "-a", 0};
if (mem_total() > 3500) if (mem_total() > 3500)
return; return;
if (stat("/etc/fstab", &statbuf) == 0) { if (stat("/etc/fstab", &statbuf) == 0) {
/* Try to turn on swap */ /* Try to turn on swap */
waitfor(run(swap_on_cmd, log, FALSE)); waitfor(run("/bin/swapon swapon -a", log, FALSE));
if (mem_total() < 3500) if (mem_total() < 3500)
goto goodnight; goto goodnight;
} else } else
@ -385,33 +433,28 @@ goodnight:
while (1) sleep(1); while (1) sleep(1);
} }
#ifndef DEBUG_INIT
static void shutdown_system(void) 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. */ /* Allow Ctrl-Alt-Del to reboot system. */
reboot(RB_ENABLE_CAD); reboot(RB_ENABLE_CAD);
#endif
message(CONSOLE, "\r\nThe system is going down NOW !!\r\n"); message(CONSOLE, "\r\nThe system is going down NOW !!\r\n");
sync(); sync();
/* Send signals to every process _except_ pid 1 */ /* Send signals to every process _except_ pid 1 */
message(CONSOLE, "Sending SIGHUP to all processes.\r\n"); message(CONSOLE, "Sending SIGHUP to all processes.\r\n");
#ifndef DEBUG_INIT
kill(-1, SIGHUP); kill(-1, SIGHUP);
#endif
sleep(2); sleep(2);
sync(); sync();
message(CONSOLE, "Sending SIGKILL to all processes.\r\n"); message(CONSOLE, "Sending SIGKILL to all processes.\r\n");
#ifndef DEBUG_INIT
kill(-1, SIGKILL); kill(-1, SIGKILL);
#endif
sleep(1); sleep(1);
message(CONSOLE, "Disabling swap.\r\n"); 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"); message(CONSOLE, "Unmounting filesystems.\r\n");
waitfor(run( umount_cmd, console, FALSE)); waitfor(run( "umount -a", console, FALSE));
sync(); sync();
if (kernel_version > 0 && kernel_version <= 2 * 65536 + 2 * 256 + 11) { if (kernel_version > 0 && kernel_version <= 2 * 65536 + 2 * 256 + 11) {
/* bdflush, kupdate not needed for kernels >2.2.11 */ /* bdflush, kupdate not needed for kernels >2.2.11 */
@ -427,14 +470,12 @@ static void halt_signal(int sig)
message(CONSOLE, message(CONSOLE,
"The system is halted. Press CTRL-ALT-DEL or turn off power\r\n"); "The system is halted. Press CTRL-ALT-DEL or turn off power\r\n");
sync(); sync();
#ifndef DEBUG_INIT
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
if (sig == SIGUSR2) if (sig == SIGUSR2)
reboot(RB_POWER_OFF); reboot(RB_POWER_OFF);
else else
#endif #endif
reboot(RB_HALT_SYSTEM); reboot(RB_HALT_SYSTEM);
#endif
exit(0); exit(0);
} }
@ -443,64 +484,157 @@ static void reboot_signal(int sig)
shutdown_system(); shutdown_system();
message(CONSOLE, "Please stand by while rebooting the system.\r\n"); message(CONSOLE, "Please stand by while rebooting the system.\r\n");
sync(); sync();
#ifndef DEBUG_INIT
reboot(RB_AUTOBOOT); reboot(RB_AUTOBOOT);
#endif
exit(0); 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) extern int init_main(int argc, char **argv)
{ {
int run_rc = FALSE; initAction *a;
pid_t wpid;
int status;
int single = FALSE; 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 #ifndef DEBUG_INIT
/* Expect to be PID 1 iff we are run as init (not linuxrc) */ /* Expect to be PID 1 iff we are run as init (not linuxrc) */
if (getpid() != 1 && strstr(argv[0], "init")!=NULL ) { if (getpid() != 1 && strstr(argv[0], "init")!=NULL ) {
usage( "init\n\nInit is the parent of all processes.\n\n" 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"); "This version of init is designed to be run only by the kernel\n");
} }
#endif
/* Set up sig handlers -- be sure to /* Set up sig handlers -- be sure to clear all of these in run() */
* clear all of these in run() */
signal(SIGUSR1, halt_signal); signal(SIGUSR1, halt_signal);
signal(SIGUSR2, reboot_signal); signal(SIGUSR2, reboot_signal);
signal(SIGINT, reboot_signal); signal(SIGINT, ctrl_alt_del_signal);
signal(SIGTERM, reboot_signal); signal(SIGTERM, reboot_signal);
/* Turn off rebooting via CTL-ALT-DEL -- we get a /* Turn off rebooting via CTL-ALT-DEL -- we get a
* SIGINT on CAD so we can shut things down gracefully... */ * SIGINT on CAD so we can shut things down gracefully... */
#ifndef DEBUG_INIT
reboot(RB_DISABLE_CAD); reboot(RB_DISABLE_CAD);
#endif #endif
/* Figure out where the default console should be */ /* Figure out where the default console should be */
console_init(); console_init();
@ -517,9 +651,13 @@ extern int init_main(int argc, char **argv)
/* Hello world */ /* Hello world */
#ifndef DEBUG_INIT #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 #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 #endif
@ -537,150 +675,77 @@ extern int init_main(int argc, char **argv)
if ( argc > 1 && (!strcmp(argv[1], "single") || if ( argc > 1 && (!strcmp(argv[1], "single") ||
!strcmp(argv[1], "-s") || !strcmp(argv[1], "1"))) { !strcmp(argv[1], "-s") || !strcmp(argv[1], "1"))) {
single = TRUE; single = TRUE;
tty1_command = shell_command; /* Ask first then start a shell on tty2 */
tty2_command = shell_command; 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 */ /* Now run everything that needs to be run */
if (single==FALSE && stat(BB_INIT_SCRIPT, &statbuf)==0) {
run_rc = TRUE;
wait_for_enter_tty1 = FALSE;
tty1_command = rc_script_command;
}
/* 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));
}
tty2_command = getty2_command;
/* Check on hooking a getty onto tty1 */ /* First run sysinit */
if (run_rc == FALSE && single==FALSE) { for( a=initActionList ; a; a=a->nextPtr) {
wait_for_enter_tty1 = FALSE; if (a->action == SYSINIT) {
where = strrchr( console, '/'); waitfor(run(a->process, console, FALSE));
if ( where != NULL) { /* Now remove the "sysinit" entry from the list */
where++; delete_initAction( a);
strncpy( which_vt1, where, sizeof(which_vt1)); }
} }
tty1_command = getty1_command; /* 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);
}
}
/* 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 (;;) { for (;;) {
pid_t wpid; for( a=initActionList ; a; a=a->nextPtr) {
int status; /* 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;
}
}
}
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);
}
#endif
wpid = wait(&status); wpid = wait(&status);
/* Find out who died and clean up their corpse */
if (wpid > 0 ) { if (wpid > 0 ) {
message(LOG, "pid %d exited, status=%x.\n", wpid, status); message(LOG, "pid %d exited, status=%x.\n", wpid, status);
} for( a=initActionList ; a; a=a->nextPtr) {
/* Don't respawn init script if it exits */ if (a->pid==wpid) {
if (wpid == pid1) { a->pid=0;
if (run_rc == FALSE) { }
pid1 = 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); 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 */
}
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

View File

@ -23,6 +23,7 @@
#include "internal.h" #include "internal.h"
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <unistd.h> #include <unistd.h>
@ -55,22 +56,57 @@
#endif #endif
#define VT_PRIMARY "/dev/tty1" /* Primary virtual console */ #define VT_PRIMARY "/dev/tty1" /* Primary virtual console */
#define VT_SECONDARY "/dev/tty2" /* Virtual console */ #define VT_SECONDARY "/dev/tty2" /* Virtual console */
#define VT_LOG "/dev/tty3" /* Virtual console */ #define VT_LOG "/dev/tty3" /* Virtual console */
#define SERIAL_CON0 "/dev/ttyS0" /* Primary serial console */ #define SERIAL_CON0 "/dev/ttyS0" /* Primary serial console */
#define SERIAL_CON1 "/dev/ttyS1" /* Serial console */ #define SERIAL_CON1 "/dev/ttyS1" /* Serial console */
#define GETTY "/sbin/getty" /* Default location of getty */ #define SHELL "/bin/sh" /* Default shell */
#define SHELL "/bin/sh" /* Default shell */ #define REBOOT "/sbin/reboot" /* Default ctrl-alt-del command */
#define INITTAB "/etc/inittab" /* inittab file location */ #define INITTAB "/etc/inittab" /* inittab file location */
#ifndef BB_INIT_SCRIPT #define INIT_SCRIPT "/etc/init.d/rcS" /* Default sysinit script. */
#define BB_INIT_SCRIPT "/etc/init.d/rcS" /* Initscript. */
#endif
#if 1
#define LOG 0x1 #define LOG 0x1
#define CONSOLE 0x2 #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 *console = _PATH_CONSOLE;
static char *second_console = VT_SECONDARY; static char *second_console = VT_SECONDARY;
static char *log = VT_LOG; 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 */ * device may be bitwise-or'd from LOG | CONSOLE */
void message(int device, char *fmt, ...) void message(int device, char *fmt, ...)
{ {
int fd;
va_list arguments; va_list arguments;
int fd;
#ifdef BB_SYSLOGD #ifdef BB_SYSLOGD
/* Log the message to 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) char *terminal, int get_enter)
{ {
int fd; int i;
pid_t pid; pid_t pid;
const char * const* cmd = command+1; char* tmpCmd;
char* cmd[255];
static const char press_enter[] = static const char press_enter[] =
"\nPlease press Enter to activate this console. "; "\nPlease press Enter to activate this console. ";
if ((pid = fork()) == 0) { if ((pid = fork()) == 0) {
int fd;
/* Clean up */ /* Clean up */
close(0); close(0);
close(1); close(1);
@ -321,7 +360,7 @@ static pid_t run(const char * const* command,
signal(SIGTERM, SIG_DFL); signal(SIGTERM, SIG_DFL);
if ((fd = device_open(terminal, O_RDWR)) < 0) { 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); exit(-1);
} }
dup(fd); dup(fd);
@ -340,21 +379,32 @@ static pid_t run(const char * const* command,
*/ */
char c; char c;
message(LOG, "Waiting for enter to start '%s' (pid %d, console %s)\r\n", message(LOG, "Waiting for enter to start '%s' (pid %d, console %s)\r\n",
*cmd, getpid(), terminal ); command, getpid(), terminal );
write(1, press_enter, sizeof(press_enter) - 1); write(fileno(stdout), press_enter, sizeof(press_enter) - 1);
read(0, &c, 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 */ /* Log the process name and args */
message(LOG|CONSOLE, "Starting pid %d, console %s: '", getpid(), terminal); message(LOG, "Starting pid %d, console %s: '%s'\r\n",
while ( *cmd) message(LOG|CONSOLE, "%s ", *cmd++); getpid(), terminal, cmd[0]);
message(LOG|CONSOLE, "'\r\n");
/* Now run it. The new program will take over this PID, /* Now run it. The new program will take over this PID,
* so nothing further in init.c should be run. */ * 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); exit(-1);
} }
return pid; return pid;
@ -365,15 +415,13 @@ static pid_t run(const char * const* command,
static void check_memory() static void check_memory()
{ {
struct stat statbuf; struct stat statbuf;
const char* const swap_on_cmd[] =
{ "/bin/swapon", "swapon", "-a", 0};
if (mem_total() > 3500) if (mem_total() > 3500)
return; return;
if (stat("/etc/fstab", &statbuf) == 0) { if (stat("/etc/fstab", &statbuf) == 0) {
/* Try to turn on swap */ /* Try to turn on swap */
waitfor(run(swap_on_cmd, log, FALSE)); waitfor(run("/bin/swapon swapon -a", log, FALSE));
if (mem_total() < 3500) if (mem_total() < 3500)
goto goodnight; goto goodnight;
} else } else
@ -385,33 +433,28 @@ goodnight:
while (1) sleep(1); while (1) sleep(1);
} }
#ifndef DEBUG_INIT
static void shutdown_system(void) 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. */ /* Allow Ctrl-Alt-Del to reboot system. */
reboot(RB_ENABLE_CAD); reboot(RB_ENABLE_CAD);
#endif
message(CONSOLE, "\r\nThe system is going down NOW !!\r\n"); message(CONSOLE, "\r\nThe system is going down NOW !!\r\n");
sync(); sync();
/* Send signals to every process _except_ pid 1 */ /* Send signals to every process _except_ pid 1 */
message(CONSOLE, "Sending SIGHUP to all processes.\r\n"); message(CONSOLE, "Sending SIGHUP to all processes.\r\n");
#ifndef DEBUG_INIT
kill(-1, SIGHUP); kill(-1, SIGHUP);
#endif
sleep(2); sleep(2);
sync(); sync();
message(CONSOLE, "Sending SIGKILL to all processes.\r\n"); message(CONSOLE, "Sending SIGKILL to all processes.\r\n");
#ifndef DEBUG_INIT
kill(-1, SIGKILL); kill(-1, SIGKILL);
#endif
sleep(1); sleep(1);
message(CONSOLE, "Disabling swap.\r\n"); 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"); message(CONSOLE, "Unmounting filesystems.\r\n");
waitfor(run( umount_cmd, console, FALSE)); waitfor(run( "umount -a", console, FALSE));
sync(); sync();
if (kernel_version > 0 && kernel_version <= 2 * 65536 + 2 * 256 + 11) { if (kernel_version > 0 && kernel_version <= 2 * 65536 + 2 * 256 + 11) {
/* bdflush, kupdate not needed for kernels >2.2.11 */ /* bdflush, kupdate not needed for kernels >2.2.11 */
@ -427,14 +470,12 @@ static void halt_signal(int sig)
message(CONSOLE, message(CONSOLE,
"The system is halted. Press CTRL-ALT-DEL or turn off power\r\n"); "The system is halted. Press CTRL-ALT-DEL or turn off power\r\n");
sync(); sync();
#ifndef DEBUG_INIT
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
if (sig == SIGUSR2) if (sig == SIGUSR2)
reboot(RB_POWER_OFF); reboot(RB_POWER_OFF);
else else
#endif #endif
reboot(RB_HALT_SYSTEM); reboot(RB_HALT_SYSTEM);
#endif
exit(0); exit(0);
} }
@ -443,64 +484,157 @@ static void reboot_signal(int sig)
shutdown_system(); shutdown_system();
message(CONSOLE, "Please stand by while rebooting the system.\r\n"); message(CONSOLE, "Please stand by while rebooting the system.\r\n");
sync(); sync();
#ifndef DEBUG_INIT
reboot(RB_AUTOBOOT); reboot(RB_AUTOBOOT);
#endif
exit(0); 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) extern int init_main(int argc, char **argv)
{ {
int run_rc = FALSE; initAction *a;
pid_t wpid;
int status;
int single = FALSE; 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 #ifndef DEBUG_INIT
/* Expect to be PID 1 iff we are run as init (not linuxrc) */ /* Expect to be PID 1 iff we are run as init (not linuxrc) */
if (getpid() != 1 && strstr(argv[0], "init")!=NULL ) { if (getpid() != 1 && strstr(argv[0], "init")!=NULL ) {
usage( "init\n\nInit is the parent of all processes.\n\n" 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"); "This version of init is designed to be run only by the kernel\n");
} }
#endif
/* Set up sig handlers -- be sure to /* Set up sig handlers -- be sure to clear all of these in run() */
* clear all of these in run() */
signal(SIGUSR1, halt_signal); signal(SIGUSR1, halt_signal);
signal(SIGUSR2, reboot_signal); signal(SIGUSR2, reboot_signal);
signal(SIGINT, reboot_signal); signal(SIGINT, ctrl_alt_del_signal);
signal(SIGTERM, reboot_signal); signal(SIGTERM, reboot_signal);
/* Turn off rebooting via CTL-ALT-DEL -- we get a /* Turn off rebooting via CTL-ALT-DEL -- we get a
* SIGINT on CAD so we can shut things down gracefully... */ * SIGINT on CAD so we can shut things down gracefully... */
#ifndef DEBUG_INIT
reboot(RB_DISABLE_CAD); reboot(RB_DISABLE_CAD);
#endif #endif
/* Figure out where the default console should be */ /* Figure out where the default console should be */
console_init(); console_init();
@ -517,9 +651,13 @@ extern int init_main(int argc, char **argv)
/* Hello world */ /* Hello world */
#ifndef DEBUG_INIT #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 #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 #endif
@ -537,150 +675,77 @@ extern int init_main(int argc, char **argv)
if ( argc > 1 && (!strcmp(argv[1], "single") || if ( argc > 1 && (!strcmp(argv[1], "single") ||
!strcmp(argv[1], "-s") || !strcmp(argv[1], "1"))) { !strcmp(argv[1], "-s") || !strcmp(argv[1], "1"))) {
single = TRUE; single = TRUE;
tty1_command = shell_command; /* Ask first then start a shell on tty2 */
tty2_command = shell_command; 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 */ /* Now run everything that needs to be run */
if (single==FALSE && stat(BB_INIT_SCRIPT, &statbuf)==0) {
run_rc = TRUE;
wait_for_enter_tty1 = FALSE;
tty1_command = rc_script_command;
}
/* 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));
}
tty2_command = getty2_command;
/* Check on hooking a getty onto tty1 */ /* First run sysinit */
if (run_rc == FALSE && single==FALSE) { for( a=initActionList ; a; a=a->nextPtr) {
wait_for_enter_tty1 = FALSE; if (a->action == SYSINIT) {
where = strrchr( console, '/'); waitfor(run(a->process, console, FALSE));
if ( where != NULL) { /* Now remove the "sysinit" entry from the list */
where++; delete_initAction( a);
strncpy( which_vt1, where, sizeof(which_vt1)); }
} }
tty1_command = getty1_command; /* 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);
}
}
/* 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 (;;) { for (;;) {
pid_t wpid; for( a=initActionList ; a; a=a->nextPtr) {
int status; /* 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;
}
}
}
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);
}
#endif
wpid = wait(&status); wpid = wait(&status);
/* Find out who died and clean up their corpse */
if (wpid > 0 ) { if (wpid > 0 ) {
message(LOG, "pid %d exited, status=%x.\n", wpid, status); message(LOG, "pid %d exited, status=%x.\n", wpid, status);
} for( a=initActionList ; a; a=a->nextPtr) {
/* Don't respawn init script if it exits */ if (a->pid==wpid) {
if (wpid == pid1) { a->pid=0;
if (run_rc == FALSE) { }
pid1 = 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); 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 */
}
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

View File

@ -169,6 +169,9 @@ extern int check_wildcard_match(const char* text, const char* pattern);
extern long getNum (const char *cp); extern long getNum (const char *cp);
extern pid_t findInitPid(); 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 #if defined BB_MTAB
#define whine_if_fstab_is_missing() {} #define whine_if_fstab_is_missing() {}

3
kill.c
View File

@ -183,7 +183,7 @@ extern int kill_main (int argc, char **argv)
do_it_now: do_it_now:
while (argc >= 1) { while (--argc >= 0) {
int pid; int pid;
struct stat statbuf; struct stat statbuf;
char pidpath[20]="/proc/"; char pidpath[20]="/proc/";
@ -198,6 +198,7 @@ do_it_now:
fprintf(stderr, "kill: (%d) - No such pid\n", pid); fprintf(stderr, "kill: (%d) - No such pid\n", pid);
exit( FALSE); exit( FALSE);
} }
fprintf(stderr, "sig = %d\n", sig);
if (kill (pid, sig) != 0) { if (kill (pid, sig) != 0) {
perror (*argv); perror (*argv);
exit ( FALSE); exit ( FALSE);

View File

@ -183,7 +183,7 @@ extern int kill_main (int argc, char **argv)
do_it_now: do_it_now:
while (argc >= 1) { while (--argc >= 0) {
int pid; int pid;
struct stat statbuf; struct stat statbuf;
char pidpath[20]="/proc/"; char pidpath[20]="/proc/";
@ -198,6 +198,7 @@ do_it_now:
fprintf(stderr, "kill: (%d) - No such pid\n", pid); fprintf(stderr, "kill: (%d) - No such pid\n", pid);
exit( FALSE); exit( FALSE);
} }
fprintf(stderr, "sig = %d\n", sig);
if (kill (pid, sig) != 0) { if (kill (pid, sig) != 0) {
perror (*argv); perror (*argv);
exit ( FALSE); exit ( FALSE);

2
sed.c
View File

@ -46,7 +46,7 @@ static const char sed_usage[] =
"\t /REGEXP/ Match specified regexp\n" "\t /REGEXP/ Match specified regexp\n"
"\t (! inverts the meaning of the match)\n\n" "\t (! inverts the meaning of the match)\n\n"
"\tand COMMAND can be:\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 which attempt to match regexp against the pattern space\n"
"\t and if successful replaces the matched portion with replacement.\n\n" "\t and if successful replaces the matched portion with replacement.\n\n"
"\t aTEXT\n" "\t aTEXT\n"

121
tar.c
View File

@ -37,6 +37,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <signal.h> #include <signal.h>
#include <time.h> #include <time.h>
#include <utime.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/sysmacros.h> #include <sys/sysmacros.h>
@ -106,8 +107,12 @@ static int warnedRoot;
static int eofFlag; static int eofFlag;
static long dataCc; static long dataCc;
static int outFd; 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. * Static data associated with the tar file.
@ -364,8 +369,9 @@ static void readTarFile (int fileCount, char **fileTable)
* message is required on errors. * message is required on errors.
*/ */
if (tostdoutFlag == FALSE) { if (tostdoutFlag == FALSE) {
if (outFd >= 0) if (outFd >= 0) {
(void) close (outFd); close (outFd);
}
} }
} }
@ -378,29 +384,25 @@ static void readTarFile (int fileCount, char **fileTable)
static void static void
readHeader (const TarHeader * hp, int fileCount, char **fileTable) readHeader (const TarHeader * hp, int fileCount, char **fileTable)
{ {
int mode;
int uid;
int gid;
int checkSum; int checkSum;
unsigned int major;
unsigned int minor;
long size;
time_t mtime;
const char *name;
int cc; int cc;
int hardLink; int hardLink;
int softLink; int softLink;
int devFileFlag; 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 * 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. * 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--) { for (cc = TAR_BLOCK_SIZE; cc > 0; cc--) {
if (*name++) if (*outName++)
return; return;
} }
@ -447,16 +449,16 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable)
/* /*
* Check for a directory. * Check for a directory.
*/ */
if (name[strlen (name) - 1] == '/') if (outName[strlen (outName) - 1] == '/')
mode |= S_IFDIR; mode |= S_IFDIR;
/* /*
* Check for absolute paths in the file. * Check for absolute paths in the file.
* If we find any, then warn the user and make them relative. * If we find any, then warn the user and make them relative.
*/ */
if (*name == '/') { if (*outName == '/') {
while (*name == '/') while (*outName == '/')
name++; outName++;
if (warnedRoot==FALSE) { if (warnedRoot==FALSE) {
fprintf (stderr, fprintf (stderr,
@ -470,7 +472,7 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable)
* See if we want this file to be restored. * See if we want this file to be restored.
* If not, then set up to skip it. * 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) if ( !hardLink && !softLink && (S_ISREG (mode) || S_ISCHR (mode)
|| S_ISBLK (mode) || S_ISSOCK(mode) || S_ISFIFO(mode) ) ) { || S_ISBLK (mode) || S_ISSOCK(mode) || S_ISFIFO(mode) ) ) {
inHeader = (size == 0)? TRUE : FALSE; inHeader = (size == 0)? TRUE : FALSE;
@ -494,7 +496,7 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable)
else else
printf ("%9ld %s ", size, timeString (mtime)); printf ("%9ld %s ", size, timeString (mtime));
} }
printf ("%s", name); printf ("%s", outName);
if (hardLink) if (hardLink)
printf (" (link to \"%s\")", hp->linkName); 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. * We really want to extract the file.
*/ */
if (verboseFlag==TRUE) if (verboseFlag==TRUE)
printf ("x %s\n", name); printf ("x %s\n", outName);
if (hardLink) { if (hardLink) {
if (link (hp->linkName, name) < 0) if (link (hp->linkName, outName) < 0)
perror (name); perror (outName);
chown(name, uid, gid); /* Set the file time */
chmod(name, mode); utb.actime = mtime;
utb.modtime = mtime;
utime (outName, &utb);
/* Set the file permissions */
chown(outName, uid, gid);
chmod(outName, mode);
return; return;
} }
if (softLink) { if (softLink) {
#ifdef S_ISLNK #ifdef S_ISLNK
if (symlink (hp->linkName, name) < 0) if (symlink (hp->linkName, outName) < 0)
perror (name); perror (outName);
chown(name, uid, gid); /* Try to change ownership of the symlink.
chmod(name, mode); * 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 #else
fprintf (stderr, "Cannot create symbolic links\n"); fprintf (stderr, "Cannot create symbolic links\n");
#endif #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 the file is a directory, then just create the path.
*/ */
if (S_ISDIR (mode)) { if (S_ISDIR (mode)) {
createPath (name, mode); createPath (outName, mode);
chown(name, uid, gid); /* Set the file time */
chmod(name, mode); utb.actime = mtime;
utb.modtime = mtime;
utime (outName, &utb);
/* Set the file permissions */
chown(outName, uid, gid);
chmod(outName, mode);
return; return;
} }
@ -556,7 +575,7 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable)
* There is a file to write. * There is a file to write.
* First create the path to it if necessary with default permissions. * First create the path to it if necessary with default permissions.
*/ */
createPath (name, 0777); createPath (outName, 0777);
inHeader = (size == 0)? TRUE : FALSE; inHeader = (size == 0)? TRUE : FALSE;
dataCc = size; dataCc = size;
@ -569,21 +588,26 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable)
else { else {
if ( S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode) ) { if ( S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode) ) {
devFileFlag = TRUE; devFileFlag = TRUE;
outFd = mknod (name, mode, makedev(major, minor) ); outFd = mknod (outName, mode, makedev(major, minor) );
} }
else if (S_ISFIFO(mode) ) { else if (S_ISFIFO(mode) ) {
devFileFlag = TRUE; devFileFlag = TRUE;
outFd = mkfifo(name, mode); outFd = mkfifo(outName, mode);
} else { } else {
outFd = open (name, O_WRONLY | O_CREAT | O_TRUNC, mode); outFd = open (outName, O_WRONLY | O_CREAT | O_TRUNC, mode);
} }
if (outFd < 0) { if (outFd < 0) {
perror (name); perror (outName);
skipFileFlag = TRUE; skipFileFlag = TRUE;
return; return;
} }
chown(name, uid, gid); /* Set the file time */
chmod(name, mode); 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 the file is empty, then that's all we need to do.
*/ */
if (size == 0 && (tostdoutFlag == FALSE) && (devFileFlag == FALSE)) { if (size == 0 && (tostdoutFlag == FALSE) && (devFileFlag == FALSE)) {
(void) close (outFd); close (outFd);
outFd = -1; outFd = -1;
} }
} }
@ -625,7 +649,7 @@ static void readData (const char *cp, int count)
if (fullWrite (outFd, cp, count) < 0) { if (fullWrite (outFd, cp, count) < 0) {
perror (outName); perror (outName);
if (tostdoutFlag == FALSE) { if (tostdoutFlag == FALSE) {
(void) close (outFd); close (outFd);
outFd = -1; outFd = -1;
} }
skipFileFlag = TRUE; skipFileFlag = TRUE;
@ -633,13 +657,21 @@ static void readData (const char *cp, int count)
} }
/* /*
* If the write failed, close the file and disable further * Check if we are done writing to the file now.
* writes to this file.
*/ */
if (dataCc <= 0 && tostdoutFlag == FALSE) { if (dataCc <= 0 && tostdoutFlag == FALSE) {
struct utimbuf utb;
if (close (outFd)) if (close (outFd))
perror (outName); 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; outFd = -1;
} }
} }
@ -720,7 +752,6 @@ static void writeTarFile (int fileCount, char **fileTable)
static void saveFile (const char *fileName, int seeLinks) static void saveFile (const char *fileName, int seeLinks)
{ {
int status; int status;
int mode;
struct stat statbuf; struct stat statbuf;
if (verboseFlag==TRUE) if (verboseFlag==TRUE)

View File

@ -379,7 +379,7 @@ int fullRead(int fd, char *buf, int len)
#endif #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 * Walk down all the directories under the specified
* location, and do something (something 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 * Given a block device, find the mount table entry if that block device
* is mounted. * is mounted.
@ -1008,7 +1008,6 @@ extern struct mntent *findMountPoint(const char *name, const char *table)
endmntent(mountTable); endmntent(mountTable);
return mountEntry; return mountEntry;
} }
#endif #endif
@ -1111,4 +1110,15 @@ findInitPid()
} }
#endif #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 */ /* END CODE */