Commit f9ddad59 authored by Theodore Ts'o's avatar Theodore Ts'o
Browse files

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).
parent fff45483
......@@ -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*
......
2003-04-14 Theodore Ts'o <tytso@mit.edu>
* 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 <tytso@mit.edu>
* mke2fs.c (PRS): If the argument to -b is negative, treat it as a
......
......@@ -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
......
.\" -*- 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)
/*
* 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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <time.h>
#include <errno.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#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);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment