1*21579Sdist /* 2*21579Sdist * Copyright (c) 1980 Regents of the University of California. 3*21579Sdist * All rights reserved. The Berkeley software License Agreement 4*21579Sdist * specifies the terms and conditions for redistribution. 5*21579Sdist */ 6*21579Sdist 717708Sbloom #ifndef lint 8*21579Sdist char copyright[] = 9*21579Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 10*21579Sdist All rights reserved.\n"; 11*21579Sdist #endif not lint 12*21579Sdist 13*21579Sdist #ifndef lint 14*21579Sdist static char sccsid[] = "@(#)tail.c 5.1 (Berkeley) 05/31/85"; 15*21579Sdist #endif not lint 16*21579Sdist 171214Sroot /* tail command 181214Sroot * 191214Sroot * tail where [file] 2013537Ssam * where is +/-n[type] 211214Sroot * - means n lines before end 221214Sroot * + means nth line from beginning 231214Sroot * type 'b' means tail n blocks, not lines 241214Sroot * type 'c' means tail n characters 251214Sroot * Type 'r' means in lines in reverse order from end 261214Sroot * (for -r, default is entire buffer ) 271214Sroot * option 'f' means loop endlessly trying to read more 281214Sroot * characters after the end of file, on the assumption 291214Sroot * that the file is growing 301214Sroot */ 311214Sroot 321214Sroot #include <stdio.h> 331214Sroot #include <ctype.h> 341214Sroot #include <sys/types.h> 351214Sroot #include <sys/stat.h> 3617708Sbloom #include <sys/file.h> 371214Sroot #include <errno.h> 381214Sroot 3916583Sralph #define LBIN 8193 4016583Sralph #undef BUFSIZ 4116583Sralph #define BUFSIZ LBIN-1 421214Sroot struct stat statb; 431214Sroot int follow; 441214Sroot int piped; 451214Sroot char bin[LBIN]; 461214Sroot int errno; 471214Sroot 481214Sroot main(argc,argv) 491214Sroot char **argv; 501214Sroot { 511214Sroot long n,di; 521214Sroot register i,j,k; 531214Sroot char *arg; 541214Sroot int partial,bylines,bkwds,fromend,lastnl; 551214Sroot char *p; 561214Sroot 571214Sroot arg = argv[1]; 581214Sroot if(argc<=1 || *arg!='-'&&*arg!='+') { 591214Sroot arg = "-10l"; 601214Sroot argc++; 611214Sroot argv--; 621214Sroot } 631214Sroot fromend = *arg=='-'; 641214Sroot arg++; 6514806Skarels if (isdigit(*arg)) { 6614806Skarels n = 0; 6714806Skarels while(isdigit(*arg)) 6814806Skarels n = n*10 + *arg++ - '0'; 6914806Skarels } else 7014806Skarels n = -1; 711214Sroot if(!fromend&&n>0) 721214Sroot n--; 731214Sroot if(argc>2) { 7417708Sbloom (void)close(0); 751214Sroot if(open(argv[2],0)!=0) { 761214Sroot perror(argv[2]); 771214Sroot exit(1); 781214Sroot } 791214Sroot } 8017708Sbloom (void)lseek(0,(off_t)0,L_INCR); 8112889Sralph piped = errno==ESPIPE; 821214Sroot bylines = -1; bkwds = 0; 831214Sroot while(*arg) 841214Sroot switch(*arg++) { 851214Sroot 861214Sroot case 'b': 8716583Sralph if (n == -1) n = 1; 881214Sroot n <<= 9; 891214Sroot if(bylines!=-1) goto errcom; 901214Sroot bylines=0; 911214Sroot break; 921214Sroot case 'c': 931214Sroot if(bylines!=-1) goto errcom; 941214Sroot bylines=0; 951214Sroot break; 961214Sroot case 'f': 971214Sroot follow = 1; 981214Sroot break; 991214Sroot case 'r': 10014806Skarels if(n==-1) n = LBIN; 1011214Sroot bkwds = 1; fromend = 1; bylines = 1; 1021214Sroot break; 1031214Sroot case 'l': 1041214Sroot if(bylines!=-1) goto errcom; 1051214Sroot bylines = 1; 1061214Sroot break; 1071214Sroot default: 1081214Sroot goto errcom; 1091214Sroot } 11014806Skarels if (n==-1) n = 10; 1111214Sroot if(bylines==-1) bylines = 1; 1121214Sroot if(bkwds) follow=0; 1131214Sroot if(fromend) 1141214Sroot goto keep; 1151214Sroot 1161214Sroot /*seek from beginning */ 1171214Sroot 1181214Sroot if(bylines) { 1191214Sroot j = 0; 1201214Sroot while(n-->0) { 1211214Sroot do { 1221214Sroot if(j--<=0) { 1231214Sroot p = bin; 1241214Sroot j = read(0,p,BUFSIZ); 1251214Sroot if(j--<=0) 1261214Sroot fexit(); 1271214Sroot } 1281214Sroot } while(*p++ != '\n'); 1291214Sroot } 13017708Sbloom (void)write(1,p,j); 1311214Sroot } else if(n>0) { 1321214Sroot if(!piped) 13317708Sbloom (void)fstat(0,&statb); 1341214Sroot if(piped||(statb.st_mode&S_IFMT)==S_IFCHR) 1351214Sroot while(n>0) { 1361214Sroot i = n>BUFSIZ?BUFSIZ:n; 1371214Sroot i = read(0,bin,i); 1381214Sroot if(i<=0) 1391214Sroot fexit(); 1401214Sroot n -= i; 1411214Sroot } 1421214Sroot else 14317708Sbloom (void)lseek(0,(off_t)n,L_SET); 1441214Sroot } 1451214Sroot copy: 1461214Sroot while((i=read(0,bin,BUFSIZ))>0) 14717708Sbloom (void)write(1,bin,i); 1481214Sroot fexit(); 1491214Sroot 1501214Sroot /*seek from end*/ 1511214Sroot 1521214Sroot keep: 1531214Sroot if(n <= 0) 1541214Sroot fexit(); 1551214Sroot if(!piped) { 15617708Sbloom (void)fstat(0,&statb); 15716583Sralph /* If by lines, back up 1 buffer: else back up as needed */ 15816583Sralph di = bylines?BUFSIZ:n; 1591214Sroot if(statb.st_size > di) 16017708Sbloom (void)lseek(0,(off_t)-di,L_XTND); 1611214Sroot if(!bylines) 1621214Sroot goto copy; 1631214Sroot } 1641214Sroot partial = 1; 1651214Sroot for(;;) { 1661214Sroot i = 0; 1671214Sroot do { 1681214Sroot j = read(0,&bin[i],LBIN-i); 1691214Sroot if(j<=0) 1701214Sroot goto brka; 1711214Sroot i += j; 1721214Sroot } while(i<LBIN); 1731214Sroot partial = 0; 1741214Sroot } 1751214Sroot brka: 1761214Sroot if(!bylines) { 1771214Sroot k = 1781214Sroot n<=i ? i-n: 1791214Sroot partial ? 0: 1801214Sroot n>=LBIN ? i+1: 1811214Sroot i-n+LBIN; 1821214Sroot k--; 1831214Sroot } else { 1841214Sroot if(bkwds && bin[i==0?LBIN-1:i-1]!='\n'){ /* force trailing newline */ 1851214Sroot bin[i]='\n'; 1861214Sroot if(++i>=LBIN) {i = 0; partial = 0;} 1871214Sroot } 1881214Sroot k = i; 1891214Sroot j = 0; 1901214Sroot do { 1911214Sroot lastnl = k; 1921214Sroot do { 1931214Sroot if(--k<0) { 1941214Sroot if(partial) { 19517708Sbloom if(bkwds) 19617708Sbloom (void)write(1,bin,lastnl+1); 1971214Sroot goto brkb; 1981214Sroot } 1991214Sroot k = LBIN -1; 2001214Sroot } 2011214Sroot } while(bin[k]!='\n'&&k!=i); 2021214Sroot if(bkwds && j>0){ 20317708Sbloom if(k<lastnl) (void)write(1,&bin[k+1],lastnl-k); 2041214Sroot else { 20517708Sbloom (void)write(1,&bin[k+1],LBIN-k-1); 20617708Sbloom (void)write(1,bin,lastnl+1); 2071214Sroot } 2081214Sroot } 2091214Sroot } while(j++<n&&k!=i); 2101214Sroot brkb: 2111214Sroot if(bkwds) exit(0); 2121214Sroot if(k==i) do { 2131214Sroot if(++k>=LBIN) 2141214Sroot k = 0; 2151214Sroot } while(bin[k]!='\n'&&k!=i); 2161214Sroot } 2171214Sroot if(k<i) 21817708Sbloom (void)write(1,&bin[k+1],i-k-1); 2191214Sroot else { 22017708Sbloom (void)write(1,&bin[k+1],LBIN-k-1); 22117708Sbloom (void)write(1,bin,i); 2221214Sroot } 2231214Sroot fexit(); 2241214Sroot errcom: 2251214Sroot fprintf(stderr, "usage: tail [+_[n][lbc][rf]] [file]\n"); 2261214Sroot exit(2); 2271214Sroot } 2281214Sroot 2291214Sroot fexit() 2301214Sroot { register int n; 2311214Sroot if (!follow || piped) exit(0); 2321214Sroot for (;;) 2331214Sroot { sleep(1); 2341214Sroot while ((n = read (0, bin, BUFSIZ)) > 0) 23517708Sbloom (void)write (1, bin, n); 2361214Sroot } 2371214Sroot } 238