1
0
mirror of git://git.sv.gnu.org/coreutils.git synced 2026-05-23 19:01:19 +02:00

merge variables: forever_multiple and forever

(recheck): New function.
Begin to support --allow-missing option.
This commit is contained in:
Jim Meyering
1998-03-22 20:55:34 +00:00
parent e8ab1c28f8
commit eeef5c523d
+153 -97
View File
@@ -75,6 +75,17 @@
} \
while (0)
#define CLOSE_FD(Fd, Name) \
do \
{ \
if ((Fd) != -1 && (Fd) != STDIN_FILENO && close (Fd)) \
{ \
error (0, errno, "closing %s (fd=%d)", (Name), (Fd)); \
} \
} \
while (0)
/* Number of items to tail. */
#define DEFAULT_N_LINES 10
@@ -85,10 +96,10 @@
enum Follow_mode
{
/* FIXME */
/* FIXME: describe */
follow_name,
/* FIXME */
/* FIXME: describe */
follow_descriptor,
};
@@ -110,9 +121,16 @@ struct File_spec
dev_t dev;
ino_t ino;
/* FIXME: describe */
unsigned int no_change_counter;
/* FIXME: describe */
int missing;
};
/* FIXME: describe */
static int allow_missing;
/* If nonzero, interpret the numeric argument as the number of lines.
Otherwise, interpret it as the number of bytes. */
static int count_lines;
@@ -122,12 +140,9 @@ static int count_lines;
/* FIXME: make follow_name the default? */
static enum Follow_mode follow_mode;
/* If nonzero, read from the end of one file until killed. */
/* If nonzero, read from the ends of all specified files until killed. */
static int forever;
/* If nonzero, read from the end of multiple files until killed. */
static int forever_multiple;
/* If nonzero, count from start of file instead of end. */
static int from_start;
@@ -162,6 +177,7 @@ static int show_version;
static struct option const long_options[] =
{
{"allow-missing", required_argument, NULL, 11},
{"bytes", required_argument, NULL, 'c'},
{"follow", no_argument, NULL, 'f'},
{"follow-descriptor", no_argument, NULL, 12},
@@ -252,6 +268,7 @@ file_lines (const char *pretty_filename, int fd, long int n_lines, off_t pos)
/* Make `pos' a multiple of `BUFSIZ' (0 if the file is short), so that all
reads will be on block boundaries, which might increase efficiency. */
pos -= bytes_read;
/* FIXME: check lseek return value */
lseek (fd, pos, SEEK_SET);
bytes_read = safe_read (fd, buffer, bytes_read);
if (bytes_read == -1)
@@ -283,10 +300,12 @@ file_lines (const char *pretty_filename, int fd, long int n_lines, off_t pos)
if (pos == 0)
{
/* Not enough lines in the file; print the entire file. */
/* FIXME: check lseek return value */
lseek (fd, (off_t) 0, SEEK_SET);
return 0;
}
pos -= BUFSIZ;
/* FIXME: check lseek return value */
lseek (fd, pos, SEEK_SET);
}
while ((bytes_read = safe_read (fd, buffer, BUFSIZ)) > 0);
@@ -566,8 +585,7 @@ start_lines (const char *pretty_filename, int fd, long int n_lines)
}
/* Display file FILENAME from the current position in FD to the end.
If `forever' is nonzero, keep reading from the end of the file
until killed. Return the number of bytes read from the file. */
Return the number of bytes read from the file. */
static long
dump_remainder (const char *pretty_filename, int fd)
@@ -577,7 +595,6 @@ dump_remainder (const char *pretty_filename, int fd)
long total;
total = 0;
output:
while ((bytes_read = safe_read (fd, buffer, BUFSIZ)) > 0)
{
XWRITE (STDOUT_FILENO, buffer, bytes_read);
@@ -585,24 +602,94 @@ output:
}
if (bytes_read == -1)
error (EXIT_FAILURE, errno, "%s", pretty_filename);
if (forever)
{
fflush (stdout);
sleep (sleep_interval);
goto output;
}
else
{
if (forever_multiple)
fflush (stdout);
}
fflush (stdout);
return total;
}
/* Tail NFILES (>1) files forever until killed.
/* FIXME: describe */
static void
recheck (struct File_spec *f)
{
/* open/fstat the file and announce if dev/ino
have changed */
struct stat new_stats;
int fd;
int fail = 0;
int is_stdin = (STREQ (f->name, "-"));
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);
if (fd == -1 || fstat (fd, &new_stats) < 0)
{
fail = 1;
error (0, errno, "%s", f->pretty_name);
}
else if (!S_ISREG (new_stats.st_mode)
&& !S_ISFIFO (new_stats.st_mode))
{
fail = 1;
error (0, 0,
_("%s has been replaced with a non-regular file; \
cannot follow end of non-regular file"),
f->pretty_name);
}
if (fail)
{
CLOSE_FD (fd, f->pretty_name);
CLOSE_FD (f->fd, f->pretty_name);
f->fd = -1;
}
else if (f->ino != new_stats.st_ino || f->dev != new_stats.st_dev)
{
/* Close the old one. */
CLOSE_FD (f->fd, f->pretty_name);
/* File has been replaced (e.g., via log rotation) --
tail the new one. */
error (0, 0,
_("%s has been replaced; following end of new file"),
f->pretty_name);
f->fd = fd;
f->size = new_stats.st_size;
f->dev = new_stats.st_dev;
f->ino = new_stats.st_ino;
f->no_change_counter = 0;
/* FIXME: check lseek return value */
lseek (f->fd, new_stats.st_size, SEEK_SET);
}
else if (f->missing)
{
error (0, 0, _("%s has reappeared"), f->pretty_name);
f->missing = 0;
f->fd = fd;
f->size = new_stats.st_size;
f->dev = new_stats.st_dev;
f->ino = new_stats.st_ino;
f->no_change_counter = 0;
/* FIXME: check lseek return value */
lseek (f->fd, new_stats.st_size, SEEK_SET);
}
else
{
CLOSE_FD (fd, f->pretty_name);
}
}
/* Tail NFILES files forever, or until killed.
The pertinent information for each file is stored in an entry of F.
Loop over each of them, doing an fstat to see if they have changed size.
Loop over each of them, doing an fstat to see if they have changed size,
and an occasional open/fstat to see if any dev/ino pair has changed.
If none of them have changed size in one iteration, sleep for a
while and try again. Continue until the user interrupts us. */
@@ -616,15 +703,20 @@ tail_forever (struct File_spec *f, int nfiles)
while (1)
{
int i;
int changed;
int any_changed;
int any_live_files;
changed = 0;
any_live_files = 0;
any_changed = 0;
for (i = 0; i < nfiles; i++)
{
struct stat stats;
if (f[i].fd < 0)
if (f[i].fd < 0 && !f[i].missing)
continue;
any_live_files = 1;
if (fstat (f[i].fd, &stats) < 0)
{
error (0, errno, "%s", f[i].pretty_name);
@@ -637,70 +729,21 @@ tail_forever (struct File_spec *f, int nfiles)
if (++f[i].no_change_counter > max_no_change_count
&& follow_mode == follow_name)
{
/* open/fstat the file and announce if dev/ino
have changed */
struct stat new_stats;
int fd;
int fail = 0;
int is_stdin = (STREQ (f[i].name, "-"));
fd = (is_stdin ? STDIN_FILENO : open (f[i].name, O_RDONLY));
if (fd == -1 || fstat (fd, &new_stats) < 0)
{
fail = 1;
error (0, errno, "%s", f[i].pretty_name);
}
else if (!S_ISREG (new_stats.st_mode))
{
fail = 1;
error (0, 0,
_("%s has been replaced with a non-regular file; \
cannot follow end of non-regular file"),
f[i].pretty_name);
}
if (fail)
{
if (fd != STDIN_FILENO)
close (fd);
if (f[i].fd != STDIN_FILENO)
close (f[i].fd);
f[i].fd = -1;
}
else if (f[i].ino != new_stats.st_ino
|| f[i].dev != new_stats.st_dev)
{
/* Close the old one. */
if (f[i].fd != STDIN_FILENO)
close (f[i].fd);
/* File has been replaced (e.g., via log rotation) --
tail the new one. */
error (0, 0,
_("%s has been replaced; following end of new file"),
f[i].pretty_name);
f[i].fd = fd;
f[i].size = new_stats.st_size;
f[i].dev = new_stats.st_dev;
f[i].ino = new_stats.st_ino;
f[i].no_change_counter = 0;
lseek (f[i].fd, new_stats.st_size, SEEK_SET);
}
else
{
close (fd);
}
recheck (&f[i]);
f[i].no_change_counter = 0;
};
}
continue;
}
/* FIXME-now:
Otherwise, a file that's unlinked or moved aside, yet always
growing will never be recognized has having been renamed. */
/* This file has changed size. Print out what we can, and
then keep looping. */
changed = 1;
any_changed = 1;
/* reset counter */
f[i].no_change_counter = 0;
@@ -709,6 +752,7 @@ cannot follow end of non-regular file"),
{
write_header (f[i].pretty_name, _("file truncated"));
last = i;
/* FIXME: check lseek return value */
lseek (f[i].fd, stats.st_size, SEEK_SET);
f[i].size = stats.st_size;
continue;
@@ -723,8 +767,14 @@ cannot follow end of non-regular file"),
f[i].size += dump_remainder (f[i].pretty_name, f[i].fd);
}
if (!any_live_files /* FIXME-now: && ! allow_missing */ )
{
error (0, 0, _("no files remaining"));
break;
}
/* If none of the files changed size, sleep. */
if (! changed)
if (!any_changed)
sleep (sleep_interval);
}
}
@@ -750,9 +800,14 @@ tail_bytes (const char *pretty_filename, int fd, off_t n_bytes)
if (from_start)
{
if (S_ISREG (stats.st_mode))
lseek (fd, n_bytes, SEEK_CUR);
{
/* FIXME: check lseek return value */
lseek (fd, n_bytes, SEEK_CUR);
}
else if (start_bytes (pretty_filename, fd, n_bytes))
return 1;
{
return 1;
}
dump_remainder (pretty_filename, fd);
}
else
@@ -782,12 +837,14 @@ tail_bytes (const char *pretty_filename, int fd, off_t n_bytes)
more bytes than have been requested. So reposition the
file pointer to the incoming current position and print
everything after that. */
/* FIXME: check lseek return value */
lseek (fd, current_pos, SEEK_SET);
}
else
{
/* There are more bytes remaining than were requested.
Back up. */
/* FIXME: check lseek return value */
lseek (fd, -n_bytes, SEEK_END);
}
dump_remainder (pretty_filename, fd);
@@ -877,9 +934,11 @@ tail_file (struct File_spec *f, off_t n_units)
fd = open (f->name, O_RDONLY);
}
f->missing = (allow_missing && fd == -1 && errno == ENOENT);
if (fd == -1)
{
if (forever_multiple)
if (forever)
f->fd = -1;
error (0, errno, "%s", f->pretty_name);
errors = 1;
@@ -889,7 +948,7 @@ tail_file (struct File_spec *f, off_t n_units)
if (print_headers)
write_header (f->pretty_name, NULL);
errors = tail (f->pretty_name, fd, n_units);
if (forever_multiple)
if (forever)
{
/* FIXME: duplicate code */
if (fstat (fd, &stats) < 0)
@@ -897,7 +956,7 @@ tail_file (struct File_spec *f, off_t n_units)
error (0, errno, "%s", f->pretty_name);
errors = 1;
}
else if (!S_ISREG (stats.st_mode))
else if (!S_ISREG (stats.st_mode) && !S_ISFIFO (stats.st_mode))
{
error (0, 0, _("%s: cannot follow end of non-regular file"),
f->pretty_name);
@@ -905,8 +964,7 @@ tail_file (struct File_spec *f, off_t n_units)
}
if (errors)
{
if (!is_stdin)
close (fd);
CLOSE_FD (fd, f->pretty_name);
f->fd = -1;
}
else
@@ -1090,7 +1148,7 @@ parse_options (int argc, char **argv,
int c;
count_lines = 1;
forever = forever_multiple = from_start = print_headers = 0;
forever = from_start = print_headers = 0;
while ((c = getopt_long (argc, argv, "c:n:fqs:v", long_options, NULL)) != -1)
{
@@ -1133,6 +1191,10 @@ parse_options (int argc, char **argv,
forever = 1;
break;
case 11:
allow_missing = 1;
break;
case 12:
follow_mode = follow_descriptor;
break;
@@ -1229,12 +1291,6 @@ main (int argc, char **argv)
n_files = argc - optind;
file = argv + optind;
if (n_files > 1 && forever)
{
forever_multiple = 1;
forever = 0;
}
if (n_files == 0)
{
static char *dummy_stdin = "-";
@@ -1253,7 +1309,7 @@ main (int argc, char **argv)
for (i = 0; i < n_files; i++)
exit_status |= tail_file (&F[i], n_units);
if (forever_multiple)
if (forever)
tail_forever (F, n_files);
if (have_read_stdin && close (0) < 0)