summaryrefslogtreecommitdiff
path: root/usr/src/lib/libcmd/common/tail.c
diff options
context:
space:
mode:
authorRoland Mainz <roland.mainz@nrubsig.org>2009-10-28 10:36:39 -0700
committerRoland Mainz <roland.mainz@nrubsig.org>2009-10-28 10:36:39 -0700
commit34f9b3eef6fdadbda0a846aa4d68691ac40eace5 (patch)
tree0b0fdfb35f8eb9324728de5a99e50e939aca650f /usr/src/lib/libcmd/common/tail.c
parent14969419acb89bb74e6c95fa472119b710224440 (diff)
downloadillumos-joyent-34f9b3eef6fdadbda0a846aa4d68691ac40eace5.tar.gz
Portions contributed by Olga Kryzhanovska <olga.kryzhanovska@gmail.com>
PSARC/2009/063 ksh93 update 2 PSARC/2009/248 ksh93 update to 2009-03-10 PSARC/2009/249 more ksh93 command conversions 6888396 libast sources should not include localedef.h 6605478 ksh93 profile shell option does not work 6631006 ksh93 hangs in situations that ksh handles okay 6661487 logname reports nothing after running the script command 6705126 first call to read doesn't honor new setting of HISTFILE 6764665 *libpp* Array overrun in libpp 6765756 *libast* Array overruns in libast 6769332 Recursive function+command substitutions terminate shell after 257 iterations 6777491 *ksh93* lacks arithmetric function iszero() 6778077 *ksh93* does not understand "THAW" as a signal for use with trap 6789247 [ku1] libast/ksh93 1-digit hexfloat base conversion rounds incorrectly 6791838 *ksh93* unset of a variable which is not set should return 0 6793714 RFE: Update /usr/bin/comm to AT&T AST "comm" 6793719 RFE: Update /usr/bin/cut to AT&T AST "cut" 6793721 RFE: Update /usr/bin/paste to AT&T AST "paste" 6793722 RFE: Update /usr/bin/cmp to AT&T AST "cmp" 6793726 RFE: Update /usr/bin/uniq to AT&T AST "uniq" 6793735 RFE: Update /usr/bin/wc to AT&T AST "wc" 6793744 RFE: Add /usr/share/doc/ksh/ for ksh93 documentation 6793747 RFE: Provide "print" builtin as /usr/bin/print for external applications 6793763 RFE: Update /usr/bin/ksh93 to ast-ksh.2009-05-05 6794952 RFE: Enable "globstar" mode in /etc/ksh.kshrc (= interactive ksh93 shells) 6805792 [ku1] Moving local compound var into array does not work 6805794 [ku1] printf returns "invalid character constant" for $ printf "%d\n" "'<euro>" 6805795 [ku1] ksh93 does not differ between -0 and +0 6805797 [ku1]Can't append to nodes of an array of compound vars if addressing them via nameref 6805799 Indexed compound variable arrays do not work... 6805800 [ku1] Declaring associative compound array does not work 6805813 RFE: Update /usr/bin/join to AT&T AST "join". 6805819 RFE: Update /usr/bin/tee to AT&T AST "tee". 6809663 shlint missing ending newline on errors 6811916 ksh93 repeatedly segfaults when "tee" builtin is interrupted via <ctrl-c> in interactive mode 6821113 SUNWosdem package issues 6828644 RFE: Update /usr/bin/logname to AT&T AST "logname". 6828692 RFE: Update /usr/bin/cksum to AT&T AST "cksum". 6834184 ksh93 gets SIGSEGV if HISTFILE is changed in place. 6834207 ksh93 gets SIGSEGV on interactive function definition with HISTSIZE unset 6835835 ksh93 "cat" builtin does not handle "-n" correctly 6841442 Need exception list for OS/Net trees managed via Subversion 6848486 "echo ${test}" with test undefined crashes the shell 6850672 ksh93 (VISUAL=vi) crashes with memory fault while scrolling through history 6855875 typeset -X x ; print $x # does not print sufficient digits to restore value 6857344 /usr/bin/hash core dump with invalid arguments 6866676 Need test suite module to test the kernel support for compiled shell scripts 6881017 Subshell doesn't exit, holds pipe open preventing callers from exiting 6884409 fts functions in libast library can result in segv with deep dir trees (similar to CERT VU#590371)
Diffstat (limited to 'usr/src/lib/libcmd/common/tail.c')
-rw-r--r--usr/src/lib/libcmd/common/tail.c214
1 files changed, 157 insertions, 57 deletions
diff --git a/usr/src/lib/libcmd/common/tail.c b/usr/src/lib/libcmd/common/tail.c
index 7eb012af7f..ca128f2938 100644
--- a/usr/src/lib/libcmd/common/tail.c
+++ b/usr/src/lib/libcmd/common/tail.c
@@ -1,7 +1,7 @@
/***********************************************************************
* *
* This software is part of the ast package *
-* Copyright (c) 1992-2008 AT&T Intellectual Property *
+* Copyright (c) 1992-2009 AT&T Intellectual Property *
* and is licensed under the *
* Common Public License, Version 1.0 *
* by AT&T Intellectual Property *
@@ -28,7 +28,7 @@
*/
static const char usage[] =
-"+[-?\n@(#)$Id: tail (AT&T Research) 2006-10-18 $\n]"
+"+[-?\n@(#)$Id: tail (AT&T Research) 2009-08-25 $\n]"
USAGE_LICENSE
"[+NAME?tail - output trailing portion of one or more files ]"
"[+DESCRIPTION?\btail\b copies one or more input files to standard output "
@@ -44,21 +44,25 @@ USAGE_LICENSE
"followed by one of the following characters to specify a different "
"unit other than a single byte:]{"
"[+b?512 bytes.]"
- "[+k?1-kilobyte.]"
- "[+m?1-megabyte.]"
+ "[+k?1 KiB.]"
+ "[+m?1 MiB.]"
+ "[+g?1 GiB.]"
"}"
"[+?For backwards compatibility, \b-\b\anumber\a is equivalent to "
"\b-n\b \anumber\a and \b+\b\anumber\a is equivalent to "
- "\b-n -\b\anumber\a.]"
+ "\b-n -\b\anumber\a. \anumber\a may also have these option "
+ "suffixes: \bb c f g k l m r\b.]"
"[n:lines]:[lines:=10?Copy \alines\a lines from each file. A negative value "
- "for \alines\a indicates an offset from the start of the file.]"
+ "for \alines\a indicates an offset from the end of the file.]"
+"[b:blocks?Copy units of 512 bytes.]"
"[c:bytes]:?[chars?Copy \achars\a bytes from each file. A negative value "
- "for \achars\a indicates an offset from the start of the file.]"
+ "for \achars\a indicates an offset from the end of the file.]"
"[f:forever|follow?Loop forever trying to read more characters as the "
"end of each file to copy new data. Ignored if reading from a pipe "
"or fifo.]"
"[h!:headers?Output filename headers.]"
+"[l:lines?Copy units of lines. This is the default.]"
"[L:log?When a \b--forever\b file times out via \b--timeout\b, verify that "
"the curent file has not been renamed and replaced by another file "
"of the same name (a common log file practice) before giving up on "
@@ -83,9 +87,11 @@ USAGE_LICENSE
"[+S?scores]"
"}"
"[v:verbose?Always ouput filename headers.]"
+
"\n"
"\n[file ...]\n"
"\n"
+
"[+EXIT STATUS?]{"
"[+0?All files copied successfully.]"
"[+>0?One or more files did not copy.]"
@@ -103,17 +109,18 @@ USAGE_LICENSE
#define ERROR (1<<1)
#define FOLLOW (1<<2)
#define HEADERS (1<<3)
-#define LOG (1<<4)
-#define NEGATIVE (1<<5)
-#define POSITIVE (1<<6)
-#define REVERSE (1<<7)
-#define SILENT (1<<8)
-#define TIMEOUT (1<<9)
-#define VERBOSE (1<<10)
+#define LINES (1<<4)
+#define LOG (1<<5)
+#define NEGATIVE (1<<6)
+#define POSITIVE (1<<7)
+#define REVERSE (1<<8)
+#define SILENT (1<<9)
+#define TIMEOUT (1<<10)
+#define VERBOSE (1<<11)
#define NOW (unsigned long)time(NiL)
-#define LINES 10
+#define DEFAULT 10
#ifdef S_ISSOCK
#define FIFO(m) (S_ISFIFO(m)||S_ISSOCK(m))
@@ -132,8 +139,11 @@ struct Tail_s
unsigned long expire;
long dev;
long ino;
+ int fifo;
};
+static const char header_fmt[] = "\n==> %s <==\n";
+
/*
* if file is seekable, position file to tail location and return offset
* otherwise, return -1
@@ -159,10 +169,10 @@ tailpos(register Sfio_t* fp, register Sfoff_t number, int delim)
return first;
return offset;
}
- if ((offset = last - SF_BUFSIZE) < first)
- offset = first;
for (;;)
{
+ if ((offset = last - SF_BUFSIZE) < first)
+ offset = first;
sfseek(fp, offset, SEEK_SET);
n = last - offset;
if (!(s = sfreserve(fp, n, SF_LOCKR)))
@@ -178,8 +188,6 @@ tailpos(register Sfio_t* fp, register Sfoff_t number, int delim)
if (offset == first)
break;
last = offset;
- if ((offset = last - SF_BUFSIZE) < first)
- offset = first;
}
return first;
}
@@ -245,11 +253,13 @@ pipetail(Sfio_t* infile, Sfio_t* outfile, Sfoff_t number, int delim)
*/
static int
-init(Tail_t* tp, Sfoff_t number, int delim, int flags)
+init(Tail_t* tp, Sfoff_t number, int delim, int flags, const char** format)
{
Sfoff_t offset;
+ Sfio_t* op;
struct stat st;
+ tp->fifo = 0;
if (tp->sp)
{
offset = 0;
@@ -273,12 +283,46 @@ init(Tail_t* tp, Sfoff_t number, int delim, int flags)
sfset(tp->sp, SF_SHARE, 0);
if (offset)
{
- if ((offset = tailpos(tp->sp, number, delim)) < 0)
+ if (number < 0 || !number && (flags & POSITIVE))
+ {
+ sfset(tp->sp, SF_SHARE, !(flags & FOLLOW));
+ if (number < -1)
+ {
+ sfmove(tp->sp, NiL, -number - 1, delim);
+ offset = sfseek(tp->sp, (Sfoff_t)0, SEEK_CUR);
+ }
+ else
+ offset = 0;
+ }
+ else if ((offset = tailpos(tp->sp, number, delim)) >= 0)
+ sfseek(tp->sp, offset, SEEK_SET);
+ else if (fstat(sffileno(tp->sp), &st))
+ {
+ error(ERROR_system(0), "%s: cannot stat", tp->name);
+ goto bad;
+ }
+ else if (!FIFO(st.st_mode))
{
error(ERROR_SYSTEM|2, "%s: cannot position file to tail", tp->name);
goto bad;
}
- sfseek(tp->sp, offset, SEEK_SET);
+ else
+ {
+ tp->fifo = 1;
+ if (flags & (HEADERS|VERBOSE))
+ {
+ sfprintf(sfstdout, *format, tp->name);
+ *format = header_fmt;
+ }
+ op = (flags & REVERSE) ? sftmp(4*SF_BUFSIZE) : sfstdout;
+ pipetail(tp->sp ? tp->sp : sfstdin, op, number, delim);
+ if (flags & REVERSE)
+ {
+ sfseek(op, (Sfoff_t)0, SEEK_SET);
+ rev_line(op, sfstdout, (Sfoff_t)0);
+ sfclose(op);
+ }
+ }
}
tp->last = offset;
if (flags & LOG)
@@ -325,10 +369,8 @@ num(register const char* s, char** e, int* f, int o)
s++;
errno = 0;
number = strtonll(s, &t, NiL, 0);
- if (!o && t > s && *(t - 1) == 'l')
- t--;
if (t == s)
- number = LINES;
+ number = DEFAULT;
if (o && *t)
{
number = 0;
@@ -346,6 +388,8 @@ num(register const char* s, char** e, int* f, int o)
else
{
*f |= COUNT;
+ if (t > s && isalpha(*(t - 1)))
+ *f &= ~LINES;
if (c == '-')
number = -number;
}
@@ -357,24 +401,23 @@ num(register const char* s, char** e, int* f, int o)
int
b_tail(int argc, char** argv, void* context)
{
- static const char header_fmt[] = "\n==> %s <==\n";
-
register Sfio_t* ip;
register int n;
register int i;
- register int delim = '\n';
- int flags = HEADERS;
+ int delim;
+ int flags = HEADERS|LINES;
+ int blocks = 0;
char* s;
char* t;
char* r;
char* e;
char* file;
Sfoff_t offset;
- Sfoff_t number = LINES;
+ Sfoff_t number = DEFAULT;
unsigned long timeout = 0;
struct stat st;
const char* format = header_fmt+1;
- size_t z;
+ ssize_t z;
Sfio_t* op;
register Tail_t* fp;
register Tail_t* pp;
@@ -386,13 +429,38 @@ b_tail(int argc, char** argv, void* context)
{
switch (n = optget(argv, usage))
{
- case 'c':
- delim = -1;
- if (opt_info.arg && *opt_info.arg=='f' && !*(opt_info.arg+1))
+ case 0:
+ if (!(flags & FOLLOW) && argv[opt_info.index] && (argv[opt_info.index][0] == '-' || argv[opt_info.index][0] == '+') && !argv[opt_info.index][1])
{
- flags |= FOLLOW;
+ number = argv[opt_info.index][0] == '-' ? 10 : -10;
+ flags |= LINES;
+ opt_info.index++;
continue;
}
+ break;
+ case 'b':
+ blocks = 512;
+ flags &= ~LINES;
+ if (opt_info.option[0] == '+')
+ number = -number;
+ continue;
+ case 'c':
+ flags &= ~LINES;
+ if (opt_info.arg == argv[opt_info.index - 1])
+ {
+ strtol(opt_info.arg, &s, 10);
+ if (*s)
+ {
+ opt_info.index--;
+ t = "";
+ goto suffix;
+ }
+ }
+ else if (opt_info.arg && isalpha(*opt_info.arg))
+ {
+ t = opt_info.arg;
+ goto suffix;
+ }
/*FALLTHROUGH*/
case 'n':
flags |= COUNT;
@@ -400,14 +468,14 @@ b_tail(int argc, char** argv, void* context)
number = num(s, &s, &flags, n);
else
{
- number = LINES;
+ number = DEFAULT;
flags &= ~(ERROR|NEGATIVE|POSITIVE);
s = "";
}
- if (n=='c' && *s=='f')
+ if (n != 'n' && s && isalpha(*s))
{
- s++;
- flags |= FOLLOW;
+ t = s;
+ goto suffix;
}
if (flags & ERROR)
continue;
@@ -425,6 +493,11 @@ b_tail(int argc, char** argv, void* context)
else
flags &= ~HEADERS;
continue;
+ case 'l':
+ flags |= LINES;
+ if (opt_info.option[0] == '+')
+ number = -number;
+ continue;
case 'L':
flags |= LOG;
continue;
@@ -448,32 +521,46 @@ b_tail(int argc, char** argv, void* context)
continue;
case ':':
/* handle old style arguments */
- r = s = argv[opt_info.index];
- number = num(s, &t, &flags, 0);
+ if (!(r = argv[opt_info.index]) || !opt_info.offset)
+ {
+ error(2, "%s", opt_info.arg);
+ break;
+ }
+ s = r + opt_info.offset - 1;
+ if (i = *(s - 1) == '-' || *(s - 1) == '+')
+ s--;
+ if ((number = num(s, &t, &flags, 0)) && i)
+ number = -number;
+ goto compatibility;
+ suffix:
+ r = 0;
+ if (opt_info.option[0] == '+')
+ number = -number;
+ compatibility:
for (;;)
{
switch (*t++)
{
case 0:
- opt_info.offset = t - r - 1;
- if (number)
- number = -number;
+ if (r)
+ opt_info.offset = t - r - 1;
break;
case 'c':
- delim = -1;
+ flags &= ~LINES;
continue;
case 'f':
flags |= FOLLOW;
continue;
case 'l':
- delim = '\n';
+ flags |= LINES;
continue;
case 'r':
flags |= REVERSE;
continue;
default:
error(2, "%s: invalid suffix", t - 1);
- opt_info.offset = strlen(r);
+ if (r)
+ opt_info.offset = strlen(r);
break;
}
break;
@@ -496,12 +583,15 @@ b_tail(int argc, char** argv, void* context)
}
else if (!*(argv + 1))
flags &= ~HEADERS;
+ delim = (flags & LINES) ? '\n' : -1;
+ if (blocks)
+ number *= blocks;
if (flags & REVERSE)
{
if (delim < 0)
error(2, "--reverse requires line mode");
- else if (!(flags & COUNT))
- number = 0;
+ if (!(flags & COUNT))
+ number = -1;
flags &= ~FOLLOW;
}
if ((flags & (FOLLOW|TIMEOUT)) == TIMEOUT)
@@ -527,7 +617,7 @@ b_tail(int argc, char** argv, void* context)
{
fp->name = s;
fp->sp = 0;
- if (!init(fp, number, delim, flags))
+ if (!init(fp, number, delim, flags, &format))
{
fp->expire = timeout ? (NOW + timeout + 1) : 0;
if (files)
@@ -542,27 +632,35 @@ b_tail(int argc, char** argv, void* context)
return error_info.errors != 0;
pp->next = 0;
hp = 0;
- for (;;)
+ while (fp = files)
{
if (sfsync(sfstdout))
error(ERROR_system(1), "write error");
+#if 0
sleep(1);
+#else
+ {
+ struct timespec rqt = { 0L, 1000000000L/4L };
+ (void)nanosleep(&rqt, NULL);
+ }
+#endif
n = 0;
pp = 0;
- fp = files;
while (fp)
{
if (fstat(sffileno(fp->sp), &st))
error(ERROR_system(0), "%s: cannot stat", fp->name);
- else if (st.st_size > fp->last)
+ else if (st.st_size > fp->last || fp->fifo)
{
n = 1;
if (timeout)
fp->expire = NOW + timeout;
- z = st.st_size - fp->last;
+ z = fp->fifo ? SF_UNBOUND : st.st_size - fp->last;
i = 0;
if ((s = sfreserve(fp->sp, z, SF_LOCKR)) || (z = sfvalue(fp->sp)) && (s = sfreserve(fp->sp, z, SF_LOCKR)) && (i = 1))
{
+ if (fp->fifo)
+ z = sfvalue(fp->sp);
r = 0;
for (e = (t = s) + z; t < e; t++)
if (*t == '\n')
@@ -594,7 +692,7 @@ b_tail(int argc, char** argv, void* context)
i = 3;
while (--i && stat(fp->name, &st))
sleep(1);
- if (i && (fp->dev != st.st_dev || fp->ino != st.st_ino) && !init(fp, 0, 0, flags))
+ if (i && (fp->dev != st.st_dev || fp->ino != st.st_ino) && !init(fp, 0, 0, flags, &format))
{
if (!(flags & SILENT))
error(ERROR_warn(0), "%s: log file change", fp->name);
@@ -636,11 +734,13 @@ b_tail(int argc, char** argv, void* context)
continue;
}
if (flags & (HEADERS|VERBOSE))
+ {
sfprintf(sfstdout, format, file);
- format = header_fmt;
+ format = header_fmt;
+ }
if (number < 0 || !number && (flags & POSITIVE))
{
- sfset(ip, SF_SHARE, !(flags & FOLLOW));
+ sfset(ip, SF_SHARE, 1);
if (number < -1)
sfmove(ip, NiL, -number - 1, delim);
if (flags & REVERSE)