aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Kraai <kraai@debian.org>2000-12-18 21:38:57 +0000
committerMatt Kraai <kraai@debian.org>2000-12-18 21:38:57 +0000
commit24ac0179617e43ab517141fe5497f4ebac108678 (patch)
tree333d1ef43d092edd4b41030112cb71559bf9cb3a
parent0d2acb0eadf2d6ae9d60fa3fe9f897e254eaadda (diff)
downloadbusybox-w32-24ac0179617e43ab517141fe5497f4ebac108678.tar.gz
busybox-w32-24ac0179617e43ab517141fe5497f4ebac108678.tar.bz2
busybox-w32-24ac0179617e43ab517141fe5497f4ebac108678.zip
Rewrote dd.
-rw-r--r--applets/usage.c17
-rw-r--r--busybox.h7
-rw-r--r--coreutils/dd.c243
-rw-r--r--coreutils/tail.c48
-rw-r--r--dd.c243
-rw-r--r--include/busybox.h7
-rw-r--r--tail.c48
-rw-r--r--usage.c17
-rw-r--r--utility.c98
9 files changed, 306 insertions, 422 deletions
diff --git a/applets/usage.c b/applets/usage.c
index 876d253ab..c7bc0e8a9 100644
--- a/applets/usage.c
+++ b/applets/usage.c
@@ -170,10 +170,11 @@ const char dd_usage[] =
170 "\tcount=N\tcopy only N input blocks\n" 170 "\tcount=N\tcopy only N input blocks\n"
171 "\tskip=N\tskip N input blocks\n" 171 "\tskip=N\tskip N input blocks\n"
172 "\tseek=N\tskip N output blocks\n" 172 "\tseek=N\tskip N output blocks\n"
173 "\tconv=notrunc\t dont truncate of at end of write\n" 173 "\tconv=notrunc\tdon't truncate output file\n"
174 "\tconv=sync\t pad the last block with zeros until blocksize\n" 174 "\tconv=sync\tpad blocks with zeros\n"
175 "\n" 175 "\n"
176 "Numbers may be suffixed by w (x2), k (x1024), b (x512), or M (x1024^2)\n" 176 "Numbers may be suffixed by c (x1), w (x2), b (x512), kD (x1000), k (x1024),\n"
177 "MD (x1000000), M (x1048576), GD (x1000000000) or G (x1073741824).\n"
177#endif 178#endif
178 ; 179 ;
179#endif 180#endif
@@ -1185,20 +1186,20 @@ const char syslogd_usage[] =
1185 1186
1186#if defined BB_TAIL 1187#if defined BB_TAIL
1187const char tail_usage[] = 1188const char tail_usage[] =
1188 "tail [OPTION] [FILE]...\n" 1189 "tail [OPTION]... [FILE]...\n"
1189#ifndef BB_FEATURE_TRIVIAL_HELP 1190#ifndef BB_FEATURE_TRIVIAL_HELP
1190 "\nPrint last 10 lines of each FILE to standard output.\n" 1191 "\nPrint last 10 lines of each FILE to standard output.\n"
1191 "With more than one FILE, precede each with a header giving the\n" 1192 "With more than one FILE, precede each with a header giving the\n"
1192 "file name. With no FILE, or when FILE is -, read standard input.\n\n" 1193 "file name. With no FILE, or when FILE is -, read standard input.\n\n"
1193 "Options:\n" 1194 "Options:\n"
1194#ifndef BB_FEATURE_SIMPLE_TAIL 1195#ifndef BB_FEATURE_SIMPLE_TAIL
1195 "\t-c=N[kbm]\toutput the last N bytes\n" 1196 "\t-c N[kbm]\toutput the last N bytes\n"
1196#endif 1197#endif
1197 "\t-n NUM\t\tPrint last NUM lines instead of first 10\n" 1198 "\t-n N[kbm]\tprint last N lines instead of last 10\n"
1198 "\t-f\t\tOutput data as the file grows.\n" 1199 "\t-f\t\toutput data as the file grows\n"
1199#ifndef BB_FEATURE_SIMPLE_TAIL 1200#ifndef BB_FEATURE_SIMPLE_TAIL
1200 "\t-q\t\tnever output headers giving file names\n" 1201 "\t-q\t\tnever output headers giving file names\n"
1201 "\t-s SEC\t\tWait SEC seconds between reads with -f\n" 1202 "\t-s SEC\t\twait SEC seconds between reads with -f\n"
1202 "\t-v\t\talways output headers giving file names\n\n" 1203 "\t-v\t\talways output headers giving file names\n\n"
1203 "If the first character of N (bytes or lines) is a `+', output begins with \n" 1204 "If the first character of N (bytes or lines) is a `+', output begins with \n"
1204 "the Nth item from the start of each file, otherwise, print the last N items\n" 1205 "the Nth item from the start of each file, otherwise, print the last N items\n"
diff --git a/busybox.h b/busybox.h
index 5ff3975b9..442352537 100644
--- a/busybox.h
+++ b/busybox.h
@@ -190,6 +190,13 @@ extern char *xstrdup (const char *s);
190#endif 190#endif
191extern char *xstrndup (const char *s, int n); 191extern char *xstrndup (const char *s, int n);
192 192
193struct suffix_mult {
194 char *suffix;
195 int mult;
196};
197
198extern unsigned long parse_number(const char *numstr, struct suffix_mult *suffixes);
199
193 200
194/* These parse entries in /etc/passwd and /etc/group. This is desirable 201/* These parse entries in /etc/passwd and /etc/group. This is desirable
195 * for BusyBox since we want to avoid using the glibc NSS stuff, which 202 * for BusyBox since we want to avoid using the glibc NSS stuff, which
diff --git a/coreutils/dd.c b/coreutils/dd.c
index 626b54898..a0d2330ea 100644
--- a/coreutils/dd.c
+++ b/coreutils/dd.c
@@ -2,15 +2,8 @@
2/* 2/*
3 * Mini dd implementation for busybox 3 * Mini dd implementation for busybox
4 * 4 *
5 * Copyright (C) 1999, 2000 by Lineo, inc.
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
7 * 5 *
8 * Based in part on code taken from sash. 6 * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
9 * Copyright (c) 1999 by David I. Bell
10 * Permission is granted to use, distribute, or modify this source,
11 * provided that this copyright notice remains intact.
12 *
13 * Permission to distribute this code under the GPL has been granted.
14 * 7 *
15 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -28,154 +21,128 @@
28 * 21 *
29 */ 22 */
30 23
31
32#include "busybox.h" 24#include "busybox.h"
33#include <features.h> 25
34#include <stdio.h> 26#include <sys/types.h>
35#include <fcntl.h> 27#include <fcntl.h>
36#include <errno.h>
37#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
38#include <inttypes.h>
39#else
40typedef unsigned long long int uintmax_t;
41#endif
42 28
43extern int dd_main(int argc, char **argv) 29static struct suffix_mult dd_suffixes[] = {
30 { "c", 1 },
31 { "w", 2 },
32 { "b", 512 },
33 { "kD", 1000 },
34 { "k", 1024 },
35 { "MD", 1000000 },
36 { "M", 1048576 },
37 { "GD", 1000000000 },
38 { "G", 1073741824 },
39 { NULL, 0 }
40};
41
42int dd_main(int argc, char **argv)
44{ 43{
45 char *inFile = NULL; 44 int i, ifd, ofd, sync = FALSE, trunc = TRUE;
46 char *outFile = NULL; 45 size_t in_full = 0, in_part = 0, out_full = 0, out_part = 0;
47 int inFd; 46 size_t bs = 512, count = -1;
48 int outFd; 47 ssize_t n;
49 int inCc = 0; 48 off_t seek = 0, skip = 0;
50 int outCc; 49 FILE *statusfp;
51 int trunc=TRUE; 50 char *infile = NULL, *outfile = NULL, *buf;
52 int sync=FALSE; 51
53 long blockSize = 512,ibs; 52 for (i = 1; i < argc; i++) {
54 uintmax_t skipBlocks = 0; 53 if (strncmp("bs=", argv[i], 3) == 0)
55 uintmax_t seekBlocks = 0; 54 bs = parse_number(argv[i]+3, dd_suffixes);
56 uintmax_t count = (uintmax_t) - 1; 55 else if (strncmp("count=", argv[i], 6) == 0)
57 uintmax_t inTotal = 0; 56 count = parse_number(argv[i]+6, dd_suffixes);
58 uintmax_t outTotal = 0; 57 else if (strncmp("seek=", argv[i], 5) == 0)
59 uintmax_t totalSize; 58 seek = parse_number(argv[i]+5, dd_suffixes);
60 59 else if (strncmp("skip=", argv[i], 5) == 0)
61 unsigned char buf[BUFSIZ]; 60 skip = parse_number(argv[i]+5, dd_suffixes);
62 char *keyword = NULL; 61 else if (strncmp("if=", argv[i], 3) == 0)
63 62 infile = argv[i]+3;
64 argc--; 63 else if (strncmp("of=", argv[i], 3) == 0)
65 argv++; 64 outfile = argv[i]+3;
66 65 else if (strncmp("conv=", argv[i], 5) == 0) {
67 /* Parse any options */ 66 buf = argv[i]+5;
68 while (argc) { 67 while (1) {
69 if (inFile == NULL && (strncmp(*argv, "if", 2) == 0)) 68 if (strncmp("notrunc", buf, 7) == 0) {
70 inFile = ((strchr(*argv, '=')) + 1); 69 trunc = FALSE;
71 else if (outFile == NULL && (strncmp(*argv, "of", 2) == 0)) 70 buf += 7;
72 outFile = ((strchr(*argv, '=')) + 1); 71 } else if (strncmp("sync", buf, 4) == 0) {
73 else if (strncmp("count", *argv, 5) == 0) { 72 sync = TRUE;
74 count = atoi_w_units((strchr(*argv, '=')) + 1); 73 buf += 4;
75 if (count < 0) { 74 } else {
76 error_msg("Bad count value %s\n", *argv); 75 error_msg_and_die("invalid conversion `%s'\n", argv[i]+5);
77 goto usage; 76 }
78 } 77 if (buf[0] == '\0')
79 } else if (strncmp(*argv, "bs", 2) == 0) { 78 break;
80 blockSize = atoi_w_units((strchr(*argv, '=')) + 1); 79 if (buf[0] == ',')
81 if (blockSize <= 0) { 80 buf++;
82 error_msg("Bad block size value %s\n", *argv);
83 goto usage;
84 }
85 } else if (strncmp(*argv, "skip", 4) == 0) {
86 skipBlocks = atoi_w_units((strchr(*argv, '=')) + 1);
87 if (skipBlocks <= 0) {
88 error_msg("Bad skip value %s\n", *argv);
89 goto usage;
90 }
91
92 } else if (strncmp(*argv, "seek", 4) == 0) {
93 seekBlocks = atoi_w_units((strchr(*argv, '=')) + 1);
94 if (seekBlocks <= 0) {
95 error_msg("Bad seek value %s\n", *argv);
96 goto usage;
97 } 81 }
98 } else if (strncmp(*argv, "conv", 4) == 0) { 82 } else
99 keyword = (strchr(*argv, '=') + 1); 83 usage(dd_usage);
100 if (strcmp(keyword, "notrunc") == 0)
101 trunc=FALSE;
102 if (strcmp(keyword, "sync") == 0)
103 sync=TRUE;
104 } else {
105 goto usage;
106 }
107 argc--;
108 argv++;
109 } 84 }
110 85
111 if (inFile == NULL) 86 buf = xmalloc(bs);
112 inFd = fileno(stdin);
113 else
114 inFd = open(inFile, 0);
115
116 if (inFd < 0) {
117 /* Note that we are not freeing buf or closing
118 * files here to save a few bytes. This exits
119 * here anyways... */
120 87
121 /* free(buf); */ 88 if (infile != NULL) {
122 perror_msg_and_die("%s", inFile); 89 if ((ifd = open(infile, O_RDONLY)) < 0)
90 perror_msg_and_die("%s", infile);
91 } else {
92 ifd = STDIN_FILENO;
93 infile = "standard input";
123 } 94 }
124 95
125 if (outFile == NULL) 96 if (outfile != NULL) {
126 outFd = fileno(stdout); 97 if ((ofd = open(outfile, O_WRONLY | O_CREAT, 0666)) < 0)
127 else 98 perror_msg_and_die("%s", outfile);
128 outFd = open(outFile, O_WRONLY | O_CREAT, 0666); 99 statusfp = stdout;
129 100 } else {
130 if (outFd < 0) { 101 ofd = STDOUT_FILENO;
131 /* Note that we are not freeing buf or closing 102 outfile = "standard output";
132 * files here to save a few bytes. This exits 103 statusfp = stderr;
133 * here anyways... */ 104 }
134 105
135 /* close(inFd); 106 if (skip) {
136 free(buf); */ 107 if (lseek(ifd, skip * bs, SEEK_CUR) < 0)
137 perror_msg_and_die("%s", outFile); 108 perror_msg_and_die("%s", infile);
138 } 109 }
139 110
140 lseek(inFd, (off_t) (skipBlocks * blockSize), SEEK_SET); 111 if (seek) {
141 lseek(outFd, (off_t) (seekBlocks * blockSize), SEEK_SET); 112 if (lseek(ofd, seek * bs, SEEK_CUR) < 0)
142 totalSize=count*blockSize; 113 perror_msg_and_die("%s", outfile);
114 }
143 115
144 ibs=blockSize; 116 if (trunc) {
145 if (ibs > BUFSIZ) 117 if (ftruncate(ofd, seek * bs) < 0)
146 ibs=BUFSIZ; 118 perror_msg_and_die("%s", outfile);
147 119 }
148 while (totalSize > outTotal) {
149 inCc = full_read(inFd, buf, ibs);
150 inTotal += inCc;
151 if ( (sync==TRUE) && (inCc>0) )
152 while (inCc<ibs)
153 buf[inCc++]='\0';
154 120
155 if ((outCc = full_write(outFd, buf, inCc)) < 1){ 121 while (in_full + in_part != count) {
156 if (outCc < 0 ){ 122 n = safe_read(ifd, buf, bs);
157 perror("Error during write"); 123 if (n < 0)
158 } 124 perror_msg_and_die("%s", infile);
125 if (n == 0)
159 break; 126 break;
127 if (n == bs)
128 in_full++;
129 else
130 in_part++;
131 if (sync) {
132 memset(buf + n, '\0', bs - n);
133 n = bs;
160 } 134 }
161 outTotal += outCc; 135 n = full_write(ofd, buf, n);
162 } 136 if (n < 0)
163 if (trunc == TRUE) { 137 perror_msg_and_die("%s", outfile);
164 ftruncate(outFd, lseek(outFd, 0, SEEK_CUR)); 138 if (n == bs)
139 out_full++;
140 else
141 out_part++;
165 } 142 }
166 /* Note that we are not freeing memory or closing
167 * files here, to save a few bytes. */
168#ifdef BB_FEATURE_CLEAN_UP
169 close(inFd);
170 close(outFd);
171#endif
172 143
173 printf("%ld+%d records in\n", (long) (inTotal / blockSize), 144 fprintf(statusfp, "%d+%d records in\n", in_full, in_part);
174 (inTotal % blockSize) != 0); 145 fprintf(statusfp, "%d+%d records out\n", out_full, out_part);
175 printf("%ld+%d records out\n", (long) (outTotal / blockSize),
176 (outTotal % blockSize) != 0);
177 return EXIT_SUCCESS;
178 usage:
179 146
180 usage(dd_usage); 147 return EXIT_SUCCESS;
181} 148}
diff --git a/coreutils/tail.c b/coreutils/tail.c
index 308bb3085..5f0381882 100644
--- a/coreutils/tail.c
+++ b/coreutils/tail.c
@@ -61,6 +61,13 @@ static char verbose = 0;
61 61
62static off_t units=0; 62static off_t units=0;
63 63
64static struct suffix_mult tail_suffixes[] = {
65 { "b", 512 },
66 { "k", 1024 },
67 { "m", 1048576 },
68 { NULL, 0 }
69};
70
64static int tail_stream(int fd) 71static int tail_stream(int fd)
65{ 72{
66 ssize_t startpoint; 73 ssize_t startpoint;
@@ -170,32 +177,6 @@ int tail_main(int argc, char **argv)
170 177
171 switch (opt) { 178 switch (opt) {
172#ifndef BB_FEATURE_SIMPLE_TAIL 179#ifndef BB_FEATURE_SIMPLE_TAIL
173 case 'c':
174 unit_type = BYTES;
175 test = atoi(optarg);
176 if(test==0)
177 usage(tail_usage);
178 if(optarg[strlen(optarg)-1]>'9') {
179 switch (optarg[strlen(optarg)-1]) {
180 case 'b':
181 test *= 512;
182 break;
183 case 'k':
184 test *= 1024;
185 break;
186 case 'm':
187 test *= (1024 * 1024);
188 break;
189 default:
190 fprintf(stderr,"Size must be b,k, or m.");
191 usage(tail_usage);
192 }
193 }
194 if(optarg[0]=='+')
195 units=test+1;
196 else
197 units=-(test+1);
198 break;
199 case 'q': 180 case 'q':
200 show_headers = 0; 181 show_headers = 0;
201 break; 182 break;
@@ -207,15 +188,12 @@ int tail_main(int argc, char **argv)
207 case 'v': 188 case 'v':
208 verbose = 1; 189 verbose = 1;
209 break; 190 break;
191 case 'c':
192 unit_type = BYTES;
193 /* FALLS THROUGH */
210#endif 194#endif
211 case 'f':
212 follow = 1;
213 break;
214 case 'h':
215 usage(tail_usage);
216 break;
217 case 'n': 195 case 'n':
218 test = atoi(optarg); 196 test = parse_number(optarg, tail_suffixes);
219 if (test) { 197 if (test) {
220 if (optarg[0] == '+') 198 if (optarg[0] == '+')
221 units = test; 199 units = test;
@@ -224,8 +202,10 @@ int tail_main(int argc, char **argv)
224 } else 202 } else
225 usage(tail_usage); 203 usage(tail_usage);
226 break; 204 break;
205 case 'f':
206 follow = 1;
207 break;
227 default: 208 default:
228 error_msg("\nUnknown arg: %c.\n\n",optopt);
229 usage(tail_usage); 209 usage(tail_usage);
230 } 210 }
231 } 211 }
diff --git a/dd.c b/dd.c
index 626b54898..a0d2330ea 100644
--- a/dd.c
+++ b/dd.c
@@ -2,15 +2,8 @@
2/* 2/*
3 * Mini dd implementation for busybox 3 * Mini dd implementation for busybox
4 * 4 *
5 * Copyright (C) 1999, 2000 by Lineo, inc.
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
7 * 5 *
8 * Based in part on code taken from sash. 6 * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
9 * Copyright (c) 1999 by David I. Bell
10 * Permission is granted to use, distribute, or modify this source,
11 * provided that this copyright notice remains intact.
12 *
13 * Permission to distribute this code under the GPL has been granted.
14 * 7 *
15 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -28,154 +21,128 @@
28 * 21 *
29 */ 22 */
30 23
31
32#include "busybox.h" 24#include "busybox.h"
33#include <features.h> 25
34#include <stdio.h> 26#include <sys/types.h>
35#include <fcntl.h> 27#include <fcntl.h>
36#include <errno.h>
37#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
38#include <inttypes.h>
39#else
40typedef unsigned long long int uintmax_t;
41#endif
42 28
43extern int dd_main(int argc, char **argv) 29static struct suffix_mult dd_suffixes[] = {
30 { "c", 1 },
31 { "w", 2 },
32 { "b", 512 },
33 { "kD", 1000 },
34 { "k", 1024 },
35 { "MD", 1000000 },
36 { "M", 1048576 },
37 { "GD", 1000000000 },
38 { "G", 1073741824 },
39 { NULL, 0 }
40};
41
42int dd_main(int argc, char **argv)
44{ 43{
45 char *inFile = NULL; 44 int i, ifd, ofd, sync = FALSE, trunc = TRUE;
46 char *outFile = NULL; 45 size_t in_full = 0, in_part = 0, out_full = 0, out_part = 0;
47 int inFd; 46 size_t bs = 512, count = -1;
48 int outFd; 47 ssize_t n;
49 int inCc = 0; 48 off_t seek = 0, skip = 0;
50 int outCc; 49 FILE *statusfp;
51 int trunc=TRUE; 50 char *infile = NULL, *outfile = NULL, *buf;
52 int sync=FALSE; 51
53 long blockSize = 512,ibs; 52 for (i = 1; i < argc; i++) {
54 uintmax_t skipBlocks = 0; 53 if (strncmp("bs=", argv[i], 3) == 0)
55 uintmax_t seekBlocks = 0; 54 bs = parse_number(argv[i]+3, dd_suffixes);
56 uintmax_t count = (uintmax_t) - 1; 55 else if (strncmp("count=", argv[i], 6) == 0)
57 uintmax_t inTotal = 0; 56 count = parse_number(argv[i]+6, dd_suffixes);
58 uintmax_t outTotal = 0; 57 else if (strncmp("seek=", argv[i], 5) == 0)
59 uintmax_t totalSize; 58 seek = parse_number(argv[i]+5, dd_suffixes);
60 59 else if (strncmp("skip=", argv[i], 5) == 0)
61 unsigned char buf[BUFSIZ]; 60 skip = parse_number(argv[i]+5, dd_suffixes);
62 char *keyword = NULL; 61 else if (strncmp("if=", argv[i], 3) == 0)
63 62 infile = argv[i]+3;
64 argc--; 63 else if (strncmp("of=", argv[i], 3) == 0)
65 argv++; 64 outfile = argv[i]+3;
66 65 else if (strncmp("conv=", argv[i], 5) == 0) {
67 /* Parse any options */ 66 buf = argv[i]+5;
68 while (argc) { 67 while (1) {
69 if (inFile == NULL && (strncmp(*argv, "if", 2) == 0)) 68 if (strncmp("notrunc", buf, 7) == 0) {
70 inFile = ((strchr(*argv, '=')) + 1); 69 trunc = FALSE;
71 else if (outFile == NULL && (strncmp(*argv, "of", 2) == 0)) 70 buf += 7;
72 outFile = ((strchr(*argv, '=')) + 1); 71 } else if (strncmp("sync", buf, 4) == 0) {
73 else if (strncmp("count", *argv, 5) == 0) { 72 sync = TRUE;
74 count = atoi_w_units((strchr(*argv, '=')) + 1); 73 buf += 4;
75 if (count < 0) { 74 } else {
76 error_msg("Bad count value %s\n", *argv); 75 error_msg_and_die("invalid conversion `%s'\n", argv[i]+5);
77 goto usage; 76 }
78 } 77 if (buf[0] == '\0')
79 } else if (strncmp(*argv, "bs", 2) == 0) { 78 break;
80 blockSize = atoi_w_units((strchr(*argv, '=')) + 1); 79 if (buf[0] == ',')
81 if (blockSize <= 0) { 80 buf++;
82 error_msg("Bad block size value %s\n", *argv);
83 goto usage;
84 }
85 } else if (strncmp(*argv, "skip", 4) == 0) {
86 skipBlocks = atoi_w_units((strchr(*argv, '=')) + 1);
87 if (skipBlocks <= 0) {
88 error_msg("Bad skip value %s\n", *argv);
89 goto usage;
90 }
91
92 } else if (strncmp(*argv, "seek", 4) == 0) {
93 seekBlocks = atoi_w_units((strchr(*argv, '=')) + 1);
94 if (seekBlocks <= 0) {
95 error_msg("Bad seek value %s\n", *argv);
96 goto usage;
97 } 81 }
98 } else if (strncmp(*argv, "conv", 4) == 0) { 82 } else
99 keyword = (strchr(*argv, '=') + 1); 83 usage(dd_usage);
100 if (strcmp(keyword, "notrunc") == 0)
101 trunc=FALSE;
102 if (strcmp(keyword, "sync") == 0)
103 sync=TRUE;
104 } else {
105 goto usage;
106 }
107 argc--;
108 argv++;
109 } 84 }
110 85
111 if (inFile == NULL) 86 buf = xmalloc(bs);
112 inFd = fileno(stdin);
113 else
114 inFd = open(inFile, 0);
115
116 if (inFd < 0) {
117 /* Note that we are not freeing buf or closing
118 * files here to save a few bytes. This exits
119 * here anyways... */
120 87
121 /* free(buf); */ 88 if (infile != NULL) {
122 perror_msg_and_die("%s", inFile); 89 if ((ifd = open(infile, O_RDONLY)) < 0)
90 perror_msg_and_die("%s", infile);
91 } else {
92 ifd = STDIN_FILENO;
93 infile = "standard input";
123 } 94 }
124 95
125 if (outFile == NULL) 96 if (outfile != NULL) {
126 outFd = fileno(stdout); 97 if ((ofd = open(outfile, O_WRONLY | O_CREAT, 0666)) < 0)
127 else 98 perror_msg_and_die("%s", outfile);
128 outFd = open(outFile, O_WRONLY | O_CREAT, 0666); 99 statusfp = stdout;
129 100 } else {
130 if (outFd < 0) { 101 ofd = STDOUT_FILENO;
131 /* Note that we are not freeing buf or closing 102 outfile = "standard output";
132 * files here to save a few bytes. This exits 103 statusfp = stderr;
133 * here anyways... */ 104 }
134 105
135 /* close(inFd); 106 if (skip) {
136 free(buf); */ 107 if (lseek(ifd, skip * bs, SEEK_CUR) < 0)
137 perror_msg_and_die("%s", outFile); 108 perror_msg_and_die("%s", infile);
138 } 109 }
139 110
140 lseek(inFd, (off_t) (skipBlocks * blockSize), SEEK_SET); 111 if (seek) {
141 lseek(outFd, (off_t) (seekBlocks * blockSize), SEEK_SET); 112 if (lseek(ofd, seek * bs, SEEK_CUR) < 0)
142 totalSize=count*blockSize; 113 perror_msg_and_die("%s", outfile);
114 }
143 115
144 ibs=blockSize; 116 if (trunc) {
145 if (ibs > BUFSIZ) 117 if (ftruncate(ofd, seek * bs) < 0)
146 ibs=BUFSIZ; 118 perror_msg_and_die("%s", outfile);
147 119 }
148 while (totalSize > outTotal) {
149 inCc = full_read(inFd, buf, ibs);
150 inTotal += inCc;
151 if ( (sync==TRUE) && (inCc>0) )
152 while (inCc<ibs)
153 buf[inCc++]='\0';
154 120
155 if ((outCc = full_write(outFd, buf, inCc)) < 1){ 121 while (in_full + in_part != count) {
156 if (outCc < 0 ){ 122 n = safe_read(ifd, buf, bs);
157 perror("Error during write"); 123 if (n < 0)
158 } 124 perror_msg_and_die("%s", infile);
125 if (n == 0)
159 break; 126 break;
127 if (n == bs)
128 in_full++;
129 else
130 in_part++;
131 if (sync) {
132 memset(buf + n, '\0', bs - n);
133 n = bs;
160 } 134 }
161 outTotal += outCc; 135 n = full_write(ofd, buf, n);
162 } 136 if (n < 0)
163 if (trunc == TRUE) { 137 perror_msg_and_die("%s", outfile);
164 ftruncate(outFd, lseek(outFd, 0, SEEK_CUR)); 138 if (n == bs)
139 out_full++;
140 else
141 out_part++;
165 } 142 }
166 /* Note that we are not freeing memory or closing
167 * files here, to save a few bytes. */
168#ifdef BB_FEATURE_CLEAN_UP
169 close(inFd);
170 close(outFd);
171#endif
172 143
173 printf("%ld+%d records in\n", (long) (inTotal / blockSize), 144 fprintf(statusfp, "%d+%d records in\n", in_full, in_part);
174 (inTotal % blockSize) != 0); 145 fprintf(statusfp, "%d+%d records out\n", out_full, out_part);
175 printf("%ld+%d records out\n", (long) (outTotal / blockSize),
176 (outTotal % blockSize) != 0);
177 return EXIT_SUCCESS;
178 usage:
179 146
180 usage(dd_usage); 147 return EXIT_SUCCESS;
181} 148}
diff --git a/include/busybox.h b/include/busybox.h
index 5ff3975b9..442352537 100644
--- a/include/busybox.h
+++ b/include/busybox.h
@@ -190,6 +190,13 @@ extern char *xstrdup (const char *s);
190#endif 190#endif
191extern char *xstrndup (const char *s, int n); 191extern char *xstrndup (const char *s, int n);
192 192
193struct suffix_mult {
194 char *suffix;
195 int mult;
196};
197
198extern unsigned long parse_number(const char *numstr, struct suffix_mult *suffixes);
199
193 200
194/* These parse entries in /etc/passwd and /etc/group. This is desirable 201/* These parse entries in /etc/passwd and /etc/group. This is desirable
195 * for BusyBox since we want to avoid using the glibc NSS stuff, which 202 * for BusyBox since we want to avoid using the glibc NSS stuff, which
diff --git a/tail.c b/tail.c
index 308bb3085..5f0381882 100644
--- a/tail.c
+++ b/tail.c
@@ -61,6 +61,13 @@ static char verbose = 0;
61 61
62static off_t units=0; 62static off_t units=0;
63 63
64static struct suffix_mult tail_suffixes[] = {
65 { "b", 512 },
66 { "k", 1024 },
67 { "m", 1048576 },
68 { NULL, 0 }
69};
70
64static int tail_stream(int fd) 71static int tail_stream(int fd)
65{ 72{
66 ssize_t startpoint; 73 ssize_t startpoint;
@@ -170,32 +177,6 @@ int tail_main(int argc, char **argv)
170 177
171 switch (opt) { 178 switch (opt) {
172#ifndef BB_FEATURE_SIMPLE_TAIL 179#ifndef BB_FEATURE_SIMPLE_TAIL
173 case 'c':
174 unit_type = BYTES;
175 test = atoi(optarg);
176 if(test==0)
177 usage(tail_usage);
178 if(optarg[strlen(optarg)-1]>'9') {
179 switch (optarg[strlen(optarg)-1]) {
180 case 'b':
181 test *= 512;
182 break;
183 case 'k':
184 test *= 1024;
185 break;
186 case 'm':
187 test *= (1024 * 1024);
188 break;
189 default:
190 fprintf(stderr,"Size must be b,k, or m.");
191 usage(tail_usage);
192 }
193 }
194 if(optarg[0]=='+')
195 units=test+1;
196 else
197 units=-(test+1);
198 break;
199 case 'q': 180 case 'q':
200 show_headers = 0; 181 show_headers = 0;
201 break; 182 break;
@@ -207,15 +188,12 @@ int tail_main(int argc, char **argv)
207 case 'v': 188 case 'v':
208 verbose = 1; 189 verbose = 1;
209 break; 190 break;
191 case 'c':
192 unit_type = BYTES;
193 /* FALLS THROUGH */
210#endif 194#endif
211 case 'f':
212 follow = 1;
213 break;
214 case 'h':
215 usage(tail_usage);
216 break;
217 case 'n': 195 case 'n':
218 test = atoi(optarg); 196 test = parse_number(optarg, tail_suffixes);
219 if (test) { 197 if (test) {
220 if (optarg[0] == '+') 198 if (optarg[0] == '+')
221 units = test; 199 units = test;
@@ -224,8 +202,10 @@ int tail_main(int argc, char **argv)
224 } else 202 } else
225 usage(tail_usage); 203 usage(tail_usage);
226 break; 204 break;
205 case 'f':
206 follow = 1;
207 break;
227 default: 208 default:
228 error_msg("\nUnknown arg: %c.\n\n",optopt);
229 usage(tail_usage); 209 usage(tail_usage);
230 } 210 }
231 } 211 }
diff --git a/usage.c b/usage.c
index 876d253ab..c7bc0e8a9 100644
--- a/usage.c
+++ b/usage.c
@@ -170,10 +170,11 @@ const char dd_usage[] =
170 "\tcount=N\tcopy only N input blocks\n" 170 "\tcount=N\tcopy only N input blocks\n"
171 "\tskip=N\tskip N input blocks\n" 171 "\tskip=N\tskip N input blocks\n"
172 "\tseek=N\tskip N output blocks\n" 172 "\tseek=N\tskip N output blocks\n"
173 "\tconv=notrunc\t dont truncate of at end of write\n" 173 "\tconv=notrunc\tdon't truncate output file\n"
174 "\tconv=sync\t pad the last block with zeros until blocksize\n" 174 "\tconv=sync\tpad blocks with zeros\n"
175 "\n" 175 "\n"
176 "Numbers may be suffixed by w (x2), k (x1024), b (x512), or M (x1024^2)\n" 176 "Numbers may be suffixed by c (x1), w (x2), b (x512), kD (x1000), k (x1024),\n"
177 "MD (x1000000), M (x1048576), GD (x1000000000) or G (x1073741824).\n"
177#endif 178#endif
178 ; 179 ;
179#endif 180#endif
@@ -1185,20 +1186,20 @@ const char syslogd_usage[] =
1185 1186
1186#if defined BB_TAIL 1187#if defined BB_TAIL
1187const char tail_usage[] = 1188const char tail_usage[] =
1188 "tail [OPTION] [FILE]...\n" 1189 "tail [OPTION]... [FILE]...\n"
1189#ifndef BB_FEATURE_TRIVIAL_HELP 1190#ifndef BB_FEATURE_TRIVIAL_HELP
1190 "\nPrint last 10 lines of each FILE to standard output.\n" 1191 "\nPrint last 10 lines of each FILE to standard output.\n"
1191 "With more than one FILE, precede each with a header giving the\n" 1192 "With more than one FILE, precede each with a header giving the\n"
1192 "file name. With no FILE, or when FILE is -, read standard input.\n\n" 1193 "file name. With no FILE, or when FILE is -, read standard input.\n\n"
1193 "Options:\n" 1194 "Options:\n"
1194#ifndef BB_FEATURE_SIMPLE_TAIL 1195#ifndef BB_FEATURE_SIMPLE_TAIL
1195 "\t-c=N[kbm]\toutput the last N bytes\n" 1196 "\t-c N[kbm]\toutput the last N bytes\n"
1196#endif 1197#endif
1197 "\t-n NUM\t\tPrint last NUM lines instead of first 10\n" 1198 "\t-n N[kbm]\tprint last N lines instead of last 10\n"
1198 "\t-f\t\tOutput data as the file grows.\n" 1199 "\t-f\t\toutput data as the file grows\n"
1199#ifndef BB_FEATURE_SIMPLE_TAIL 1200#ifndef BB_FEATURE_SIMPLE_TAIL
1200 "\t-q\t\tnever output headers giving file names\n" 1201 "\t-q\t\tnever output headers giving file names\n"
1201 "\t-s SEC\t\tWait SEC seconds between reads with -f\n" 1202 "\t-s SEC\t\twait SEC seconds between reads with -f\n"
1202 "\t-v\t\talways output headers giving file names\n\n" 1203 "\t-v\t\talways output headers giving file names\n\n"
1203 "If the first character of N (bytes or lines) is a `+', output begins with \n" 1204 "If the first character of N (bytes or lines) is a `+', output begins with \n"
1204 "the Nth item from the start of each file, otherwise, print the last N items\n" 1205 "the Nth item from the start of each file, otherwise, print the last N items\n"
diff --git a/utility.c b/utility.c
index 794a9281a..34341c8d3 100644
--- a/utility.c
+++ b/utility.c
@@ -562,10 +562,9 @@ int full_write(int fd, const char *buf, int len)
562 562
563 return total; 563 return total;
564} 564}
565#endif /* BB_TAR || BB_CP_MV || BB_AR */ 565#endif
566
567 566
568#if defined BB_TAR || defined BB_TAIL || defined BB_AR || defined BB_SH || defined BB_CP_MV || defined BB_DD 567#if defined BB_AR || defined BB_CP_MV || defined BB_SH || defined BB_TAR
569/* 568/*
570 * Read all of the supplied buffer from a file. 569 * Read all of the supplied buffer from a file.
571 * This does multiple reads as necessary. 570 * This does multiple reads as necessary.
@@ -1215,58 +1214,6 @@ extern struct mntent *find_mount_point(const char *name, const char *table)
1215} 1214}
1216#endif /* BB_DF || BB_MTAB */ 1215#endif /* BB_DF || BB_MTAB */
1217 1216
1218
1219
1220#if defined BB_DD || defined BB_TAIL
1221/*
1222 * Read a number with a possible multiplier.
1223 * Returns -1 if the number format is illegal.
1224 */
1225extern long atoi_w_units(const char *cp)
1226{
1227 long value;
1228
1229 if (!is_decimal(*cp))
1230 return -1;
1231
1232 value = 0;
1233
1234 while (is_decimal(*cp))
1235 value = value * 10 + *cp++ - '0';
1236
1237 switch (*cp++) {
1238 case 'M':
1239 case 'm': /* `tail' uses it traditionally */
1240 value *= 1048576;
1241 break;
1242
1243 case 'k':
1244 value *= 1024;
1245 break;
1246
1247 case 'b':
1248 value *= 512;
1249 break;
1250
1251 case 'w':
1252 value *= 2;
1253 break;
1254
1255 case '\0':
1256 return value;
1257
1258 default:
1259 return -1;
1260 }
1261
1262 if (*cp)
1263 return -1;
1264
1265 return value;
1266}
1267#endif /* BB_DD || BB_TAIL */
1268
1269
1270#if defined BB_INIT || defined BB_SYSLOGD 1217#if defined BB_INIT || defined BB_SYSLOGD
1271/* try to open up the specified device */ 1218/* try to open up the specified device */
1272extern int device_open(char *device, int mode) 1219extern int device_open(char *device, int mode)
@@ -1313,11 +1260,11 @@ extern pid_t* find_pid_by_name( char* pidName)
1313 /* open device */ 1260 /* open device */
1314 fd = open(device, O_RDONLY); 1261 fd = open(device, O_RDONLY);
1315 if (fd < 0) 1262 if (fd < 0)
1316 perror_msg_and_die( "open failed for `%s'", device); 1263 perror_msg_and_die("open failed for `%s'", device);
1317 1264
1318 /* Find out how many processes there are */ 1265 /* Find out how many processes there are */
1319 if (ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids)<0) 1266 if (ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids)<0)
1320 perror_msg_and_die( "\nDEVPS_GET_PID_LIST"); 1267 perror_msg_and_die("\nDEVPS_GET_PID_LIST");
1321 1268
1322 /* Allocate some memory -- grab a few extras just in case 1269 /* Allocate some memory -- grab a few extras just in case
1323 * some new processes start up while we wait. The kernel will 1270 * some new processes start up while we wait. The kernel will
@@ -1328,7 +1275,7 @@ extern pid_t* find_pid_by_name( char* pidName)
1328 1275
1329 /* Now grab the pid list */ 1276 /* Now grab the pid list */
1330 if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0) 1277 if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0)
1331 perror_msg_and_die( "\nDEVPS_GET_PID_LIST"); 1278 perror_msg_and_die("\nDEVPS_GET_PID_LIST");
1332 1279
1333 /* Now search for a match */ 1280 /* Now search for a match */
1334 for (i=1, j=0; i<pid_array[0] ; i++) { 1281 for (i=1, j=0; i<pid_array[0] ; i++) {
@@ -1337,7 +1284,7 @@ extern pid_t* find_pid_by_name( char* pidName)
1337 1284
1338 info.pid = pid_array[i]; 1285 info.pid = pid_array[i];
1339 if (ioctl (fd, DEVPS_GET_PID_INFO, &info)<0) 1286 if (ioctl (fd, DEVPS_GET_PID_INFO, &info)<0)
1340 perror_msg_and_die( "\nDEVPS_GET_PID_INFO"); 1287 perror_msg_and_die("\nDEVPS_GET_PID_INFO");
1341 1288
1342 /* Make sure we only match on the process name */ 1289 /* Make sure we only match on the process name */
1343 p=info.command_line+1; 1290 p=info.command_line+1;
@@ -1361,7 +1308,7 @@ extern pid_t* find_pid_by_name( char* pidName)
1361 1308
1362 /* close device */ 1309 /* close device */
1363 if (close (fd) != 0) 1310 if (close (fd) != 0)
1364 perror_msg_and_die( "close failed for `%s'", device); 1311 perror_msg_and_die("close failed for `%s'", device);
1365 1312
1366 return pidList; 1313 return pidList;
1367} 1314}
@@ -1387,7 +1334,7 @@ extern pid_t* find_pid_by_name( char* pidName)
1387 1334
1388 dir = opendir("/proc"); 1335 dir = opendir("/proc");
1389 if (!dir) 1336 if (!dir)
1390 perror_msg_and_die( "Cannot open /proc"); 1337 perror_msg_and_die("Cannot open /proc");
1391 1338
1392 while ((next = readdir(dir)) != NULL) { 1339 while ((next = readdir(dir)) != NULL) {
1393 FILE *status; 1340 FILE *status;
@@ -1791,7 +1738,34 @@ int applet_name_compare(const void *x, const void *y)
1791 return strcmp(applet1->name, applet2->name); 1738 return strcmp(applet1->name, applet2->name);
1792} 1739}
1793 1740
1794#if defined BB_NC 1741#if defined BB_DD || defined BB_TAIL
1742unsigned long parse_number(const char *numstr, struct suffix_mult *suffixes)
1743{
1744 struct suffix_mult *sm;
1745 unsigned long int ret;
1746 int len;
1747 char *end;
1748
1749 ret = strtoul(numstr, &end, 10);
1750 if (numstr == end)
1751 error_msg_and_die("invalid number `%s'\n", numstr);
1752 while (end[0] != '\0') {
1753 for (sm = suffixes; sm->suffix != NULL; sm++) {
1754 len = strlen(sm->suffix);
1755 if (strncmp(sm->suffix, end, len) == 0) {
1756 ret *= sm->mult;
1757 end += len;
1758 break;
1759 }
1760 }
1761 if (sm->suffix == NULL)
1762 error_msg_and_die("invalid number `%s'\n", numstr);
1763 }
1764 return ret;
1765}
1766#endif
1767
1768#if defined BB_DD || defined BB_NC
1795ssize_t safe_read(int fd, void *buf, size_t count) 1769ssize_t safe_read(int fd, void *buf, size_t count)
1796{ 1770{
1797 ssize_t n; 1771 ssize_t n;