1*17708Sbloom #ifndef lint 2*17708Sbloom static char *sccsid = "@(#)tail.c 4.6 (Berkeley) 01/14/85"; 3*17708Sbloom #endif 41214Sroot /* tail command 51214Sroot * 61214Sroot * tail where [file] 713537Ssam * where is +/-n[type] 81214Sroot * - means n lines before end 91214Sroot * + means nth line from beginning 101214Sroot * type 'b' means tail n blocks, not lines 111214Sroot * type 'c' means tail n characters 121214Sroot * Type 'r' means in lines in reverse order from end 131214Sroot * (for -r, default is entire buffer ) 141214Sroot * option 'f' means loop endlessly trying to read more 151214Sroot * characters after the end of file, on the assumption 161214Sroot * that the file is growing 171214Sroot */ 181214Sroot 191214Sroot #include <stdio.h> 201214Sroot #include <ctype.h> 211214Sroot #include <sys/types.h> 221214Sroot #include <sys/stat.h> 23*17708Sbloom #include <sys/file.h> 241214Sroot #include <errno.h> 251214Sroot 2616583Sralph #define LBIN 8193 2716583Sralph #undef BUFSIZ 2816583Sralph #define BUFSIZ LBIN-1 291214Sroot struct stat statb; 301214Sroot int follow; 311214Sroot int piped; 321214Sroot char bin[LBIN]; 331214Sroot int errno; 341214Sroot 351214Sroot main(argc,argv) 361214Sroot char **argv; 371214Sroot { 381214Sroot long n,di; 391214Sroot register i,j,k; 401214Sroot char *arg; 411214Sroot int partial,bylines,bkwds,fromend,lastnl; 421214Sroot char *p; 431214Sroot 441214Sroot arg = argv[1]; 451214Sroot if(argc<=1 || *arg!='-'&&*arg!='+') { 461214Sroot arg = "-10l"; 471214Sroot argc++; 481214Sroot argv--; 491214Sroot } 501214Sroot fromend = *arg=='-'; 511214Sroot arg++; 5214806Skarels if (isdigit(*arg)) { 5314806Skarels n = 0; 5414806Skarels while(isdigit(*arg)) 5514806Skarels n = n*10 + *arg++ - '0'; 5614806Skarels } else 5714806Skarels n = -1; 581214Sroot if(!fromend&&n>0) 591214Sroot n--; 601214Sroot if(argc>2) { 61*17708Sbloom (void)close(0); 621214Sroot if(open(argv[2],0)!=0) { 631214Sroot perror(argv[2]); 641214Sroot exit(1); 651214Sroot } 661214Sroot } 67*17708Sbloom (void)lseek(0,(off_t)0,L_INCR); 6812889Sralph piped = errno==ESPIPE; 691214Sroot bylines = -1; bkwds = 0; 701214Sroot while(*arg) 711214Sroot switch(*arg++) { 721214Sroot 731214Sroot case 'b': 7416583Sralph if (n == -1) n = 1; 751214Sroot n <<= 9; 761214Sroot if(bylines!=-1) goto errcom; 771214Sroot bylines=0; 781214Sroot break; 791214Sroot case 'c': 801214Sroot if(bylines!=-1) goto errcom; 811214Sroot bylines=0; 821214Sroot break; 831214Sroot case 'f': 841214Sroot follow = 1; 851214Sroot break; 861214Sroot case 'r': 8714806Skarels if(n==-1) n = LBIN; 881214Sroot bkwds = 1; fromend = 1; bylines = 1; 891214Sroot break; 901214Sroot case 'l': 911214Sroot if(bylines!=-1) goto errcom; 921214Sroot bylines = 1; 931214Sroot break; 941214Sroot default: 951214Sroot goto errcom; 961214Sroot } 9714806Skarels if (n==-1) n = 10; 981214Sroot if(bylines==-1) bylines = 1; 991214Sroot if(bkwds) follow=0; 1001214Sroot if(fromend) 1011214Sroot goto keep; 1021214Sroot 1031214Sroot /*seek from beginning */ 1041214Sroot 1051214Sroot if(bylines) { 1061214Sroot j = 0; 1071214Sroot while(n-->0) { 1081214Sroot do { 1091214Sroot if(j--<=0) { 1101214Sroot p = bin; 1111214Sroot j = read(0,p,BUFSIZ); 1121214Sroot if(j--<=0) 1131214Sroot fexit(); 1141214Sroot } 1151214Sroot } while(*p++ != '\n'); 1161214Sroot } 117*17708Sbloom (void)write(1,p,j); 1181214Sroot } else if(n>0) { 1191214Sroot if(!piped) 120*17708Sbloom (void)fstat(0,&statb); 1211214Sroot if(piped||(statb.st_mode&S_IFMT)==S_IFCHR) 1221214Sroot while(n>0) { 1231214Sroot i = n>BUFSIZ?BUFSIZ:n; 1241214Sroot i = read(0,bin,i); 1251214Sroot if(i<=0) 1261214Sroot fexit(); 1271214Sroot n -= i; 1281214Sroot } 1291214Sroot else 130*17708Sbloom (void)lseek(0,(off_t)n,L_SET); 1311214Sroot } 1321214Sroot copy: 1331214Sroot while((i=read(0,bin,BUFSIZ))>0) 134*17708Sbloom (void)write(1,bin,i); 1351214Sroot fexit(); 1361214Sroot 1371214Sroot /*seek from end*/ 1381214Sroot 1391214Sroot keep: 1401214Sroot if(n <= 0) 1411214Sroot fexit(); 1421214Sroot if(!piped) { 143*17708Sbloom (void)fstat(0,&statb); 14416583Sralph /* If by lines, back up 1 buffer: else back up as needed */ 14516583Sralph di = bylines?BUFSIZ:n; 1461214Sroot if(statb.st_size > di) 147*17708Sbloom (void)lseek(0,(off_t)-di,L_XTND); 1481214Sroot if(!bylines) 1491214Sroot goto copy; 1501214Sroot } 1511214Sroot partial = 1; 1521214Sroot for(;;) { 1531214Sroot i = 0; 1541214Sroot do { 1551214Sroot j = read(0,&bin[i],LBIN-i); 1561214Sroot if(j<=0) 1571214Sroot goto brka; 1581214Sroot i += j; 1591214Sroot } while(i<LBIN); 1601214Sroot partial = 0; 1611214Sroot } 1621214Sroot brka: 1631214Sroot if(!bylines) { 1641214Sroot k = 1651214Sroot n<=i ? i-n: 1661214Sroot partial ? 0: 1671214Sroot n>=LBIN ? i+1: 1681214Sroot i-n+LBIN; 1691214Sroot k--; 1701214Sroot } else { 1711214Sroot if(bkwds && bin[i==0?LBIN-1:i-1]!='\n'){ /* force trailing newline */ 1721214Sroot bin[i]='\n'; 1731214Sroot if(++i>=LBIN) {i = 0; partial = 0;} 1741214Sroot } 1751214Sroot k = i; 1761214Sroot j = 0; 1771214Sroot do { 1781214Sroot lastnl = k; 1791214Sroot do { 1801214Sroot if(--k<0) { 1811214Sroot if(partial) { 182*17708Sbloom if(bkwds) 183*17708Sbloom (void)write(1,bin,lastnl+1); 1841214Sroot goto brkb; 1851214Sroot } 1861214Sroot k = LBIN -1; 1871214Sroot } 1881214Sroot } while(bin[k]!='\n'&&k!=i); 1891214Sroot if(bkwds && j>0){ 190*17708Sbloom if(k<lastnl) (void)write(1,&bin[k+1],lastnl-k); 1911214Sroot else { 192*17708Sbloom (void)write(1,&bin[k+1],LBIN-k-1); 193*17708Sbloom (void)write(1,bin,lastnl+1); 1941214Sroot } 1951214Sroot } 1961214Sroot } while(j++<n&&k!=i); 1971214Sroot brkb: 1981214Sroot if(bkwds) exit(0); 1991214Sroot if(k==i) do { 2001214Sroot if(++k>=LBIN) 2011214Sroot k = 0; 2021214Sroot } while(bin[k]!='\n'&&k!=i); 2031214Sroot } 2041214Sroot if(k<i) 205*17708Sbloom (void)write(1,&bin[k+1],i-k-1); 2061214Sroot else { 207*17708Sbloom (void)write(1,&bin[k+1],LBIN-k-1); 208*17708Sbloom (void)write(1,bin,i); 2091214Sroot } 2101214Sroot fexit(); 2111214Sroot errcom: 2121214Sroot fprintf(stderr, "usage: tail [+_[n][lbc][rf]] [file]\n"); 2131214Sroot exit(2); 2141214Sroot } 2151214Sroot 2161214Sroot fexit() 2171214Sroot { register int n; 2181214Sroot if (!follow || piped) exit(0); 2191214Sroot for (;;) 2201214Sroot { sleep(1); 2211214Sroot while ((n = read (0, bin, BUFSIZ)) > 0) 222*17708Sbloom (void)write (1, bin, n); 2231214Sroot } 2241214Sroot } 225