Blame


1 bc7cb1a1 2003-11-23 devnull #include <u.h>
2 bc7cb1a1 2003-11-23 devnull #include <libc.h>
3 bc7cb1a1 2003-11-23 devnull #include <ctype.h>
4 bc7cb1a1 2003-11-23 devnull #include <bio.h>
5 bc7cb1a1 2003-11-23 devnull
6 bc7cb1a1 2003-11-23 devnull /*
7 bc7cb1a1 2003-11-23 devnull * tail command, posix plus v10 option -r.
8 bc7cb1a1 2003-11-23 devnull * the simple command tail -c, legal in v10, is illegal
9 bc7cb1a1 2003-11-23 devnull */
10 bc7cb1a1 2003-11-23 devnull
11 b707cb51 2004-06-13 devnull vlong count;
12 bc7cb1a1 2003-11-23 devnull int anycount;
13 bc7cb1a1 2003-11-23 devnull int follow;
14 bc7cb1a1 2003-11-23 devnull int file = 0;
15 bc7cb1a1 2003-11-23 devnull char* umsg = "usage: tail [-n N] [-c N] [-f] [-r] [+-N[bc][fr]] [file]";
16 bc7cb1a1 2003-11-23 devnull
17 bc7cb1a1 2003-11-23 devnull Biobuf bout;
18 bc7cb1a1 2003-11-23 devnull enum
19 bc7cb1a1 2003-11-23 devnull {
20 bc7cb1a1 2003-11-23 devnull BEG,
21 bc7cb1a1 2003-11-23 devnull END
22 bc7cb1a1 2003-11-23 devnull } origin = END;
23 bc7cb1a1 2003-11-23 devnull enum
24 bc7cb1a1 2003-11-23 devnull {
25 bc7cb1a1 2003-11-23 devnull CHARS,
26 bc7cb1a1 2003-11-23 devnull LINES
27 bc7cb1a1 2003-11-23 devnull } units = LINES;
28 bc7cb1a1 2003-11-23 devnull enum
29 bc7cb1a1 2003-11-23 devnull {
30 bc7cb1a1 2003-11-23 devnull FWD,
31 bc7cb1a1 2003-11-23 devnull REV
32 bc7cb1a1 2003-11-23 devnull } dir = FWD;
33 bc7cb1a1 2003-11-23 devnull
34 bc7cb1a1 2003-11-23 devnull extern void copy(void);
35 bc7cb1a1 2003-11-23 devnull extern void fatal(char*);
36 bc7cb1a1 2003-11-23 devnull extern int getnumber(char*);
37 bc7cb1a1 2003-11-23 devnull extern void keep(void);
38 bc7cb1a1 2003-11-23 devnull extern void reverse(void);
39 bc7cb1a1 2003-11-23 devnull extern void skip(void);
40 bc7cb1a1 2003-11-23 devnull extern void suffix(char*);
41 bc7cb1a1 2003-11-23 devnull extern long tread(char*, long);
42 cedbe4a4 2003-11-24 devnull #define trunc tailtrunc
43 bc7cb1a1 2003-11-23 devnull extern void trunc(Dir*, Dir**);
44 b707cb51 2004-06-13 devnull extern vlong tseek(vlong, int);
45 bc7cb1a1 2003-11-23 devnull extern void twrite(char*, long);
46 bc7cb1a1 2003-11-23 devnull extern void usage(void);
47 bc7cb1a1 2003-11-23 devnull
48 bc7cb1a1 2003-11-23 devnull #define JUMP(o,p) tseek(o,p), copy()
49 bc7cb1a1 2003-11-23 devnull
50 bc7cb1a1 2003-11-23 devnull void
51 bc7cb1a1 2003-11-23 devnull main(int argc, char **argv)
52 bc7cb1a1 2003-11-23 devnull {
53 bc7cb1a1 2003-11-23 devnull int seekable, c;
54 bc7cb1a1 2003-11-23 devnull
55 bc7cb1a1 2003-11-23 devnull Binit(&bout, 1, OWRITE);
56 bc7cb1a1 2003-11-23 devnull for(; argc > 1 && ((c=*argv[1])=='-'||c=='+'); argc--,argv++ ) {
57 bc7cb1a1 2003-11-23 devnull if(getnumber(argv[1])) {
58 bc7cb1a1 2003-11-23 devnull suffix(argv[1]);
59 bc7cb1a1 2003-11-23 devnull continue;
60 bc7cb1a1 2003-11-23 devnull } else
61 bc7cb1a1 2003-11-23 devnull if(c == '-')
62 bc7cb1a1 2003-11-23 devnull switch(argv[1][1]) {
63 bc7cb1a1 2003-11-23 devnull case 'c':
64 bc7cb1a1 2003-11-23 devnull units = CHARS;
65 bc7cb1a1 2003-11-23 devnull case 'n':
66 bc7cb1a1 2003-11-23 devnull if(getnumber(argv[1]+2))
67 bc7cb1a1 2003-11-23 devnull continue;
68 bc7cb1a1 2003-11-23 devnull else
69 bc7cb1a1 2003-11-23 devnull if(argc > 2 && getnumber(argv[2])) {
70 bc7cb1a1 2003-11-23 devnull argc--, argv++;
71 bc7cb1a1 2003-11-23 devnull continue;
72 bc7cb1a1 2003-11-23 devnull } else
73 bc7cb1a1 2003-11-23 devnull usage();
74 bc7cb1a1 2003-11-23 devnull case 'r':
75 bc7cb1a1 2003-11-23 devnull dir = REV;
76 bc7cb1a1 2003-11-23 devnull continue;
77 bc7cb1a1 2003-11-23 devnull case 'f':
78 bc7cb1a1 2003-11-23 devnull follow++;
79 bc7cb1a1 2003-11-23 devnull continue;
80 bc7cb1a1 2003-11-23 devnull case '-':
81 bc7cb1a1 2003-11-23 devnull argc--, argv++;
82 bc7cb1a1 2003-11-23 devnull }
83 bc7cb1a1 2003-11-23 devnull break;
84 bc7cb1a1 2003-11-23 devnull }
85 bc7cb1a1 2003-11-23 devnull if(dir==REV && (units==CHARS || follow || origin==BEG))
86 bc7cb1a1 2003-11-23 devnull fatal("incompatible options");
87 bc7cb1a1 2003-11-23 devnull if(!anycount)
88 b707cb51 2004-06-13 devnull count = dir==REV? ~0ULL>>1: 10;
89 bc7cb1a1 2003-11-23 devnull if(origin==BEG && units==LINES && count>0)
90 bc7cb1a1 2003-11-23 devnull count--;
91 bc7cb1a1 2003-11-23 devnull if(argc > 2)
92 bc7cb1a1 2003-11-23 devnull usage();
93 bc7cb1a1 2003-11-23 devnull if(argc > 1 && (file=open(argv[1],0)) < 0)
94 bc7cb1a1 2003-11-23 devnull fatal(argv[1]);
95 bc7cb1a1 2003-11-23 devnull seekable = seek(file,0L,0) == 0;
96 bc7cb1a1 2003-11-23 devnull
97 bc7cb1a1 2003-11-23 devnull if(!seekable && origin==END)
98 bc7cb1a1 2003-11-23 devnull keep();
99 bc7cb1a1 2003-11-23 devnull else
100 bc7cb1a1 2003-11-23 devnull if(!seekable && origin==BEG)
101 bc7cb1a1 2003-11-23 devnull skip();
102 bc7cb1a1 2003-11-23 devnull else
103 bc7cb1a1 2003-11-23 devnull if(units==CHARS && origin==END)
104 bc7cb1a1 2003-11-23 devnull JUMP(-count, 2);
105 bc7cb1a1 2003-11-23 devnull else
106 bc7cb1a1 2003-11-23 devnull if(units==CHARS && origin==BEG)
107 bc7cb1a1 2003-11-23 devnull JUMP(count, 0);
108 bc7cb1a1 2003-11-23 devnull else
109 bc7cb1a1 2003-11-23 devnull if(units==LINES && origin==END)
110 bc7cb1a1 2003-11-23 devnull reverse();
111 bc7cb1a1 2003-11-23 devnull else
112 bc7cb1a1 2003-11-23 devnull if(units==LINES && origin==BEG)
113 bc7cb1a1 2003-11-23 devnull skip();
114 bc7cb1a1 2003-11-23 devnull if(follow && seekable)
115 bc7cb1a1 2003-11-23 devnull for(;;) {
116 bc7cb1a1 2003-11-23 devnull static Dir *sb0, *sb1;
117 bc7cb1a1 2003-11-23 devnull trunc(sb1, &sb0);
118 bc7cb1a1 2003-11-23 devnull copy();
119 bc7cb1a1 2003-11-23 devnull trunc(sb0, &sb1);
120 bc7cb1a1 2003-11-23 devnull sleep(5000);
121 bc7cb1a1 2003-11-23 devnull }
122 bc7cb1a1 2003-11-23 devnull exits(0);
123 bc7cb1a1 2003-11-23 devnull }
124 bc7cb1a1 2003-11-23 devnull
125 bc7cb1a1 2003-11-23 devnull void
126 bc7cb1a1 2003-11-23 devnull trunc(Dir *old, Dir **new)
127 bc7cb1a1 2003-11-23 devnull {
128 bc7cb1a1 2003-11-23 devnull Dir *d;
129 b707cb51 2004-06-13 devnull vlong olength;
130 bc7cb1a1 2003-11-23 devnull
131 bc7cb1a1 2003-11-23 devnull d = dirfstat(file);
132 bc7cb1a1 2003-11-23 devnull if(d == nil)
133 bc7cb1a1 2003-11-23 devnull return;
134 bc7cb1a1 2003-11-23 devnull olength = 0;
135 bc7cb1a1 2003-11-23 devnull if(old)
136 bc7cb1a1 2003-11-23 devnull olength = old->length;
137 bc7cb1a1 2003-11-23 devnull if(d->length < olength)
138 bc7cb1a1 2003-11-23 devnull d->length = tseek(0L, 0);
139 bc7cb1a1 2003-11-23 devnull free(*new);
140 bc7cb1a1 2003-11-23 devnull *new = d;
141 bc7cb1a1 2003-11-23 devnull }
142 bc7cb1a1 2003-11-23 devnull
143 bc7cb1a1 2003-11-23 devnull void
144 bc7cb1a1 2003-11-23 devnull suffix(char *s)
145 bc7cb1a1 2003-11-23 devnull {
146 bc7cb1a1 2003-11-23 devnull while(*s && strchr("0123456789+-", *s))
147 bc7cb1a1 2003-11-23 devnull s++;
148 bc7cb1a1 2003-11-23 devnull switch(*s) {
149 bc7cb1a1 2003-11-23 devnull case 'b':
150 bc7cb1a1 2003-11-23 devnull if((count *= 1024) < 0)
151 bc7cb1a1 2003-11-23 devnull fatal("too big");
152 bc7cb1a1 2003-11-23 devnull case 'c':
153 bc7cb1a1 2003-11-23 devnull units = CHARS;
154 bc7cb1a1 2003-11-23 devnull case 'l':
155 bc7cb1a1 2003-11-23 devnull s++;
156 bc7cb1a1 2003-11-23 devnull }
157 bc7cb1a1 2003-11-23 devnull switch(*s) {
158 bc7cb1a1 2003-11-23 devnull case 'r':
159 bc7cb1a1 2003-11-23 devnull dir = REV;
160 bc7cb1a1 2003-11-23 devnull return;
161 bc7cb1a1 2003-11-23 devnull case 'f':
162 bc7cb1a1 2003-11-23 devnull follow++;
163 bc7cb1a1 2003-11-23 devnull return;
164 bc7cb1a1 2003-11-23 devnull case 0:
165 bc7cb1a1 2003-11-23 devnull return;
166 bc7cb1a1 2003-11-23 devnull }
167 bc7cb1a1 2003-11-23 devnull usage();
168 bc7cb1a1 2003-11-23 devnull }
169 bc7cb1a1 2003-11-23 devnull
170 bc7cb1a1 2003-11-23 devnull /*
171 bc7cb1a1 2003-11-23 devnull * read past head of the file to find tail
172 bc7cb1a1 2003-11-23 devnull */
173 bc7cb1a1 2003-11-23 devnull void
174 bc7cb1a1 2003-11-23 devnull skip(void)
175 bc7cb1a1 2003-11-23 devnull {
176 bc7cb1a1 2003-11-23 devnull int i;
177 bc7cb1a1 2003-11-23 devnull long n;
178 bc7cb1a1 2003-11-23 devnull char buf[Bsize];
179 bc7cb1a1 2003-11-23 devnull if(units == CHARS) {
180 bc7cb1a1 2003-11-23 devnull for( ; count>0; count -=n) {
181 bc7cb1a1 2003-11-23 devnull n = count<Bsize? count: Bsize;
182 bc7cb1a1 2003-11-23 devnull if(!(n = tread(buf, n)))
183 bc7cb1a1 2003-11-23 devnull return;
184 bc7cb1a1 2003-11-23 devnull }
185 bc7cb1a1 2003-11-23 devnull } else /*units == LINES*/ {
186 bc7cb1a1 2003-11-23 devnull n = i = 0;
187 bc7cb1a1 2003-11-23 devnull while(count > 0) {
188 bc7cb1a1 2003-11-23 devnull if(!(n = tread(buf, Bsize)))
189 bc7cb1a1 2003-11-23 devnull return;
190 bc7cb1a1 2003-11-23 devnull for(i=0; i<n && count>0; i++)
191 bc7cb1a1 2003-11-23 devnull if(buf[i]=='\n')
192 bc7cb1a1 2003-11-23 devnull count--;
193 bc7cb1a1 2003-11-23 devnull }
194 bc7cb1a1 2003-11-23 devnull twrite(buf+i, n-i);
195 bc7cb1a1 2003-11-23 devnull }
196 bc7cb1a1 2003-11-23 devnull copy();
197 bc7cb1a1 2003-11-23 devnull }
198 bc7cb1a1 2003-11-23 devnull
199 bc7cb1a1 2003-11-23 devnull void
200 bc7cb1a1 2003-11-23 devnull copy(void)
201 bc7cb1a1 2003-11-23 devnull {
202 bc7cb1a1 2003-11-23 devnull long n;
203 bc7cb1a1 2003-11-23 devnull char buf[Bsize];
204 bc7cb1a1 2003-11-23 devnull while((n=tread(buf, Bsize)) > 0) {
205 bc7cb1a1 2003-11-23 devnull twrite(buf, n);
206 bc7cb1a1 2003-11-23 devnull Bflush(&bout); /* for FWD on pipe; else harmless */
207 bc7cb1a1 2003-11-23 devnull }
208 bc7cb1a1 2003-11-23 devnull }
209 bc7cb1a1 2003-11-23 devnull
210 bc7cb1a1 2003-11-23 devnull /*
211 bc7cb1a1 2003-11-23 devnull * read whole file, keeping the tail
212 bc7cb1a1 2003-11-23 devnull * complexity is length(file)*length(tail).
213 bc7cb1a1 2003-11-23 devnull * could be linear.
214 bc7cb1a1 2003-11-23 devnull */
215 bc7cb1a1 2003-11-23 devnull void
216 bc7cb1a1 2003-11-23 devnull keep(void)
217 bc7cb1a1 2003-11-23 devnull {
218 bc7cb1a1 2003-11-23 devnull int len = 0;
219 bc7cb1a1 2003-11-23 devnull long bufsiz = 0;
220 bc7cb1a1 2003-11-23 devnull char *buf = 0;
221 bc7cb1a1 2003-11-23 devnull int j, k, n;
222 bc7cb1a1 2003-11-23 devnull
223 bc7cb1a1 2003-11-23 devnull for(n=1; n;) {
224 bc7cb1a1 2003-11-23 devnull if(len+Bsize > bufsiz) {
225 bc7cb1a1 2003-11-23 devnull bufsiz += 2*Bsize;
226 bc7cb1a1 2003-11-23 devnull if(!(buf = realloc(buf, bufsiz+1)))
227 bc7cb1a1 2003-11-23 devnull fatal("out of space");
228 bc7cb1a1 2003-11-23 devnull }
229 bc7cb1a1 2003-11-23 devnull for(; n && len<bufsiz; len+=n)
230 bc7cb1a1 2003-11-23 devnull n = tread(buf+len, bufsiz-len);
231 bc7cb1a1 2003-11-23 devnull if(count >= len)
232 bc7cb1a1 2003-11-23 devnull continue;
233 bc7cb1a1 2003-11-23 devnull if(units == CHARS)
234 bc7cb1a1 2003-11-23 devnull j = len - count;
235 bc7cb1a1 2003-11-23 devnull else {
236 bc7cb1a1 2003-11-23 devnull /* units == LINES */
237 bc7cb1a1 2003-11-23 devnull j = buf[len-1]=='\n'? len-1: len;
238 bc7cb1a1 2003-11-23 devnull for(k=0; j>0; j--)
239 bc7cb1a1 2003-11-23 devnull if(buf[j-1] == '\n')
240 bc7cb1a1 2003-11-23 devnull if(++k >= count)
241 bc7cb1a1 2003-11-23 devnull break;
242 bc7cb1a1 2003-11-23 devnull }
243 bc7cb1a1 2003-11-23 devnull memmove(buf, buf+j, len-=j);
244 bc7cb1a1 2003-11-23 devnull }
245 bc7cb1a1 2003-11-23 devnull if(dir == REV) {
246 bc7cb1a1 2003-11-23 devnull if(len>0 && buf[len-1]!='\n')
247 bc7cb1a1 2003-11-23 devnull buf[len++] = '\n';
248 bc7cb1a1 2003-11-23 devnull for(j=len-1 ; j>0; j--)
249 bc7cb1a1 2003-11-23 devnull if(buf[j-1] == '\n') {
250 bc7cb1a1 2003-11-23 devnull twrite(buf+j, len-j);
251 bc7cb1a1 2003-11-23 devnull if(--count <= 0)
252 bc7cb1a1 2003-11-23 devnull return;
253 bc7cb1a1 2003-11-23 devnull len = j;
254 bc7cb1a1 2003-11-23 devnull }
255 bc7cb1a1 2003-11-23 devnull }
256 bc7cb1a1 2003-11-23 devnull if(count > 0)
257 bc7cb1a1 2003-11-23 devnull twrite(buf, len);
258 bc7cb1a1 2003-11-23 devnull }
259 bc7cb1a1 2003-11-23 devnull
260 bc7cb1a1 2003-11-23 devnull /*
261 bc7cb1a1 2003-11-23 devnull * count backward and print tail of file
262 bc7cb1a1 2003-11-23 devnull */
263 bc7cb1a1 2003-11-23 devnull void
264 bc7cb1a1 2003-11-23 devnull reverse(void)
265 bc7cb1a1 2003-11-23 devnull {
266 bc7cb1a1 2003-11-23 devnull int first;
267 bc7cb1a1 2003-11-23 devnull long len = 0;
268 bc7cb1a1 2003-11-23 devnull long n = 0;
269 bc7cb1a1 2003-11-23 devnull long bufsiz = 0;
270 bc7cb1a1 2003-11-23 devnull char *buf = 0;
271 b707cb51 2004-06-13 devnull vlong pos = tseek(0L, 2);
272 bc7cb1a1 2003-11-23 devnull
273 bc7cb1a1 2003-11-23 devnull for(first=1; pos>0 && count>0; first=0) {
274 bc7cb1a1 2003-11-23 devnull n = pos>Bsize? Bsize: (int)pos;
275 bc7cb1a1 2003-11-23 devnull pos -= n;
276 bc7cb1a1 2003-11-23 devnull if(len+n > bufsiz) {
277 bc7cb1a1 2003-11-23 devnull bufsiz += 2*Bsize;
278 bc7cb1a1 2003-11-23 devnull if(!(buf = realloc(buf, bufsiz+1)))
279 bc7cb1a1 2003-11-23 devnull fatal("out of space");
280 bc7cb1a1 2003-11-23 devnull }
281 bc7cb1a1 2003-11-23 devnull memmove(buf+n, buf, len);
282 bc7cb1a1 2003-11-23 devnull len += n;
283 bc7cb1a1 2003-11-23 devnull tseek(pos, 0);
284 bc7cb1a1 2003-11-23 devnull if(tread(buf, n) != n)
285 bc7cb1a1 2003-11-23 devnull fatal("length error");
286 bc7cb1a1 2003-11-23 devnull if(first && buf[len-1]!='\n')
287 bc7cb1a1 2003-11-23 devnull buf[len++] = '\n';
288 bc7cb1a1 2003-11-23 devnull for(n=len-1 ; n>0 && count>0; n--)
289 bc7cb1a1 2003-11-23 devnull if(buf[n-1] == '\n') {
290 bc7cb1a1 2003-11-23 devnull count--;
291 bc7cb1a1 2003-11-23 devnull if(dir == REV)
292 bc7cb1a1 2003-11-23 devnull twrite(buf+n, len-n);
293 bc7cb1a1 2003-11-23 devnull len = n;
294 bc7cb1a1 2003-11-23 devnull }
295 bc7cb1a1 2003-11-23 devnull }
296 bc7cb1a1 2003-11-23 devnull if(dir == FWD) {
297 bc7cb1a1 2003-11-23 devnull tseek(n==0? 0 : pos+n+1, 0);
298 bc7cb1a1 2003-11-23 devnull copy();
299 bc7cb1a1 2003-11-23 devnull } else
300 bc7cb1a1 2003-11-23 devnull if(count > 0)
301 bc7cb1a1 2003-11-23 devnull twrite(buf, len);
302 bc7cb1a1 2003-11-23 devnull }
303 bc7cb1a1 2003-11-23 devnull
304 b707cb51 2004-06-13 devnull vlong
305 b707cb51 2004-06-13 devnull tseek(vlong o, int p)
306 bc7cb1a1 2003-11-23 devnull {
307 bc7cb1a1 2003-11-23 devnull o = seek(file, o, p);
308 bc7cb1a1 2003-11-23 devnull if(o == -1)
309 bc7cb1a1 2003-11-23 devnull fatal("");
310 bc7cb1a1 2003-11-23 devnull return o;
311 bc7cb1a1 2003-11-23 devnull }
312 bc7cb1a1 2003-11-23 devnull
313 bc7cb1a1 2003-11-23 devnull long
314 bc7cb1a1 2003-11-23 devnull tread(char *buf, long n)
315 bc7cb1a1 2003-11-23 devnull {
316 bc7cb1a1 2003-11-23 devnull int r = read(file, buf, n);
317 bc7cb1a1 2003-11-23 devnull if(r == -1)
318 bc7cb1a1 2003-11-23 devnull fatal("");
319 bc7cb1a1 2003-11-23 devnull return r;
320 bc7cb1a1 2003-11-23 devnull }
321 bc7cb1a1 2003-11-23 devnull
322 bc7cb1a1 2003-11-23 devnull void
323 bc7cb1a1 2003-11-23 devnull twrite(char *s, long n)
324 bc7cb1a1 2003-11-23 devnull {
325 bc7cb1a1 2003-11-23 devnull if(Bwrite(&bout, s, n) != n)
326 bc7cb1a1 2003-11-23 devnull fatal("");
327 bc7cb1a1 2003-11-23 devnull }
328 bc7cb1a1 2003-11-23 devnull
329 bc7cb1a1 2003-11-23 devnull int
330 bc7cb1a1 2003-11-23 devnull getnumber(char *s)
331 bc7cb1a1 2003-11-23 devnull {
332 bc7cb1a1 2003-11-23 devnull if(*s=='-' || *s=='+')
333 bc7cb1a1 2003-11-23 devnull s++;
334 1c171e3a 2005-07-19 devnull if(!isdigit((uchar)*s))
335 bc7cb1a1 2003-11-23 devnull return 0;
336 bc7cb1a1 2003-11-23 devnull if(s[-1] == '+')
337 bc7cb1a1 2003-11-23 devnull origin = BEG;
338 bc7cb1a1 2003-11-23 devnull if(anycount++)
339 bc7cb1a1 2003-11-23 devnull fatal("excess option");
340 bc7cb1a1 2003-11-23 devnull count = atol(s);
341 bc7cb1a1 2003-11-23 devnull
342 bc7cb1a1 2003-11-23 devnull /* check range of count */
343 1c171e3a 2005-07-19 devnull if(count < 0 || (int)count != count)
344 bc7cb1a1 2003-11-23 devnull fatal("too big");
345 bc7cb1a1 2003-11-23 devnull return 1;
346 fa325e9b 2020-01-10 cross }
347 bc7cb1a1 2003-11-23 devnull
348 fa325e9b 2020-01-10 cross void
349 bc7cb1a1 2003-11-23 devnull fatal(char *s)
350 bc7cb1a1 2003-11-23 devnull {
351 bc7cb1a1 2003-11-23 devnull char buf[ERRMAX];
352 bc7cb1a1 2003-11-23 devnull
353 bc7cb1a1 2003-11-23 devnull errstr(buf, sizeof buf);
354 bc7cb1a1 2003-11-23 devnull fprint(2, "tail: %s: %s\n", s, buf);
355 bc7cb1a1 2003-11-23 devnull exits(s);
356 bc7cb1a1 2003-11-23 devnull }
357 bc7cb1a1 2003-11-23 devnull
358 bc7cb1a1 2003-11-23 devnull void
359 bc7cb1a1 2003-11-23 devnull usage(void)
360 bc7cb1a1 2003-11-23 devnull {
361 bc7cb1a1 2003-11-23 devnull fprint(2, "%s\n", umsg);
362 bc7cb1a1 2003-11-23 devnull exits("usage");
363 bc7cb1a1 2003-11-23 devnull }