summaryrefslogtreecommitdiff
path: root/usr.bin/tail
diff options
context:
space:
mode:
authorTed Unangst <tedu@cvs.openbsd.org>2015-11-19 17:50:05 +0000
committerTed Unangst <tedu@cvs.openbsd.org>2015-11-19 17:50:05 +0000
commit7e93d06b71185308b6a3c3295b4bbead7f4d5aa0 (patch)
tree46befb3934164ee48f168e2cc84126558d3d225f /usr.bin/tail
parent3ea70f02c2b97325aeb062585273131d1d14106d (diff)
another try to allow tailing multiple files. maybe it works?
commit now to allow people to test. from Martijn van Duren
Diffstat (limited to 'usr.bin/tail')
-rw-r--r--usr.bin/tail/extern.h20
-rw-r--r--usr.bin/tail/forward.c376
-rw-r--r--usr.bin/tail/misc.c12
-rw-r--r--usr.bin/tail/read.c18
-rw-r--r--usr.bin/tail/reverse.c68
-rw-r--r--usr.bin/tail/tail.c56
6 files changed, 322 insertions, 228 deletions
diff --git a/usr.bin/tail/extern.h b/usr.bin/tail/extern.h
index 948f4e49bb0..628d875b1cb 100644
--- a/usr.bin/tail/extern.h
+++ b/usr.bin/tail/extern.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: extern.h,v 1.11 2008/11/13 18:33:03 landry Exp $ */
+/* $OpenBSD: extern.h,v 1.12 2015/11/19 17:50:04 tedu Exp $ */
/* $NetBSD: extern.h,v 1.3 1994/11/23 07:42:00 jtc Exp $ */
/*-
@@ -36,17 +36,23 @@
if (write(STDOUT_FILENO, p, size) != size) \
oerr();
+struct tailfile {
+ char *fname;
+ FILE *fp;
+ struct stat sb;
+};
+
enum STYLE { NOTSET = 0, FBYTES, FLINES, RBYTES, RLINES, REVERSE };
-void forward(FILE *, enum STYLE, off_t, struct stat *);
-void reverse(FILE *, enum STYLE, off_t, struct stat *);
+void forward(struct tailfile *, int, enum STYLE, off_t);
+void reverse(struct tailfile *, int, enum STYLE, off_t);
-int bytes(FILE *, off_t);
-int lines(FILE *, off_t);
+int bytes(struct tailfile *, off_t);
+int lines(struct tailfile *, off_t);
-void ierr(void);
+void ierr(const char *);
void oerr(void);
+void printfname(const char *);
extern int fflag, rflag, rval;
-extern char *fname;
extern int is_stdin;
diff --git a/usr.bin/tail/forward.c b/usr.bin/tail/forward.c
index a601f3ef063..a009ab698cc 100644
--- a/usr.bin/tail/forward.c
+++ b/usr.bin/tail/forward.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: forward.c,v 1.26 2009/10/27 23:59:44 deraadt Exp $ */
+/* $OpenBSD: forward.c,v 1.27 2015/11/19 17:50:04 tedu Exp $ */
/* $NetBSD: forward.c,v 1.7 1996/02/13 16:49:10 ghudson Exp $ */
/*-
@@ -38,13 +38,19 @@
#include <sys/event.h>
#include <err.h>
+#include <errno.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "extern.h"
-static int rlines(FILE *, off_t, struct stat *);
+static int rlines(struct tailfile *, off_t);
+static int tfqueue(struct tailfile *tf);
+static const struct timespec *tfreopen(struct tailfile *tf);
+
+static int kq = -1;
/*
* forward -- display the file, from an offset, forward.
@@ -69,179 +75,176 @@ static int rlines(FILE *, off_t, struct stat *);
* 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(struct tailfile *tf, int nfiles, enum STYLE style, off_t off)
{
int ch;
- struct stat nsb;
- int kq, queue;
+ struct tailfile *ctf, *ltf;
struct kevent ke;
+ const struct timespec *ts = NULL;
+ int i;
+ int nevents;
- switch(style) {
- case FBYTES:
- if (off == 0)
- break;
- if (S_ISREG(sbp->st_mode)) {
- if (sbp->st_size < off)
- off = sbp->st_size;
- if (fseeko(fp, off, SEEK_SET) == -1) {
- ierr();
- return;
- }
- } else while (off--)
- if ((ch = getc(fp)) == EOF) {
- if (ferror(fp)) {
- ierr();
+ if (nfiles < 1)
+ return;
+
+ if ((kq = kqueue()) < 0)
+ warn("kqueue");
+
+ for (i = 0; i < nfiles; i++) {
+ if (nfiles > 1)
+ printfname(tf[i].fname);
+
+ switch(style) {
+ case FBYTES:
+ if (off == 0)
+ break;
+ if (S_ISREG(tf[i].sb.st_mode)) {
+ if (tf[i].sb.st_size < off)
+ off = tf[i].sb.st_size;
+ if (fseeko(tf[i].fp, off, SEEK_SET) == -1) {
+ ierr(tf[i].fname);
return;
}
+ } else while (off--)
+ if ((ch = getc(tf[i].fp)) == EOF) {
+ if (ferror(tf[i].fp)) {
+ ierr(tf[i].fname);
+ return;
+ }
+ break;
+ }
+ break;
+ case FLINES:
+ if (off == 0)
break;
+ for (;;) {
+ if ((ch = getc(tf[i].fp)) == EOF) {
+ if (ferror(tf[i].fp)) {
+ ierr(tf[i].fname);
+ return;
+ }
+ break;
+ }
+ if (ch == '\n' && !--off)
+ break;
}
- break;
- case FLINES:
- if (off == 0)
break;
- for (;;) {
- if ((ch = getc(fp)) == EOF) {
- if (ferror(fp)) {
- ierr();
+ case RBYTES:
+ if (S_ISREG(tf[i].sb.st_mode)) {
+ if (tf[i].sb.st_size >= off &&
+ fseeko(tf[i].fp, -off, SEEK_END) == -1) {
+ ierr(tf[i].fname);
return;
}
- break;
- }
- if (ch == '\n' && !--off)
- break;
- }
- break;
- case RBYTES:
- if (S_ISREG(sbp->st_mode)) {
- if (sbp->st_size >= off &&
- fseeko(fp, -off, SEEK_END) == -1) {
- ierr();
- return;
- }
- } else if (off == 0) {
- while (getc(fp) != EOF)
- ;
- if (ferror(fp)) {
- ierr();
- return;
+ } else if (off == 0) {
+ while (getc(tf[i].fp) != EOF)
+ ;
+ if (ferror(tf[i].fp)) {
+ ierr(tf[i].fname);
+ return;
+ }
+ } else {
+ if (bytes(&(tf[i]), off))
+ return;
}
- } else {
- if (bytes(fp, off))
- return;
- }
- break;
- case RLINES:
- if (S_ISREG(sbp->st_mode)) {
- if (!off) {
- if (fseeko(fp, (off_t)0, SEEK_END) == -1) {
- ierr();
+ break;
+ case RLINES:
+ if (S_ISREG(tf[i].sb.st_mode)) {
+ if (!off) {
+ if (fseeko(tf[i].fp, (off_t)0,
+ SEEK_END) == -1) {
+ ierr(tf[i].fname);
+ return;
+ }
+ } else if (rlines(&(tf[i]), off) != 0)
+ lines(&(tf[i]), off);
+ } else if (off == 0) {
+ while (getc(tf[i].fp) != EOF)
+ ;
+ if (ferror(tf[i].fp)) {
+ ierr(tf[i].fname);
return;
}
- } else if (rlines(fp, off, sbp) != 0)
- lines(fp, off);
- } else if (off == 0) {
- while (getc(fp) != EOF)
- ;
- if (ferror(fp)) {
- ierr();
- return;
+ } else {
+ if (lines(&(tf[i]), off))
+ return;
}
- } else {
- if (lines(fp, off))
- return;
+ break;
+ default:
+ err(1, "Unsupported style");
}
- break;
- }
- kq = -1;
-kq_retry:
- if (fflag && ((kq = kqueue()) >= 0)) {
- EV_SET(&ke, fileno(fp), EVFILT_READ,
- EV_ENABLE | EV_ADD | EV_CLEAR,
- 0,
- 0, NULL);
- if (kevent(kq, &ke, 1, NULL, 0, NULL) < 0) {
- close(kq);
- kq = -1;
- } else if (S_ISREG(sbp->st_mode)) {
- EV_SET(&ke, fileno(fp), EVFILT_VNODE,
- EV_ENABLE | EV_ADD | EV_CLEAR,
- NOTE_DELETE | NOTE_RENAME | NOTE_TRUNCATE,
- 0, NULL);
- if (kevent(kq, &ke, 1, NULL, 0, NULL) < 0) {
- close(kq);
- kq = -1;
- }
- }
+ if (tfqueue(&(tf[i])) == -1)
+ warn("Unable to follow %s", tf[i].fname);
+
}
+ ltf = &(tf[i-1]);
+
+ (void)fflush(stdout);
+ if (!fflag || kq < 0)
+ return;
- for (;;) {
- while (!feof(fp) && (ch = getc(fp)) != EOF)
- if (putchar(ch) == EOF)
- oerr();
- if (ferror(fp)) {
- ierr();
- if (kq != -1)
+ while (1) {
+ if ((nevents = kevent(kq, NULL, 0, &ke, 1, ts)) <= 0) {
+ if (errno == EINTR) {
close(kq);
- return;
- }
- (void)fflush(stdout);
- if (!fflag)
- break;
- clearerr(fp);
- queue = 1;
- if (kq < 0 || kevent(kq, NULL, 0, &ke, 1, NULL) <= 0) {
- queue = 0;
- sleep(1);
- } else if (ke.filter == EVFILT_READ) {
- continue;
- } else if ((ke.fflags & NOTE_TRUNCATE) == 0) {
- /*
- * File was renamed or deleted.
- *
- * Continue to look at it until a new file reappears
- * with the same name.
- * Fall back to the old algorithm for that.
- */
- close(kq);
- kq = -1;
+ return;
+ }
}
- if (is_stdin || stat(fname, &nsb) != 0)
- continue;
- /* Reopen file if the inode changes or file was truncated */
- if (nsb.st_ino != sbp->st_ino) {
- warnx("%s has been replaced, reopening.", fname);
- if ((fp = freopen(fname, "r", fp)) == NULL) {
- ierr();
- if (kq >= 0)
- close(kq);
- return;
+ ctf = ke.udata;
+ if (nevents > 0) {
+ if (ke.filter == EVFILT_READ) {
+ if (ctf != ltf) {
+ printfname(ctf->fname);
+ ltf = ctf;
+ }
+ clearerr(ctf->fp);
+ while (!feof(ctf->fp) &&
+ (ch = getc(ctf->fp)) != EOF) {
+ if (putchar(ch) == EOF)
+ oerr();
+ }
+ if (ferror(ctf->fp)) {
+ ierr(ctf->fname);
+ fclose(ctf->fp);
+ warn("Lost file %s", ctf->fname);
+ continue;
+ }
+ (void)fflush(stdout);
+ clearerr(ctf->fp);
+ } else if (ke.filter == EVFILT_VNODE) {
+ if (ke.fflags & (NOTE_DELETE | NOTE_RENAME)) {
+ /*
+ * File was deleted or renamed.
+ *
+ * Continue to look at it until
+ * a new file reappears with
+ * the same name.
+ */
+ (void) tfreopen(ctf);
+ } else if (ke.fflags & NOTE_TRUNCATE) {
+ warnx("%s has been truncated, "
+ "resetting.", ctf->fname);
+ fpurge(ctf->fp);
+ rewind(ctf->fp);
+ }
}
- (void)memcpy(sbp, &nsb, sizeof(nsb));
- goto kq_retry;
- } else if ((queue && (ke.fflags & NOTE_TRUNCATE)) ||
- (!queue && nsb.st_size < sbp->st_size)) {
- warnx("%s has been truncated, resetting.", fname);
- fpurge(fp);
- rewind(fp);
}
- (void)memcpy(sbp, &nsb, sizeof(nsb));
+ ts = tfreopen(NULL);
}
- if (kq >= 0)
- close(kq);
}
/*
* rlines -- display the last offset lines of the file.
*/
static int
-rlines(FILE *fp, off_t off, struct stat *sbp)
+rlines(struct tailfile *tf, off_t off)
{
off_t pos;
int ch;
- pos = sbp->st_size;
+ pos = tf->sb.st_size;
if (pos == 0)
return (0);
@@ -253,33 +256,106 @@ rlines(FILE *fp, off_t off, struct stat *sbp)
ch = EOF;
for (; off > 0 && pos >= 0; pos--) {
/* A seek per char isn't a problem with a smart stdio */
- if (fseeko(fp, pos, SEEK_SET) == -1) {
- ierr();
+ if (fseeko(tf[0].fp, pos, SEEK_SET) == -1) {
+ ierr(tf->fname);
return (1);
}
- if ((ch = getc(fp)) == '\n')
+ if ((ch = getc(tf[0].fp)) == '\n')
off--;
else if (ch == EOF) {
- if (ferror(fp)) {
- ierr();
+ if (ferror(tf[0].fp)) {
+ ierr(tf->fname);
return (1);
}
break;
}
}
/* If we read until start of file, put back last read char */
- if (pos < 0 && off > 0 && ch != EOF && ungetc(ch, fp) == EOF) {
- ierr();
+ if (pos < 0 && off > 0 && ch != EOF && ungetc(ch, tf[0].fp) == EOF) {
+ ierr(tf->fname);
return (1);
}
- while (!feof(fp) && (ch = getc(fp)) != EOF)
+ while (!feof(tf[0].fp) && (ch = getc(tf[0].fp)) != EOF)
if (putchar(ch) == EOF)
oerr();
- if (ferror(fp)) {
- ierr();
+ if (ferror(tf[0].fp)) {
+ ierr(tf->fname);
return (1);
}
return (0);
}
+
+static int
+tfqueue(struct tailfile *tf)
+{
+ struct kevent ke[2];
+ int i = 1;
+
+ if (kq < 0) {
+ errno = EBADF;
+ return -1;
+ }
+
+ EV_SET(&(ke[0]), fileno(tf->fp), EVFILT_READ,
+ EV_ENABLE | EV_ADD | EV_CLEAR, 0, 0, tf);
+
+ if (S_ISREG(tf->sb.st_mode)) {
+ i = 2;
+ EV_SET(&(ke[1]), fileno(tf->fp), EVFILT_VNODE,
+ EV_ENABLE | EV_ADD | EV_CLEAR,
+ NOTE_DELETE | NOTE_RENAME | NOTE_TRUNCATE,
+ 0, tf);
+ }
+ if (kevent(kq, ke, i, NULL, 0, NULL) < 0) {
+ ierr(tf->fname);
+ return -1;
+ }
+ return 0;
+}
+
+#define AFILESINCR 8
+static const struct timespec *
+tfreopen(struct tailfile *tf) {
+ static struct tailfile **reopen = NULL;
+ static int nfiles = 0, afiles = 0;
+ static const struct timespec ts = {1, 0};
+
+ struct stat sb;
+ struct tailfile **treopen, *ttf;
+ int i;
+
+ if (tf && ((stat(tf->fname, &sb) != 0) || sb.st_ino != tf->sb.st_ino)) {
+ if (afiles < ++nfiles) {
+ afiles += AFILESINCR;
+ treopen = reallocarray(reopen, afiles, sizeof(*reopen));
+ if (treopen)
+ reopen = treopen;
+ else
+ afiles -= AFILESINCR;
+ }
+ if (nfiles < afiles)
+ reopen[nfiles-1] = tf;
+ }
+
+ for (i = 0; i < nfiles; i++) {
+ ttf = reopen[i];
+ if (stat(ttf->fname, &sb) == -1)
+ continue;
+ if (sb.st_ino != ttf->sb.st_ino) {
+ (void) memcpy(&(ttf->sb), &sb, sizeof(ttf->sb));
+ ttf->fp = freopen(ttf->fname, "r", ttf->fp);
+ if (ttf->fp == NULL)
+ ierr(ttf->fname);
+ else {
+ warnx("%s has been replaced, reopening.",
+ ttf->fname);
+ tfqueue(ttf);
+ }
+ }
+ reopen[i] = reopen[--nfiles];
+ }
+
+ return nfiles ? &ts : NULL;
+}
diff --git a/usr.bin/tail/misc.c b/usr.bin/tail/misc.c
index 97650b4f85b..80187d406d6 100644
--- a/usr.bin/tail/misc.c
+++ b/usr.bin/tail/misc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.c,v 1.8 2009/10/27 23:59:44 deraadt Exp $ */
+/* $OpenBSD: misc.c,v 1.9 2015/11/19 17:50:04 tedu Exp $ */
/*-
* Copyright (c) 1991, 1993
@@ -41,7 +41,7 @@
#include "extern.h"
void
-ierr(void)
+ierr(const char *fname)
{
warn("%s", fname);
rval = 1;
@@ -52,3 +52,11 @@ oerr(void)
{
err(1, "stdout");
}
+
+void printfname(const char *fname)
+{
+ static int first = 1;
+ (void)printf("%s==> %s <==\n", first ? "" : "\n", fname);
+ first = 0;
+ (void)fflush(stdout);
+}
diff --git a/usr.bin/tail/read.c b/usr.bin/tail/read.c
index 757e8cd12b0..72d521d037c 100644
--- a/usr.bin/tail/read.c
+++ b/usr.bin/tail/read.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: read.c,v 1.16 2015/03/26 21:26:43 tobias Exp $ */
+/* $OpenBSD: read.c,v 1.17 2015/11/19 17:50:04 tedu Exp $ */
/* $NetBSD: read.c,v 1.4 1994/11/23 07:42:07 jtc Exp $ */
/*-
@@ -59,7 +59,7 @@
*
*/
int
-bytes(FILE *fp, off_t off)
+bytes(struct tailfile *tf, off_t off)
{
int ch;
size_t len, tlen;
@@ -73,15 +73,15 @@ bytes(FILE *fp, off_t off)
if ((sp = p = malloc(off)) == NULL)
err(1, NULL);
- for (wrap = 0, ep = p + off; (ch = getc(fp)) != EOF;) {
+ for (wrap = 0, ep = p + off; (ch = getc(tf->fp)) != EOF;) {
*p = ch;
if (++p == ep) {
wrap = 1;
p = sp;
}
}
- if (ferror(fp)) {
- ierr();
+ if (ferror(tf->fp)) {
+ ierr(tf->fname);
free(sp);
return(1);
}
@@ -135,7 +135,7 @@ bytes(FILE *fp, off_t off)
*
*/
int
-lines(FILE *fp, off_t off)
+lines(struct tailfile *tf, off_t off)
{
struct {
size_t blen;
@@ -156,7 +156,7 @@ lines(FILE *fp, off_t off)
blen = cnt = recno = wrap = 0;
- while ((ch = getc(fp)) != EOF) {
+ while ((ch = getc(tf->fp)) != EOF) {
if (++cnt > blen) {
newsize = blen + 1024;
if ((newp = realloc(sp, newsize)) == NULL)
@@ -184,8 +184,8 @@ lines(FILE *fp, off_t off)
}
}
}
- if (ferror(fp)) {
- ierr();
+ if (ferror(tf->fp)) {
+ ierr(tf->fname);
rc = 1;
goto done;
}
diff --git a/usr.bin/tail/reverse.c b/usr.bin/tail/reverse.c
index a88041078a6..144c481b6f0 100644
--- a/usr.bin/tail/reverse.c
+++ b/usr.bin/tail/reverse.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: reverse.c,v 1.20 2015/07/22 16:37:04 tobias Exp $ */
+/* $OpenBSD: reverse.c,v 1.21 2015/11/19 17:50:04 tedu Exp $ */
/* $NetBSD: reverse.c,v 1.6 1994/11/23 07:42:10 jtc Exp $ */
/*-
@@ -43,12 +43,12 @@
#include "extern.h"
static void r_buf(FILE *);
-static int r_reg(FILE *, enum STYLE, off_t, struct stat *);
+static int r_reg(struct tailfile *, enum STYLE, off_t);
-#define COPYCHAR(fp, ch) \
+#define COPYCHAR(tf, ch) \
do { \
- if ((ch = getc(fp)) == EOF) { \
- ierr(); \
+ if ((ch = getc(tf->fp)) == EOF) { \
+ ierr(tf->fname); \
return (0); \
} \
if (putchar(ch) == EOF) { \
@@ -76,37 +76,47 @@ static int 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(struct tailfile *tf, int nfiles, enum STYLE style, off_t off)
{
+ int i;
+
if (style != REVERSE && off == 0)
return;
- if (!S_ISREG(sbp->st_mode) || r_reg(fp, style, off, sbp) != 0)
- switch(style) {
- case FBYTES:
- case RBYTES:
- (void)bytes(fp, off);
- break;
- case FLINES:
- case RLINES:
- (void)lines(fp, off);
- break;
- case REVERSE:
- r_buf(fp);
- break;
+ for (i = 0; i < nfiles; i++) {
+ if (nfiles > 1)
+ printfname(tf[i].fname);
+ if (!S_ISREG(tf[i].sb.st_mode) ||
+ r_reg(&(tf[i]), style, off) != 0) {
+ switch(style) {
+ case FBYTES:
+ case RBYTES:
+ (void)bytes(&(tf[i]), off);
+ break;
+ case FLINES:
+ case RLINES:
+ (void)lines(&(tf[i]), off);
+ break;
+ case REVERSE:
+ r_buf(tf[i].fp);
+ break;
+ default:
+ err(1, "Unsupported style");
+ }
}
+ }
}
/*
* r_reg -- display a regular file in reverse order by line.
*/
static int
-r_reg(FILE *fp, enum STYLE style, off_t off, struct stat *sbp)
+r_reg(struct tailfile *tf, enum STYLE style, off_t off)
{
off_t start, pos, end;
int ch;
- end = sbp->st_size;
+ end = tf->sb.st_size;
if (end == 0)
return (0);
@@ -120,29 +130,29 @@ r_reg(FILE *fp, enum STYLE style, off_t off, struct stat *sbp)
for (; pos >= start; pos--) {
/* A seek per char isn't a problem with a smart stdio */
- if (fseeko(fp, pos, SEEK_SET) != 0) {
- ierr();
+ if (fseeko(tf->fp, pos, SEEK_SET) != 0) {
+ ierr(tf->fname);
return (0);
}
- if ((ch = getc(fp)) == '\n') {
+ if ((ch = getc(tf->fp)) == '\n') {
while (--end > pos)
- COPYCHAR(fp, ch);
+ COPYCHAR(tf, ch);
end++;
if (style == RLINES && --off == 0)
break;
}
else if (ch == EOF) {
- ierr();
+ ierr(tf->fname);
return (0);
}
}
if (pos < start) {
- if (ch != EOF && ungetc(ch, fp) == EOF) {
- ierr();
+ if (ch != EOF && ungetc(ch, tf->fp) == EOF) {
+ ierr(tf->fname);
return (0);
}
while (--end >= start)
- COPYCHAR(fp, ch);
+ COPYCHAR(tf, ch);
}
return (0);
}
diff --git a/usr.bin/tail/tail.c b/usr.bin/tail/tail.c
index e543e0b9b2f..0d66b83e54f 100644
--- a/usr.bin/tail/tail.c
+++ b/usr.bin/tail/tail.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tail.c,v 1.19 2015/10/09 01:37:09 deraadt Exp $ */
+/* $OpenBSD: tail.c,v 1.20 2015/11/19 17:50:04 tedu Exp $ */
/*-
* Copyright (c) 1991, 1993
@@ -45,7 +45,6 @@
#include "extern.h"
int fflag, rflag, rval;
-char *fname;
int is_stdin;
static void obsolete(char **);
@@ -54,11 +53,11 @@ static void usage(void);
int
main(int argc, char *argv[])
{
- struct stat sb;
- FILE *fp;
+ struct tailfile *tf;
off_t off = 0;
enum STYLE style;
- int ch, first;
+ int ch;
+ int i;
char *p;
if (pledge("stdio rpath", NULL) == -1)
@@ -123,9 +122,6 @@ main(int argc, char *argv[])
argc -= optind;
argv += optind;
- if (fflag && argc > 1)
- errx(1, "-f option only appropriate for a single file");
-
/*
* If displaying in reverse, don't permit follow option, and convert
* style values.
@@ -153,35 +149,33 @@ main(int argc, char *argv[])
}
}
- if (*argv)
- for (first = 1; (fname = *argv++);) {
- if ((fp = fopen(fname, "r")) == NULL ||
- fstat(fileno(fp), &sb)) {
- ierr();
+ if ((tf = reallocarray(NULL, argc ? argc : 1, sizeof(*tf))) == NULL)
+ err(1, "reallocarray");
+
+ if (argc) {
+ for (i = 0; (tf[i].fname = *argv++); i++) {
+ if ((tf[i].fp = fopen(tf[i].fname, "r")) == NULL ||
+ fstat(fileno(tf[i].fp), &(tf[i].sb))) {
+ ierr(tf[i].fname);
+ i--;
continue;
}
- if (argc > 1) {
- (void)printf("%s==> %s <==\n",
- first ? "" : "\n", fname);
- first = 0;
- (void)fflush(stdout);
- }
-
- if (rflag)
- reverse(fp, style, off, &sb);
- else
- forward(fp, style, off, &sb);
- (void)fclose(fp);
}
+ if (rflag)
+ reverse(tf, i, style, off);
+ else
+ forward(tf, i, style, off);
+ }
else {
if (pledge("stdio", NULL) == -1)
err(1, "pledge");
- fname = "stdin";
+ tf[0].fname = "stdin";
+ tf[0].fp = stdin;
is_stdin = 1;
- if (fstat(fileno(stdin), &sb)) {
- ierr();
+ if (fstat(fileno(stdin), &(tf[0].sb))) {
+ ierr(tf[0].fname);
exit(1);
}
@@ -189,16 +183,16 @@ main(int argc, char *argv[])
* Determine if input is a pipe. 4.4BSD will set the SOCKET
* bit in the st_mode field for pipes. Fix this then.
*/
- if (lseek(fileno(stdin), (off_t)0, SEEK_CUR) == -1 &&
+ if (lseek(fileno(tf[0].fp), (off_t)0, SEEK_CUR) == -1 &&
errno == ESPIPE) {
errno = 0;
fflag = 0; /* POSIX.2 requires this. */
}
if (rflag)
- reverse(stdin, style, off, &sb);
+ reverse(tf, 1, style, off);
else
- forward(stdin, style, off, &sb);
+ forward(tf, 1, style, off);
}
exit(rval);
}