OSDN Git Service

Commit the rewrite of tail by Allen Soard
[android-x86/external-busybox.git] / tail.c
1 /* vi: set sw=4 ts=4: */
2 /* tail -- output the last part of file(s)
3    Copyright (C) 89, 90, 91, 95, 1996 Free Software Foundation, Inc.
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2, or (at your option)
8    any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19    Original version by Paul Rubin <phr@ocf.berkeley.edu>.
20    Extensions by David MacKenzie <djm@gnu.ai.mit.edu>.
21    tail -f for multiple files by Ian Lance Taylor <ian@airs.com>.  
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
30    Compleate Rewrite to correctly support "-NUM", "+NUM", and "-s" by
31    E.Allen Soard (esp@espsw.net).
32
33  */
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <string.h>
41 #include <getopt.h>
42 #include "internal.h"
43
44 #define STDIN "standard input"
45 #define LINES 0
46 #define BYTES 1
47
48 static int n_files = 0;
49 static char **files = NULL;
50
51 static char follow=0;
52
53 #ifdef BB_FEATURE_SIMPLE_TAIL
54 static const char unit_type=LINES;
55 static const char sleep_int=1;
56 #else
57 static char unit_type=LINES;
58 static int sleep_int=1;
59 static char verbose = 0;
60 #endif
61
62 //static off_t units=-11;
63 static off_t units=0;
64
65 int tail_stream(int file_id)
66 {
67         int fd;
68         ssize_t bytes_read=0;
69         ssize_t bs=BUFSIZ;
70         ssize_t startpoint=bs;
71         ssize_t endpoint=0;
72         ssize_t count=0;
73         ssize_t filesize=0;
74         ssize_t filelocation=0;
75         char direction=1;
76         char * buffer;
77         char pipe;
78
79
80         if (!strcmp(files[file_id], STDIN))
81                 fd = 0;
82         else
83                 fd = open(files[file_id], O_RDONLY);
84         if (fd == -1)
85                 fatalError("Unable to open file %s.\n", files[file_id]);
86
87         buffer=malloc(bs);
88
89         filesize=lseek(fd, -1, SEEK_END)+1;
90         pipe=(filesize<=0);
91
92         if(units>=0)
93                 lseek(fd,0,SEEK_SET);
94         else {
95                 direction=-1;
96                 count=1;
97         }
98         while(units != 0) {
99                 if (pipe) {
100                         char * line;
101                         ssize_t f_size=0;
102
103                         bs=BUFSIZ;
104                         line=malloc(bs);
105                         while(1) {
106                                 bytes_read=read(fd,line,bs);
107                                 if(bytes_read<=0)
108                                         break;
109                                 buffer=realloc(buffer,f_size+bytes_read);
110                                 memcpy(&buffer[f_size],line,bytes_read);
111                                 filelocation=f_size+=bytes_read;
112                         }
113                         bs=f_size;
114                         if(direction<0)
115                                 bs--;
116                         if (line)
117                                 free(line);
118                 } else {
119                         filelocation = lseek(fd, 0, SEEK_CUR);
120                         if(direction<0) {
121                                 if(filelocation<bs)
122                                         bs=filelocation;
123                                 filelocation = lseek(fd, -bs, SEEK_CUR);
124                         }
125                         bytes_read = read(fd, buffer, bs);
126                         if (bytes_read <= 0)
127                                 break;
128                         bs=bytes_read;
129                 }
130                 startpoint=bs;
131                 if(direction>0) {
132                         endpoint=startpoint;
133                         startpoint=0;
134                 }
135                 for(;startpoint!=endpoint;startpoint+=direction) {
136 #ifndef BB_FEATURE_SIMPLE_TAIL
137                         if(unit_type==BYTES)
138                                 count++;
139                         else
140 #endif
141                                 if(buffer[startpoint-1]=='\n')
142                                         count++;
143                         if (!pipe)
144                                 filelocation=lseek(fd,0,SEEK_CUR);
145                         if(count==abs(units))
146                                 break;
147                 }
148                 if((count==abs(units)) | pipe)
149                         break;
150                 if(direction<0){
151                         filelocation = lseek(fd, -bytes_read, SEEK_CUR);
152                         if(filelocation==0)
153                                 break;
154                 }
155         }
156         if(pipe && (direction<0))
157                 bs++;
158         bytes_read=bs-startpoint;
159         memcpy(&buffer[0],&buffer[startpoint],bytes_read);
160
161         bs=BUFSIZ;
162         while (1) {
163                 if((filelocation>0 || pipe)){
164                         write(1,buffer,bytes_read);
165                 }
166                 bytes_read = read(fd, buffer, bs);
167                 filelocation+=bytes_read;
168                 if (bytes_read <= 0) {
169                         if (!follow) {
170                                 close(fd);
171                                 break;
172                         }
173                         sleep(sleep_int);
174                 }
175                 usleep(sleep_int * 1000);
176         }
177         if (buffer)
178                 free(buffer);
179         return 0;
180 }
181
182 void add_file(char *name)
183 {
184         ++n_files;
185         files = realloc(files, n_files);
186         files[n_files - 1] = (char *) malloc(strlen(name) + 1);
187         strcpy(files[n_files - 1], name);
188 }
189
190
191 int tail_main(int argc, char **argv)
192 {
193         int show_headers = 1;
194         int test;
195         int c;
196         int nargs=0;
197         char **argn=NULL;
198
199         opterr = 0;
200         
201         for(c=0;c<argc;c++){
202                 test=atoi(argv[c]);
203                 if(test){
204                         units=test;
205                         if(units<0)
206                                 units=units-1;
207                 }else{
208                         nargs++;
209                         argn = realloc(argn, nargs);
210                         argn[nargs - 1] = (char *) malloc(strlen(argv[c]) + 1);
211                         strcpy(argn[nargs - 1], argv[c]);
212                 }
213         }
214         while (1) {
215                 int opt_index = 0;
216
217                 c = getopt_long_only(nargs, argn,
218                         "c:fhn:s:qv", NULL, &opt_index);
219                 if (c == -1)
220                         break;
221                 switch (c) {
222
223 #ifndef BB_FEATURE_SIMPLE_TAIL
224
225                 case 'c':
226                         unit_type = BYTES;
227                         test = atoi(optarg);
228                         if(test==0)
229                                 usage(tail_usage);
230                         if(optarg[strlen(optarg)-1]>'9') {
231                                 switch (optarg[strlen(optarg)-1]) {
232                                 case 'b':
233                                         test *= 512;
234                                         break;
235                                 case 'k':
236                                         test *= 1024;
237                                         break;
238                                 case 'm':
239                                         test *= (1024 * 1024);
240                                         break;
241                                 default:
242                                         fprintf(stderr,"Size must be b,k, or m.");
243                                         usage(tail_usage);
244                                 }
245                         }
246                         if(optarg[0]=='+')
247                                 units=test+1;
248                         else
249                                 units=-(test+1);
250                         break;
251                 case 'q':
252                         show_headers = 0;
253                         break;
254                 case 's':
255                         sleep_int = atoi(optarg);
256                         if(sleep_int<1)
257                                 sleep_int=1;
258                         break;
259                 case 'v':
260                         verbose = 1;
261                         break;
262 #endif
263                 case 'f':
264                         follow = 1;
265                         break;
266                 case 'h':
267                         usage(tail_usage);
268                         break;
269                 case 'n':
270                         test = atoi(optarg);
271                         if (test) {
272                                 if (optarg[0] == '+')
273                                         units = test;
274                                 else
275                                         units = -(test+1);
276                         } else
277                                 usage(tail_usage);
278                         break;
279                 default:
280                         errorMsg("\nUnknown arg: %c.\n\n",c);
281                         usage(tail_usage);
282                 }
283         }
284         while (optind < nargs) {
285                 if (!strcmp(argn[optind], "-"))
286                         add_file(STDIN);
287                 else
288                         add_file(argn[optind]);
289                 optind++;
290         }
291         if(units==0)
292                 units=-11;
293         if(units>0)
294                 units--;
295         if (n_files == 0)
296                 add_file(STDIN);
297         if (n_files == 1)
298 #ifndef BB_FEATURE_SIMPLE_TAIL
299                 if (!verbose)
300 #endif
301                         show_headers = 0;
302         for (test = 0; test < n_files; test++) {
303                 if (show_headers)
304                         printf("==> %s <==\n", files[test]);
305                 tail_stream(test);
306         }
307         if(files)
308                 free(files);
309         if(argn)
310                 free(argn);
311         return 0;
312 }
313
314 /*
315 Local Variables:
316 c-file-style: "linux"
317 c-basic-offset: 4
318 tab-width: 4
319 End:
320 */