Re: [patch] tail(1) follow multiple files

2015-11-20 Thread Stuart Henderson
This is broken:

$ echo moo | tail -c +2


>From an older working system:

$ echo moo | tail -c +2
oo

Noticed while trying to package /usr/ports/sysutils/firmware/ulpt.



Re: [patch] tail(1) follow multiple files

2015-11-20 Thread Ted Unangst
Stuart Henderson wrote:
> This is broken:
> 
> $ echo moo | tail -c +2
> 
> 
> From an older working system:
> 
> $ echo moo | tail -c +2
> oo

yes, same as the case with lines which i hack/fixed. martijn sent me a patch,
pending review. 



Re: [patch] tail(1) follow multiple files

2015-11-16 Thread Martijn van Duren

Isn't anyone willing to take a stab at this patch?

On 11/09/15 12:56, Martijn van Duren wrote:

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 

Re: [patch] tail(1) follow multiple files

2015-11-16 Thread Ted Unangst
Martijn van Duren wrote:
> Isn't anyone willing to take a stab at this patch?
> 
> On 11/09/15 12:56, Martijn van Duren wrote:
> > 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.

hmm, i think "burned before" scares off many would be champions, but i think
it's worth a try as well.



Re: [patch] tail(1) follow multiple files

2015-11-09 Thread Martijn van Duren

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);
+

Re: [patch] tail(1) follow multiple files

2015-11-05 Thread Eugene Yunak
On 5 November 2015 at 00:29, Martijn van Duren  wrote:
>
> 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.

Thank you for sharing this, hope it gets accepted.

> (void)printf("%s==> %s <==\n", first ? "" : "\n", fname);

I've recently encountered a problem where I wanted to execute some code for
every new line in a set of files, but the code would be different for each file.
This "==> name <==" format is standard across systems, but it's awkward to
parse. Would OpenBSD be open to a different, non-standard and optional output
format that prefixes each line with "fname:" if there are multiple input files,
much like grep does?

--
The best the little guy can do is what
the little guy does right



[patch] tail(1) follow multiple files

2015-11-04 Thread Martijn van Duren

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,