From 30ca6838a2898d0482df790249f3d53f8f5e553c Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 8 Jun 2007 15:19:48 +0200 Subject: inotail.c: Prepare for implementation of tail_pipe_{lines,bytes} Split in two functions --- inotail.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/inotail.c b/inotail.c index bb27702..0b77deb 100644 --- a/inotail.c +++ b/inotail.c @@ -218,15 +218,11 @@ static off_t bytes_to_offset(struct file_struct *f, unsigned long n_bytes) return offset; } -static ssize_t tail_pipe(struct file_struct *f) +static ssize_t tail_pipe_lines(struct file_struct *f, unsigned long n_lines) { ssize_t rc; char buf[BUFFER_SIZE]; - if (verbose) - write_header(f->name); - - /* FIXME: We will just tail everything here for now */ while ((rc = read(f->fd, buf, BUFFER_SIZE)) > 0) { if (write(STDOUT_FILENO, buf, (size_t) rc) <= 0) { /* e.g. when writing to a pipe which gets closed */ @@ -238,6 +234,11 @@ static ssize_t tail_pipe(struct file_struct *f) return rc; } +static ssize_t tail_pipe_bytes(struct file_struct *f, unsigned long n_bytes) { + /* TODO: Implement me :) */ + return 0; +} + static int tail_file(struct file_struct *f, unsigned long n_units, char mode, char forever) { ssize_t bytes_read = 0; @@ -269,8 +270,15 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch } /* Cannot seek on these */ - if (IS_PIPELIKE(finfo.st_mode) || f->fd == STDIN_FILENO) - return tail_pipe(f); + if (IS_PIPELIKE(finfo.st_mode) || f->fd == STDIN_FILENO) { + if (verbose) + write_header(f->name); + + if (mode == M_LINES) + return tail_pipe_lines(f, n_units); + else + return tail_pipe_bytes(f, n_units); + } f->st_size = finfo.st_size; -- cgit v1.2.3-54-g00ecf From 37ce2be45bb911b5e0a54ec7f1cacd8039af0510 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 11 Jun 2007 17:31:52 +0200 Subject: inotail.c: Implement tail_pipe_lines() For now the function is more or less a copy from coreutils tail. This could need some work. --- inotail.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 131 insertions(+), 8 deletions(-) diff --git a/inotail.c b/inotail.c index 0b77deb..228a6e9 100644 --- a/inotail.c +++ b/inotail.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -64,6 +65,18 @@ static const struct option long_opts[] = { { NULL, 0, NULL, 0 } }; +static char *emalloc(size_t size) +{ + char *ret = malloc(size); + + if (unlikely(!ret)) { + fprintf(stderr, "Error: Failed to allocate %d bytes of memory (%s)\n", size, strerror(errno)); + exit(EXIT_FAILURE); + } + + return ret; +} + static void usage(const int status) { fprintf(stdout, "Usage: %s [OPTION]... [FILE]...\n\n" @@ -218,7 +231,122 @@ static off_t bytes_to_offset(struct file_struct *f, unsigned long n_bytes) return offset; } +/* For now more or less a copy of pipe_lines() from coreutils tail */ static ssize_t tail_pipe_lines(struct file_struct *f, unsigned long n_lines) +{ + struct line_buf { + char buf[BUFFER_SIZE]; + size_t n_lines; + size_t n_bytes; + struct line_buf *next; + }; + struct line_buf *first, *last, *tmp; + ssize_t rc; + unsigned long total_lines = 0; + + dprintf("in tail_pipe_lines (%d)\n"); + + if (n_lines == 0) + return 0; + + first = last = emalloc(sizeof(struct line_buf)); + first->n_bytes = first->n_lines = 0; + first->next = NULL; + tmp = emalloc(sizeof(struct line_buf)); + + while (1) { + const char *p; + + if ((rc = read(f->fd, tmp->buf, BUFFER_SIZE)) <= 0) + break; + tmp->n_bytes = rc; + tmp->n_lines = 0; + tmp->next = NULL; + p = tmp->buf; + + /* Count the lines in the current buffer */ + while ((p = memchr(p, '\n', tmp->buf + rc - p))) { + ++p; + ++tmp->n_lines; + } + total_lines += tmp->n_lines; + + /* Try to append to the previous buffer if there's enough free + * space + */ + if (tmp->n_bytes + last->n_bytes < BUFFER_SIZE) { + memcpy(&last->buf[last->n_bytes], tmp->buf, tmp->n_bytes); + last->n_bytes += tmp->n_bytes; + last->n_lines += tmp->n_lines; + } else { + last = last->next = tmp; + if (total_lines - first->n_lines > n_lines) { + tmp = first; + total_lines -= first->n_lines; + first = first->next; + } else + tmp = emalloc(sizeof(struct line_buf)); + } + } + + free(tmp); + + /* XXX: Even necessary? */ + if (rc < 0) { + fprintf(stderr, "Error: Could not read from %s\n", pretty_name(f->name)); + rc = -1; + goto err_out; + } + + if (last->n_bytes == 0) + goto err_out; + + /* Count incomplete lines */ + if (last->buf[last->n_bytes - 1] != '\n') { + ++last->n_lines; + ++total_lines; + } + + /* Skip unneeded buffers */ + for (tmp = first; total_lines - tmp->n_lines > n_lines; tmp = tmp->next) + total_lines -= tmp->n_lines; + + { + char const *p = tmp->buf; + if (total_lines > n_lines) { + size_t j; + for (j = total_lines - n_lines; j; --j) { + p = memchr(p, '\n', tmp->buf + tmp->n_bytes - p); + assert(p); + ++p; + } + } + + write(STDOUT_FILENO, p, tmp->buf + tmp->n_bytes - p); + } + + for (tmp = tmp->next; tmp; tmp = tmp->next) + if (write(STDOUT_FILENO, tmp->buf, tmp->n_bytes) <= 0) { + /* e.g. when writing to a pipe which gets closed */ + fprintf(stderr, "Error: Could not write to stdout (%s)\n", strerror(errno)); + rc = -1; + break; + } + + rc = 0; + +err_out: + while (first) { + tmp = first->next; + free(first); + first = tmp; + } + + return rc; +} + +/* TODO: Implement me :) */ +static ssize_t tail_pipe_bytes(struct file_struct *f, unsigned long n_bytes) { ssize_t rc; char buf[BUFFER_SIZE]; @@ -234,11 +362,6 @@ static ssize_t tail_pipe_lines(struct file_struct *f, unsigned long n_lines) return rc; } -static ssize_t tail_pipe_bytes(struct file_struct *f, unsigned long n_bytes) { - /* TODO: Implement me :) */ - return 0; -} - static int tail_file(struct file_struct *f, unsigned long n_units, char mode, char forever) { ssize_t bytes_read = 0; @@ -293,14 +416,14 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch return -1; } - if (verbose) - write_header(f->name); - if (lseek(f->fd, offset, SEEK_SET) == (off_t) -1) { fprintf(stderr, "Error: Could not seek in file '%s' (%s)\n", f->name, strerror(errno)); return -1; } + if (verbose) + write_header(f->name); + while ((bytes_read = read(f->fd, buf, BUFFER_SIZE)) > 0) write(STDOUT_FILENO, buf, (size_t) bytes_read); -- cgit v1.2.3-54-g00ecf From b46b85361b47506fd097b2067d9cca1d2cfd6560 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 11 Jun 2007 17:32:21 +0200 Subject: inotail.c: remove debugging output --- inotail.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/inotail.c b/inotail.c index 228a6e9..58c37de 100644 --- a/inotail.c +++ b/inotail.c @@ -244,8 +244,6 @@ static ssize_t tail_pipe_lines(struct file_struct *f, unsigned long n_lines) ssize_t rc; unsigned long total_lines = 0; - dprintf("in tail_pipe_lines (%d)\n"); - if (n_lines == 0) return 0; -- cgit v1.2.3-54-g00ecf From 9c0be883f40880366241e5953cfa36f20f3c3fc4 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 11 Jun 2007 19:55:50 +0200 Subject: inotail.c: Fix stupid data type error in emalloc() --- inotail.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inotail.c b/inotail.c index 2144d6a..480e60f 100644 --- a/inotail.c +++ b/inotail.c @@ -64,9 +64,9 @@ static const struct option long_opts[] = { { NULL, 0, NULL, 0 } }; -static char *emalloc(size_t size) +static void *emalloc(size_t size) { - char *ret = malloc(size); + void *ret = malloc(size); if (unlikely(!ret)) { fprintf(stderr, "Error: Failed to allocate %d bytes of memory (%s)\n", size, strerror(errno)); -- cgit v1.2.3-54-g00ecf From b50204eabab7a2f5f21f12e5668f7c8d954aa84a Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 11 Jun 2007 20:08:11 +0200 Subject: inotail.c/.h: Clean up a bit --- inotail.c | 9 --------- inotail.h | 12 ++++++++++-- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/inotail.c b/inotail.c index 480e60f..e98a881 100644 --- a/inotail.c +++ b/inotail.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include @@ -40,7 +39,6 @@ #include "inotail.h" #define PROGRAM_NAME "inotail" -#define BUFFER_SIZE 4096 /* inotify event buffer length for one file */ #define INOTIFY_BUFLEN (4 * sizeof(struct inotify_event)) @@ -233,12 +231,6 @@ static off_t bytes_to_offset(struct file_struct *f, unsigned long n_bytes) /* For now more or less a copy of pipe_lines() from coreutils tail */ static ssize_t tail_pipe_lines(struct file_struct *f, unsigned long n_lines) { - struct line_buf { - char buf[BUFFER_SIZE]; - size_t n_lines; - size_t n_bytes; - struct line_buf *next; - }; struct line_buf *first, *last, *tmp; ssize_t rc; unsigned long total_lines = 0; @@ -314,7 +306,6 @@ static ssize_t tail_pipe_lines(struct file_struct *f, unsigned long n_lines) size_t j; for (j = total_lines - n_lines; j; --j) { p = memchr(p, '\n', tmp->buf + tmp->n_bytes - p); - assert(p); ++p; } } diff --git a/inotail.h b/inotail.h index 836c1de..8e0f30a 100644 --- a/inotail.h +++ b/inotail.h @@ -7,8 +7,8 @@ #ifndef _INOTAIL_H #define _INOTAIL_H -/* Number of items to tail. */ -#define DEFAULT_N_LINES 10 +#define BUFFER_SIZE 4096 +#define DEFAULT_N_LINES 10 /* Number of items to tail. */ /* tail modes */ enum { M_LINES, M_BYTES }; @@ -22,6 +22,14 @@ struct file_struct { int i_watch; /* Inotify watch associated with file_struct */ }; +/* struct for linked list of buffers/lines in tail_pipe_lines */ +struct line_buf { + char buf[BUFFER_SIZE]; + size_t n_lines; + size_t n_bytes; + struct line_buf *next; +}; + #define IS_PIPELIKE(mode) \ (S_ISFIFO(mode) || S_ISSOCK(mode)) -- cgit v1.2.3-54-g00ecf From 82ffa4b8fcfdcd4ec98563daa06ec135f66ad181 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 12 Jun 2007 18:31:12 +0200 Subject: inotail.c: Handle EINTR and EAGAIN in tail_pipe_lines() --- inotail.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/inotail.c b/inotail.c index e98a881..912db03 100644 --- a/inotail.c +++ b/inotail.c @@ -246,8 +246,12 @@ static ssize_t tail_pipe_lines(struct file_struct *f, unsigned long n_lines) while (1) { const char *p; - if ((rc = read(f->fd, tmp->buf, BUFFER_SIZE)) <= 0) - break; + if ((rc = read(f->fd, tmp->buf, BUFFER_SIZE)) <= 0) { + if (rc < 0 && (errno == EINTR || errno == EAGAIN)) + continue; + else + break; + } tmp->n_bytes = rc; tmp->n_lines = 0; tmp->next = NULL; @@ -280,10 +284,8 @@ static ssize_t tail_pipe_lines(struct file_struct *f, unsigned long n_lines) free(tmp); - /* XXX: Even necessary? */ if (rc < 0) { fprintf(stderr, "Error: Could not read from %s\n", pretty_name(f->name)); - rc = -1; goto err_out; } -- cgit v1.2.3-54-g00ecf From c93ac5bc511623f1a7b0d8d741bbe2a837d927f7 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 15 Jun 2007 21:57:40 +0200 Subject: inotail.c: Simplify tail_pipe_lines() --- inotail.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/inotail.c b/inotail.c index 28eebfd..6c4eb47 100644 --- a/inotail.c +++ b/inotail.c @@ -231,6 +231,7 @@ static ssize_t tail_pipe_lines(struct file_struct *f, unsigned long n_lines) struct line_buf *first, *last, *tmp; ssize_t rc; unsigned long total_lines = 0; + const char *p; if (n_lines == 0) return 0; @@ -241,8 +242,6 @@ static ssize_t tail_pipe_lines(struct file_struct *f, unsigned long n_lines) tmp = emalloc(sizeof(struct line_buf)); while (1) { - const char *p; - if ((rc = read(f->fd, tmp->buf, BUFFER_SIZE)) <= 0) { if (rc < 0 && (errno == EINTR || errno == EAGAIN)) continue; @@ -283,11 +282,11 @@ static ssize_t tail_pipe_lines(struct file_struct *f, unsigned long n_lines) if (rc < 0) { fprintf(stderr, "Error: Could not read from %s\n", pretty_name(f->name)); - goto err_out; + goto out; } if (last->n_bytes == 0) - goto err_out; + goto out; /* Count incomplete lines */ if (last->buf[last->n_bytes - 1] != '\n') { @@ -299,19 +298,18 @@ static ssize_t tail_pipe_lines(struct file_struct *f, unsigned long n_lines) for (tmp = first; total_lines - tmp->n_lines > n_lines; tmp = tmp->next) total_lines -= tmp->n_lines; - { - char const *p = tmp->buf; - if (total_lines > n_lines) { - size_t j; - for (j = total_lines - n_lines; j; --j) { - p = memchr(p, '\n', tmp->buf + tmp->n_bytes - p); - ++p; - } - } + p = tmp->buf; - write(STDOUT_FILENO, p, tmp->buf + tmp->n_bytes - p); + if (total_lines > n_lines) { + size_t j; + for (j = total_lines - n_lines; j; --j) { + p = memchr(p, '\n', tmp->buf + tmp->n_bytes - p); + ++p; + } } + write(STDOUT_FILENO, p, tmp->buf + tmp->n_bytes - p); + for (tmp = tmp->next; tmp; tmp = tmp->next) if (write(STDOUT_FILENO, tmp->buf, tmp->n_bytes) <= 0) { /* e.g. when writing to a pipe which gets closed */ @@ -322,7 +320,7 @@ static ssize_t tail_pipe_lines(struct file_struct *f, unsigned long n_lines) rc = 0; -err_out: +out: while (first) { tmp = first->next; free(first); -- cgit v1.2.3-54-g00ecf From e46c83b30b4dcf9d0e38803c8ee8cc58c915f9d7 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 17 Sep 2007 16:00:45 +0200 Subject: inotail.c: Fix initialization of blksize --- inotail.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inotail.c b/inotail.c index e6ad90d..2676176 100644 --- a/inotail.c +++ b/inotail.c @@ -94,7 +94,7 @@ static inline void setup_file(struct file_struct *f) { f->fd = f->i_watch = -1; f->size = 0; - f->blksize = DEFAULT_BUFFER_SIZE; + f->blksize = BUFFER_SIZE; f->ignore = 0; } -- cgit v1.2.3-54-g00ecf From 6c881352db2c4200b89b3d9700e7353f36ae823f Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 17 Sep 2007 23:44:04 +0200 Subject: inotail.c: Correct error handling in tail_pipe_lines() --- inotail.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/inotail.c b/inotail.c index 2676176..fdb2919 100644 --- a/inotail.c +++ b/inotail.c @@ -322,14 +322,17 @@ static ssize_t tail_pipe_lines(struct file_struct *f, unsigned long n_lines) } } - write(STDOUT_FILENO, p, tmp->buf + tmp->n_bytes - p); + if ((rc = write(STDOUT_FILENO, p, tmp->buf + tmp->n_bytes - p)) <= 0) { + /* e.g. when writing to a pipe which gets closed */ + fprintf(stderr, "Error: Could not write to stdout (%s)\n", strerror(errno)); + goto out; + } for (tmp = tmp->next; tmp; tmp = tmp->next) - if (write(STDOUT_FILENO, tmp->buf, tmp->n_bytes) <= 0) { + if ((rc = write(STDOUT_FILENO, tmp->buf, tmp->n_bytes)) <= 0) { /* e.g. when writing to a pipe which gets closed */ fprintf(stderr, "Error: Could not write to stdout (%s)\n", strerror(errno)); - rc = -1; - break; + goto out; } rc = 0; -- cgit v1.2.3-54-g00ecf From 21fc4aa4615803896f28bfc8e0009504effdd690 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 18 Sep 2007 11:50:38 +0200 Subject: inotail.c: Use BUFSIZ and post-increment For consistency reasons mostly :-) --- inotail.c | 22 ++++++++++------------ inotail.h | 3 +-- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/inotail.c b/inotail.c index fdb2919..02cf462 100644 --- a/inotail.c +++ b/inotail.c @@ -94,7 +94,7 @@ static inline void setup_file(struct file_struct *f) { f->fd = f->i_watch = -1; f->size = 0; - f->blksize = BUFFER_SIZE; + f->blksize = BUFSIZ; f->ignore = 0; } @@ -256,7 +256,7 @@ static ssize_t tail_pipe_lines(struct file_struct *f, unsigned long n_lines) tmp = emalloc(sizeof(struct line_buf)); while (1) { - if ((rc = read(f->fd, tmp->buf, BUFFER_SIZE)) <= 0) { + if ((rc = read(f->fd, tmp->buf, BUFSIZ)) <= 0) { if (rc < 0 && (errno == EINTR || errno == EAGAIN)) continue; else @@ -269,15 +269,15 @@ static ssize_t tail_pipe_lines(struct file_struct *f, unsigned long n_lines) /* Count the lines in the current buffer */ while ((p = memchr(p, '\n', tmp->buf + rc - p))) { - ++p; - ++tmp->n_lines; + p++; + tmp->n_lines++; } total_lines += tmp->n_lines; /* Try to append to the previous buffer if there's enough free * space */ - if (tmp->n_bytes + last->n_bytes < BUFFER_SIZE) { + if (tmp->n_bytes + last->n_bytes < BUFSIZ) { memcpy(&last->buf[last->n_bytes], tmp->buf, tmp->n_bytes); last->n_bytes += tmp->n_bytes; last->n_lines += tmp->n_lines; @@ -304,8 +304,8 @@ static ssize_t tail_pipe_lines(struct file_struct *f, unsigned long n_lines) /* Count incomplete lines */ if (last->buf[last->n_bytes - 1] != '\n') { - ++last->n_lines; - ++total_lines; + last->n_lines++; + total_lines++; } /* Skip unneeded buffers */ @@ -315,10 +315,10 @@ static ssize_t tail_pipe_lines(struct file_struct *f, unsigned long n_lines) p = tmp->buf; if (total_lines > n_lines) { - size_t j; + unsigned long j; for (j = total_lines - n_lines; j; --j) { p = memchr(p, '\n', tmp->buf + tmp->n_bytes - p); - ++p; + p++; } } @@ -330,13 +330,11 @@ static ssize_t tail_pipe_lines(struct file_struct *f, unsigned long n_lines) for (tmp = tmp->next; tmp; tmp = tmp->next) if ((rc = write(STDOUT_FILENO, tmp->buf, tmp->n_bytes)) <= 0) { - /* e.g. when writing to a pipe which gets closed */ fprintf(stderr, "Error: Could not write to stdout (%s)\n", strerror(errno)); goto out; } rc = 0; - out: while (first) { tmp = first->next; @@ -351,7 +349,7 @@ out: static ssize_t tail_pipe_bytes(struct file_struct *f, unsigned long n_bytes) { ssize_t rc; - char buf[BUFFER_SIZE]; + char buf[BUFSIZ]; /* We will just tail everything here */ while ((rc = read(f->fd, buf, f->blksize)) > 0) { diff --git a/inotail.h b/inotail.h index dcc948d..f9eabba 100644 --- a/inotail.h +++ b/inotail.h @@ -9,7 +9,6 @@ #include -#define BUFFER_SIZE 4096 #define DEFAULT_N_LINES 10 /* Number of items to tail. */ /* tail modes */ @@ -27,7 +26,7 @@ struct file_struct { /* struct for linked list of buffers/lines in tail_pipe_lines */ struct line_buf { - char buf[BUFFER_SIZE]; + char buf[BUFSIZ]; size_t n_lines; size_t n_bytes; struct line_buf *next; -- cgit v1.2.3-54-g00ecf From 8787c5e9f422ae6a9d3e3f5445301f753c3fe02d Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 18 Sep 2007 13:28:59 +0200 Subject: inotail.c: Implement tail_pipe_bytes() For now more or less a copy from coreutils --- inotail.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- inotail.h | 7 ++++++ 2 files changed, 77 insertions(+), 9 deletions(-) diff --git a/inotail.c b/inotail.c index 02cf462..cd96ec1 100644 --- a/inotail.c +++ b/inotail.c @@ -345,23 +345,84 @@ out: return rc; } -/* TODO: Implement me :) */ static ssize_t tail_pipe_bytes(struct file_struct *f, unsigned long n_bytes) { + struct char_buf *first, *last, *tmp; ssize_t rc; - char buf[BUFSIZ]; + unsigned long total_bytes = 0; + unsigned long i = 0; /* Index into buffer */ - /* We will just tail everything here */ - while ((rc = read(f->fd, buf, f->blksize)) > 0) { - if (write(STDOUT_FILENO, buf, (size_t) rc) <= 0) { - /* e.g. when writing to a pipe which gets closed */ + if (n_bytes == 0) + return 0; + + first = last = emalloc(sizeof(struct char_buf)); + first->n_bytes = 0; + first->next = NULL; + tmp = emalloc(sizeof(struct char_buf)); + + while(1) { + if ((rc = read(f->fd, tmp->buf, BUFSIZ)) <= 0) { + if (rc < 0 && (errno == EINTR || errno == EAGAIN)) + continue; + else + break; + } + total_bytes += rc; + tmp->n_bytes = rc; + tmp->next = NULL; + + /* Try to append to the previous buffer if there's enough free + * space + */ + if (tmp->n_bytes + last->n_bytes < BUFSIZ) { + memcpy(&last->buf[last->n_bytes], tmp->buf, tmp->n_bytes); + last->n_bytes += tmp->n_bytes; + } else { + last = last->next = tmp; + if (total_bytes - first->n_bytes > n_bytes) { + tmp = first; + total_bytes -= first->n_bytes; + first = first->next; + } else + tmp = emalloc(sizeof(struct char_buf)); + } + } + + free(tmp); + + if (rc < 0) { + fprintf(stderr, "Error: Could not read from %s\n", pretty_name(f->name)); + goto out; + } + + /* Skip unneeded buffers */ + for (tmp = first; total_bytes - tmp->n_bytes > n_bytes; tmp = tmp->next) + total_bytes -= tmp->n_bytes; + + if (total_bytes > n_bytes) + i = total_bytes - n_bytes; + + if ((rc = write(STDOUT_FILENO, &tmp->buf[i], tmp->n_bytes - i)) <= 0) { + /* e.g. when writing to a pipe which gets closed */ + fprintf(stderr, "Error: Could not write to stdout (%s)\n", strerror(errno)); + goto out; + } + + for (tmp = tmp->next; tmp; tmp = tmp->next) + if ((rc = write(STDOUT_FILENO, tmp->buf, tmp->n_bytes)) <= 0) { fprintf(stderr, "Error: Could not write to stdout (%s)\n", strerror(errno)); - rc = -1; - break; + goto out; } + + + rc = 0; +out: + while (first) { + tmp = first->next; + free(first); + first = tmp; } - free(buf); return rc; } diff --git a/inotail.h b/inotail.h index f9eabba..5029540 100644 --- a/inotail.h +++ b/inotail.h @@ -32,6 +32,13 @@ struct line_buf { struct line_buf *next; }; +/* struct for linked list of byte buffers in tail_pipe_bytes */ +struct char_buf { + char buf[BUFSIZ]; + size_t n_bytes; + struct char_buf *next; +}; + #define IS_PIPELIKE(mode) \ (S_ISFIFO(mode) || S_ISSOCK(mode)) -- cgit v1.2.3-54-g00ecf From 6b1ce4b2a1eb356541bbc5ed661344b30f7bab85 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 18 Sep 2007 13:37:46 +0200 Subject: intotail.c: Check for n_units == 0 before calling tail_pipe_*() --- inotail.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/inotail.c b/inotail.c index cd96ec1..c455fd0 100644 --- a/inotail.c +++ b/inotail.c @@ -247,9 +247,6 @@ static ssize_t tail_pipe_lines(struct file_struct *f, unsigned long n_lines) unsigned long total_lines = 0; const char *p; - if (n_lines == 0) - return 0; - first = last = emalloc(sizeof(struct line_buf)); first->n_bytes = first->n_lines = 0; first->next = NULL; @@ -352,9 +349,6 @@ static ssize_t tail_pipe_bytes(struct file_struct *f, unsigned long n_bytes) unsigned long total_bytes = 0; unsigned long i = 0; /* Index into buffer */ - if (n_bytes == 0) - return 0; - first = last = emalloc(sizeof(struct char_buf)); first->n_bytes = 0; first->next = NULL; @@ -461,6 +455,9 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch if (verbose) write_header(f->name); + if (n_units == 0) + return 0; + if (mode == M_LINES) return tail_pipe_lines(f, n_units); else -- cgit v1.2.3-54-g00ecf From f4c22bb16fc842f66060d4f7a79338c900f8dfb9 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 18 Sep 2007 18:30:19 +0200 Subject: inotail.c: Implement pipe tailing lines from begin Use a general function for lines and bytes to prevent duplicating code. --- inotail.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 5 deletions(-) diff --git a/inotail.c b/inotail.c index c455fd0..7ed5b31 100644 --- a/inotail.c +++ b/inotail.c @@ -239,14 +239,63 @@ static off_t bytes_to_offset(struct file_struct *f, unsigned long n_bytes) return offset; } -/* For now more or less a copy of pipe_lines() from coreutils tail */ -static ssize_t tail_pipe_lines(struct file_struct *f, unsigned long n_lines) +static int tail_pipe_from_begin(struct file_struct *f, unsigned long n_units, const char mode) +{ + int bytes_read = 0; + char buf[BUFSIZ]; + + n_units--; + + while (n_units > 0) { + if ((bytes_read = read(f->fd, buf, BUFSIZ)) <= 0) { + if (bytes_read < 0 && (errno == EINTR || errno == EAGAIN)) + continue; + else + return bytes_read; + } + + if (mode == M_LINES) { + int i; + ssize_t block_size = BUFSIZ; + + if (bytes_read < BUFSIZ) + block_size = bytes_read; + + for (i = 0; i < block_size; i++) { + if (buf[i] == '\n') { + if (--n_units == 0) + break; + } + } + + if (++i < block_size) + write(STDOUT_FILENO, &buf[i], bytes_read - i); + } else { + if ((unsigned long) bytes_read > n_units) { + write(STDOUT_FILENO, &buf[n_units], bytes_read - n_units); + bytes_read = n_units; + } + + n_units -= bytes_read; + } + } + + while ((bytes_read = read(f->fd, buf, BUFSIZ)) > 0) + write(STDOUT_FILENO, buf, (size_t) bytes_read); + + return 0; +} + +static int tail_pipe_lines(struct file_struct *f, unsigned long n_lines) { struct line_buf *first, *last, *tmp; - ssize_t rc; + int rc; unsigned long total_lines = 0; const char *p; + if (from_begin) + return tail_pipe_from_begin(f, n_lines, M_LINES); + first = last = emalloc(sizeof(struct line_buf)); first->n_bytes = first->n_lines = 0; first->next = NULL; @@ -342,13 +391,16 @@ out: return rc; } -static ssize_t tail_pipe_bytes(struct file_struct *f, unsigned long n_bytes) +static int tail_pipe_bytes(struct file_struct *f, unsigned long n_bytes) { struct char_buf *first, *last, *tmp; - ssize_t rc; + int rc; unsigned long total_bytes = 0; unsigned long i = 0; /* Index into buffer */ + if (from_begin) + return tail_pipe_from_begin(f, n_bytes, M_BYTES); + first = last = emalloc(sizeof(struct char_buf)); first->n_bytes = 0; first->next = NULL; -- cgit v1.2.3-54-g00ecf From 6ec61a62e5a1a586766d46108d5ae7e1aaf3dd8c Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 19 Sep 2007 10:13:44 +0200 Subject: inotail.c: Check for n_units == 0 only if tailing from end inotail -n+0/-c+0 should be allowed --- inotail.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/inotail.c b/inotail.c index 7ed5b31..483306e 100644 --- a/inotail.c +++ b/inotail.c @@ -244,7 +244,8 @@ static int tail_pipe_from_begin(struct file_struct *f, unsigned long n_units, co int bytes_read = 0; char buf[BUFSIZ]; - n_units--; + if (n_units) + n_units--; while (n_units > 0) { if ((bytes_read = read(f->fd, buf, BUFSIZ)) <= 0) { @@ -296,6 +297,9 @@ static int tail_pipe_lines(struct file_struct *f, unsigned long n_lines) if (from_begin) return tail_pipe_from_begin(f, n_lines, M_LINES); + if (n_lines == 0) + return 0; + first = last = emalloc(sizeof(struct line_buf)); first->n_bytes = first->n_lines = 0; first->next = NULL; @@ -401,6 +405,10 @@ static int tail_pipe_bytes(struct file_struct *f, unsigned long n_bytes) if (from_begin) return tail_pipe_from_begin(f, n_bytes, M_BYTES); + /* XXX: Needed? */ + if (n_bytes == 0) + return 0; + first = last = emalloc(sizeof(struct char_buf)); first->n_bytes = 0; first->next = NULL; @@ -507,9 +515,6 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch if (verbose) write_header(f->name); - if (n_units == 0) - return 0; - if (mode == M_LINES) return tail_pipe_lines(f, n_units); else -- cgit v1.2.3-54-g00ecf From 21cddfba5f53ed0ad9d8f14bc1555c57cad9790e Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 25 Sep 2007 23:51:29 +0200 Subject: inotail.c: Decrement n_units before calling tail_pipe_from_begin Saves 2 lines of code --- inotail.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/inotail.c b/inotail.c index 483306e..2eef622 100644 --- a/inotail.c +++ b/inotail.c @@ -244,9 +244,6 @@ static int tail_pipe_from_begin(struct file_struct *f, unsigned long n_units, co int bytes_read = 0; char buf[BUFSIZ]; - if (n_units) - n_units--; - while (n_units > 0) { if ((bytes_read = read(f->fd, buf, BUFSIZ)) <= 0) { if (bytes_read < 0 && (errno == EINTR || errno == EAGAIN)) @@ -295,7 +292,7 @@ static int tail_pipe_lines(struct file_struct *f, unsigned long n_lines) const char *p; if (from_begin) - return tail_pipe_from_begin(f, n_lines, M_LINES); + return tail_pipe_from_begin(f, n_lines - 1, M_LINES); if (n_lines == 0) return 0; @@ -403,7 +400,7 @@ static int tail_pipe_bytes(struct file_struct *f, unsigned long n_bytes) unsigned long i = 0; /* Index into buffer */ if (from_begin) - return tail_pipe_from_begin(f, n_bytes, M_BYTES); + return tail_pipe_from_begin(f, n_bytes - 1, M_BYTES); /* XXX: Needed? */ if (n_bytes == 0) -- cgit v1.2.3-54-g00ecf From a4d7f34d0210344d2e25e5af1c2e61057422521d Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Sun, 11 Nov 2007 21:17:57 +0100 Subject: Revert "inotail.c: Decrement n_units before calling tail_pipe_from_begin" This reverts commit 21cddfba5f53ed0ad9d8f14bc1555c57cad9790e. Makes inotail -n +0 work again. Sometimes reducing code leads to unrecognised errors ;-) --- inotail.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/inotail.c b/inotail.c index 2eef622..483306e 100644 --- a/inotail.c +++ b/inotail.c @@ -244,6 +244,9 @@ static int tail_pipe_from_begin(struct file_struct *f, unsigned long n_units, co int bytes_read = 0; char buf[BUFSIZ]; + if (n_units) + n_units--; + while (n_units > 0) { if ((bytes_read = read(f->fd, buf, BUFSIZ)) <= 0) { if (bytes_read < 0 && (errno == EINTR || errno == EAGAIN)) @@ -292,7 +295,7 @@ static int tail_pipe_lines(struct file_struct *f, unsigned long n_lines) const char *p; if (from_begin) - return tail_pipe_from_begin(f, n_lines - 1, M_LINES); + return tail_pipe_from_begin(f, n_lines, M_LINES); if (n_lines == 0) return 0; @@ -400,7 +403,7 @@ static int tail_pipe_bytes(struct file_struct *f, unsigned long n_bytes) unsigned long i = 0; /* Index into buffer */ if (from_begin) - return tail_pipe_from_begin(f, n_bytes - 1, M_BYTES); + return tail_pipe_from_begin(f, n_bytes, M_BYTES); /* XXX: Needed? */ if (n_bytes == 0) -- cgit v1.2.3-54-g00ecf