diff options
author | Matt Kraai <kraai@debian.org> | 2001-01-05 02:57:53 +0000 |
---|---|---|
committer | Matt Kraai <kraai@debian.org> | 2001-01-05 02:57:53 +0000 |
commit | 55bccf315edda48fa9f3af4516b0897f29a78a9e (patch) | |
tree | 0be02e54fb51eec3d8316105a581e1bf9939ba26 /coreutils/tail.c | |
parent | defcd5e75eec72aa31e9bdbd9ac854832318f82f (diff) | |
download | busybox-w32-55bccf315edda48fa9f3af4516b0897f29a78a9e.tar.gz busybox-w32-55bccf315edda48fa9f3af4516b0897f29a78a9e.tar.bz2 busybox-w32-55bccf315edda48fa9f3af4516b0897f29a78a9e.zip |
Rewrote tail.
Diffstat (limited to 'coreutils/tail.c')
-rw-r--r-- | coreutils/tail.c | 456 |
1 files changed, 203 insertions, 253 deletions
diff --git a/coreutils/tail.c b/coreutils/tail.c index 5f0381882..8e6488931 100644 --- a/coreutils/tail.c +++ b/coreutils/tail.c | |||
@@ -1,65 +1,30 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | 1 | /* vi: set sw=4 ts=4: */ |
2 | /* tail -- output the last part of file(s) | 2 | /* |
3 | Copyright (C) 89, 90, 91, 95, 1996 Free Software Foundation, Inc. | 3 | * Mini tail implementation for busybox |
4 | 4 | * | |
5 | This program is free software; you can redistribute it and/or modify | 5 | * |
6 | it under the terms of the GNU General Public License as published by | 6 | * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu> |
7 | the Free Software Foundation; either version 2, or (at your option) | 7 | * |
8 | any later version. | 8 | * This program is free software; you can redistribute it and/or modify |
9 | 9 | * it under the terms of the GNU General Public License as published by | |
10 | This program is distributed in the hope that it will be useful, | 10 | * the Free Software Foundation; either version 2 of the License, or |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | * (at your option) any later version. |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * |
13 | GNU General Public License for more details. | 13 | * This program is distributed in the hope that it will be useful, |
14 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | You should have received a copy of the GNU General Public License | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | along with this program; if not, write to the Free Software | 16 | * General Public License for more details. |
17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 17 | * |
18 | 18 | * You should have received a copy of the GNU General Public License | |
19 | Original version by Paul Rubin <phr@ocf.berkeley.edu>. | 19 | * along with this program; if not, write to the Free Software |
20 | Extensions by David MacKenzie <djm@gnu.ai.mit.edu>. | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | tail -f for multiple files by Ian Lance Taylor <ian@airs.com>. | 21 | * |
22 | 22 | */ | |
23 | Rewrote the option parser, removed locales support, | ||
24 | and generally busyboxed, Erik Andersen <andersen@lineo.com> | ||
25 | |||
26 | Removed superfluous options and associated code ("-c", "-n", "-q"). | ||
27 | Removed "tail -f" support for multiple files. | ||
28 | Both changes by Friedrich Vedder <fwv@myrtle.lahn.de>. | ||
29 | 23 | ||
30 | Compleate Rewrite to correctly support "-NUM", "+NUM", and "-s" by | 24 | #include "busybox.h" |
31 | E.Allen Soard (esp@espsw.net). | ||
32 | 25 | ||
33 | */ | ||
34 | #include <sys/types.h> | 26 | #include <sys/types.h> |
35 | #include <fcntl.h> | 27 | #include <fcntl.h> |
36 | #include <stdio.h> | ||
37 | #include <stdlib.h> | ||
38 | #include <unistd.h> | ||
39 | #include <string.h> | ||
40 | #include <getopt.h> | ||
41 | #include "busybox.h" | ||
42 | |||
43 | #define STDIN "standard input" | ||
44 | #define LINES 0 | ||
45 | #define BYTES 1 | ||
46 | |||
47 | static int n_files = 0; | ||
48 | static char **files = NULL; | ||
49 | static char * buffer; | ||
50 | static ssize_t bytes_read=0; | ||
51 | static ssize_t bs; | ||
52 | static ssize_t filelocation=0; | ||
53 | static char pip; | ||
54 | |||
55 | #ifdef BB_FEATURE_SIMPLE_TAIL | ||
56 | static const char unit_type=LINES; | ||
57 | #else | ||
58 | static char unit_type=LINES; | ||
59 | static char verbose = 0; | ||
60 | #endif | ||
61 | |||
62 | static off_t units=0; | ||
63 | 28 | ||
64 | static struct suffix_mult tail_suffixes[] = { | 29 | static struct suffix_mult tail_suffixes[] = { |
65 | { "b", 512 }, | 30 | { "b", 512 }, |
@@ -68,232 +33,217 @@ static struct suffix_mult tail_suffixes[] = { | |||
68 | { NULL, 0 } | 33 | { NULL, 0 } |
69 | }; | 34 | }; |
70 | 35 | ||
71 | static int tail_stream(int fd) | ||
72 | { | ||
73 | ssize_t startpoint; | ||
74 | ssize_t endpoint=0; | ||
75 | ssize_t count=0; | ||
76 | ssize_t filesize=0; | ||
77 | int direction=1; | ||
78 | |||
79 | filelocation=0; | ||
80 | startpoint=bs=BUFSIZ; | ||
81 | |||
82 | filesize=lseek(fd, -1, SEEK_END)+1; | ||
83 | pip=(filesize<=0); | ||
84 | |||
85 | if(units>=0) | ||
86 | lseek(fd,0,SEEK_SET); | ||
87 | else { | ||
88 | direction=-1; | ||
89 | count=1; | ||
90 | } | ||
91 | while(units != 0) { | ||
92 | if (pip) { | ||
93 | char * line; | ||
94 | ssize_t f_size=0; | ||
95 | |||
96 | bs=BUFSIZ; | ||
97 | line=xmalloc(bs); | ||
98 | while(1) { | ||
99 | bytes_read=read(fd,line,bs); | ||
100 | if(bytes_read<=0) | ||
101 | break; | ||
102 | buffer=xrealloc(buffer,f_size+bytes_read); | ||
103 | memcpy(&buffer[f_size],line,bytes_read); | ||
104 | filelocation=f_size+=bytes_read; | ||
105 | } | ||
106 | bs=f_size; | ||
107 | if(direction<0) | ||
108 | bs--; | ||
109 | if (line) | ||
110 | free(line); | ||
111 | } else { | ||
112 | filelocation = lseek(fd, 0, SEEK_CUR); | ||
113 | if(direction<0) { | ||
114 | if(filelocation<bs) | ||
115 | bs=filelocation; | ||
116 | filelocation = lseek(fd, -bs, SEEK_CUR); | ||
117 | } | ||
118 | bytes_read = read(fd, buffer, bs); | ||
119 | if (bytes_read <= 0) | ||
120 | break; | ||
121 | bs=bytes_read; | ||
122 | } | ||
123 | startpoint=bs; | ||
124 | if(direction>0) { | ||
125 | endpoint=startpoint; | ||
126 | startpoint=0; | ||
127 | } | ||
128 | for(;startpoint!=endpoint;startpoint+=direction) { | ||
129 | #ifndef BB_FEATURE_SIMPLE_TAIL | 36 | #ifndef BB_FEATURE_SIMPLE_TAIL |
130 | if(unit_type==BYTES) | 37 | static struct suffix_mult null_suffixes[] = { |
131 | count++; | 38 | { NULL, 0 } |
132 | else | 39 | }; |
133 | #endif | 40 | #endif |
134 | if(buffer[startpoint-1]=='\n') | ||
135 | count++; | ||
136 | if (!pip) | ||
137 | filelocation=lseek(fd,0,SEEK_CUR); | ||
138 | if(count==units*direction) | ||
139 | break; | ||
140 | } | ||
141 | if((count==units*direction) | pip) | ||
142 | break; | ||
143 | if(direction<0){ | ||
144 | filelocation = lseek(fd, -bytes_read, SEEK_CUR); | ||
145 | if(filelocation==0) | ||
146 | break; | ||
147 | } | ||
148 | } | ||
149 | if(pip && (direction<0)) | ||
150 | bs++; | ||
151 | bytes_read=bs-startpoint; | ||
152 | memcpy(&buffer[0],&buffer[startpoint],bytes_read); | ||
153 | 41 | ||
154 | return 0; | 42 | #define BYTES 0 |
43 | #define LINES 1 | ||
44 | |||
45 | static char *tailbuf; | ||
46 | static int taillen; | ||
47 | static int newline; | ||
48 | |||
49 | void tailbuf_append(char *buf, int len) | ||
50 | { | ||
51 | tailbuf = xrealloc(tailbuf, taillen + len); | ||
52 | memcpy(tailbuf + taillen, buf, len); | ||
53 | taillen += len; | ||
155 | } | 54 | } |
156 | 55 | ||
157 | void add_file(char *name) | 56 | void tailbuf_trunc() |
158 | { | 57 | { |
159 | ++n_files; | 58 | char *s; |
160 | files = xrealloc(files, n_files); | 59 | s = memchr(tailbuf, '\n', taillen); |
161 | files[n_files - 1] = (char *) xmalloc(strlen(name) + 1); | 60 | memmove(tailbuf, s + 1, taillen - ((s + 1) - tailbuf)); |
162 | strcpy(files[n_files - 1], name); | 61 | taillen -= (s + 1) - tailbuf; |
62 | newline = 0; | ||
163 | } | 63 | } |
164 | 64 | ||
165 | int tail_main(int argc, char **argv) | 65 | int tail_main(int argc, char **argv) |
166 | { | 66 | { |
167 | int show_headers = 1; | 67 | int from_top = 0, units = LINES, count = 10, sleep_period = 1; |
168 | int test; | 68 | int show_headers = 0, hide_headers = 0, follow = 0; |
169 | int opt; | 69 | int *fds, nfiles = 0, status = EXIT_SUCCESS, nread, nwrite, seen = 0; |
170 | char follow=0; | 70 | char *s, *start, *end, buf[BUFSIZ]; |
171 | int sleep_int=1; | 71 | int i, opt; |
172 | int *fd; | ||
173 | |||
174 | opterr = 0; | ||
175 | |||
176 | while ((opt=getopt(argc,argv,"c:fhn:s:q:v")) >0) { | ||
177 | 72 | ||
73 | while ((opt = getopt(argc, argv, "c:fhn:q:s:v")) > 0) { | ||
178 | switch (opt) { | 74 | switch (opt) { |
75 | case 'f': | ||
76 | follow = 1; | ||
77 | break; | ||
179 | #ifndef BB_FEATURE_SIMPLE_TAIL | 78 | #ifndef BB_FEATURE_SIMPLE_TAIL |
180 | case 'q': | 79 | case 'c': |
181 | show_headers = 0; | 80 | units = BYTES; |
182 | break; | 81 | /* FALLS THROUGH */ |
183 | case 's': | ||
184 | sleep_int = atoi(optarg); | ||
185 | if(sleep_int<1) | ||
186 | sleep_int=1; | ||
187 | break; | ||
188 | case 'v': | ||
189 | verbose = 1; | ||
190 | break; | ||
191 | case 'c': | ||
192 | unit_type = BYTES; | ||
193 | /* FALLS THROUGH */ | ||
194 | #endif | 82 | #endif |
195 | case 'n': | 83 | case 'n': |
196 | test = parse_number(optarg, tail_suffixes); | 84 | count = parse_number(optarg, tail_suffixes); |
197 | if (test) { | 85 | if (count < 0) |
86 | count = -count; | ||
198 | if (optarg[0] == '+') | 87 | if (optarg[0] == '+') |
199 | units = test; | 88 | from_top = 1; |
200 | else | 89 | break; |
201 | units = -(test+1); | 90 | #ifndef BB_FEATURE_SIMPLE_TAIL |
202 | } else | 91 | case 'q': |
92 | hide_headers = 1; | ||
93 | break; | ||
94 | case 's': | ||
95 | sleep_period = parse_number(optarg, null_suffixes); | ||
96 | break; | ||
97 | case 'v': | ||
98 | show_headers = 1; | ||
99 | break; | ||
100 | #endif | ||
101 | default: | ||
203 | usage(tail_usage); | 102 | usage(tail_usage); |
204 | break; | ||
205 | case 'f': | ||
206 | follow = 1; | ||
207 | break; | ||
208 | default: | ||
209 | usage(tail_usage); | ||
210 | } | 103 | } |
211 | } | 104 | } |
212 | while (optind <= argc) { | 105 | |
213 | if(optind==argc) { | 106 | /* open all the files */ |
214 | if (n_files==0) | 107 | fds = (int *)xmalloc(sizeof(int) * (argc - optind + 1)); |
215 | add_file(STDIN); | 108 | if (argc == optind) { |
216 | else | 109 | fds[nfiles++] = STDIN_FILENO; |
217 | break; | 110 | argv[optind] = "standard input"; |
218 | }else { | 111 | } else { |
219 | if (!strcmp(argv[optind], "-")) { | 112 | for (i = optind; i < argc; i++) { |
220 | add_file(STDIN); | 113 | if (strcmp(argv[i], "-") == 0) { |
221 | } else { | 114 | fds[nfiles++] = STDIN_FILENO; |
222 | add_file(argv[optind]); | 115 | argv[i] = "standard input"; |
116 | } else if ((fds[nfiles++] = open(argv[i], O_RDONLY)) < 0) { | ||
117 | perror_msg("%s", argv[i]); | ||
118 | status = EXIT_FAILURE; | ||
223 | } | 119 | } |
224 | optind++; | ||
225 | } | 120 | } |
226 | } | 121 | } |
227 | if(units==0) | 122 | |
228 | units=-11; | ||
229 | if(units>0) | ||
230 | units--; | ||
231 | fd=xmalloc(sizeof(int)*n_files); | ||
232 | if (n_files == 1) | ||
233 | #ifndef BB_FEATURE_SIMPLE_TAIL | 123 | #ifndef BB_FEATURE_SIMPLE_TAIL |
234 | if (!verbose) | 124 | /* tail the files */ |
125 | if (!from_top && units == BYTES) | ||
126 | tailbuf = xmalloc(count); | ||
235 | #endif | 127 | #endif |
236 | show_headers = 0; | ||
237 | buffer=xmalloc(BUFSIZ); | ||
238 | for (test = 0; test < n_files; test++) { | ||
239 | if (show_headers) | ||
240 | printf("==> %s <==\n", files[test]); | ||
241 | if (!strcmp(files[test], STDIN)) | ||
242 | fd[test] = 0; | ||
243 | else | ||
244 | fd[test] = open(files[test], O_RDONLY); | ||
245 | if (fd[test] == -1) | ||
246 | error_msg_and_die("Unable to open file %s.\n", files[test]); | ||
247 | tail_stream(fd[test]); | ||
248 | 128 | ||
249 | bs=BUFSIZ; | 129 | for (i = 0; i < nfiles; i++) { |
250 | while (1) { | 130 | if (fds[i] == -1) |
251 | if((filelocation>0 || pip)){ | 131 | continue; |
252 | write(1,buffer,bytes_read); | 132 | seen = 0; |
133 | if (show_headers || (!hide_headers && nfiles > 1)) | ||
134 | printf("%s==> %s <==\n", i == 0 ? "" : "\n", argv[optind + i]); | ||
135 | while ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0) { | ||
136 | if (from_top) { | ||
137 | #ifndef BB_FEATURE_SIMPLE_TAIL | ||
138 | if (units == BYTES) { | ||
139 | if (count - 1 <= seen) | ||
140 | nwrite = nread; | ||
141 | else if (count - 1 <= seen + nread) | ||
142 | nwrite = nread + seen - (count - 1); | ||
143 | else | ||
144 | nwrite = 0; | ||
145 | seen += nread; | ||
146 | } else { | ||
147 | #else | ||
148 | { | ||
149 | #endif | ||
150 | if (count - 1 <= seen) | ||
151 | nwrite = nread; | ||
152 | else { | ||
153 | nwrite = 0; | ||
154 | for (s = memchr(buf, '\n', nread); s != NULL; | ||
155 | s = memchr(s+1, '\n', nread - (s + 1 - buf))) { | ||
156 | if (count - 1 <= ++seen) { | ||
157 | nwrite = nread - (s + 1 - buf); | ||
158 | break; | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | } | ||
163 | if (full_write(STDOUT_FILENO, buf + nread - nwrite, | ||
164 | nwrite) < 0) { | ||
165 | perror_msg("write"); | ||
166 | status = EXIT_FAILURE; | ||
167 | break; | ||
168 | } | ||
169 | } else { | ||
170 | #ifndef BB_FEATURE_SIMPLE_TAIL | ||
171 | if (units == BYTES) { | ||
172 | if (nread < count) { | ||
173 | memmove(tailbuf, tailbuf + nread, count - nread); | ||
174 | memcpy(tailbuf + count - nread, buf, nread); | ||
175 | } else { | ||
176 | memcpy(tailbuf, buf + nread - count, count); | ||
177 | } | ||
178 | seen += nread; | ||
179 | } else { | ||
180 | #else | ||
181 | { | ||
182 | #endif | ||
183 | for (start = buf, end = memchr(buf, '\n', nread); | ||
184 | end != NULL; start = end+1, | ||
185 | end = memchr(start, '\n', nread - (start - buf))) { | ||
186 | if (newline && count <= seen) | ||
187 | tailbuf_trunc(); | ||
188 | tailbuf_append(start, end - start + 1); | ||
189 | seen++; | ||
190 | newline = 1; | ||
191 | } | ||
192 | if (newline && count <= seen && nread - (start - buf) > 0) | ||
193 | tailbuf_trunc(); | ||
194 | tailbuf_append(start, nread - (start - buf)); | ||
195 | } | ||
253 | } | 196 | } |
254 | bytes_read = read(fd[test], buffer, bs); | 197 | } |
255 | filelocation+=bytes_read; | 198 | |
256 | if (bytes_read <= 0) { | 199 | if (nread < 0) { |
257 | break; | 200 | perror_msg("read"); |
201 | status = EXIT_FAILURE; | ||
202 | } | ||
203 | |||
204 | #ifndef BB_FEATURE_SIMPLE_TAIL | ||
205 | if (!from_top && units == BYTES) { | ||
206 | if (count < seen) | ||
207 | seen = count; | ||
208 | if (full_write(STDOUT_FILENO, tailbuf + count - seen, seen) < 0) { | ||
209 | perror_msg("write"); | ||
210 | status = EXIT_FAILURE; | ||
258 | } | 211 | } |
259 | usleep(sleep_int * 1000); | ||
260 | } | 212 | } |
261 | if(n_files>1) | 213 | #endif |
262 | printf("\n"); | 214 | |
215 | if (!from_top && units == LINES) { | ||
216 | if (full_write(STDOUT_FILENO, tailbuf, taillen) < 0) { | ||
217 | perror_msg("write"); | ||
218 | status = EXIT_FAILURE; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | taillen = 0; | ||
263 | } | 223 | } |
264 | while(1){ | 224 | |
265 | for (test = 0; test < n_files; test++) { | 225 | while (follow) { |
266 | if(!follow){ | 226 | sleep(sleep_period); |
267 | close(fd[test]); | 227 | |
228 | for (i = 0; i < nfiles; i++) { | ||
229 | if (fds[i] == -1) | ||
268 | continue; | 230 | continue; |
269 | } else { | 231 | |
270 | sleep(sleep_int); | 232 | if ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0) { |
271 | bytes_read = read(fd[test], buffer, bs); | 233 | if (show_headers || (!hide_headers && nfiles > 1)) |
272 | if(bytes_read>0) { | 234 | printf("\n==> %s <==\n", argv[optind + i]); |
273 | if (show_headers) | 235 | |
274 | printf("==> %s <==\n", files[test]); | 236 | do { |
275 | write(1,buffer,bytes_read); | 237 | full_write(STDOUT_FILENO, buf, nread); |
276 | if(n_files>1) | 238 | } while ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0); |
277 | printf("\n"); | 239 | } |
278 | } | 240 | |
241 | if (nread < 0) { | ||
242 | perror_msg("read"); | ||
243 | status = EXIT_FAILURE; | ||
279 | } | 244 | } |
280 | } | 245 | } |
281 | if(!follow) | ||
282 | break; | ||
283 | } | 246 | } |
284 | if (fd) | ||
285 | free(fd); | ||
286 | if (buffer) | ||
287 | free(buffer); | ||
288 | if(files) | ||
289 | free(files); | ||
290 | return 0; | ||
291 | } | ||
292 | 247 | ||
293 | /* | 248 | return status; |
294 | Local Variables: | 249 | } |
295 | c-file-style: "linux" | ||
296 | c-basic-offset: 4 | ||
297 | tab-width: 4 | ||
298 | End: | ||
299 | */ | ||