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