From: Theodore Ts'o Date: Mon, 14 Apr 2003 22:05:12 +0000 (-0400) Subject: Add logsave, a new program which saves the output of a command X-Git-Tag: E2FSPROGS-1_33-WIP-0414~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f9ddad598237900e147e3095e7a1bde36f6a1d2f;p=thirdparty%2Fe2fsprogs.git Add logsave, a new program which saves the output of a command in a log file, even if the containing directory hasn't been mounted yet (in which case the it saves the output in memory until it can write out the logfile). --- diff --git a/e2fsprogs.spec.in b/e2fsprogs.spec.in index ca5069ba8..d37620d6a 100644 --- a/e2fsprogs.spec.in +++ b/e2fsprogs.spec.in @@ -99,6 +99,7 @@ fi %{_root_sbindir}/fsck %{_root_sbindir}/fsck.ext2 %{_root_sbindir}/fsck.ext3 +%{_root_sbindir}/logsave %{_root_sbindir}/mke2fs %{_root_sbindir}/mkfs.ext2 %{_root_sbindir}/mkfs.ext3 @@ -131,6 +132,7 @@ fi %{_mandir}/man8/e2image.8* %{_mandir}/man8/e2label.8* %{_mandir}/man8/fsck.8* +%{_mandir}/man8/logsave.8* %{_mandir}/man8/mke2fs.8* %{_mandir}/man8/mkfs.ext2.8* %{_mandir}/man8/mkfs.ext3.8* diff --git a/misc/ChangeLog b/misc/ChangeLog index fd2e4b233..90518b2e7 100644 --- a/misc/ChangeLog +++ b/misc/ChangeLog @@ -1,3 +1,10 @@ +2003-04-14 Theodore Ts'o + + * logsave.c: New program which saves the output of a command in a + log file, even if the containing directory hasn't been + mounted yet (in which case the it saves the output in + memory until it can write out the logfile). + 2003-04-11 Theodore Ts'o * mke2fs.c (PRS): If the argument to -b is negative, treat it as a diff --git a/misc/Makefile.in b/misc/Makefile.in index 07594795b..ec19a90ce 100644 --- a/misc/Makefile.in +++ b/misc/Makefile.in @@ -14,10 +14,12 @@ INSTALL = @INSTALL@ @IMAGER_CMT@E2IMAGE_PROG= e2image @IMAGER_CMT@E2IMAGE_MAN= e2image.8 -SPROGS= mke2fs badblocks tune2fs dumpe2fs blkid $(E2IMAGE_PROG) @FSCK_PROG@ +SPROGS= mke2fs badblocks tune2fs dumpe2fs blkid logsave \ + $(E2IMAGE_PROG) @FSCK_PROG@ USPROGS= mklost+found SMANPAGES= tune2fs.8 mklost+found.8 mke2fs.8 dumpe2fs.8 badblocks.8 \ - e2label.8 findfs.8 blkid.8 $(E2IMAGE_MAN) @FSCK_MAN@ + e2label.8 findfs.8 blkid.8 $(E2IMAGE_MAN) \ + logsave.8 @FSCK_MAN@ UPROGS= chattr lsattr uuidgen UMANPAGES= chattr.1 lsattr.1 uuidgen.1 @@ -109,6 +111,9 @@ fsck: $(FSCK_OBJS) $(DEBLIBS_BLKID) badblocks: $(BADBLOCKS_OBJS) $(DEPLIBS) $(CC) $(ALL_LDFLAGS) -o badblocks $(BADBLOCKS_OBJS) $(LIBS) +logsave: logsave.o + $(CC) $(ALL_LDFLAGS) -o logsave logsave.o + tune2fs.8: $(DEP_SUBSTITUTE) $(srcdir)/tune2fs.8.in $(SUBSTITUTE) $(srcdir)/tune2fs.8.in tune2fs.8 @@ -139,6 +144,9 @@ fsck.8: $(DEP_SUBSTITUTE) $(srcdir)/fsck.8.in blkid.8: $(DEP_SUBSTITUTE) $(srcdir)/blkid.8.in $(SUBSTITUTE) $(srcdir)/blkid.8.in blkid.8 +logsave.8: $(DEP_SUBSTITUTE) $(srcdir)/logsave.8.in + $(SUBSTITUTE) $(srcdir)/logsave.8.in logsave.8 + chattr.1: $(DEP_SUBSTITUTE) $(srcdir)/chattr.1.in $(SUBSTITUTE) $(srcdir)/chattr.1.in chattr.1 diff --git a/misc/logsave.8.in b/misc/logsave.8.in new file mode 100644 index 000000000..0455cd072 --- /dev/null +++ b/misc/logsave.8.in @@ -0,0 +1,52 @@ +.\" -*- nroff -*- +.\" Copyright 2003 by Theodore Ts'o. All Rights Reserved. +.\" This file may be copied under the terms of the GNU Public License. +.\" +.TH LOGSAVE 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@" +.SH NAME +logsave \- save the output of a command in a logfile +.SH SYNOPSIS +.B logsave +[ +.B \-v +] +.I logfile command [ ... ] +.SH DESCRIPTION +The +.B logsave +program will execute +.I command +with the specified argument, and save a copy of its output to +.IR logfile . +If the containing directory for +.I logfile +does not exist, +.B logsave +will accumulate the output in memory until it can be written out. +A copy of the output will also be written to standard output. +.PP +If +.I command +is a single hyphen ('-'), then instead of executing a program, +.B logsave +will take the input from standard input. +.PP +.B logsave +is useful for saving the output of initial boot scripts +until the /var partition is mounted, so the output can be written to +/var/log. +.SH OPTIONS +.TP +.B \-a +This option will cause the output to be appended to +.IR logfile , +instead of replacing the current contents. +.TP +.B \-v +This option will +.B logsave +more verbose. +.SH AUTHOR +Theodore Ts'o (tytso@mit.edu) +.SH SEE ALSO +.BR fsck (8) diff --git a/misc/logsave.c b/misc/logsave.c new file mode 100644 index 000000000..dd2e286f9 --- /dev/null +++ b/misc/logsave.c @@ -0,0 +1,215 @@ +/* + * logsave.c --- A program which saves the output of a program until + * /var/log is mounted. + * + * Copyright (C) 2003 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_GETOPT_H +#include +#else +extern char *optarg; +extern int optind; +#endif + +int outfd = -1; +int outbufsize = 0; +void *outbuf = 0; +int verbose = 0; + +static void usage(char *progname) +{ + printf("Usage: %s [-v] [-d dir] logfile program\n", progname); + exit(1); +} + +static void process_output(const char *buffer, int c) +{ + char *n; + + if (c == 0) + c = strlen(buffer); + + write(1, buffer, c); + if (outfd > 0) + write(outfd, buffer, c); + else { + n = realloc(outbuf, outbufsize + c); + if (n) { + outbuf = n; + memcpy(((char *)outbuf)+outbufsize, buffer, c); + outbufsize += c; + } + } +} + +static void do_read(int fd) +{ + int c; + char buffer[4096]; + + c = read(fd, buffer, sizeof(buffer)); + process_output(buffer, c); +} + +static int run_program(char **argv) +{ + int fds[2]; + char **cpp; + int status, rc, pid; + char buffer[80]; + time_t t; + + if (pipe(fds) < 0) { + perror("pipe"); + exit(1); + } + + if (verbose) { + process_output("Log of ", 0); + for (cpp = argv; *cpp; cpp++) { + process_output(*cpp, 0); + process_output(" ", 0); + } + process_output("\n", 0); + t = time(0); + process_output(ctime(&t), 0); + process_output("\n", 0); + } + + pid = fork(); + if (pid < 0) { + perror("vfork"); + exit(1); + } + if (pid == 0) { + dup2(fds[1],1); /* fds[1] replaces stdout */ + dup2(fds[1],2); /* fds[1] replaces stderr */ + close(fds[0]); /* don't need this here */ + + execvp(argv[0], argv); + perror(argv[0]); + exit(1); + } + close(fds[1]); + + while (!(waitpid(pid, &status, WNOHANG ))) { + do_read(fds[0]); + } + do_read(fds[0]); + close(fds[0]); + + if ( WIFEXITED(status) ) { + rc = WEXITSTATUS(status); + if (rc) { + process_output(argv[0], 0); + sprintf(buffer, " died with exit status %d", rc); + process_output(buffer, 0); + } + } else { + if (WIFSIGNALED(status)) { + process_output(argv[0], 0); + sprintf(buffer, "died with signal %d", + WTERMSIG(status)); + process_output(buffer, 0); + rc = 1; + } + rc = 0; + } + return rc; +} + +static int copy_from_stdin(void) +{ + char buffer[4096]; + int c; + int bad_read = 0; + + while (1) { + c = read(0, buffer, sizeof(buffer)); + if ((c == 0 ) || + ((c < 0) && ((errno == EAGAIN) || (errno == EINTR)))) { + if (bad_read++ > 3) + break; + continue; + } + if (c < 0) { + perror("read"); + exit(1); + } + process_output(buffer, c); + bad_read = 0; + } + return 0; +} + + + +int main(int argc, char **argv) +{ + int c, pid, rc; + char *outfn; + int openflags = O_CREAT|O_WRONLY|O_TRUNC; + + while ((c = getopt(argc, argv, "+v")) != EOF) { + switch (c) { + case 'a': + openflags &= ~O_TRUNC; + openflags |= O_APPEND; + break; + case 'v': + verbose++; + break; + } + } + if (optind == argc || optind+1 == argc) + usage(argv[0]); + outfn = argv[optind]; + optind++; + argv += optind; + argc -= optind; + + outfd = open(outfn, O_CREAT|O_WRONLY|O_TRUNC, 0644); + + if (strcmp(argv[0], "-")) + rc = run_program(argv); + else + rc = copy_from_stdin(); + + if (outbuf) { + pid = fork(); + if (pid < 0) { + perror("fork"); + exit(1); + } + if (pid) { + if (verbose) + printf("Backgrounding to save %s later\n", + outfn); + exit(rc); + } + while (outfd < 0) { + outfd = open(outfn, O_CREAT|O_WRONLY|O_TRUNC, 0644); + sleep(1); + } + write(outfd, outbuf, outbufsize); + free(outbuf); + } + close(outfd); + + exit(rc); +}