Re: [patch] tail(1) follow multiple files
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
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
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
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 RLINES
Re: [patch] tail(1) follow multiple files
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
Re: [patch] tail(1) follow multiple files
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
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, "Unsupport