aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changelog8
-rw-r--r--TODO7
-rw-r--r--coreutils/dd.c46
-rw-r--r--coreutils/tail.c176
-rw-r--r--dd.c46
-rw-r--r--hostname.c2
-rw-r--r--internal.h1
-rw-r--r--networking/hostname.c2
-rw-r--r--networking/ping.c50
-rw-r--r--ping.c50
-rw-r--r--tail.c176
-rw-r--r--utility.c53
12 files changed, 241 insertions, 376 deletions
diff --git a/Changelog b/Changelog
index 62a317123..99963cef9 100644
--- a/Changelog
+++ b/Changelog
@@ -2,19 +2,19 @@
* New Apps: ping and hostname contributed by Randolph Chung
<tausq@debian.org>. 2 items off the TODO list!
* I wrote free (just calls "cat /proc/meminfo").
+ * Added tail, based on tail from GNU textutils-1.19, but adjusted
+ to suit my evil purposes. Costs 6k.
* on reboot, init called 'umount -a -n', which caused errors
when BB_MTAB was not enabled. Changed to 'umount -a',
which does the right thing.
* init will now try to run /sbin/getty if it is present (for easy
integration with the about-to-be-released tinylogin.)
* kill now behaves itself properly, added 'kill -l' to list signals
- * Began to add tail, but it doesn't work yet.
- * my_getid was leaking file descriptors, causing 'ls -l' on long
- directories to fail
+ * 'ls -l' was failing on long directories, since my_getid was leaking
+ one file descriptor per file. Oops.
-Erik Andrsen
-
0.38
* Fixed a segfault in 'umount -a' when a badly formed /etc/fstab
file existed.
diff --git a/TODO b/TODO
index 668338299..08b2fd736 100644
--- a/TODO
+++ b/TODO
@@ -18,13 +18,14 @@ around to it some time. If you have any good ideas, please let me know.
* traceroute/nslookup/netstat
* rdate
* hwclock
-* login/getty
* killall
* tee
* stty
-* head/tail
+* head
* sort/uniq
* wc
* tr
-* expr (maybe)?
+* expr (maybe)? (ash builtin?)
+* login/sulogin/passwd/getty (These are actully now part of tinylogin, which
+ I've just started to maintain).
diff --git a/coreutils/dd.c b/coreutils/dd.c
index b37038748..90c1004fa 100644
--- a/coreutils/dd.c
+++ b/coreutils/dd.c
@@ -48,54 +48,10 @@ static const char dd_usage[] =
"\tcount=n\tcopy only n input blocks\n"
//"\tskip=n\tskip n input blocks\n"
"\n"
-"BYTES may be suffixed: by k for x1024, b for x512, and w for x2.\n";
+"BYTES may be suffixed by w (x2), k (x1024), b (x512), or m (x1024^2).\n";
-
-/*
- * Read a number with a possible multiplier.
- * Returns -1 if the number format is illegal.
- */
-static long getNum (const char *cp)
-{
- long value;
-
- if (!isDecimal (*cp))
- return -1;
-
- value = 0;
-
- while (isDecimal (*cp))
- value = value * 10 + *cp++ - '0';
-
- switch (*cp++) {
- case 'k':
- value *= 1024;
- break;
-
- case 'b':
- value *= 512;
- break;
-
- case 'w':
- value *= 2;
- break;
-
- case '\0':
- return value;
-
- default:
- return -1;
- }
-
- if (*cp)
- return -1;
-
- return value;
-}
-
-
extern int dd_main (int argc, char **argv)
{
const char *inFile = NULL;
diff --git a/coreutils/tail.c b/coreutils/tail.c
index 058d462a5..7a64c4ca3 100644
--- a/coreutils/tail.c
+++ b/coreutils/tail.c
@@ -13,35 +13,16 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* Can display any amount of data, unlike the Unix version, which uses
- a fixed size buffer and therefore can only deliver a limited number
- of lines.
-
- Options:
- -b Tail by N 512-byte blocks.
- -c, --bytes=N[bkm] Tail by N bytes
- [or 512-byte blocks, kilobytes, or megabytes].
- -f, --follow Loop forever trying to read more characters at the
- end of the file, on the assumption that the file
- is growing. Ignored if reading from a pipe.
- -n, --lines=N Tail by N lines.
- -q, --quiet, --silent Never print filename headers.
- -v, --verbose Always print filename headers.
-
- If a number (N) starts with a `+', begin printing with the Nth item
- from the start of each file, instead of from the end.
-
- Reads from standard input if no files are given or when a filename of
- ``-'' is encountered.
- By default, filename headers are printed only more than one file
- is given.
- By default, prints the last 10 lines (tail -n 10).
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Original version by Paul Rubin <phr@ocf.berkeley.edu>.
Extensions by David MacKenzie <djm@gnu.ai.mit.edu>.
- tail -f for multiple files by Ian Lance Taylor <ian@airs.com>. */
+ tail -f for multiple files by Ian Lance Taylor <ian@airs.com>.
+
+ Rewrote the option parser, removed locales support,
+ and generally busyboxed, Erik Andersen <andersen@lineo.com>
+
+ */
#include "internal.h"
@@ -49,16 +30,25 @@
#include <assert.h>
#include <errno.h>
#include <sys/types.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <ctype.h>
+
/* Disable assertions. Some systems have broken assert macros. */
#define NDEBUG 1
-static void error(int i, int errnum, char* fmt, const char *msg)
+static void error(int i, int errnum, char* fmt, ...)
{
- fprintf(stderr, fmt, msg);
- perror( errnum);
+ va_list arguments;
+
+ va_start(arguments, fmt);
+ vfprintf(stderr, fmt, arguments);
+ fprintf(stderr, "\n%s\n", strerror( errnum));
+ va_end(arguments);
exit(i);
}
@@ -69,7 +59,7 @@ static void error(int i, int errnum, char* fmt, const char *msg)
assert ((fd) == 1); \
assert ((n_bytes) >= 0); \
if (n_bytes > 0 && fwrite ((buffer), 1, (n_bytes), stdout) == 0) \
- error (EXIT_FAILURE, errno, "write error", NULL); \
+ error (EXIT_FAILURE, errno, "write error"); \
} \
while (0)
@@ -110,7 +100,6 @@ enum header_mode
};
char *xmalloc ();
-int safe_read ();
/* The name this program was run with. */
char *program_name;
@@ -118,33 +107,24 @@ char *program_name;
/* Nonzero if we have ever read standard input. */
static int have_read_stdin;
-/* If nonzero, display usage information and exit. */
-static int show_help;
-
-/* If nonzero, print the version on standard output then exit. */
-static int show_version;
static const char tail_usage[] =
"tail [OPTION]... [FILE]...\n\
+\n\
Print last 10 lines of each FILE to standard output.\n\
With more than one FILE, precede each with a header giving the file name.\n\
With no FILE, or when FILE is -, read standard input.\n\
\n\
- -c, --bytes=N output the last N bytes\n\
- -f, --follow output appended data as the file grows\n\
- -n, --lines=N output the last N lines, instead of last 10\n\
- -q, --quiet, --silent never output headers giving file names\n\
- -v, --verbose always output headers giving file names\n\
- --help display this help and exit\n\
- --version output version information and exit\n\
+ -c=N[kbm] output the last N bytes\n\
+ -f output appended data as the file grows\n\
+ -n=N output the last N lines, instead of last 10\n\
+ -q never output headers giving file names\n\
+ -v always output headers giving file names\n\
+ --help display this help and exit\n\
\n\
-If the first character of N (the number of bytes or lines) is a `+',\n\
-print beginning with the Nth item from the start of each file, otherwise,\n\
-print the last N items in the file. N may have a multiplier suffix:\n\
-b for 512, k for 1024, m for 1048576 (1 Meg). A first OPTION of -VALUE\n\
-or +VALUE is treated like -n VALUE or -n +VALUE unless VALUE has one of\n\
-the [bkm] suffix multipliers, in which case it is treated like -c VALUE\n\
-or -c +VALUE.\n";
+If the first character of N (bytes or lines) is a `+', output begins with \n\
+the Nth item from the start of each file, otherwise, print the last N items\n\
+in the file. N bytes may be suffixed by k (x1024), b (x512), or m (1024^2).\n\n";
static void
write_header (const char *filename, const char *comment)
@@ -184,7 +164,7 @@ file_lines (const char *filename, int fd, long int n_lines, off_t pos)
reads will be on block boundaries, which might increase efficiency. */
pos -= bytes_read;
lseek (fd, pos, SEEK_SET);
- bytes_read = safe_read (fd, buffer, bytes_read);
+ bytes_read = fullRead (fd, buffer, bytes_read);
if (bytes_read == -1)
{
error (0, errno, "%s", filename);
@@ -220,7 +200,7 @@ file_lines (const char *filename, int fd, long int n_lines, off_t pos)
pos -= BUFSIZ;
lseek (fd, pos, SEEK_SET);
}
- while ((bytes_read = safe_read (fd, buffer, BUFSIZ)) > 0);
+ while ((bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0);
if (bytes_read == -1)
{
error (0, errno, "%s", filename);
@@ -255,7 +235,7 @@ pipe_lines (const char *filename, int fd, long int n_lines)
tmp = (LBUFFER *) xmalloc (sizeof (LBUFFER));
/* Input is always read into a fresh buffer. */
- while ((tmp->nbytes = safe_read (fd, tmp->buffer, BUFSIZ)) > 0)
+ while ((tmp->nbytes = fullRead (fd, tmp->buffer, BUFSIZ)) > 0)
{
tmp->nlines = 0;
tmp->next = NULL;
@@ -374,7 +354,7 @@ pipe_bytes (const char *filename, int fd, off_t n_bytes)
tmp = (CBUFFER *) xmalloc (sizeof (CBUFFER));
/* Input is always read into a fresh buffer. */
- while ((tmp->nbytes = safe_read (fd, tmp->buffer, BUFSIZ)) > 0)
+ while ((tmp->nbytes = fullRead (fd, tmp->buffer, BUFSIZ)) > 0)
{
tmp->next = NULL;
@@ -453,7 +433,7 @@ start_bytes (const char *filename, int fd, off_t n_bytes)
char buffer[BUFSIZ];
int bytes_read = 0;
- while (n_bytes > 0 && (bytes_read = safe_read (fd, buffer, BUFSIZ)) > 0)
+ while (n_bytes > 0 && (bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0)
n_bytes -= bytes_read;
if (bytes_read == -1)
{
@@ -476,7 +456,7 @@ start_lines (const char *filename, int fd, long int n_lines)
int bytes_read = 0;
int bytes_to_skip = 0;
- while (n_lines && (bytes_read = safe_read (fd, buffer, BUFSIZ)) > 0)
+ while (n_lines && (bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0)
{
bytes_to_skip = 0;
while (bytes_to_skip < bytes_read)
@@ -509,7 +489,7 @@ dump_remainder (const char *filename, int fd)
total = 0;
output:
- while ((bytes_read = safe_read (fd, buffer, BUFSIZ)) > 0)
+ while ((bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0)
{
XWRITE (STDOUT_FILENO, buffer, bytes_read);
total += bytes_read;
@@ -731,7 +711,7 @@ tail_file (const char *filename, off_t n_units, int filenum)
int fd, errors;
struct stat stats;
- if (!strcmp (filename, "-")
+ if (!strcmp (filename, "-"))
{
have_read_stdin = 1;
filename = "standard input";
@@ -815,16 +795,15 @@ tail_file (const char *filename, off_t n_units, int filenum)
}
extern int
-tai_main (int argc, char **argv)
+tail_main (int argc, char **argv)
{
+ int stopit = 0;
enum header_mode header_mode = multiple_files;
int exit_status = 0;
/* If from_start, the number of items to skip before printing; otherwise,
the number of items at the end of the file to print. Initially, -1
means the value has not been set. */
off_t n_units = -1;
- long int tmp_long;
- int c; /* Option character. */
int n_files;
char **file;
@@ -832,48 +811,38 @@ tai_main (int argc, char **argv)
have_read_stdin = 0;
count_lines = 1;
forever = forever_multiple = from_start = print_headers = 0;
-
- if (argc > 1
- && ((argv[1][0] == '-' && ISDIGIT (argv[1][1]))
- || (argv[1][0] == '+' && (ISDIGIT (argv[1][1])
- || argv[1][1] == 0))))
- {
- /* Old option syntax: a dash or plus, one or more digits (zero digits
- are acceptable with a plus), and one or more option letters. */
- if (argv[1][0] == '+')
- from_start = 1;
- if (argv[1][1] != '\0')
- {
- strtol_error s_err;
- char *p;
-
- s_err = xstrtol (++argv[1], &p, 0, &tmp_long, "bkm");
- n_units = tmp_long;
- if (s_err == LONGINT_OVERFLOW)
- {
- STRTOL_FATAL_ERROR (argv[1], "argument", s_err);
- }
-
- /* If a [bkm] suffix was given then count bytes, not lines. */
- if (p[-1] == 'b' || p[-1] == 'k' || p[-1] == 'm')
- count_lines = 0;
-
- /* Parse any appended option letters. */
- while (*p)
- {
- switch (*p)
- {
+
+ /* Parse any options */
+ //fprintf(stderr, "argc=%d, argv=%s\n", argc, *argv);
+ while (--argc > 0 && ( **(++argv) == '-' || **argv == '+' )) {
+ if (**argv == '+') {
+ from_start = 1;
+ }
+ stopit = 0;
+ while (stopit == 0 && *(++(*argv))) {
+ switch (**argv) {
case 'c':
- /* Interpret N_UNITS as # of bytes. */
count_lines = 0;
+
+ if (--argc < 1) {
+ usage(tail_usage);
+ }
+ n_units = getNum(*(++argv));
+ stopit = 1;
break;
case 'f':
forever = 1;
break;
- case 'l':
+ case 'n':
count_lines = 1;
+
+ if (--argc < 1) {
+ usage(tail_usage);
+ }
+ n_units = atol(*(++argv));
+ stopit = 1;
break;
case 'q':
@@ -885,26 +854,11 @@ tai_main (int argc, char **argv)
break;
default:
- error (0, 0, "unrecognized option '%c'", *p);
usage (tail_usage);
- }
- ++p;
}
}
- /* Make the options we just parsed invisible to getopt. */
- argv[1] = argv[0];
- argv++;
- argc--;
- }
-
- if (show_version)
- {
- printf ("tail - %s\n", PACKAGE_VERSION);
- exit (EXIT_SUCCESS);
}
- if (show_help)
- usage (tail_usage);
if (n_units == -1)
n_units = DEFAULT_N_LINES;
@@ -918,8 +872,8 @@ tai_main (int argc, char **argv)
--n_units;
}
- n_files = argc - optind;
- file = argv + optind;
+ n_files = argc;
+ file = argv;
if (n_files > 1 && forever)
{
diff --git a/dd.c b/dd.c
index b37038748..90c1004fa 100644
--- a/dd.c
+++ b/dd.c
@@ -48,54 +48,10 @@ static const char dd_usage[] =
"\tcount=n\tcopy only n input blocks\n"
//"\tskip=n\tskip n input blocks\n"
"\n"
-"BYTES may be suffixed: by k for x1024, b for x512, and w for x2.\n";
+"BYTES may be suffixed by w (x2), k (x1024), b (x512), or m (x1024^2).\n";
-
-/*
- * Read a number with a possible multiplier.
- * Returns -1 if the number format is illegal.
- */
-static long getNum (const char *cp)
-{
- long value;
-
- if (!isDecimal (*cp))
- return -1;
-
- value = 0;
-
- while (isDecimal (*cp))
- value = value * 10 + *cp++ - '0';
-
- switch (*cp++) {
- case 'k':
- value *= 1024;
- break;
-
- case 'b':
- value *= 512;
- break;
-
- case 'w':
- value *= 2;
- break;
-
- case '\0':
- return value;
-
- default:
- return -1;
- }
-
- if (*cp)
- return -1;
-
- return value;
-}
-
-
extern int dd_main (int argc, char **argv)
{
const char *inFile = NULL;
diff --git a/hostname.c b/hostname.c
index be49de395..20e174187 100644
--- a/hostname.c
+++ b/hostname.c
@@ -1,5 +1,5 @@
/*
- * $Id: hostname.c,v 1.4 1999/12/08 23:19:36 andersen Exp $
+ * $Id: hostname.c,v 1.5 1999/12/09 06:11:36 andersen Exp $
* Mini hostname implementation for busybox
*
* Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
diff --git a/internal.h b/internal.h
index 48bad0c69..42c6b93ab 100644
--- a/internal.h
+++ b/internal.h
@@ -155,6 +155,7 @@ extern void write_mtab(char* blockDevice, char* directory,
char* filesystemType, long flags, char* string_flags);
extern void erase_mtab(const char * name);
extern int check_wildcard_match(const char* text, const char* pattern);
+extern long getNum (const char *cp);
#if defined BB_MTAB
diff --git a/networking/hostname.c b/networking/hostname.c
index be49de395..20e174187 100644
--- a/networking/hostname.c
+++ b/networking/hostname.c
@@ -1,5 +1,5 @@
/*
- * $Id: hostname.c,v 1.4 1999/12/08 23:19:36 andersen Exp $
+ * $Id: hostname.c,v 1.5 1999/12/09 06:11:36 andersen Exp $
* Mini hostname implementation for busybox
*
* Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
diff --git a/networking/ping.c b/networking/ping.c
index 45f3c20aa..4176ab390 100644
--- a/networking/ping.c
+++ b/networking/ping.c
@@ -1,5 +1,5 @@
/*
- * $Id: ping.c,v 1.4 1999/12/08 23:19:36 andersen Exp $
+ * $Id: ping.c,v 1.5 1999/12/09 06:11:36 andersen Exp $
* Mini ping implementation for busybox
*
* Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
@@ -53,6 +53,7 @@
#define MAXPACKET 65468
#define MAX_DUP_CHK (8 * 128)
#define MAXWAIT 10
+#define PINGINTERVAL 1 /* second */
#define O_QUIET (1 << 0)
@@ -155,8 +156,8 @@ static void sendping(int ign)
}
signal(SIGALRM, sendping);
- if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next */
- alarm(1);
+ if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next in 1s */
+ alarm(PINGINTERVAL);
} else { /* done, wait for the last ping to come back */
/* todo, don't necessarily need to wait so long... */
signal(SIGALRM, pingstats);
@@ -243,9 +244,8 @@ static void ping(char *host)
exit(1);
}
-#ifdef SUID_BUSYBOX
+ /* drop root privs if running setuid */
setuid(getuid());
-#endif
memset(&pingaddr, 0, sizeof(struct sockaddr_in));
pingaddr.sin_family = AF_INET;
@@ -305,35 +305,31 @@ static void ping(char *host)
extern int ping_main(int argc, char **argv)
{
+ char *thisarg;
+
argc--;
argv++;
options = 0;
/* Parse any options */
- if (argc < 1) usage(ping_usage);
-
- while (**argv == '-') {
- while (*++(*argv))
- switch (**argv) {
- case 'c':
- argc--; argv++;
- if (argc < 1) usage(ping_usage);
- pingcount = atoi(*argv);
- break;
- case 'q':
- options |= O_QUIET;
- break;
- default:
- usage(ping_usage);
- }
- argc--;
- argv++;
+ while (argc > 1) {
+ if (**argv != '-') usage(ping_usage);
+ thisarg = *argv; thisarg++;
+ switch (*thisarg) {
+ case 'q': options |= O_QUIET; break;
+ case 'c':
+ argc--; argv++;
+ pingcount = atoi(*argv);
+ break;
+ default:
+ usage(ping_usage);
+ }
+ argc--; argv++;
}
-
- if (argc < 1) usage(ping_usage);
+ if (argc < 1) usage(ping_usage);
myid = getpid() & 0xFFFF;
- ping(*(argv++));
- exit( TRUE);
+ ping(*argv);
+ exit(TRUE);
}
/*
diff --git a/ping.c b/ping.c
index 45f3c20aa..4176ab390 100644
--- a/ping.c
+++ b/ping.c
@@ -1,5 +1,5 @@
/*
- * $Id: ping.c,v 1.4 1999/12/08 23:19:36 andersen Exp $
+ * $Id: ping.c,v 1.5 1999/12/09 06:11:36 andersen Exp $
* Mini ping implementation for busybox
*
* Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
@@ -53,6 +53,7 @@
#define MAXPACKET 65468
#define MAX_DUP_CHK (8 * 128)
#define MAXWAIT 10
+#define PINGINTERVAL 1 /* second */
#define O_QUIET (1 << 0)
@@ -155,8 +156,8 @@ static void sendping(int ign)
}
signal(SIGALRM, sendping);
- if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next */
- alarm(1);
+ if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next in 1s */
+ alarm(PINGINTERVAL);
} else { /* done, wait for the last ping to come back */
/* todo, don't necessarily need to wait so long... */
signal(SIGALRM, pingstats);
@@ -243,9 +244,8 @@ static void ping(char *host)
exit(1);
}
-#ifdef SUID_BUSYBOX
+ /* drop root privs if running setuid */
setuid(getuid());
-#endif
memset(&pingaddr, 0, sizeof(struct sockaddr_in));
pingaddr.sin_family = AF_INET;
@@ -305,35 +305,31 @@ static void ping(char *host)
extern int ping_main(int argc, char **argv)
{
+ char *thisarg;
+
argc--;
argv++;
options = 0;
/* Parse any options */
- if (argc < 1) usage(ping_usage);
-
- while (**argv == '-') {
- while (*++(*argv))
- switch (**argv) {
- case 'c':
- argc--; argv++;
- if (argc < 1) usage(ping_usage);
- pingcount = atoi(*argv);
- break;
- case 'q':
- options |= O_QUIET;
- break;
- default:
- usage(ping_usage);
- }
- argc--;
- argv++;
+ while (argc > 1) {
+ if (**argv != '-') usage(ping_usage);
+ thisarg = *argv; thisarg++;
+ switch (*thisarg) {
+ case 'q': options |= O_QUIET; break;
+ case 'c':
+ argc--; argv++;
+ pingcount = atoi(*argv);
+ break;
+ default:
+ usage(ping_usage);
+ }
+ argc--; argv++;
}
-
- if (argc < 1) usage(ping_usage);
+ if (argc < 1) usage(ping_usage);
myid = getpid() & 0xFFFF;
- ping(*(argv++));
- exit( TRUE);
+ ping(*argv);
+ exit(TRUE);
}
/*
diff --git a/tail.c b/tail.c
index 058d462a5..7a64c4ca3 100644
--- a/tail.c
+++ b/tail.c
@@ -13,35 +13,16 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* Can display any amount of data, unlike the Unix version, which uses
- a fixed size buffer and therefore can only deliver a limited number
- of lines.
-
- Options:
- -b Tail by N 512-byte blocks.
- -c, --bytes=N[bkm] Tail by N bytes
- [or 512-byte blocks, kilobytes, or megabytes].
- -f, --follow Loop forever trying to read more characters at the
- end of the file, on the assumption that the file
- is growing. Ignored if reading from a pipe.
- -n, --lines=N Tail by N lines.
- -q, --quiet, --silent Never print filename headers.
- -v, --verbose Always print filename headers.
-
- If a number (N) starts with a `+', begin printing with the Nth item
- from the start of each file, instead of from the end.
-
- Reads from standard input if no files are given or when a filename of
- ``-'' is encountered.
- By default, filename headers are printed only more than one file
- is given.
- By default, prints the last 10 lines (tail -n 10).
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Original version by Paul Rubin <phr@ocf.berkeley.edu>.
Extensions by David MacKenzie <djm@gnu.ai.mit.edu>.
- tail -f for multiple files by Ian Lance Taylor <ian@airs.com>. */
+ tail -f for multiple files by Ian Lance Taylor <ian@airs.com>.
+
+ Rewrote the option parser, removed locales support,
+ and generally busyboxed, Erik Andersen <andersen@lineo.com>
+
+ */
#include "internal.h"
@@ -49,16 +30,25 @@
#include <assert.h>
#include <errno.h>
#include <sys/types.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <ctype.h>
+
/* Disable assertions. Some systems have broken assert macros. */
#define NDEBUG 1
-static void error(int i, int errnum, char* fmt, const char *msg)
+static void error(int i, int errnum, char* fmt, ...)
{
- fprintf(stderr, fmt, msg);
- perror( errnum);
+ va_list arguments;
+
+ va_start(arguments, fmt);
+ vfprintf(stderr, fmt, arguments);
+ fprintf(stderr, "\n%s\n", strerror( errnum));
+ va_end(arguments);
exit(i);
}
@@ -69,7 +59,7 @@ static void error(int i, int errnum, char* fmt, const char *msg)
assert ((fd) == 1); \
assert ((n_bytes) >= 0); \
if (n_bytes > 0 && fwrite ((buffer), 1, (n_bytes), stdout) == 0) \
- error (EXIT_FAILURE, errno, "write error", NULL); \
+ error (EXIT_FAILURE, errno, "write error"); \
} \
while (0)
@@ -110,7 +100,6 @@ enum header_mode
};
char *xmalloc ();
-int safe_read ();
/* The name this program was run with. */
char *program_name;
@@ -118,33 +107,24 @@ char *program_name;
/* Nonzero if we have ever read standard input. */
static int have_read_stdin;
-/* If nonzero, display usage information and exit. */
-static int show_help;
-
-/* If nonzero, print the version on standard output then exit. */
-static int show_version;
static const char tail_usage[] =
"tail [OPTION]... [FILE]...\n\
+\n\
Print last 10 lines of each FILE to standard output.\n\
With more than one FILE, precede each with a header giving the file name.\n\
With no FILE, or when FILE is -, read standard input.\n\
\n\
- -c, --bytes=N output the last N bytes\n\
- -f, --follow output appended data as the file grows\n\
- -n, --lines=N output the last N lines, instead of last 10\n\
- -q, --quiet, --silent never output headers giving file names\n\
- -v, --verbose always output headers giving file names\n\
- --help display this help and exit\n\
- --version output version information and exit\n\
+ -c=N[kbm] output the last N bytes\n\
+ -f output appended data as the file grows\n\
+ -n=N output the last N lines, instead of last 10\n\
+ -q never output headers giving file names\n\
+ -v always output headers giving file names\n\
+ --help display this help and exit\n\
\n\
-If the first character of N (the number of bytes or lines) is a `+',\n\
-print beginning with the Nth item from the start of each file, otherwise,\n\
-print the last N items in the file. N may have a multiplier suffix:\n\
-b for 512, k for 1024, m for 1048576 (1 Meg). A first OPTION of -VALUE\n\
-or +VALUE is treated like -n VALUE or -n +VALUE unless VALUE has one of\n\
-the [bkm] suffix multipliers, in which case it is treated like -c VALUE\n\
-or -c +VALUE.\n";
+If the first character of N (bytes or lines) is a `+', output begins with \n\
+the Nth item from the start of each file, otherwise, print the last N items\n\
+in the file. N bytes may be suffixed by k (x1024), b (x512), or m (1024^2).\n\n";
static void
write_header (const char *filename, const char *comment)
@@ -184,7 +164,7 @@ file_lines (const char *filename, int fd, long int n_lines, off_t pos)
reads will be on block boundaries, which might increase efficiency. */
pos -= bytes_read;
lseek (fd, pos, SEEK_SET);
- bytes_read = safe_read (fd, buffer, bytes_read);
+ bytes_read = fullRead (fd, buffer, bytes_read);
if (bytes_read == -1)
{
error (0, errno, "%s", filename);
@@ -220,7 +200,7 @@ file_lines (const char *filename, int fd, long int n_lines, off_t pos)
pos -= BUFSIZ;
lseek (fd, pos, SEEK_SET);
}
- while ((bytes_read = safe_read (fd, buffer, BUFSIZ)) > 0);
+ while ((bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0);
if (bytes_read == -1)
{
error (0, errno, "%s", filename);
@@ -255,7 +235,7 @@ pipe_lines (const char *filename, int fd, long int n_lines)
tmp = (LBUFFER *) xmalloc (sizeof (LBUFFER));
/* Input is always read into a fresh buffer. */
- while ((tmp->nbytes = safe_read (fd, tmp->buffer, BUFSIZ)) > 0)
+ while ((tmp->nbytes = fullRead (fd, tmp->buffer, BUFSIZ)) > 0)
{
tmp->nlines = 0;
tmp->next = NULL;
@@ -374,7 +354,7 @@ pipe_bytes (const char *filename, int fd, off_t n_bytes)
tmp = (CBUFFER *) xmalloc (sizeof (CBUFFER));
/* Input is always read into a fresh buffer. */
- while ((tmp->nbytes = safe_read (fd, tmp->buffer, BUFSIZ)) > 0)
+ while ((tmp->nbytes = fullRead (fd, tmp->buffer, BUFSIZ)) > 0)
{
tmp->next = NULL;
@@ -453,7 +433,7 @@ start_bytes (const char *filename, int fd, off_t n_bytes)
char buffer[BUFSIZ];
int bytes_read = 0;
- while (n_bytes > 0 && (bytes_read = safe_read (fd, buffer, BUFSIZ)) > 0)
+ while (n_bytes > 0 && (bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0)
n_bytes -= bytes_read;
if (bytes_read == -1)
{
@@ -476,7 +456,7 @@ start_lines (const char *filename, int fd, long int n_lines)
int bytes_read = 0;
int bytes_to_skip = 0;
- while (n_lines && (bytes_read = safe_read (fd, buffer, BUFSIZ)) > 0)
+ while (n_lines && (bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0)
{
bytes_to_skip = 0;
while (bytes_to_skip < bytes_read)
@@ -509,7 +489,7 @@ dump_remainder (const char *filename, int fd)
total = 0;
output:
- while ((bytes_read = safe_read (fd, buffer, BUFSIZ)) > 0)
+ while ((bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0)
{
XWRITE (STDOUT_FILENO, buffer, bytes_read);
total += bytes_read;
@@ -731,7 +711,7 @@ tail_file (const char *filename, off_t n_units, int filenum)
int fd, errors;
struct stat stats;
- if (!strcmp (filename, "-")
+ if (!strcmp (filename, "-"))
{
have_read_stdin = 1;
filename = "standard input";
@@ -815,16 +795,15 @@ tail_file (const char *filename, off_t n_units, int filenum)
}
extern int
-tai_main (int argc, char **argv)
+tail_main (int argc, char **argv)
{
+ int stopit = 0;
enum header_mode header_mode = multiple_files;
int exit_status = 0;
/* If from_start, the number of items to skip before printing; otherwise,
the number of items at the end of the file to print. Initially, -1
means the value has not been set. */
off_t n_units = -1;
- long int tmp_long;
- int c; /* Option character. */
int n_files;
char **file;
@@ -832,48 +811,38 @@ tai_main (int argc, char **argv)
have_read_stdin = 0;
count_lines = 1;
forever = forever_multiple = from_start = print_headers = 0;
-
- if (argc > 1
- && ((argv[1][0] == '-' && ISDIGIT (argv[1][1]))
- || (argv[1][0] == '+' && (ISDIGIT (argv[1][1])
- || argv[1][1] == 0))))
- {
- /* Old option syntax: a dash or plus, one or more digits (zero digits
- are acceptable with a plus), and one or more option letters. */
- if (argv[1][0] == '+')
- from_start = 1;
- if (argv[1][1] != '\0')
- {
- strtol_error s_err;
- char *p;
-
- s_err = xstrtol (++argv[1], &p, 0, &tmp_long, "bkm");
- n_units = tmp_long;
- if (s_err == LONGINT_OVERFLOW)
- {
- STRTOL_FATAL_ERROR (argv[1], "argument", s_err);
- }
-
- /* If a [bkm] suffix was given then count bytes, not lines. */
- if (p[-1] == 'b' || p[-1] == 'k' || p[-1] == 'm')
- count_lines = 0;
-
- /* Parse any appended option letters. */
- while (*p)
- {
- switch (*p)
- {
+
+ /* Parse any options */
+ //fprintf(stderr, "argc=%d, argv=%s\n", argc, *argv);
+ while (--argc > 0 && ( **(++argv) == '-' || **argv == '+' )) {
+ if (**argv == '+') {
+ from_start = 1;
+ }
+ stopit = 0;
+ while (stopit == 0 && *(++(*argv))) {
+ switch (**argv) {
case 'c':
- /* Interpret N_UNITS as # of bytes. */
count_lines = 0;
+
+ if (--argc < 1) {
+ usage(tail_usage);
+ }
+ n_units = getNum(*(++argv));
+ stopit = 1;
break;
case 'f':
forever = 1;
break;
- case 'l':
+ case 'n':
count_lines = 1;
+
+ if (--argc < 1) {
+ usage(tail_usage);
+ }
+ n_units = atol(*(++argv));
+ stopit = 1;
break;
case 'q':
@@ -885,26 +854,11 @@ tai_main (int argc, char **argv)
break;
default:
- error (0, 0, "unrecognized option '%c'", *p);
usage (tail_usage);
- }
- ++p;
}
}
- /* Make the options we just parsed invisible to getopt. */
- argv[1] = argv[0];
- argv++;
- argc--;
- }
-
- if (show_version)
- {
- printf ("tail - %s\n", PACKAGE_VERSION);
- exit (EXIT_SUCCESS);
}
- if (show_help)
- usage (tail_usage);
if (n_units == -1)
n_units = DEFAULT_N_LINES;
@@ -918,8 +872,8 @@ tai_main (int argc, char **argv)
--n_units;
}
- n_files = argc - optind;
- file = argv + optind;
+ n_files = argc;
+ file = argv;
if (n_files > 1 && forever)
{
diff --git a/utility.c b/utility.c
index 469275f2d..de7a0fbfc 100644
--- a/utility.c
+++ b/utility.c
@@ -289,7 +289,7 @@ const char *modeString(int mode)
#endif
-#ifdef BB_TAR
+#if defined BB_TAR
/*
* Return the standard ls-like time string from a time_t
* This is static and so is overwritten on each call.
@@ -340,8 +340,10 @@ int fullWrite(int fd, const char *buf, int len)
return total;
}
+#endif
+#if defined BB_TAR || defined BB_TAIL
/*
* Read all of the supplied buffer from a file.
* This does multiple reads as necessary.
@@ -1018,6 +1020,55 @@ extern void whine_if_fstab_is_missing()
#endif
+#if defined BB_DD || defined BB_TAIL
+/*
+ * Read a number with a possible multiplier.
+ * Returns -1 if the number format is illegal.
+ */
+extern long getNum (const char *cp)
+{
+ long value;
+
+ if (!isDecimal (*cp))
+ return -1;
+
+ value = 0;
+
+ while (isDecimal (*cp))
+ value = value * 10 + *cp++ - '0';
+
+ switch (*cp++) {
+ case 'm':
+ value *= 1048576;
+ break;
+
+ case 'k':
+ value *= 1024;
+ break;
+
+ case 'b':
+ value *= 512;
+ break;
+
+ case 'w':
+ value *= 2;
+ break;
+
+ case '\0':
+ return value;
+
+ default:
+ return -1;
+ }
+
+ if (*cp)
+ return -1;
+
+ return value;
+}
+#endif
+
+
/* END CODE */