add some sanity checks
[unix-history] / usr / src / usr.bin / tail / tail.c
CommitLineData
2b63311e 1static char *sccsid = "@(#)tail.c 4.4 (Berkeley) %G%";
15dbf57f
BJ
2/* tail command
3 *
4 * tail where [file]
bf98c161 5 * where is +/-n[type]
15dbf57f
BJ
6 * - means n lines before end
7 * + means nth line from beginning
8 * type 'b' means tail n blocks, not lines
9 * type 'c' means tail n characters
10 * Type 'r' means in lines in reverse order from end
11 * (for -r, default is entire buffer )
12 * option 'f' means loop endlessly trying to read more
13 * characters after the end of file, on the assumption
14 * that the file is growing
15*/
16
17#include <stdio.h>
18#include <ctype.h>
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <errno.h>
22
23#define LBIN 4097
24struct stat statb;
25int follow;
26int piped;
27char bin[LBIN];
28int errno;
29
30main(argc,argv)
31char **argv;
32{
33 long n,di;
34 register i,j,k;
35 char *arg;
36 int partial,bylines,bkwds,fromend,lastnl;
37 char *p;
38
15dbf57f
BJ
39 arg = argv[1];
40 if(argc<=1 || *arg!='-'&&*arg!='+') {
41 arg = "-10l";
42 argc++;
43 argv--;
44 }
45 fromend = *arg=='-';
46 arg++;
2b63311e
MK
47 if (isdigit(*arg)) {
48 n = 0;
49 while(isdigit(*arg))
50 n = n*10 + *arg++ - '0';
51 } else
52 n = -1;
15dbf57f
BJ
53 if(!fromend&&n>0)
54 n--;
55 if(argc>2) {
56 close(0);
57 if(open(argv[2],0)!=0) {
58 perror(argv[2]);
59 exit(1);
60 }
61 }
76c3d437
RC
62 lseek(0,(long)0,1);
63 piped = errno==ESPIPE;
15dbf57f
BJ
64 bylines = -1; bkwds = 0;
65 while(*arg)
66 switch(*arg++) {
67
68 case 'b':
69 n <<= 9;
70 if(bylines!=-1) goto errcom;
71 bylines=0;
72 break;
73 case 'c':
74 if(bylines!=-1) goto errcom;
75 bylines=0;
76 break;
77 case 'f':
78 follow = 1;
79 break;
80 case 'r':
2b63311e 81 if(n==-1) n = LBIN;
15dbf57f
BJ
82 bkwds = 1; fromend = 1; bylines = 1;
83 break;
84 case 'l':
85 if(bylines!=-1) goto errcom;
86 bylines = 1;
87 break;
88 default:
89 goto errcom;
90 }
2b63311e 91 if (n==-1) n = 10;
15dbf57f
BJ
92 if(bylines==-1) bylines = 1;
93 if(bkwds) follow=0;
94 if(fromend)
95 goto keep;
96
97 /*seek from beginning */
98
99 if(bylines) {
100 j = 0;
101 while(n-->0) {
102 do {
103 if(j--<=0) {
104 p = bin;
105 j = read(0,p,BUFSIZ);
106 if(j--<=0)
107 fexit();
108 }
109 } while(*p++ != '\n');
110 }
111 write(1,p,j);
112 } else if(n>0) {
113 if(!piped)
114 fstat(0,&statb);
115 if(piped||(statb.st_mode&S_IFMT)==S_IFCHR)
116 while(n>0) {
117 i = n>BUFSIZ?BUFSIZ:n;
118 i = read(0,bin,i);
119 if(i<=0)
120 fexit();
121 n -= i;
122 }
123 else
124 lseek(0,n,0);
125 }
126copy:
127 while((i=read(0,bin,BUFSIZ))>0)
128 write(1,bin,i);
129 fexit();
130
131 /*seek from end*/
132
133keep:
134 if(n <= 0)
135 fexit();
136 if(!piped) {
137 fstat(0,&statb);
138 di = !bylines&&n<LBIN?n:LBIN-1;
139 if(statb.st_size > di)
140 lseek(0,-di,2);
141 if(!bylines)
142 goto copy;
143 }
144 partial = 1;
145 for(;;) {
146 i = 0;
147 do {
148 j = read(0,&bin[i],LBIN-i);
149 if(j<=0)
150 goto brka;
151 i += j;
152 } while(i<LBIN);
153 partial = 0;
154 }
155brka:
156 if(!bylines) {
157 k =
158 n<=i ? i-n:
159 partial ? 0:
160 n>=LBIN ? i+1:
161 i-n+LBIN;
162 k--;
163 } else {
164 if(bkwds && bin[i==0?LBIN-1:i-1]!='\n'){ /* force trailing newline */
165 bin[i]='\n';
166 if(++i>=LBIN) {i = 0; partial = 0;}
167 }
168 k = i;
169 j = 0;
170 do {
171 lastnl = k;
172 do {
173 if(--k<0) {
174 if(partial) {
175 if(bkwds) write(1,bin,lastnl+1);
176 goto brkb;
177 }
178 k = LBIN -1;
179 }
180 } while(bin[k]!='\n'&&k!=i);
181 if(bkwds && j>0){
182 if(k<lastnl) write(1,&bin[k+1],lastnl-k);
183 else {
184 write(1,&bin[k+1],LBIN-k-1);
185 write(1,bin,lastnl+1);
186 }
187 }
188 } while(j++<n&&k!=i);
189brkb:
190 if(bkwds) exit(0);
191 if(k==i) do {
192 if(++k>=LBIN)
193 k = 0;
194 } while(bin[k]!='\n'&&k!=i);
195 }
196 if(k<i)
197 write(1,&bin[k+1],i-k-1);
198 else {
199 write(1,&bin[k+1],LBIN-k-1);
200 write(1,bin,i);
201 }
202 fexit();
203errcom:
204 fprintf(stderr, "usage: tail [+\b_[n][lbc][rf]] [file]\n");
205 exit(2);
206}
207
208fexit()
209{ register int n;
210 if (!follow || piped) exit(0);
211 for (;;)
212 { sleep(1);
213 while ((n = read (0, bin, BUFSIZ)) > 0)
214 write (1, bin, n);
215 }
216}