aboutsummaryrefslogtreecommitdiff
path: root/usr.bin/tail
diff options
context:
space:
mode:
authorBrian Somers <brian@FreeBSD.org>2009-06-05 09:08:53 +0000
committerBrian Somers <brian@FreeBSD.org>2009-06-05 09:08:53 +0000
commit22da50cfc88081e487465042b96f969349ecb6c5 (patch)
treee543b101f94f862f5071b48f0a4c466e2afa6f25 /usr.bin/tail
parentca67260eba65dc34291d094e40466327479d29de (diff)
downloadsrc-22da50cfc88081e487465042b96f969349ecb6c5.tar.gz
src-22da50cfc88081e487465042b96f969349ecb6c5.zip
Change the behaviour of -F slightly; it now persists (forever) in
trying to open files rather than giving up when it encounters an error. ENOENT errors are not reported. As a result, files that are moved away then recreated are not at risk of being 'lost' to tail. Files that are recreated and temporarily have unreadable permissions will be shown when they are fixed. This behaviour is consistent with the GNU version of tail but without the verbiage that goes with the GNU version. This change also fixes error messages accompanying -f and -F. They no longer report problems with (null)! MFC after: 3 weeks
Notes
Notes: svn path=/head/; revision=193488
Diffstat (limited to 'usr.bin/tail')
-rw-r--r--usr.bin/tail/extern.h11
-rw-r--r--usr.bin/tail/forward.c150
-rw-r--r--usr.bin/tail/misc.c2
-rw-r--r--usr.bin/tail/read.c8
-rw-r--r--usr.bin/tail/reverse.c28
-rw-r--r--usr.bin/tail/tail.111
-rw-r--r--usr.bin/tail/tail.c41
7 files changed, 144 insertions, 107 deletions
diff --git a/usr.bin/tail/extern.h b/usr.bin/tail/extern.h
index d9566807a529..f91495df52e4 100644
--- a/usr.bin/tail/extern.h
+++ b/usr.bin/tail/extern.h
@@ -61,16 +61,15 @@ typedef struct file_info file_info_t;
enum STYLE { NOTSET = 0, FBYTES, FLINES, RBYTES, RLINES, REVERSE };
void follow(file_info_t *, enum STYLE, off_t);
-void forward(FILE *, enum STYLE, off_t, struct stat *);
-void reverse(FILE *, enum STYLE, off_t, struct stat *);
+void forward(FILE *, const char *, enum STYLE, off_t, struct stat *);
+void reverse(FILE *, const char *, enum STYLE, off_t, struct stat *);
-int bytes(FILE *, off_t);
-int lines(FILE *, off_t);
+int bytes(FILE *, const char *, off_t);
+int lines(FILE *, const char *, off_t);
-void ierr(void);
+void ierr(const char *);
void oerr(void);
int mapprint(struct mapinfo *, off_t, off_t);
int maparound(struct mapinfo *, off_t);
extern int Fflag, fflag, qflag, rflag, rval, no_files;
-extern const char *fname;
diff --git a/usr.bin/tail/forward.c b/usr.bin/tail/forward.c
index c79c4382de04..6dab72ed0087 100644
--- a/usr.bin/tail/forward.c
+++ b/usr.bin/tail/forward.c
@@ -61,8 +61,8 @@ static const char sccsid[] = "@(#)forward.c 8.1 (Berkeley) 6/6/93";
#include "extern.h"
-static void rlines(FILE *, off_t, struct stat *);
-static void show(file_info_t *);
+static void rlines(FILE *, const char *fn, off_t, struct stat *);
+static int show(file_info_t *);
static void set_events(file_info_t *files);
/* defines for inner loop actions */
@@ -99,7 +99,7 @@ static const file_info_t *last;
* NOREG cyclically read lines into a wrap-around array of buffers
*/
void
-forward(FILE *fp, enum STYLE style, off_t off, struct stat *sbp)
+forward(FILE *fp, const char *fn, enum STYLE style, off_t off, struct stat *sbp)
{
int ch;
@@ -111,13 +111,13 @@ forward(FILE *fp, enum STYLE style, off_t off, struct stat *sbp)
if (sbp->st_size < off)
off = sbp->st_size;
if (fseeko(fp, off, SEEK_SET) == -1) {
- ierr();
+ ierr(fn);
return;
}
} else while (off--)
if ((ch = getc(fp)) == EOF) {
if (ferror(fp)) {
- ierr();
+ ierr(fn);
return;
}
break;
@@ -129,7 +129,7 @@ forward(FILE *fp, enum STYLE style, off_t off, struct stat *sbp)
for (;;) {
if ((ch = getc(fp)) == EOF) {
if (ferror(fp)) {
- ierr();
+ ierr(fn);
return;
}
break;
@@ -142,36 +142,36 @@ forward(FILE *fp, enum STYLE style, off_t off, struct stat *sbp)
if (S_ISREG(sbp->st_mode)) {
if (sbp->st_size >= off &&
fseeko(fp, -off, SEEK_END) == -1) {
- ierr();
+ ierr(fn);
return;
}
} else if (off == 0) {
while (getc(fp) != EOF);
if (ferror(fp)) {
- ierr();
+ ierr(fn);
return;
}
} else
- if (bytes(fp, off))
+ if (bytes(fp, fn, off))
return;
break;
case RLINES:
if (S_ISREG(sbp->st_mode))
if (!off) {
if (fseeko(fp, (off_t)0, SEEK_END) == -1) {
- ierr();
+ ierr(fn);
return;
}
} else
- rlines(fp, off, sbp);
+ rlines(fp, fn, off, sbp);
else if (off == 0) {
while (getc(fp) != EOF);
if (ferror(fp)) {
- ierr();
+ ierr(fn);
return;
}
} else
- if (lines(fp, off))
+ if (lines(fp, fn, off))
return;
break;
default:
@@ -182,7 +182,7 @@ forward(FILE *fp, enum STYLE style, off_t off, struct stat *sbp)
if (putchar(ch) == EOF)
oerr();
if (ferror(fp)) {
- ierr();
+ ierr(fn);
return;
}
(void)fflush(stdout);
@@ -192,10 +192,7 @@ forward(FILE *fp, enum STYLE style, off_t off, struct stat *sbp)
* rlines -- display the last offset lines of the file.
*/
static void
-rlines(fp, off, sbp)
- FILE *fp;
- off_t off;
- struct stat *sbp;
+rlines(FILE *fp, const char *fn, off_t off, struct stat *sbp)
{
struct mapinfo map;
off_t curoff, size;
@@ -214,7 +211,7 @@ rlines(fp, off, sbp)
curoff = size - 2;
while (curoff >= 0) {
if (curoff < map.mapoff && maparound(&map, curoff) != 0) {
- ierr();
+ ierr(fn);
return;
}
for (i = curoff - map.mapoff; i >= 0; i--)
@@ -227,41 +224,44 @@ rlines(fp, off, sbp)
}
curoff++;
if (mapprint(&map, curoff, size - curoff) != 0) {
- ierr();
+ ierr(fn);
exit(1);
}
/* Set the file pointer to reflect the length displayed. */
if (fseeko(fp, sbp->st_size, SEEK_SET) == -1) {
- ierr();
+ ierr(fn);
return;
}
if (map.start != NULL && munmap(map.start, map.maplen)) {
- ierr();
+ ierr(fn);
return;
}
}
-static void
+static int
show(file_info_t *file)
{
- int ch;
+ int ch;
- while ((ch = getc(file->fp)) != EOF) {
- if (last != file && no_files > 1) {
- if (!qflag)
- (void)printf("\n==> %s <==\n", file->file_name);
- last = file;
+ while ((ch = getc(file->fp)) != EOF) {
+ if (last != file && no_files > 1) {
+ if (!qflag)
+ (void)printf("\n==> %s <==\n", file->file_name);
+ last = file;
+ }
+ if (putchar(ch) == EOF)
+ oerr();
+ }
+ (void)fflush(stdout);
+ if (ferror(file->fp)) {
+ fclose(file->fp);
+ file->fp = NULL;
+ ierr(file->file_name);
+ return 0;
}
- if (putchar(ch) == EOF)
- oerr();
- }
- (void)fflush(stdout);
- if (ferror(file->fp)) {
- file->fp = NULL;
- ierr();
- } else
- clearerr(file->fp);
+ clearerr(file->fp);
+ return 1;
}
static void
@@ -309,7 +309,7 @@ set_events(file_info_t *files)
void
follow(file_info_t *files, enum STYLE style, off_t off)
{
- int active, i, n = -1;
+ int active, ev_change, i, n = -1;
struct stat sb2;
file_info_t *file;
struct timespec ts;
@@ -325,12 +325,12 @@ follow(file_info_t *files, enum STYLE style, off_t off)
n++;
if (no_files > 1 && !qflag)
(void)printf("\n==> %s <==\n", file->file_name);
- forward(file->fp, style, off, &file->st);
+ forward(file->fp, file->file_name, style, off, &file->st);
if (Fflag && fileno(file->fp) != STDIN_FILENO)
- n++;
+ n++;
}
}
- if (! active)
+ if (!Fflag && !active)
return;
last = --file;
@@ -344,28 +344,56 @@ follow(file_info_t *files, enum STYLE style, off_t off)
set_events(files);
for (;;) {
- for (i = 0, file = files; i < no_files; i++, file++) {
- if (! file->fp)
- continue;
- if (Fflag && file->fp && fileno(file->fp) != STDIN_FILENO) {
- if (stat(file->file_name, &sb2) == 0 &&
- (sb2.st_ino != file->st.st_ino ||
- sb2.st_dev != file->st.st_dev ||
- sb2.st_nlink == 0)) {
- show(file);
- file->fp = freopen(file->file_name, "r", file->fp);
- if (file->fp == NULL) {
- ierr();
- continue;
- } else {
- memcpy(&file->st, &sb2, sizeof(struct stat));
- set_events(files);
+ ev_change = 0;
+ if (Fflag) {
+ for (i = 0, file = files; i < no_files; i++, file++) {
+ if (!file->fp) {
+ file->fp = fopen(file->file_name, "r");
+ if (file->fp != NULL &&
+ fstat(fileno(file->fp), &file->st)
+ == -1) {
+ fclose(file->fp);
+ file->fp = NULL;
}
+ if (file->fp != NULL)
+ ev_change++;
+ continue;
+ }
+ if (fileno(file->fp) == STDIN_FILENO)
+ continue;
+ if (stat(file->file_name, &sb2) == -1) {
+ if (errno != ENOENT)
+ ierr(file->file_name);
+ show(file);
+ fclose(file->fp);
+ file->fp = NULL;
+ ev_change++;
+ continue;
+ }
+
+ if (sb2.st_ino != file->st.st_ino ||
+ sb2.st_dev != file->st.st_dev ||
+ sb2.st_nlink == 0) {
+ show(file);
+ file->fp = freopen(file->file_name, "r",
+ file->fp);
+ if (file->fp != NULL)
+ memcpy(&file->st, &sb2,
+ sizeof(struct stat));
+ else if (errno != ENOENT)
+ ierr(file->file_name);
+ ev_change++;
}
}
- show(file);
}
+ for (i = 0, file = files; i < no_files; i++, file++)
+ if (file->fp && !show(file))
+ ev_change++;
+
+ if (ev_change)
+ set_events(files);
+
switch (action) {
case USE_KQUEUE:
ts.tv_sec = 1;
@@ -381,9 +409,9 @@ follow(file_info_t *files, enum STYLE style, off_t off)
/* timeout */
break;
} else if (ev->filter == EVFILT_READ && ev->data < 0) {
- /* file shrank, reposition to end */
+ /* file shrank, reposition to end */
if (lseek(ev->ident, (off_t)0, SEEK_END) == -1) {
- ierr();
+ ierr(file->file_name);
continue;
}
}
diff --git a/usr.bin/tail/misc.c b/usr.bin/tail/misc.c
index 584e3d103eab..7e57504f818a 100644
--- a/usr.bin/tail/misc.c
+++ b/usr.bin/tail/misc.c
@@ -56,7 +56,7 @@ static const char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/6/93";
#include "extern.h"
void
-ierr()
+ierr(const char *fname)
{
warn("%s", fname);
rval = 1;
diff --git a/usr.bin/tail/read.c b/usr.bin/tail/read.c
index d290ed41da18..14086e7c8d0a 100644
--- a/usr.bin/tail/read.c
+++ b/usr.bin/tail/read.c
@@ -66,7 +66,7 @@ static const char sccsid[] = "@(#)read.c 8.1 (Berkeley) 6/6/93";
* the end.
*/
int
-bytes(FILE *fp, off_t off)
+bytes(FILE *fp, const char *fn, off_t off)
{
int ch, len, tlen;
char *ep, *p, *t;
@@ -84,7 +84,7 @@ bytes(FILE *fp, off_t off)
}
}
if (ferror(fp)) {
- ierr();
+ ierr(fn);
free(sp);
return 1;
}
@@ -136,7 +136,7 @@ bytes(FILE *fp, off_t off)
* the end.
*/
int
-lines(FILE *fp, off_t off)
+lines(FILE *fp, const char *fn, off_t off)
{
struct {
int blen;
@@ -178,7 +178,7 @@ lines(FILE *fp, off_t off)
}
}
if (ferror(fp)) {
- ierr();
+ ierr(fn);
rc = 1;
goto done;
}
diff --git a/usr.bin/tail/reverse.c b/usr.bin/tail/reverse.c
index 462b39227f5f..d86c46b70456 100644
--- a/usr.bin/tail/reverse.c
+++ b/usr.bin/tail/reverse.c
@@ -58,8 +58,8 @@ __FBSDID("$FreeBSD$");
#include "extern.h"
-static void r_buf(FILE *);
-static void r_reg(FILE *, enum STYLE, off_t, struct stat *);
+static void r_buf(FILE *, const char *);
+static void r_reg(FILE *, const char *, enum STYLE, off_t, struct stat *);
/*
* reverse -- display input in reverse order by line.
@@ -80,25 +80,25 @@ static void r_reg(FILE *, enum STYLE, off_t, struct stat *);
* NOREG cyclically read input into a linked list of buffers
*/
void
-reverse(FILE *fp, enum STYLE style, off_t off, struct stat *sbp)
+reverse(FILE *fp, const char *fn, enum STYLE style, off_t off, struct stat *sbp)
{
if (style != REVERSE && off == 0)
return;
if (S_ISREG(sbp->st_mode))
- r_reg(fp, style, off, sbp);
+ r_reg(fp, fn, style, off, sbp);
else
switch(style) {
case FBYTES:
case RBYTES:
- bytes(fp, off);
+ bytes(fp, fn, off);
break;
case FLINES:
case RLINES:
- lines(fp, off);
+ lines(fp, fn, off);
break;
case REVERSE:
- r_buf(fp);
+ r_buf(fp, fn);
break;
default:
break;
@@ -109,7 +109,7 @@ reverse(FILE *fp, enum STYLE style, off_t off, struct stat *sbp)
* r_reg -- display a regular file in reverse order by line.
*/
static void
-r_reg(FILE *fp, enum STYLE style, off_t off, struct stat *sbp)
+r_reg(FILE *fp, const char *fn, enum STYLE style, off_t off, struct stat *sbp)
{
struct mapinfo map;
off_t curoff, size, lineend;
@@ -132,7 +132,7 @@ r_reg(FILE *fp, enum STYLE style, off_t off, struct stat *sbp)
if (curoff < map.mapoff ||
curoff >= map.mapoff + (off_t)map.maplen) {
if (maparound(&map, curoff) != 0) {
- ierr();
+ ierr(fn);
return;
}
}
@@ -149,7 +149,7 @@ r_reg(FILE *fp, enum STYLE style, off_t off, struct stat *sbp)
/* Print the line and update offsets. */
if (mapprint(&map, curoff + 1, lineend - curoff - 1) != 0) {
- ierr();
+ ierr(fn);
return;
}
lineend = curoff + 1;
@@ -165,11 +165,11 @@ r_reg(FILE *fp, enum STYLE style, off_t off, struct stat *sbp)
}
}
if (curoff < 0 && mapprint(&map, 0, lineend) != 0) {
- ierr();
+ ierr(fn);
return;
}
if (map.start != NULL && munmap(map.start, map.maplen))
- ierr();
+ ierr(fn);
}
typedef struct bf {
@@ -190,7 +190,7 @@ typedef struct bf {
* user warned).
*/
static void
-r_buf(FILE *fp)
+r_buf(FILE *fp, const char *fn)
{
BF *mark, *tl, *tr;
int ch, len, llen;
@@ -227,7 +227,7 @@ r_buf(FILE *fp)
*p++ = ch;
if (ferror(fp)) {
- ierr();
+ ierr(fn);
return;
}
diff --git a/usr.bin/tail/tail.1 b/usr.bin/tail/tail.1
index 251511a86eb8..7f91e7159511 100644
--- a/usr.bin/tail/tail.1
+++ b/usr.bin/tail/tail.1
@@ -35,7 +35,7 @@
.\" @(#)tail.1 8.1 (Berkeley) 6/6/93
.\" $FreeBSD$
.\"
-.Dd June 29, 2006
+.Dd June 05, 2009
.Dt TAIL 1
.Os
.Sh NAME
@@ -106,9 +106,16 @@ will also check to see if the file being followed has been renamed or rotated.
The file is closed and reopened when
.Nm
detects that the filename being read from has a new inode number.
+.Pp
+If the file being followed does not (yet) exist or if it is removed, tail
+will keep looking and will display the file from the beginning if and when
+it is created.
+.Pp
The
.Fl F
-option is ignored if reading from standard input rather than a file.
+option is the same as the
+.Fl f
+option if reading from standard input rather than a file.
.It Fl n Ar number
The location is
.Ar number
diff --git a/usr.bin/tail/tail.c b/usr.bin/tail/tail.c
index d2f9df7cb523..0a807ee79168 100644
--- a/usr.bin/tail/tail.c
+++ b/usr.bin/tail/tail.c
@@ -61,7 +61,6 @@ static const char sccsid[] = "@(#)tail.c 8.1 (Berkeley) 6/6/93";
#include "extern.h"
int Fflag, fflag, qflag, rflag, rval, no_files;
-const char *fname;
file_info_t *files;
@@ -72,6 +71,7 @@ int
main(int argc, char *argv[])
{
struct stat sb;
+ const char *fn;
FILE *fp;
off_t off;
enum STYLE style;
@@ -175,20 +175,23 @@ main(int argc, char *argv[])
}
if (*argv && fflag) {
- files = (struct file_info *) malloc(no_files * sizeof(struct file_info));
- if (! files)
+ files = (struct file_info *) malloc(no_files *
+ sizeof(struct file_info));
+ if (!files)
err(1, "Couldn't malloc space for file descriptors.");
- for (file = files; (fname = *argv++); file++) {
- file->file_name = malloc(strlen(fname)+1);
+ for (file = files; (fn = *argv++); file++) {
+ file->file_name = strdup(fn);
if (! file->file_name)
errx(1, "Couldn't malloc space for file name.");
- strncpy(file->file_name, fname, strlen(fname)+1);
if ((file->fp = fopen(file->file_name, "r")) == NULL ||
fstat(fileno(file->fp), &file->st)) {
- file->fp = NULL;
- ierr();
- continue;
+ if (file->fp != NULL) {
+ fclose(file->fp);
+ file->fp = NULL;
+ }
+ if (!Fflag || errno != ENOENT)
+ ierr(file->file_name);
}
}
follow(files, style, off);
@@ -197,29 +200,29 @@ main(int argc, char *argv[])
}
free(files);
} else if (*argv) {
- for (first = 1; (fname = *argv++);) {
- if ((fp = fopen(fname, "r")) == NULL ||
+ for (first = 1; (fn = *argv++);) {
+ if ((fp = fopen(fn, "r")) == NULL ||
fstat(fileno(fp), &sb)) {
- ierr();
+ ierr(fn);
continue;
}
if (argc > 1 && !qflag) {
(void)printf("%s==> %s <==\n",
- first ? "" : "\n", fname);
+ first ? "" : "\n", fn);
first = 0;
(void)fflush(stdout);
}
if (rflag)
- reverse(fp, style, off, &sb);
+ reverse(fp, fn, style, off, &sb);
else
- forward(fp, style, off, &sb);
+ forward(fp, fn, style, off, &sb);
}
} else {
- fname = "stdin";
+ fn = "stdin";
if (fstat(fileno(stdin), &sb)) {
- ierr();
+ ierr(fn);
exit(1);
}
@@ -234,9 +237,9 @@ main(int argc, char *argv[])
}
if (rflag)
- reverse(stdin, style, off, &sb);
+ reverse(stdin, fn, style, off, &sb);
else
- forward(stdin, style, off, &sb);
+ forward(stdin, fn, style, off, &sb);
}
exit(rval);
}