ping

On 11/04/15 23:29, Martijn van Duren wrote:
Hello tech@,

I got somewhat annoyed by the fact that OpenBSD's tail can't follow
multiple files and since the last attempt at it was from 2008 I thought
I'd give it a shot. I already sent an earlier version of this diff to
Landry who called it "a welcomed addition", but doesn't have time to
review my patch.

I've field tested this patch for a couple of days now and I didn't
experienced any problems. I also run it through
/usr/src/regress/usr.bin/tail/ both on UFS and NFS (v3), so it should
not suffer from the same issues as before.

The patch isn't based on any other follow implementation (at least not
by intent) and leans fully on kqueue for reading, deletion/renaming, and
truncation. When a file gets deleted I set a timeout to kevent(2) of 1
second and poll for the files individually, since the parent directory
might not always be available for kqueue monitoring.

Sincerely,

Martijn van Duren
Index: extern.h
===================================================================
--- extern.h	(revision 1)
+++ extern.h	(revision 34)
@@ -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;
Index: misc.c
===================================================================
--- misc.c	(revision 1)
+++ misc.c	(revision 34)
@@ -41,7 +41,7 @@
 #include "extern.h"
 
 void
-ierr(void)
+ierr(const char *fname)
 {
 	warn("%s", fname);
 	rval = 1;
@@ -52,3 +52,11 @@
 {
 	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);
+}
Index: read.c
===================================================================
--- read.c	(revision 1)
+++ read.c	(revision 34)
@@ -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,7 +73,7 @@
 	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;
@@ -80,8 +80,8 @@
 			p = sp;
 		}
 	}
-	if (ferror(fp)) {
-		ierr();
+	if (ferror(tf->fp)) {
+		ierr(tf->fname);
 		free(sp);
 		return(1);
 	}
@@ -135,7 +135,7 @@
  *
  */
 int
-lines(FILE *fp, off_t off)
+lines(struct tailfile *tf, off_t off)
 {
 	struct {
 		size_t blen;
@@ -156,7 +156,7 @@
 
 	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 @@
 			}
 		}
 	}
-	if (ferror(fp)) {
-		ierr();
+	if (ferror(tf->fp)) {
+		ierr(tf->fname);
 		rc = 1;
 		goto done;
 	}
Index: reverse.c
===================================================================
--- reverse.c	(revision 1)
+++ reverse.c	(revision 34)
@@ -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,25 +76,35 @@
  *	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");
+			}
 		}
+	}
 }
 
 /*
@@ -101,12 +111,12 @@
  * 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 @@
 
 	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);
 }
Index: Makefile
===================================================================
--- Makefile	(revision 1)
+++ Makefile	(revision 34)
@@ -2,5 +2,6 @@
 
 PROG=	tail
 SRCS=	forward.c misc.c read.c reverse.c tail.c
+COPTS+=	-Wall -Werror
 
 .include <bsd.prog.mk>
Index: forward.c
===================================================================
--- forward.c	(revision 1)
+++ forward.c	(revision 34)
@@ -38,14 +38,20 @@
 #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,167 +75,164 @@
  *	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;
+			} 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;
 			}
-			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 (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;
+
+		if (tfqueue(&(tf[i])) == -1)
+			warn("Unable to follow %s", tf[i].fname);
+
 	}
+	ltf = &(tf[i-1]);
 
-	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) {
+	(void)fflush(stdout);
+	if (!fflag || kq < 0)
+		return;
+
+	while (1) {
+		if ((nevents = kevent(kq, NULL, 0, &ke, 1, ts)) <= 0) {
+			if (errno == EINTR) {
 				close(kq);
-				kq = -1;
+				return;
 			}
 		}
-	}
 
-	for (;;) {
-		while (!feof(fp) && (ch = getc(fp)) != EOF)
-			if (putchar(ch) == EOF)
-				oerr();
-		if (ferror(fp)) {
-			ierr();
-			if (kq != -1)
-				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;
-		}
-
-		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);
 }
 
 /*
@@ -236,12 +239,12 @@
  * 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,15 +256,15 @@
 	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;
@@ -268,18 +271,91 @@
 		}
 	}
 	/* 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;
+}
Index: tail.c
===================================================================
--- tail.c	(revision 1)
+++ tail.c	(revision 34)
@@ -45,7 +45,6 @@
 #include "extern.h"
 
 int fflag, rflag, rval;
-char *fname;
 int is_stdin;
 
 static void obsolete(char **);
@@ -54,11 +53,11 @@
 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 @@
 	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 @@
 		}
 	}
 
-	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,7 +183,7 @@
 		 * 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. */
@@ -196,9 +190,9 @@
 		}
 
 		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);
 }

Reply via email to