summaryrefslogtreecommitdiff
path: root/inotail.c
diff options
context:
space:
mode:
authorDominguez Bonini, David <dominguez.d@ikusi.es>2009-10-30 15:24:20 +0100
committerTobias Klauser <klto@zhaw.ch>2009-10-30 15:27:31 +0100
commit727e55497fa03e9312c1e73bea005233aa03c8d6 (patch)
tree166b6b9ec123b859bf4b9e3593afec2fff06ca96 /inotail.c
parent3a7017f169c598356d406f5c941cb463536f5e11 (diff)
inotail: Support reopening rotated files
We changed the behaviour of the "follow" option so that it detects that file has been moved or deleted it keeps monitoring for the file instead of ignoring it. This is useful when tailing syslog circular logs, where syslog periodically moves the log to another filename and recreates the log file. Without the patch inotail would issue a "file has been moved" or a "file has been deleted message" and stop tracking the file. Now it will close the file and refresh the inotify +descriptor. When a notification arrives with a CREATE or MODIFY event, it will reopen the file and set the size to zero. We are using the patched program in an embedded ARM system with satisfactory results.
Diffstat (limited to 'inotail.c')
-rw-r--r--inotail.c48
1 files changed, 36 insertions, 12 deletions
diff --git a/inotail.c b/inotail.c
index 735c4b7..de16a60 100644
--- a/inotail.c
+++ b/inotail.c
@@ -615,15 +615,28 @@ static int tail_file(struct file_struct *f, unsigned long n_units, char mode)
return 0;
}
-static int handle_inotify_event(struct inotify_event *inev, struct file_struct *f)
+static int handle_inotify_event(int ifd, struct inotify_event *inev, struct file_struct *f)
{
int ret = 0;
- if (inev->mask & IN_MODIFY) {
+ if (inev->mask & (IN_MODIFY|IN_CREATE)) {
char *fbuf;
ssize_t bytes_read;
struct stat finfo;
+ if (f->fd < 0) {
+ fprintf(stderr, "File '%s' needs to get reopened.\n", f->name);
+ f->fd = open(f->name, O_RDONLY);
+ if (unlikely(f->fd < 0)) {
+ fprintf(stderr, "Error: Could not open file '%s' (%s)\n", f->name, strerror(errno));
+ ignore_file(f);
+ return -1;
+ }
+
+ /* File got rotated away, so start again */
+ f->size = 0;
+ }
+
if (verbose)
write_header(f->name);
@@ -653,10 +666,24 @@ static int handle_inotify_event(struct inotify_event *inev, struct file_struct *
free(fbuf);
return ret;
- } else if (inev->mask & IN_DELETE_SELF) {
- fprintf(stderr, "File '%s' deleted.\n", f->name);
- } else if (inev->mask & IN_MOVE_SELF) {
- fprintf(stderr, "File '%s' moved.\n", f->name);
+ } else if (inev->mask & (IN_DELETE_SELF|IN_MOVE_SELF)) {
+ inotify_rm_watch(ifd, f->i_watch);
+ close(f->fd);
+ f->fd = -1;
+
+ if (inev->mask & IN_DELETE_SELF)
+ fprintf(stderr, "File '%s' deleted.\n", f->name);
+ else
+ fprintf(stderr, "File '%s' moved.\n", f->name);
+
+ f->i_watch = inotify_add_watch(ifd, f->name, INOTAIL_WATCH_MASK);
+ if (f->i_watch < 0) {
+ fprintf(stderr, "Error: Could not create inotify watch on file '%s' (%s)\n",
+ f->name, strerror(errno));
+ ignore_file(f);
+ return -1;
+ }
+
return 0;
} else if (inev->mask & IN_UNMOUNT) {
fprintf(stderr, "Device containing file '%s' unmounted.\n", f->name);
@@ -685,8 +712,7 @@ static int watch_files(struct file_struct *files, int n_files)
for (i = 0; i < n_files; i++) {
if (!files[i].ignore) {
- files[i].i_watch = inotify_add_watch(ifd, files[i].name,
- IN_MODIFY|IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT);
+ files[i].i_watch = inotify_add_watch(ifd, files[i].name, INOTAIL_WATCH_MASK);
if (files[i].i_watch < 0) {
fprintf(stderr, "Error: Could not create inotify watch on file '%s' (%s)\n",
@@ -720,9 +746,7 @@ static int watch_files(struct file_struct *files, int n_files)
/* Which file has produced the event? */
for (i = 0; i < n_files; i++) {
- if (!files[i].ignore
- && files[i].fd >= 0
- && files[i].i_watch == inev->wd) {
+ if (!files[i].ignore && files[i].i_watch == inev->wd) {
f = &files[i];
break;
}
@@ -734,7 +758,7 @@ static int watch_files(struct file_struct *files, int n_files)
continue;
}
- if (handle_inotify_event(inev, f) < 0 && n_ignored == n_files)
+ if (handle_inotify_event(ifd, inev, f) < 0 && n_ignored == n_files)
/* Got an error handling the event and no files
* left unignored */
break;