1*48313Sbostic /*- 2*48313Sbostic * Copyright (c) 1980 The Regents of the University of California. 3*48313Sbostic * All rights reserved. 4*48313Sbostic * 5*48313Sbostic * %sccs.include.proprietary.c% 621579Sdist */ 721579Sdist 817708Sbloom #ifndef lint 921579Sdist char copyright[] = 10*48313Sbostic "@(#) Copyright (c) 1980 The Regents of the University of California.\n\ 1121579Sdist All rights reserved.\n"; 12*48313Sbostic #endif /* not lint */ 1321579Sdist 1421579Sdist #ifndef lint 15*48313Sbostic static char sccsid[] = "@(#)tail.c 5.4 (Berkeley) 04/18/91"; 16*48313Sbostic #endif /* not lint */ 1721579Sdist 181214Sroot /* tail command 191214Sroot * 201214Sroot * tail where [file] 2113537Ssam * where is +/-n[type] 221214Sroot * - means n lines before end 231214Sroot * + means nth line from beginning 241214Sroot * type 'b' means tail n blocks, not lines 251214Sroot * type 'c' means tail n characters 261214Sroot * Type 'r' means in lines in reverse order from end 271214Sroot * (for -r, default is entire buffer ) 281214Sroot * option 'f' means loop endlessly trying to read more 291214Sroot * characters after the end of file, on the assumption 301214Sroot * that the file is growing 311214Sroot */ 321214Sroot 331214Sroot #include <stdio.h> 341214Sroot #include <ctype.h> 351214Sroot #include <sys/types.h> 361214Sroot #include <sys/stat.h> 3717708Sbloom #include <sys/file.h> 381214Sroot #include <errno.h> 391214Sroot 4025804Slepreau #define LBIN 32769 4116583Sralph #undef BUFSIZ 4225804Slepreau #define BUFSIZ 8192 431214Sroot struct stat statb; 441214Sroot int follow; 451214Sroot int piped; 461214Sroot char bin[LBIN]; 471214Sroot int errno; 481214Sroot 491214Sroot main(argc,argv) 501214Sroot char **argv; 511214Sroot { 521214Sroot long n,di; 531214Sroot register i,j,k; 541214Sroot char *arg; 551214Sroot int partial,bylines,bkwds,fromend,lastnl; 561214Sroot char *p; 571214Sroot 581214Sroot arg = argv[1]; 591214Sroot if(argc<=1 || *arg!='-'&&*arg!='+') { 601214Sroot arg = "-10l"; 611214Sroot argc++; 621214Sroot argv--; 631214Sroot } 641214Sroot fromend = *arg=='-'; 651214Sroot arg++; 6614806Skarels if (isdigit(*arg)) { 6714806Skarels n = 0; 6814806Skarels while(isdigit(*arg)) 6914806Skarels n = n*10 + *arg++ - '0'; 7014806Skarels } else 7114806Skarels n = -1; 721214Sroot if(!fromend&&n>0) 731214Sroot n--; 741214Sroot if(argc>2) { 7517708Sbloom (void)close(0); 761214Sroot if(open(argv[2],0)!=0) { 771214Sroot perror(argv[2]); 781214Sroot exit(1); 791214Sroot } 801214Sroot } 8117708Sbloom (void)lseek(0,(off_t)0,L_INCR); 8212889Sralph piped = errno==ESPIPE; 831214Sroot bylines = -1; bkwds = 0; 841214Sroot while(*arg) 851214Sroot switch(*arg++) { 861214Sroot 871214Sroot case 'b': 8816583Sralph if (n == -1) n = 1; 891214Sroot n <<= 9; 901214Sroot if(bylines!=-1) goto errcom; 911214Sroot bylines=0; 921214Sroot break; 931214Sroot case 'c': 941214Sroot if(bylines!=-1) goto errcom; 951214Sroot bylines=0; 961214Sroot break; 971214Sroot case 'f': 981214Sroot follow = 1; 991214Sroot break; 1001214Sroot case 'r': 10114806Skarels if(n==-1) n = LBIN; 1021214Sroot bkwds = 1; fromend = 1; bylines = 1; 1031214Sroot break; 1041214Sroot case 'l': 1051214Sroot if(bylines!=-1) goto errcom; 1061214Sroot bylines = 1; 1071214Sroot break; 1081214Sroot default: 1091214Sroot goto errcom; 1101214Sroot } 11114806Skarels if (n==-1) n = 10; 1121214Sroot if(bylines==-1) bylines = 1; 1131214Sroot if(bkwds) follow=0; 1141214Sroot if(fromend) 1151214Sroot goto keep; 1161214Sroot 1171214Sroot /*seek from beginning */ 1181214Sroot 1191214Sroot if(bylines) { 1201214Sroot j = 0; 1211214Sroot while(n-->0) { 1221214Sroot do { 1231214Sroot if(j--<=0) { 1241214Sroot p = bin; 1251214Sroot j = read(0,p,BUFSIZ); 1261214Sroot if(j--<=0) 1271214Sroot fexit(); 1281214Sroot } 1291214Sroot } while(*p++ != '\n'); 1301214Sroot } 13117708Sbloom (void)write(1,p,j); 1321214Sroot } else if(n>0) { 1331214Sroot if(!piped) 13417708Sbloom (void)fstat(0,&statb); 1351214Sroot if(piped||(statb.st_mode&S_IFMT)==S_IFCHR) 1361214Sroot while(n>0) { 1371214Sroot i = n>BUFSIZ?BUFSIZ:n; 1381214Sroot i = read(0,bin,i); 1391214Sroot if(i<=0) 1401214Sroot fexit(); 1411214Sroot n -= i; 1421214Sroot } 1431214Sroot else 14417708Sbloom (void)lseek(0,(off_t)n,L_SET); 1451214Sroot } 1461214Sroot copy: 1471214Sroot while((i=read(0,bin,BUFSIZ))>0) 14817708Sbloom (void)write(1,bin,i); 1491214Sroot fexit(); 1501214Sroot 1511214Sroot /*seek from end*/ 1521214Sroot 1531214Sroot keep: 1541214Sroot if(n <= 0) 1551214Sroot fexit(); 1561214Sroot if(!piped) { 15717708Sbloom (void)fstat(0,&statb); 15816583Sralph /* If by lines, back up 1 buffer: else back up as needed */ 15925804Slepreau di = bylines?LBIN-1:n; 1601214Sroot if(statb.st_size > di) 16117708Sbloom (void)lseek(0,(off_t)-di,L_XTND); 1621214Sroot if(!bylines) 1631214Sroot goto copy; 1641214Sroot } 1651214Sroot partial = 1; 1661214Sroot for(;;) { 1671214Sroot i = 0; 1681214Sroot do { 1691214Sroot j = read(0,&bin[i],LBIN-i); 1701214Sroot if(j<=0) 1711214Sroot goto brka; 1721214Sroot i += j; 1731214Sroot } while(i<LBIN); 1741214Sroot partial = 0; 1751214Sroot } 1761214Sroot brka: 1771214Sroot if(!bylines) { 1781214Sroot k = 1791214Sroot n<=i ? i-n: 1801214Sroot partial ? 0: 1811214Sroot n>=LBIN ? i+1: 1821214Sroot i-n+LBIN; 1831214Sroot k--; 1841214Sroot } else { 1851214Sroot if(bkwds && bin[i==0?LBIN-1:i-1]!='\n'){ /* force trailing newline */ 1861214Sroot bin[i]='\n'; 1871214Sroot if(++i>=LBIN) {i = 0; partial = 0;} 1881214Sroot } 1891214Sroot k = i; 1901214Sroot j = 0; 1911214Sroot do { 1921214Sroot lastnl = k; 1931214Sroot do { 1941214Sroot if(--k<0) { 1951214Sroot if(partial) { 19617708Sbloom if(bkwds) 19717708Sbloom (void)write(1,bin,lastnl+1); 1981214Sroot goto brkb; 1991214Sroot } 2001214Sroot k = LBIN -1; 2011214Sroot } 2021214Sroot } while(bin[k]!='\n'&&k!=i); 2031214Sroot if(bkwds && j>0){ 20417708Sbloom if(k<lastnl) (void)write(1,&bin[k+1],lastnl-k); 2051214Sroot else { 20617708Sbloom (void)write(1,&bin[k+1],LBIN-k-1); 20717708Sbloom (void)write(1,bin,lastnl+1); 2081214Sroot } 2091214Sroot } 2101214Sroot } while(j++<n&&k!=i); 2111214Sroot brkb: 2121214Sroot if(bkwds) exit(0); 2131214Sroot if(k==i) do { 2141214Sroot if(++k>=LBIN) 2151214Sroot k = 0; 2161214Sroot } while(bin[k]!='\n'&&k!=i); 2171214Sroot } 2181214Sroot if(k<i) 21917708Sbloom (void)write(1,&bin[k+1],i-k-1); 2201214Sroot else { 22117708Sbloom (void)write(1,&bin[k+1],LBIN-k-1); 22217708Sbloom (void)write(1,bin,i); 2231214Sroot } 2241214Sroot fexit(); 2251214Sroot errcom: 2261214Sroot fprintf(stderr, "usage: tail [+_[n][lbc][rf]] [file]\n"); 2271214Sroot exit(2); 2281214Sroot } 2291214Sroot 2301214Sroot fexit() 2311214Sroot { register int n; 2321214Sroot if (!follow || piped) exit(0); 2331214Sroot for (;;) 2341214Sroot { sleep(1); 2351214Sroot while ((n = read (0, bin, BUFSIZ)) > 0) 23630064Skarels if (write (1, bin, n) < 0) 23730064Skarels exit(1); 2381214Sroot } 2391214Sroot } 240