diff options
author | Jim Meyering <jim@meyering.net> | 1999-07-10 12:24:10 +0000 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 1999-07-10 12:24:10 +0000 |
commit | 54651dc73c80f1336a6cd0e813e7ff11a7aea838 (patch) | |
tree | ae300d6b3f407c81c5fefbfae477fb628305852e /src/tail.c | |
parent | ae1e1e5e19f4e8f4c7e574772c7d19404a124d52 (diff) | |
download | coreutils-54651dc73c80f1336a6cd0e813e7ff11a7aea838.tar.xz |
(struct File_spec) [tailable]: Rename from `missing' and
document. Change all uses and locals like was_missing to was_tailable.
Invert expressions as appropriate.
(reopen_inaccessible_files): Rename from allow_missing.
(sleep_interval): Describe.
(--allow-missing): Deprecate.
(--retry): New option, equivalent to --allow-missing.
(usage): Document name vs. descriptor differences.
Refer to manual for descriptions of --max-unchanged-stats=N
and --max-consecutive-size-changes=N.
(valid_file_spec): New function.
(recheck): Assert valid_file_spec.
Remove dead else-if block (suggestion from Eli Zaretskii).
Adjust stmts that set f->tailable -- unlike for `missing', tailable
doesn't depend on errno == ENOENT.
(parse_options): Give a warning if --retry is used when not following
by name.
Diffstat (limited to 'src/tail.c')
-rw-r--r-- | src/tail.c | 106 |
1 files changed, 73 insertions, 33 deletions
diff --git a/src/tail.c b/src/tail.c index 12f472073..567893046 100644 --- a/src/tail.c +++ b/src/tail.c @@ -111,8 +111,9 @@ struct File_spec /* FIXME: describe */ unsigned int n_consecutive_size_changes; - /* FIXME: describe */ - int missing; + /* A file is tailable if it is a regular file or a fifo and it is + readable. */ + int tailable; /* The value of errno seen last time we checked this file. */ int errnum; @@ -120,7 +121,7 @@ struct File_spec }; /* FIXME: describe */ -static int allow_missing; +static int reopen_inaccessible_files; /* If nonzero, interpret the numeric argument as the number of lines. Otherwise, interpret it as the number of bytes. */ @@ -146,7 +147,7 @@ enum header_mode }; /* When tailing a file by name, if there have been this many consecutive - stat calls for which the size has remained the same, then open/fstat + iterations for which the size has remained the same, then open/fstat the file to determine if that file name is still associated with the same device/inode-number pair as before. This option is meaningful only when following by name. --max-unchanged-stats=N */ @@ -159,7 +160,7 @@ static unsigned long max_n_unchanged_stats_between_opens = After detecting this many consecutive size changes for a file, open/fstat the file to determine if that file name is still associated with the same device/inode-number pair as before. This option is meaningful only - when following by name. --max-n-consecutive-size-changes=N */ + when following by name. --max-consecutive-size-changes=N */ #define DEFAULT_MAX_N_CONSECUTIVE_SIZE_CHANGES 200 static unsigned long max_n_consecutive_size_changes_between_opens = DEFAULT_MAX_N_CONSECUTIVE_SIZE_CHANGES; @@ -167,7 +168,10 @@ static unsigned long max_n_consecutive_size_changes_between_opens = /* The name this program was run with. */ char *program_name; -/* The number of seconds to sleep between accesses. */ +/* The number of seconds to sleep between iterations. + During one iteration, every file name or descriptor is checked to + see if it has changed. */ +/* FIXME: allow fractional seconds */ static unsigned int sleep_interval = 1; /* Nonzero if we have ever read standard input. */ @@ -175,6 +179,8 @@ static int have_read_stdin; static struct option const long_options[] = { + /* --allow-missing is deprecated; use --retry instead + FIXME: remove it some day */ {"allow-missing", no_argument, NULL, CHAR_MAX + 1}, {"bytes", required_argument, NULL, 'c'}, {"follow", optional_argument, NULL, 'f'}, @@ -182,6 +188,7 @@ static struct option const long_options[] = {"max-unchanged-stats", required_argument, NULL, CHAR_MAX + 2}, {"max-consecutive-size-changes", required_argument, NULL, CHAR_MAX + 3}, {"quiet", no_argument, NULL, 'q'}, + {"retry", no_argument, NULL, CHAR_MAX + 1}, {"silent", no_argument, NULL, 'q'}, {"sleep-interval", required_argument, NULL, 's'}, {"verbose", no_argument, NULL, 'v'}, @@ -203,16 +210,22 @@ Usage: %s [OPTION]... [FILE]...\n\ "), program_name); printf (_("\ -Print last 10 lines of each FILE to standard output.\n\ +Print the last %d lines of each FILE to standard output.\n\ With more than one FILE, precede each with a header giving the file name.\n\ With no FILE, or when FILE is -, read standard input.\n\ \n\ - --allow-missing FIXME\n\ + --retry keep trying to open a file even if it is\n\ + inaccessible when tail starts or if it becomes\n\ + inaccessible later -- useful only with -f\n\ -c, --bytes=N output the last N bytes\n\ - -f, --follow[={name|descriptor}] output appended data as the file grows\n\ - -n, --lines=N output the last N lines, instead of last 10\n\ - --max-unchanged-stats=N FIXME describe and mention default\n\ - --max-consecutive-size-changes=N FIXME describe and mention default\n\ + -f, --follow[={name|descriptor}] output appended data as the file grows;\n\ + -f, --follow, and --follow=descriptor are\n\ + equivalent\n\ + -n, --lines=N output the last N lines, instead of the last %d\n\ + --max-unchanged-stats=N see the texinfo documentation\n\ + (the default is %d)\n\ + --max-consecutive-size-changes=N see the texinfo documentation\n\ + (the default is %d)\n\ -q, --quiet, --silent never output headers giving file names\n\ -s, --sleep-interval=S with -f, sleep S seconds between iterations\n\ -v, --verbose always output headers giving file names\n\ @@ -226,13 +239,32 @@ b for 512, k for 1024, m for 1048576 (1 Meg). A first OPTION of -VALUE\n\ or +VALUE is treated like -n VALUE or -n +VALUE unless VALUE has one of\n\ the [bkm] suffix multipliers, in which case it is treated like -c VALUE\n\ or -c +VALUE.\n\ -FIXME: describe name vs descriptor\n\ -")); +\n\ +With --follow (-f), tail defaults to following the file descriptor, which\n\ +means that even if a tail'ed file is renamed, tail will continue to track\n\ +its end. This default behavior is not desirable when you really want to\n\ +track the actual name of the file, not the file descriptor (e.g., log\n\ +rotation). Use --follow=name in that case. That causes tail to track the\n\ +named file by reopening it periodically to see if it has been removed and\n\ +recreated by some other program.\n\ +\n\ +"), + DEFAULT_N_LINES, DEFAULT_N_LINES, + DEFAULT_MAX_N_UNCHANGED_STATS_BETWEEN_OPENS, + DEFAULT_MAX_N_CONSECUTIVE_SIZE_CHANGES + ); puts (_("\nReport bugs to <bug-textutils@gnu.org>.")); } exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); } +static int +valid_file_spec (struct File_spec const *f) +{ + /* Exactly one of the following subexpressions must be true. */ + return ((f->fd == -1) ^ (f->errnum == 0)); +} + static char * pretty_name (struct File_spec const *f) { @@ -656,27 +688,36 @@ recheck (struct File_spec *f) int fd; int fail = 0; int is_stdin = (STREQ (f->name, "-")); - int was_missing = f->missing; + int was_tailable = f->tailable; int prev_errnum = f->errnum; int new_file; + assert (valid_file_spec (f)); + fd = (is_stdin ? STDIN_FILENO : open (f->name, O_RDONLY)); /* If the open fails because the file doesn't exist, - then mark the file as missing. */ - f->missing = (allow_missing && fd == -1 && errno == ENOENT); + then mark the file as not tailable. */ + f->tailable = !(reopen_inaccessible_files && fd == -1); if (fd == -1 || fstat (fd, &new_stats) < 0) { fail = 1; f->errnum = errno; - if (f->missing) + if (!f->tailable) { - if (!was_missing) - error (0, 0, "`%s' has been removed", pretty_name (f)); + if (was_tailable) + { + /* FIXME-maybe: detect the case in which the file first becomes + unreadable (perms), and later becomes readable again and can + be seen to be the same file (dev/ino). Otherwise, tail prints + the entire contents of the file when it becomes readable. */ + error (0, f->errnum, _("`%s' has become inaccessible"), + pretty_name (f)); + } else { - /* say nothing... it's still missing */ + /* say nothing... it's still not tailable */ } } else if (prev_errnum != errno) @@ -695,7 +736,9 @@ cannot follow end of non-regular file"), pretty_name (f)); } else - f->errnum = 0; + { + f->errnum = 0; + } new_file = 0; if (fail) @@ -707,8 +750,8 @@ cannot follow end of non-regular file"), else if (prev_errnum && prev_errnum != ENOENT) { new_file = 1; - if (f->fd != -1) - close_fd (f->fd, pretty_name (f)); /* close the old handle */ + /* FIXME-now: is this close ever necessary? */ + close_fd (f->fd, pretty_name (f)); /* close the old handle */ error (0, 0, _("`%s' has become accessible"), pretty_name (f)); } else if (f->ino != new_stats.st_ino || f->dev != new_stats.st_dev) @@ -732,12 +775,6 @@ cannot follow end of non-regular file"), pretty_name (f)); } } - else if (f->missing) - { - new_file = 1; - error (0, 0, _("`%s' has reappeared"), pretty_name (f)); - f->missing = 0; - } else { close_fd (fd, pretty_name (f)); @@ -865,7 +902,7 @@ tail_forever (struct File_spec *f, int nfiles) COPY_TO_EOF); } - if (n_live_files (f, nfiles) == 0 && ! allow_missing) + if (n_live_files (f, nfiles) == 0 && ! reopen_inaccessible_files) { error (0, 0, _("no files remaining")); break; @@ -1033,7 +1070,7 @@ tail_file (struct File_spec *f, off_t n_units) fd = open (f->name, O_RDONLY); } - f->missing = (allow_missing && fd == -1 && errno == ENOENT); + f->tailable = !(reopen_inaccessible_files && fd == -1); if (fd == -1) { @@ -1304,7 +1341,7 @@ parse_options (int argc, char **argv, break; case CHAR_MAX + 1: - allow_missing = 1; + reopen_inaccessible_files = 1; break; case CHAR_MAX + 2: @@ -1360,6 +1397,9 @@ parse_options (int argc, char **argv, usage (1); } } + + if (reopen_inaccessible_files && follow_mode != Follow_name) + error (0, 0, _("warning: --retry is useful only when following by name")); } int |