diff options
author | Eric Lammerts <busybox@lists.lammerts.org> | 2009-07-22 00:31:27 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2009-07-22 00:31:27 +0200 |
commit | 3b5a66444030949027dacf4c372713fe33f1d9d9 (patch) | |
tree | cde2fc60c110415d134e232d3a6e4eac810a1bde | |
parent | 997538ab586e9b061b33c24f2ddced18a0379826 (diff) | |
download | busybox-w32-3b5a66444030949027dacf4c372713fe33f1d9d9.tar.gz busybox-w32-3b5a66444030949027dacf4c372713fe33f1d9d9.tar.bz2 busybox-w32-3b5a66444030949027dacf4c372713fe33f1d9d9.zip |
tail: implement -F
function old new delta
tail_main 1190 1494 +304
Signed-off-by: Eric Lammerts <busybox@lists.lammerts.org>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | coreutils/Config.in | 2 | ||||
-rw-r--r-- | coreutils/tail.c | 85 |
2 files changed, 66 insertions, 21 deletions
diff --git a/coreutils/Config.in b/coreutils/Config.in index 1bc047c9a..cacfb9661 100644 --- a/coreutils/Config.in +++ b/coreutils/Config.in | |||
@@ -635,7 +635,7 @@ config TAIL | |||
635 | from files. | 635 | from files. |
636 | 636 | ||
637 | config FEATURE_FANCY_TAIL | 637 | config FEATURE_FANCY_TAIL |
638 | bool "Enable extra tail options (-q, -s, and -v)" | 638 | bool "Enable extra tail options (-q, -s, -v, and -F)" |
639 | default y | 639 | default y |
640 | depends on TAIL | 640 | depends on TAIL |
641 | help | 641 | help |
diff --git a/coreutils/tail.c b/coreutils/tail.c index 3ce6be0bd..ef1326c83 100644 --- a/coreutils/tail.c +++ b/coreutils/tail.c | |||
@@ -85,18 +85,15 @@ int tail_main(int argc, char **argv) | |||
85 | unsigned count = 10; | 85 | unsigned count = 10; |
86 | unsigned sleep_period = 1; | 86 | unsigned sleep_period = 1; |
87 | bool from_top; | 87 | bool from_top; |
88 | int header_threshhold = 1; | ||
89 | const char *str_c, *str_n; | 88 | const char *str_c, *str_n; |
90 | 89 | ||
91 | char *tailbuf; | 90 | char *tailbuf; |
92 | size_t tailbufsize; | 91 | size_t tailbufsize; |
93 | int taillen = 0; | 92 | unsigned header_threshhold = 1; |
94 | int newlines_seen = 0; | 93 | unsigned nfiles; |
95 | int nfiles, nread, nwrite, i, opt; | 94 | int i, opt; |
96 | unsigned seen; | ||
97 | 95 | ||
98 | int *fds; | 96 | int *fds; |
99 | char *s, *buf; | ||
100 | const char *fmt; | 97 | const char *fmt; |
101 | 98 | ||
102 | #if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_TAIL | 99 | #if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_TAIL |
@@ -110,8 +107,9 @@ int tail_main(int argc, char **argv) | |||
110 | } | 107 | } |
111 | #endif | 108 | #endif |
112 | 109 | ||
113 | IF_FEATURE_FANCY_TAIL(opt_complementary = "s+";) /* -s N */ | 110 | /* -s NUM, -F imlies -f */ |
114 | opt = getopt32(argv, "fc:n:" IF_FEATURE_FANCY_TAIL("qs:v"), | 111 | IF_FEATURE_FANCY_TAIL(opt_complementary = "s+:Ff";) |
112 | opt = getopt32(argv, "fc:n:" IF_FEATURE_FANCY_TAIL("qs:vF"), | ||
115 | &str_c, &str_n IF_FEATURE_FANCY_TAIL(,&sleep_period)); | 113 | &str_c, &str_n IF_FEATURE_FANCY_TAIL(,&sleep_period)); |
116 | #define FOLLOW (opt & 0x1) | 114 | #define FOLLOW (opt & 0x1) |
117 | #define COUNT_BYTES (opt & 0x2) | 115 | #define COUNT_BYTES (opt & 0x2) |
@@ -119,8 +117,12 @@ int tail_main(int argc, char **argv) | |||
119 | if (opt & 0x2) count = eat_num(str_c); // -c | 117 | if (opt & 0x2) count = eat_num(str_c); // -c |
120 | if (opt & 0x4) count = eat_num(str_n); // -n | 118 | if (opt & 0x4) count = eat_num(str_n); // -n |
121 | #if ENABLE_FEATURE_FANCY_TAIL | 119 | #if ENABLE_FEATURE_FANCY_TAIL |
122 | if (opt & 0x8) header_threshhold = INT_MAX; // -q | 120 | /* q: make it impossible for nfiles to be > header_threshhold */ |
121 | if (opt & 0x8) header_threshhold = UINT_MAX; // -q | ||
123 | if (opt & 0x20) header_threshhold = 0; // -v | 122 | if (opt & 0x20) header_threshhold = 0; // -v |
123 | #define FOLLOW_RETRY (opt & 0x40) | ||
124 | #else | ||
125 | #define FOLLOW_RETRY 0 | ||
124 | #endif | 126 | #endif |
125 | argc -= optind; | 127 | argc -= optind; |
126 | argv += optind; | 128 | argv += optind; |
@@ -128,19 +130,21 @@ int tail_main(int argc, char **argv) | |||
128 | G.status = EXIT_SUCCESS; | 130 | G.status = EXIT_SUCCESS; |
129 | 131 | ||
130 | /* open all the files */ | 132 | /* open all the files */ |
131 | fds = xmalloc(sizeof(int) * (argc + 1)); | 133 | fds = xmalloc(sizeof(fds[0]) * (argc + 1)); |
132 | if (!argv[0]) { | 134 | if (!argv[0]) { |
133 | struct stat statbuf; | 135 | struct stat statbuf; |
134 | 136 | ||
135 | if (!fstat(STDIN_FILENO, &statbuf) && S_ISFIFO(statbuf.st_mode)) { | 137 | if (fstat(STDIN_FILENO, &statbuf) == 0 |
138 | && S_ISFIFO(statbuf.st_mode) | ||
139 | ) { | ||
136 | opt &= ~1; /* clear FOLLOW */ | 140 | opt &= ~1; /* clear FOLLOW */ |
137 | } | 141 | } |
138 | *argv = (char *) bb_msg_standard_input; | 142 | argv[0] = (char *) bb_msg_standard_input; |
139 | } | 143 | } |
140 | nfiles = i = 0; | 144 | nfiles = i = 0; |
141 | do { | 145 | do { |
142 | int fd = open_or_warn_stdin(argv[i]); | 146 | int fd = open_or_warn_stdin(argv[i]); |
143 | if (fd < 0) { | 147 | if (fd < 0 && !FOLLOW_RETRY) { |
144 | G.status = EXIT_FAILURE; | 148 | G.status = EXIT_FAILURE; |
145 | continue; | 149 | continue; |
146 | } | 150 | } |
@@ -161,9 +165,18 @@ int tail_main(int argc, char **argv) | |||
161 | tailbuf = xmalloc(tailbufsize); | 165 | tailbuf = xmalloc(tailbufsize); |
162 | 166 | ||
163 | /* tail the files */ | 167 | /* tail the files */ |
164 | fmt = header_fmt + 1; /* Skip header leading newline on first output. */ | 168 | fmt = header_fmt + 1; /* skip header leading newline on first output */ |
165 | i = 0; | 169 | i = 0; |
166 | do { | 170 | do { |
171 | char *buf; | ||
172 | int taillen; | ||
173 | int newlines_seen; | ||
174 | unsigned seen; | ||
175 | int nread; | ||
176 | |||
177 | if (ENABLE_FEATURE_FANCY_TAIL && fds[i] < 0) | ||
178 | continue; /* may happen with -E */ | ||
179 | |||
167 | if (nfiles > header_threshhold) { | 180 | if (nfiles > header_threshhold) { |
168 | tail_xprint_header(fmt, argv[i]); | 181 | tail_xprint_header(fmt, argv[i]); |
169 | fmt = header_fmt; | 182 | fmt = header_fmt; |
@@ -192,13 +205,13 @@ int tail_main(int argc, char **argv) | |||
192 | newlines_seen = 0; | 205 | newlines_seen = 0; |
193 | while ((nread = tail_read(fds[i], buf, tailbufsize-taillen)) > 0) { | 206 | while ((nread = tail_read(fds[i], buf, tailbufsize-taillen)) > 0) { |
194 | if (from_top) { | 207 | if (from_top) { |
195 | nwrite = nread; | 208 | int nwrite = nread; |
196 | if (seen < count) { | 209 | if (seen < count) { |
197 | if (COUNT_BYTES) { | 210 | if (COUNT_BYTES) { |
198 | nwrite -= (count - seen); | 211 | nwrite -= (count - seen); |
199 | seen = count; | 212 | seen = count; |
200 | } else { | 213 | } else { |
201 | s = buf; | 214 | char *s = buf; |
202 | do { | 215 | do { |
203 | --nwrite; | 216 | --nwrite; |
204 | if (*s++ == '\n' && ++seen == count) { | 217 | if (*s++ == '\n' && ++seen == count) { |
@@ -231,6 +244,7 @@ int tail_main(int argc, char **argv) | |||
231 | taillen += nread; | 244 | taillen += nread; |
232 | } else { | 245 | } else { |
233 | int extra = (buf[nread-1] != '\n'); | 246 | int extra = (buf[nread-1] != '\n'); |
247 | char *s; | ||
234 | 248 | ||
235 | k = newlines_seen + newlines_in_buf + extra - count; | 249 | k = newlines_seen + newlines_in_buf + extra - count; |
236 | s = tailbuf; | 250 | s = tailbuf; |
@@ -257,23 +271,54 @@ int tail_main(int argc, char **argv) | |||
257 | } | 271 | } |
258 | } while (++i < nfiles); | 272 | } while (++i < nfiles); |
259 | 273 | ||
260 | buf = xrealloc(tailbuf, BUFSIZ); | 274 | tailbuf = xrealloc(tailbuf, BUFSIZ); |
261 | 275 | ||
262 | fmt = NULL; | 276 | fmt = NULL; |
263 | 277 | ||
264 | if (FOLLOW) while (1) { | 278 | if (FOLLOW) while (1) { |
265 | sleep(sleep_period); | 279 | sleep(sleep_period); |
280 | |||
266 | i = 0; | 281 | i = 0; |
267 | do { | 282 | do { |
283 | int nread; | ||
284 | const char *filename = argv[i]; | ||
285 | int fd = fds[i]; | ||
286 | |||
287 | if (FOLLOW_RETRY) { | ||
288 | struct stat sbuf, fsbuf; | ||
289 | |||
290 | if (fd < 0 | ||
291 | || fstat(fd, &fsbuf) < 0 | ||
292 | || stat(filename, &sbuf) < 0 | ||
293 | || fsbuf.st_dev != sbuf.st_dev | ||
294 | || fsbuf.st_ino != sbuf.st_ino | ||
295 | ) { | ||
296 | int new_fd; | ||
297 | |||
298 | if (fd >= 0) | ||
299 | close(fd); | ||
300 | new_fd = open(filename, O_RDONLY); | ||
301 | if (new_fd >= 0) { | ||
302 | bb_error_msg("%s has %s; following end of new file", | ||
303 | filename, (fd < 0) ? "appeared" : "been replaced" | ||
304 | ); | ||
305 | } else if (fd >= 0) { | ||
306 | bb_perror_msg("%s has become inaccessible", filename); | ||
307 | } | ||
308 | fds[i] = fd = new_fd; | ||
309 | } | ||
310 | } | ||
311 | if (ENABLE_FEATURE_FANCY_TAIL && fd < 0) | ||
312 | continue; | ||
268 | if (nfiles > header_threshhold) { | 313 | if (nfiles > header_threshhold) { |
269 | fmt = header_fmt; | 314 | fmt = header_fmt; |
270 | } | 315 | } |
271 | while ((nread = tail_read(fds[i], buf, BUFSIZ)) > 0) { | 316 | while ((nread = tail_read(fd, tailbuf, BUFSIZ)) > 0) { |
272 | if (fmt) { | 317 | if (fmt) { |
273 | tail_xprint_header(fmt, argv[i]); | 318 | tail_xprint_header(fmt, filename); |
274 | fmt = NULL; | 319 | fmt = NULL; |
275 | } | 320 | } |
276 | xwrite(STDOUT_FILENO, buf, nread); | 321 | xwrite(STDOUT_FILENO, tailbuf, nread); |
277 | } | 322 | } |
278 | } while (++i < nfiles); | 323 | } while (++i < nfiles); |
279 | } | 324 | } |