From 2bc261d8289552d21ac7ae652c95d121f5b9561c Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 21 May 2007 17:52:48 +0200 Subject: Use optimal buffer size depending on the filesystem containing the file The st_blksize attribute of struct stat conatains the blocksize for filesystem I/O (see stat(2)) which is the optimal size for reading/writing chunks of data. Based on a patch by Folkert van Heusden --- inotail.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++--------------- inotail.h | 3 +++ 2 files changed, 66 insertions(+), 19 deletions(-) diff --git a/inotail.c b/inotail.c index 3384d5b..6f02f78 100644 --- a/inotail.c +++ b/inotail.c @@ -40,7 +40,7 @@ #include "inotail.h" #define PROGRAM_NAME "inotail" -#define BUFFER_SIZE 4096 +#define DEFAULT_BUFFER_SIZE 4096 /* inotify event buffer length for one file */ #define INOTIFY_BUFLEN (4 * sizeof(struct inotify_event)) @@ -84,6 +84,7 @@ static inline void setup_file(struct file_struct *f) { f->fd = -1; f->st_size = 0; + f->st_blksize = DEFAULT_BUFFER_SIZE; f->ignore = 0; f->i_watch = -1; } @@ -115,18 +116,34 @@ static void write_header(char *filename) last = filename; } +static char *alloc_buffer(struct file_struct *f) +{ + char *buf; + + buf = malloc(f->st_blksize); + if (!buf) { + fprintf(stderr, "Error: Failed to allocate memory (%s)\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + return buf; +} + static off_t lines_to_offset_from_end(struct file_struct *f, unsigned long n_lines) { - char buf[BUFFER_SIZE]; + char *buf; off_t offset = f->st_size; + ssize_t buffer_size = f->st_blksize; + + buf = alloc_buffer(f); n_lines++; /* We also count the last \n */ while (offset > 0 && n_lines > 0) { int i; - ssize_t rc, block_size = BUFFER_SIZE; /* Size of the current block we're reading */ + ssize_t rc, block_size = buffer_size; /* Size of the current block we're reading */ - if (offset < BUFFER_SIZE) + if (offset < buffer_size) block_size = offset; /* Start of current block */ @@ -137,25 +154,31 @@ static off_t lines_to_offset_from_end(struct file_struct *f, unsigned long n_lin rc = read(f->fd, buf, block_size); if (unlikely(rc < 0)) { fprintf(stderr, "Error: Could not read from file '%s' (%s)\n", f->name, strerror(errno)); + free(buf); return -1; } for (i = block_size - 1; i > 0; i--) { if (buf[i] == '\n') { - if (--n_lines == 0) + if (--n_lines == 0) { + free(buf); return offset += i + 1; /* We don't want the first \n */ + } } } } + free(buf); return offset; } static off_t lines_to_offset_from_begin(struct file_struct *f, unsigned long n_lines) { - char buf[BUFFER_SIZE]; + char *buf; off_t offset = 0; + buf = alloc_buffer(f); + /* tail everything for 'inotail -n +0' */ if (n_lines == 0) return 0; @@ -164,27 +187,31 @@ static off_t lines_to_offset_from_begin(struct file_struct *f, unsigned long n_l while (offset <= f->st_size && n_lines > 0) { int i; - ssize_t rc, block_size = BUFFER_SIZE; + ssize_t rc, block_size = f->st_blksize; lseek(f->fd, offset, SEEK_SET); rc = read(f->fd, buf, block_size); if (unlikely(rc < 0)) { fprintf(stderr, "Error: Could not read from file '%s' (%s)\n", f->name, strerror(errno)); + free(buf); return -1; } else if (rc < block_size) block_size = rc; for (i = 0; i < block_size; i++) { if (buf[i] == '\n') { - if (--n_lines == 0) + if (--n_lines == 0) { + free(buf); return offset + i + 1; + } } } offset += block_size; } + free(buf); return offset; } @@ -214,14 +241,16 @@ static off_t bytes_to_offset(struct file_struct *f, unsigned long n_bytes) static ssize_t tail_pipe(struct file_struct *f) { - ssize_t rc; - char buf[BUFFER_SIZE]; + ssize_t rc, buffer_size = f->st_blksize; + char *buf; + + buf = alloc_buffer(f); if (verbose) write_header(f->name); /* We will just tail everything here */ - while ((rc = read(f->fd, buf, BUFFER_SIZE)) > 0) { + 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 */ fprintf(stderr, "Error: Could not write to stdout (%s)\n", strerror(errno)); @@ -229,6 +258,7 @@ static ssize_t tail_pipe(struct file_struct *f) } } + free(buf); return rc; } @@ -236,9 +266,12 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch { ssize_t bytes_read = 0; off_t offset = 0; - char buf[BUFFER_SIZE]; + char *buf; + ssize_t buffer_size; struct stat finfo; + buf = alloc_buffer(f); + if (strcmp(f->name, "-") == 0) f->fd = STDIN_FILENO; else { @@ -267,6 +300,7 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch return tail_pipe(f); f->st_size = finfo.st_size; + f->st_blksize = finfo.st_blksize; /* TODO: Can this value be 0 or negative? */ if (mode == M_LINES) offset = lines_to_offset(f, n_units); @@ -284,7 +318,8 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch lseek(f->fd, offset, SEEK_SET); - while ((bytes_read = read(f->fd, buf, BUFFER_SIZE)) > 0) + buffer_size = f->st_blksize; + while ((bytes_read = read(f->fd, buf, buffer_size)) > 0) write(STDOUT_FILENO, buf, (size_t) bytes_read); if (!forever) { @@ -302,15 +337,17 @@ static int handle_inotify_event(struct inotify_event *inev, struct file_struct * int ret = 0; if (inev->mask & IN_MODIFY) { - ssize_t rc; - char fbuf[BUFFER_SIZE]; + ssize_t rc, buffer_size = f->st_blksize; + char *fbuf; struct stat finfo; + fbuf = alloc_buffer(f); + if (verbose) write_header(f->name); lseek(f->fd, f->st_size, SEEK_SET); /* Old file size */ - while ((rc = read(f->fd, fbuf, BUFFER_SIZE)) != 0) + while ((rc = read(f->fd, fbuf, buffer_size)) != 0) write(STDOUT_FILENO, fbuf, (size_t) rc); if (fstat(f->fd, &finfo) < 0) { @@ -321,6 +358,7 @@ static int handle_inotify_event(struct inotify_event *inev, struct file_struct * f->st_size = finfo.st_size; + free(fbuf); return ret; } else if (inev->mask & IN_DELETE_SELF) { fprintf(stderr, "File '%s' deleted.\n", f->name); @@ -460,15 +498,21 @@ int main(int argc, char **argv) specified and standard input is a pipe. */ if (forever) { struct stat finfo; - if (fstat(STDIN_FILENO, &finfo) == 0 - && IS_PIPELIKE(finfo.st_mode)) + int rc = fstat(STDIN_FILENO, &finfo); + + if (rc == -1) { + fprintf(stderr, "Error: Could not stat stdin (%s)\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + if (rc == 0 && IS_PIPELIKE(finfo.st_mode)) forever = 0; } } files = malloc(n_files * sizeof(struct file_struct)); if (unlikely(!files)) { - fprintf(stderr, "Error: Not enough memory (%s)\n", strerror(errno)); + fprintf(stderr, "Error: Could not allocate memory (%s)\n", strerror(errno)); exit(EXIT_FAILURE); } diff --git a/inotail.h b/inotail.h index 4c57867..d1874b5 100644 --- a/inotail.h +++ b/inotail.h @@ -7,6 +7,8 @@ #ifndef _INOTAIL_H #define _INOTAIL_H +#include + /* Number of items to tail. */ #define DEFAULT_N_LINES 10 @@ -18,6 +20,7 @@ struct file_struct { char *name; /* Name of file (or '-' for stdin) */ int fd; /* File descriptor (or -1 if file is not open */ off_t st_size; /* File size */ + blksize_t st_blksize; /* Blocksize for filesystem I/O */ unsigned ignore; /* Whether to ignore the file in further processing */ int i_watch; /* Inotify watch associated with file_struct */ }; -- cgit v1.2.3-54-g00ecf From e383af6209d3e9983c6989b171bbedc40fc9ffbe Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 21 May 2007 17:58:58 +0200 Subject: Get rid of one variable --- inotail.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/inotail.c b/inotail.c index 6f02f78..f9126b7 100644 --- a/inotail.c +++ b/inotail.c @@ -133,7 +133,6 @@ static off_t lines_to_offset_from_end(struct file_struct *f, unsigned long n_lin { char *buf; off_t offset = f->st_size; - ssize_t buffer_size = f->st_blksize; buf = alloc_buffer(f); @@ -141,9 +140,9 @@ static off_t lines_to_offset_from_end(struct file_struct *f, unsigned long n_lin while (offset > 0 && n_lines > 0) { int i; - ssize_t rc, block_size = buffer_size; /* Size of the current block we're reading */ + ssize_t rc, block_size = f->st_blksize; /* Size of the current block we're reading */ - if (offset < buffer_size) + if (offset < f->st_blksize) block_size = offset; /* Start of current block */ -- cgit v1.2.3-54-g00ecf From 000fdf04a941b5d306c9c0cc54b9fce08b4379b8 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 21 May 2007 18:09:08 +0200 Subject: Prevent from some possible memory leaks --- inotail.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/inotail.c b/inotail.c index f9126b7..9d5229e 100644 --- a/inotail.c +++ b/inotail.c @@ -253,6 +253,7 @@ static ssize_t tail_pipe(struct file_struct *f) if (write(STDOUT_FILENO, buf, (size_t) rc) < 0) { /* e.g. when writing to a pipe which gets closed */ fprintf(stderr, "Error: Could not write to stdout (%s)\n", strerror(errno)); + free(buf); return -1; } } @@ -265,12 +266,10 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch { ssize_t bytes_read = 0; off_t offset = 0; - char *buf; + char *buf = NULL; ssize_t buffer_size; struct stat finfo; - buf = alloc_buffer(f); - if (strcmp(f->name, "-") == 0) f->fd = STDIN_FILENO; else { @@ -298,6 +297,8 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch if (IS_PIPELIKE(finfo.st_mode) || f->fd == STDIN_FILENO) return tail_pipe(f); + buf = alloc_buffer(f); + f->st_size = finfo.st_size; f->st_blksize = finfo.st_blksize; /* TODO: Can this value be 0 or negative? */ @@ -309,6 +310,7 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch /* We only get negative offsets on errors */ if (unlikely(offset < 0)) { ignore_file(f); + free(buf); return -1; } @@ -324,6 +326,7 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch if (!forever) { if (close(f->fd) < 0) { fprintf(stderr, "Error: Could not close file '%s' (%s)\n", f->name, strerror(errno)); + free(buf); return -1; } } /* Let the fd open otherwise, we'll need it */ @@ -333,11 +336,11 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch static int handle_inotify_event(struct inotify_event *inev, struct file_struct *f) { + char *fbuf; int ret = 0; if (inev->mask & IN_MODIFY) { ssize_t rc, buffer_size = f->st_blksize; - char *fbuf; struct stat finfo; fbuf = alloc_buffer(f); @@ -370,7 +373,7 @@ static int handle_inotify_event(struct inotify_event *inev, struct file_struct * ignore: ignore_file(f); - + free(fbuf); return ret; } -- cgit v1.2.3-54-g00ecf From ec290fea4468a13a8019ce24b9bf2896f4725330 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 21 May 2007 23:45:41 +0200 Subject: Some housekeeping after introduction of alloc_buffer() --- inotail.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/inotail.c b/inotail.c index 9d5229e..4664a62 100644 --- a/inotail.c +++ b/inotail.c @@ -142,7 +142,7 @@ static off_t lines_to_offset_from_end(struct file_struct *f, unsigned long n_lin int i; ssize_t rc, block_size = f->st_blksize; /* Size of the current block we're reading */ - if (offset < f->st_blksize) + if (offset < block_size) block_size = offset; /* Start of current block */ @@ -176,13 +176,12 @@ static off_t lines_to_offset_from_begin(struct file_struct *f, unsigned long n_l char *buf; off_t offset = 0; - buf = alloc_buffer(f); - /* tail everything for 'inotail -n +0' */ if (n_lines == 0) return 0; n_lines--; + buf = alloc_buffer(f); while (offset <= f->st_size && n_lines > 0) { int i; -- cgit v1.2.3-54-g00ecf From 8c7670513eb7b98d6c72ccfdcc919e8811333530 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 23 May 2007 19:31:30 +0200 Subject: Change alloc_buffer to take a size_t which is more logical Some additional cleanups e.g. deletion of unecessary buffer_size variables --- inotail.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/inotail.c b/inotail.c index fc021dd..f7f6a40 100644 --- a/inotail.c +++ b/inotail.c @@ -116,11 +116,11 @@ static void write_header(char *filename) last = filename; } -static char *alloc_buffer(struct file_struct *f) +static char *alloc_buffer(size_t buffer_size) { char *buf; - buf = malloc(f->st_blksize); + buf = malloc(buffer_size); if (!buf) { fprintf(stderr, "Error: Failed to allocate memory (%s)\n", strerror(errno)); exit(EXIT_FAILURE); @@ -131,10 +131,8 @@ static char *alloc_buffer(struct file_struct *f) static off_t lines_to_offset_from_end(struct file_struct *f, unsigned long n_lines) { - char *buf; off_t offset = f->st_size; - - buf = alloc_buffer(f); + char *buf = alloc_buffer(f->st_blksize); n_lines++; /* We also count the last \n */ @@ -181,7 +179,7 @@ static off_t lines_to_offset_from_begin(struct file_struct *f, unsigned long n_l return 0; n_lines--; - buf = alloc_buffer(f); + buf = alloc_buffer(f->st_blksize); while (offset <= f->st_size && n_lines > 0) { int i; @@ -239,21 +237,19 @@ static off_t bytes_to_offset(struct file_struct *f, unsigned long n_bytes) static ssize_t tail_pipe(struct file_struct *f) { - ssize_t rc, buffer_size = f->st_blksize; - char *buf; - - buf = alloc_buffer(f); + ssize_t rc; + char *buf = alloc_buffer(f->st_blksize); if (verbose) write_header(f->name); /* We will just tail everything here */ - while ((rc = read(f->fd, buf, buffer_size)) > 0) { + while ((rc = read(f->fd, buf, f->st_blksize)) > 0) { if (write(STDOUT_FILENO, buf, (size_t) rc) < 0) { /* e.g. when writing to a pipe which gets closed */ fprintf(stderr, "Error: Could not write to stdout (%s)\n", strerror(errno)); - free(buf); - return -1; + rc = -1; + break; } } @@ -265,8 +261,7 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch { ssize_t bytes_read = 0; off_t offset = 0; - char *buf = NULL; - ssize_t buffer_size; + char *buf; struct stat finfo; if (strcmp(f->name, "-") == 0) @@ -296,11 +291,11 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch if (IS_PIPELIKE(finfo.st_mode) || f->fd == STDIN_FILENO) return tail_pipe(f); - buf = alloc_buffer(f); - f->st_size = finfo.st_size; f->st_blksize = finfo.st_blksize; /* TODO: Can this value be 0 or negative? */ + buf = alloc_buffer(f->st_blksize); + if (mode == M_LINES) offset = lines_to_offset(f, n_units); else @@ -318,8 +313,7 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch lseek(f->fd, offset, SEEK_SET); - buffer_size = f->st_blksize; - while ((bytes_read = read(f->fd, buf, buffer_size)) > 0) + while ((bytes_read = read(f->fd, buf, f->st_blksize)) > 0) write(STDOUT_FILENO, buf, (size_t) bytes_read); if (!forever) { @@ -330,6 +324,7 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch } } /* Let the fd open otherwise, we'll need it */ + free(buf); return 0; } @@ -339,16 +334,16 @@ static int handle_inotify_event(struct inotify_event *inev, struct file_struct * int ret = 0; if (inev->mask & IN_MODIFY) { - ssize_t rc, buffer_size = f->st_blksize; + ssize_t rc; struct stat finfo; - fbuf = alloc_buffer(f); + fbuf = alloc_buffer(f->st_blksize); if (verbose) write_header(f->name); lseek(f->fd, f->st_size, SEEK_SET); /* Old file size */ - while ((rc = read(f->fd, fbuf, buffer_size)) != 0) + while ((rc = read(f->fd, fbuf, f->st_blksize)) != 0) write(STDOUT_FILENO, fbuf, (size_t) rc); if (fstat(f->fd, &finfo) < 0) { -- cgit v1.2.3-54-g00ecf From 7f1ae64d5610c5ed4ceb9c07d6fd6ed7e7b98165 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 8 Jun 2007 15:47:01 +0200 Subject: inotail.c: Rename alloc_buffer() to emalloc() This better describes what the function really does. It will be used for the allocating of the line buffers in tail_pipe too. --- inotail.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/inotail.c b/inotail.c index f7f6a40..065edf5 100644 --- a/inotail.c +++ b/inotail.c @@ -64,6 +64,18 @@ static const struct option long_opts[] = { { NULL, 0, NULL, 0 } }; +static char *emalloc(size_t size) +{ + char *ret = malloc(size); + + if (!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" @@ -116,23 +128,10 @@ static void write_header(char *filename) last = filename; } -static char *alloc_buffer(size_t buffer_size) -{ - char *buf; - - buf = malloc(buffer_size); - if (!buf) { - fprintf(stderr, "Error: Failed to allocate memory (%s)\n", strerror(errno)); - exit(EXIT_FAILURE); - } - - return buf; -} - static off_t lines_to_offset_from_end(struct file_struct *f, unsigned long n_lines) { off_t offset = f->st_size; - char *buf = alloc_buffer(f->st_blksize); + char *buf = emalloc(f->st_blksize); n_lines++; /* We also count the last \n */ @@ -179,7 +178,7 @@ static off_t lines_to_offset_from_begin(struct file_struct *f, unsigned long n_l return 0; n_lines--; - buf = alloc_buffer(f->st_blksize); + buf = emalloc(f->st_blksize); while (offset <= f->st_size && n_lines > 0) { int i; @@ -238,7 +237,7 @@ static off_t bytes_to_offset(struct file_struct *f, unsigned long n_bytes) static ssize_t tail_pipe(struct file_struct *f) { ssize_t rc; - char *buf = alloc_buffer(f->st_blksize); + char *buf = emalloc(f->st_blksize); if (verbose) write_header(f->name); @@ -294,7 +293,7 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch f->st_size = finfo.st_size; f->st_blksize = finfo.st_blksize; /* TODO: Can this value be 0 or negative? */ - buf = alloc_buffer(f->st_blksize); + buf = emalloc(f->st_blksize); if (mode == M_LINES) offset = lines_to_offset(f, n_units); @@ -337,7 +336,7 @@ static int handle_inotify_event(struct inotify_event *inev, struct file_struct * ssize_t rc; struct stat finfo; - fbuf = alloc_buffer(f->st_blksize); + fbuf = emalloc(f->st_blksize); if (verbose) write_header(f->name); -- cgit v1.2.3-54-g00ecf From 06da83bc3a969c18ee99aa1b3ea511bf4c3763ff Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 15 Jun 2007 21:58:49 +0200 Subject: inotail.c: s/Inotify/inotify/ --- inotail.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inotail.c b/inotail.c index 967a0fa..aecbc1a 100644 --- a/inotail.c +++ b/inotail.c @@ -355,10 +355,10 @@ static int watch_files(struct file_struct *files, int n_files) ifd = inotify_init(); if (errno == ENOSYS) { - fprintf(stderr, "Error: Inotify is not supported by the kernel you're currently running.\n"); + fprintf(stderr, "Error: inotify is not supported by the kernel you're currently running.\n"); exit(EXIT_FAILURE); } else if (unlikely(ifd < 0)) { - fprintf(stderr, "Error: Could not initialize Inotify (%s)\n", strerror(errno)); + fprintf(stderr, "Error: Could not initialize inotify (%s)\n", strerror(errno)); exit(EXIT_FAILURE); } -- cgit v1.2.3-54-g00ecf From 68d456507035555516a5b586303ea166ac9b5c40 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Sun, 17 Jun 2007 11:41:27 +0200 Subject: inotail.c: Cleanup comments --- inotail.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/inotail.c b/inotail.c index aecbc1a..5c96a50 100644 --- a/inotail.c +++ b/inotail.c @@ -344,7 +344,6 @@ static int handle_inotify_event(struct inotify_event *inev, struct file_struct * ignore: ignore_file(f); - return ret; } @@ -381,9 +380,9 @@ static int watch_files(struct file_struct *files, int n_files) len = read(ifd, buf, (n_files * INOTIFY_BUFLEN)); if (unlikely(len < 0)) { - /* Some form of signal, likely ^Z/fg's STOP and CONT interrupted the inotify read, retry */ + /* Some signal, likely ^Z/fg's STOP and CONT interrupted the inotify read, retry */ if (errno == EINTR || errno == EAGAIN) - continue; /* Keep trying */ + continue; else { fprintf(stderr, "Error: Could not read inotify events (%s)\n", strerror(errno)); exit(EXIT_FAILURE); -- cgit v1.2.3-54-g00ecf From 72d3076d685075808fa9b1533fbaf9ea385df289 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Sun, 17 Jun 2007 12:19:46 +0200 Subject: inotail.c: Use emalloc --- inotail.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/inotail.c b/inotail.c index 069762b..3643c13 100644 --- a/inotail.c +++ b/inotail.c @@ -522,11 +522,7 @@ int main(int argc, char **argv) } } - files = malloc(n_files * sizeof(struct file_struct)); - if (unlikely(!files)) { - fprintf(stderr, "Error: Failed to allocate memory (%s)\n", strerror(errno)); - exit(EXIT_FAILURE); - } + files = emalloc(n_files * sizeof(struct file_struct)); for (i = 0; i < n_files; i++) { files[i].name = filenames[i]; -- cgit v1.2.3-54-g00ecf From e7dd7209b8b3c7fcf0a2ca681470d33a9cb09267 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Sun, 17 Jun 2007 12:21:59 +0200 Subject: inotail.c: emalloc should return void * Also add the unlikely() to the check of the malloc retval. This patch seems to have gotten lost during a merge. --- inotail.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/inotail.c b/inotail.c index 3643c13..a9282c5 100644 --- a/inotail.c +++ b/inotail.c @@ -63,11 +63,11 @@ 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 (!ret) { + if (unlikely(!ret)) { fprintf(stderr, "Error: Failed to allocate %d bytes of memory (%s)\n", size, strerror(errno)); exit(EXIT_FAILURE); } -- cgit v1.2.3-54-g00ecf From b054120a5cde828bf2ca54d434dfb7f12ea0bf01 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Sun, 17 Jun 2007 12:52:33 +0200 Subject: inotail.c: One more unlikely --- inotail.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inotail.c b/inotail.c index a9282c5..9bd7f21 100644 --- a/inotail.c +++ b/inotail.c @@ -512,7 +512,7 @@ int main(int argc, char **argv) struct stat finfo; int rc = fstat(STDIN_FILENO, &finfo); - if (rc == -1) { + if (unlikely(rc == -1)) { fprintf(stderr, "Error: Could not stat stdin (%s)\n", strerror(errno)); exit(EXIT_FAILURE); } -- cgit v1.2.3-54-g00ecf From b9848ce99f13bdf07ab5e538422d83280a6fe321 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 20 Jun 2007 10:50:01 +0200 Subject: inotail.c: Add missing free() calls after lseek() failure --- inotail.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/inotail.c b/inotail.c index 9bd7f21..5917d4a 100644 --- a/inotail.c +++ b/inotail.c @@ -145,6 +145,7 @@ static off_t lines_to_offset_from_end(struct file_struct *f, unsigned long n_lin 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)); + free(buf); return -1; } @@ -187,6 +188,7 @@ static off_t lines_to_offset_from_begin(struct file_struct *f, unsigned long n_l 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)); + free(buf); return -1; } @@ -314,6 +316,7 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch 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)); + free(buf); return -1; } -- cgit v1.2.3-54-g00ecf From 19699a5c202019e98c612eb1db28adb7588f78bd Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 20 Jun 2007 10:59:39 +0200 Subject: inotail.c: Move allocation of buffer before place where buf is used This saves two possible free calls --- inotail.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/inotail.c b/inotail.c index 5917d4a..9000f46 100644 --- a/inotail.c +++ b/inotail.c @@ -297,8 +297,6 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch f->st_size = finfo.st_size; f->st_blksize = finfo.st_blksize; /* TODO: Can this value be 0 or negative? */ - buf = emalloc(f->st_blksize); - if (mode == M_LINES) offset = lines_to_offset(f, n_units); else @@ -307,7 +305,6 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch /* We only get negative offsets on errors */ if (unlikely(offset < 0)) { ignore_file(f); - free(buf); return -1; } @@ -316,10 +313,11 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch 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)); - free(buf); return -1; } + buf = emalloc(f->st_blksize); + while ((bytes_read = read(f->fd, buf, f->st_blksize)) > 0) write(STDOUT_FILENO, buf, (size_t) bytes_read); -- cgit v1.2.3-54-g00ecf From 8c6779184514c772319608110d520bae583e4887 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 20 Jun 2007 14:47:25 +0200 Subject: inotail.c: Correct comment --- inotail.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inotail.c b/inotail.c index 9000f46..8561054 100644 --- a/inotail.c +++ b/inotail.c @@ -295,7 +295,7 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch return tail_pipe(f); f->st_size = finfo.st_size; - f->st_blksize = finfo.st_blksize; /* TODO: Can this value be 0 or negative? */ + f->st_blksize = finfo.st_blksize; /* TODO: Can this value be 0? */ if (mode == M_LINES) offset = lines_to_offset(f, n_units); -- cgit v1.2.3-54-g00ecf From cbb5d0cebbe344ef13aa3f4baf3e8af2b31e7c75 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 20 Jun 2007 14:47:53 +0200 Subject: inotail.h: Update copyright --- inotail.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inotail.h b/inotail.h index b215b43..f7c1406 100644 --- a/inotail.h +++ b/inotail.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2006, Tobias Klauser + * Copyright (C) 2005-2007, Tobias Klauser * * Licensed under the terms of the GNU General Public License; version 2 or later. */ -- cgit v1.2.3-54-g00ecf From 30282557d1e76a43b804d868b121cd640fcc99ba Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 20 Jun 2007 15:01:56 +0200 Subject: Release inotail 0.4 --- Makefile | 2 +- changelog | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a93a097..bcb8cd4 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # # Licensed under the terms of the GNU General Public License; version 2 or later. -VERSION = 0.3 +VERSION = 0.4 # Paths prefix = /usr/local diff --git a/changelog b/changelog index 8af070a..851ac3e 100644 --- a/changelog +++ b/changelog @@ -1,3 +1,14 @@ +inotail 0.4 + + * Use dynamic buffers of optimal size (st_blksize in struct stat) for + filesystem I/O (patch by Folkert van Heusden) + * Added handling of EINTR/EAGAIN while watching files for changes (patch by + Anthony Martinez) + * Better error checking and handling (patch by Folkert van Heusden) + * Various cleanups + + -- Tobias Klauser 2007-06-20 15:00 + inotail 0.3 * Follow files even if they were moved -- cgit v1.2.3-54-g00ecf From 8748c6cedcd5d2d9c23a1c4b5aa019c82b735f90 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Thu, 21 Jun 2007 17:08:38 +0200 Subject: inotail.c: Reorder emalloc/free in handle_inotify_event() Get rid of the following warning when compiling with -Os: inotail.c:338: warning: 'fbuf' may be used uninitialized in this function --- inotail.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/inotail.c b/inotail.c index 8561054..6a000f7 100644 --- a/inotail.c +++ b/inotail.c @@ -335,15 +335,13 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch static int handle_inotify_event(struct inotify_event *inev, struct file_struct *f) { - char *fbuf; int ret = 0; if (inev->mask & IN_MODIFY) { + char *fbuf; ssize_t rc; struct stat finfo; - fbuf = emalloc(f->st_blksize); - if (verbose) write_header(f->name); @@ -354,12 +352,15 @@ static int handle_inotify_event(struct inotify_event *inev, struct file_struct * goto ignore; } + fbuf = emalloc(f->st_blksize); + while ((rc = read(f->fd, fbuf, f->st_blksize)) != 0) write(STDOUT_FILENO, fbuf, (size_t) rc); if (fstat(f->fd, &finfo) < 0) { fprintf(stderr, "Error: Could not stat file '%s' (%s)\n", f->name, strerror(errno)); ret = -1; + free(fbuf); goto ignore; } @@ -378,7 +379,6 @@ static int handle_inotify_event(struct inotify_event *inev, struct file_struct * ignore: ignore_file(f); - free(fbuf); return ret; } -- cgit v1.2.3-54-g00ecf From 86bad98403604f4738e8c252519755654f954eb0 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Sun, 24 Jun 2007 20:08:58 +0200 Subject: inotail.c: Flush stdout in write_header() To make sure the header is also printed when piping inotail output to pipes. --- inotail.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/inotail.c b/inotail.c index 6a000f7..8fcf9fd 100644 --- a/inotail.c +++ b/inotail.c @@ -119,8 +119,10 @@ static void write_header(char *filename) static unsigned short first_file = 1; static char *last = NULL; - if (last != filename) + if (last != filename) { fprintf(stdout, "%s==> %s <==\n", (first_file ? "" : "\n"), pretty_name(filename)); + fflush(stdout); /* Make sure the header is printed before the content */ + } first_file = 0; last = filename; -- cgit v1.2.3-54-g00ecf From a86c62dd8c18d34b5a85efc5baa80224ce3cf4a4 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 2 Jul 2007 15:16:40 +0200 Subject: inotail.c: Correct error message These could also be bytes --- inotail.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inotail.c b/inotail.c index 8fcf9fd..89e213c 100644 --- a/inotail.c +++ b/inotail.c @@ -478,7 +478,7 @@ int main(int argc, char **argv) optarg++; if (!is_digit(*optarg)) { - fprintf(stderr, "Invalid number of lines: %s\n", optarg); + fprintf(stderr, "Error: Invalid number of units: %s\n", optarg); exit(EXIT_FAILURE); } n_units = strtoul(optarg, NULL, 0); -- cgit v1.2.3-54-g00ecf From 6bd2fd4980190c05ccfde6474f380082a6cfcaeb Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 7 Sep 2007 12:25:57 +0200 Subject: Also print strerror when file type is not supported --- inotail.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inotail.c b/inotail.c index 89e213c..993bd68 100644 --- a/inotail.c +++ b/inotail.c @@ -287,7 +287,7 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch } if (!IS_TAILABLE(finfo.st_mode)) { - fprintf(stderr, "Error: '%s' of unsupported file type\n", f->name); + fprintf(stderr, "Error: '%s' of unsupported file type (%s)\n", f->name, strerror(errno)); ignore_file(f); return -1; } -- cgit v1.2.3-54-g00ecf From fb63f7543d0e5a79bcd9cc1b4650360267314703 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 7 Sep 2007 12:43:56 +0200 Subject: Rename file_struct members The rationale behind this is to only use the 'st_' prefix for values gotten by calls to fstat() --- inotail.c | 40 ++++++++++++++++++++-------------------- inotail.h | 4 ++-- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/inotail.c b/inotail.c index 993bd68..920d5a5 100644 --- a/inotail.c +++ b/inotail.c @@ -94,8 +94,8 @@ static void usage(const int status) static inline void setup_file(struct file_struct *f) { f->fd = f->i_watch = -1; - f->st_size = 0; - f->st_blksize = DEFAULT_BUFFER_SIZE; + f->size = 0; + f->blksize = DEFAULT_BUFFER_SIZE; f->ignore = 0; } @@ -130,14 +130,14 @@ static void write_header(char *filename) static off_t lines_to_offset_from_end(struct file_struct *f, unsigned long n_lines) { - off_t offset = f->st_size; - char *buf = emalloc(f->st_blksize); + off_t offset = f->size; + char *buf = emalloc(f->blksize); n_lines++; /* We also count the last \n */ while (offset > 0 && n_lines > 0) { int i; - ssize_t rc, block_size = f->st_blksize; /* Size of the current block we're reading */ + ssize_t rc, block_size = f->blksize; /* Size of the current block we're reading */ if (offset < block_size) block_size = offset; @@ -182,11 +182,11 @@ static off_t lines_to_offset_from_begin(struct file_struct *f, unsigned long n_l return 0; n_lines--; - buf = emalloc(f->st_blksize); + buf = emalloc(f->blksize); - while (offset <= f->st_size && n_lines > 0) { + while (offset <= f->size && n_lines > 0) { int i; - ssize_t rc, block_size = f->st_blksize; + ssize_t rc, block_size = f->blksize; 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)); @@ -234,8 +234,8 @@ static off_t bytes_to_offset(struct file_struct *f, unsigned long n_bytes) if (from_begin) { if (n_bytes > 0) offset = (off_t) n_bytes - 1; - } else if ((off_t) n_bytes < f->st_size) - offset = f->st_size - (off_t) n_bytes; + } else if ((off_t) n_bytes < f->size) + offset = f->size - (off_t) n_bytes; return offset; } @@ -243,13 +243,13 @@ static off_t bytes_to_offset(struct file_struct *f, unsigned long n_bytes) static ssize_t tail_pipe(struct file_struct *f) { ssize_t rc; - char *buf = emalloc(f->st_blksize); + char *buf = emalloc(f->blksize); if (verbose) write_header(f->name); /* We will just tail everything here */ - while ((rc = read(f->fd, buf, f->st_blksize)) > 0) { + 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 */ fprintf(stderr, "Error: Could not write to stdout (%s)\n", strerror(errno)); @@ -296,8 +296,8 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch if (IS_PIPELIKE(finfo.st_mode) || f->fd == STDIN_FILENO) return tail_pipe(f); - f->st_size = finfo.st_size; - f->st_blksize = finfo.st_blksize; /* TODO: Can this value be 0? */ + f->size = finfo.st_size; + f->blksize = finfo.st_blksize; /* TODO: Can this value be 0? */ if (mode == M_LINES) offset = lines_to_offset(f, n_units); @@ -318,9 +318,9 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode, ch return -1; } - buf = emalloc(f->st_blksize); + buf = emalloc(f->blksize); - while ((bytes_read = read(f->fd, buf, f->st_blksize)) > 0) + while ((bytes_read = read(f->fd, buf, f->blksize)) > 0) write(STDOUT_FILENO, buf, (size_t) bytes_read); if (!forever) { @@ -348,15 +348,15 @@ static int handle_inotify_event(struct inotify_event *inev, struct file_struct * write_header(f->name); /* Seek to old file size */ - if (lseek(f->fd, f->st_size, SEEK_SET) == (off_t) -1) { + if (lseek(f->fd, f->size, SEEK_SET) == (off_t) -1) { fprintf(stderr, "Error: Could not seek in file '%s' (%s)\n", f->name, strerror(errno)); ret = -1; goto ignore; } - fbuf = emalloc(f->st_blksize); + fbuf = emalloc(f->blksize); - while ((rc = read(f->fd, fbuf, f->st_blksize)) != 0) + while ((rc = read(f->fd, fbuf, f->blksize)) != 0) write(STDOUT_FILENO, fbuf, (size_t) rc); if (fstat(f->fd, &finfo) < 0) { @@ -366,7 +366,7 @@ static int handle_inotify_event(struct inotify_event *inev, struct file_struct * goto ignore; } - f->st_size = finfo.st_size; + f->size = finfo.st_size; free(fbuf); return ret; diff --git a/inotail.h b/inotail.h index f7c1406..c95c4f8 100644 --- a/inotail.h +++ b/inotail.h @@ -19,8 +19,8 @@ enum { M_LINES, M_BYTES }; struct file_struct { char *name; /* Name of file (or '-' for stdin) */ int fd; /* File descriptor (or -1 if file is not open */ - off_t st_size; /* File size */ - blksize_t st_blksize; /* Blocksize for filesystem I/O */ + off_t size; /* File size */ + blksize_t blksize; /* Blocksize for filesystem I/O */ unsigned ignore; /* Whether to ignore the file in further processing */ int i_watch; /* Inotify watch associated with file_struct */ }; -- cgit v1.2.3-54-g00ecf