Whamcloud - gitweb
mke2fs: Add support for [devices] stanza in mke2fs.conf
[tools/e2fsprogs.git] / misc / logsave.c
index dd2e286..74e09f7 100644 (file)
@@ -10,6 +10,8 @@
  * %End-Header%
  */
 
+#define _XOPEN_SOURCE 600 /* for inclusion of sa_handler in Solaris */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -19,6 +21,9 @@
 #include <fcntl.h>
 #include <time.h>
 #include <errno.h>
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
 #ifdef HAVE_GETOPT_H
 #include <getopt.h>
 #else
@@ -30,23 +35,75 @@ int outfd = -1;
 int    outbufsize = 0;
 void   *outbuf = 0;
 int    verbose = 0;
+int    do_skip = 0;
+int    skip_mode = 0;
+pid_t  child_pid = -1;
 
 static void usage(char *progname)
 {
-       printf("Usage: %s [-v] [-d dir] logfile program\n", progname);
+       printf("Usage: %s [-asv] logfile program\n", progname);
        exit(1);
 }
 
-static void process_output(const char *buffer, int c)
+#define SEND_LOG       0x01
+#define SEND_CONSOLE   0x02
+#define SEND_BOTH      0x03
+
+/*
+ * Helper function that does the right thing if write returns a
+ * partial write, or an EGAIN/EINTR error.
+ */
+static int write_all(int fd, const char *buf, size_t count)
+{
+       ssize_t ret;
+       int c = 0;
+
+       while (count > 0) {
+               ret = write(fd, buf, count);
+               if (ret < 0) {
+                       if ((errno == EAGAIN) || (errno == EINTR))
+                               continue;
+                       return -1;
+               }
+               count -= ret;
+               buf += ret;
+               c += ret;
+       }
+       return c;
+}
+
+static void send_output(const char *buffer, int c, int flag)
 {
-       char    *n;
-       
+       const char      *cp;
+       char            *n;
+       int             cnt, d, del;
+
        if (c == 0)
                c = strlen(buffer);
-       
-       write(1, buffer, c);
+
+       if (flag & SEND_CONSOLE) {
+               cnt = c;
+               cp = buffer;
+               while (cnt) {
+                       del = 0;
+                       for (d=0; d < cnt; d++) {
+                               if (skip_mode &&
+                                   (cp[d] == '\001' || cp[d] == '\002')) {
+                                       del = 1;
+                                       break;
+                               }
+                       }
+                       write_all(1, cp, d);
+                       if (del)
+                               d++;
+                       cnt -= d;
+                       cp += d;
+               }
+       }
+       if (!(flag & SEND_LOG))
+               return;
        if (outfd > 0)
-               write(outfd, buffer, c);
+               write_all(outfd, buffer, c);
        else {
                n = realloc(outbuf, outbufsize + c);
                if (n) {
@@ -57,40 +114,72 @@ static void process_output(const char *buffer, int c)
        }
 }
 
-static void do_read(int fd)
+static int do_read(int fd)
 {
        int     c;
-       char    buffer[4096];
+       char    buffer[4096], *cp, *sep;
+
+       c = read(fd, buffer, sizeof(buffer)-1);
+       if (c <= 0)
+               return c;
+       if (do_skip) {
+               send_output(buffer, c, SEND_CONSOLE);
+               buffer[c] = 0;
+               cp = buffer;
+               while (*cp) {
+                       if (skip_mode) {
+                               cp = strchr(cp, '\002');
+                               if (!cp)
+                                       return 0;
+                               cp++;
+                               skip_mode = 0;
+                               continue;
+                       }
+                       sep = strchr(cp, '\001');
+                       if (sep)
+                               *sep = 0;
+                       send_output(cp, 0, SEND_LOG);
+                       if (sep) {
+                               cp = sep + 1;
+                               skip_mode = 1;
+                       } else
+                               break;
+               }
+       } else
+               send_output(buffer, c, SEND_BOTH);
+       return c;
+}
 
-       c = read(fd, buffer, sizeof(buffer));
-       process_output(buffer, c);
+static void signal_term(int sig)
+{
+       if (child_pid > 0)
+               kill(child_pid, sig);
 }
 
 static int run_program(char **argv)
 {
        int     fds[2];
-       char    **cpp;
        int     status, rc, pid;
        char    buffer[80];
-       time_t  t;
+#ifdef HAVE_SIGNAL_H
+       struct sigaction        sa;
+#endif
 
        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);
-       }
-       
+#ifdef HAVE_SIGNAL_H
+       memset(&sa, 0, sizeof(struct sigaction));
+       sa.sa_handler = signal_term;
+       sigaction(SIGINT, &sa, 0);
+       sigaction(SIGTERM, &sa, 0);
+#ifdef SA_RESTART
+       sa.sa_flags = SA_RESTART;
+#endif
+#endif
+
        pid = fork();
        if (pid < 0) {
                perror("vfork");
@@ -100,32 +189,34 @@ static int run_program(char **argv)
                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);
        }
+       child_pid = pid;
        close(fds[1]);
 
        while (!(waitpid(pid, &status, WNOHANG ))) {
                do_read(fds[0]);
        }
+       child_pid = -1;
        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);
+                       send_output(argv[0], 0, SEND_BOTH);
+                       sprintf(buffer, " died with exit status %d\n", rc);
+                       send_output(buffer, 0, SEND_BOTH);
                }
        } else {
                if (WIFSIGNALED(status)) {
-                       process_output(argv[0], 0);
-                       sprintf(buffer, "died with signal %d",
+                       send_output(argv[0], 0, SEND_BOTH);
+                       sprintf(buffer, "died with signal %d\n",
                                WTERMSIG(status));
-                       process_output(buffer, 0);
+                       send_output(buffer, 0, SEND_BOTH);
                        rc = 1;
                }
                rc = 0;
@@ -135,12 +226,10 @@ static int run_program(char **argv)
 
 static int copy_from_stdin(void)
 {
-       char    buffer[4096];
-       int     c;
-       int     bad_read = 0;
+       int     c, bad_read = 0;
 
        while (1) {
-               c = read(0, buffer, sizeof(buffer));
+               c = do_read(0);
                if ((c == 0 ) ||
                    ((c < 0) && ((errno == EAGAIN) || (errno == EINTR)))) {
                        if (bad_read++ > 3)
@@ -151,28 +240,34 @@ static int copy_from_stdin(void)
                        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;
+       char    *outfn, **cpp;
        int     openflags = O_CREAT|O_WRONLY|O_TRUNC;
-       
-       while ((c = getopt(argc, argv, "+v")) != EOF) {
+       int     send_flag = SEND_LOG;
+       int     do_stdin;
+       time_t  t;
+
+       while ((c = getopt(argc, argv, "+asv")) != EOF) {
                switch (c) {
                case 'a':
                        openflags &= ~O_TRUNC;
                        openflags |= O_APPEND;
                        break;
+               case 's':
+                       do_skip = 1;
+                       break;
                case 'v':
                        verbose++;
+                       send_flag |= SEND_CONSOLE;
                        break;
                }
        }
@@ -183,13 +278,33 @@ int main(int argc, char **argv)
        argv += optind;
        argc -= optind;
 
-       outfd = open(outfn, O_CREAT|O_WRONLY|O_TRUNC, 0644);
+       outfd = open(outfn, openflags, 0644);
+       do_stdin = !strcmp(argv[0], "-");
 
-       if (strcmp(argv[0], "-"))
-               rc = run_program(argv);
-       else
+       send_output("Log of ", 0, send_flag);
+       if (do_stdin)
+               send_output("stdin", 0, send_flag);
+       else {
+               for (cpp = argv; *cpp; cpp++) {
+                       send_output(*cpp, 0, send_flag);
+                       send_output(" ", 0, send_flag);
+               }
+       }
+       send_output("\n", 0, send_flag);
+       t = time(0);
+       send_output(ctime(&t), 0, send_flag);
+       send_output("\n", 0, send_flag);
+
+       if (do_stdin)
                rc = copy_from_stdin();
-       
+       else
+               rc = run_program(argv);
+
+       send_output("\n", 0, send_flag);
+       t = time(0);
+       send_output(ctime(&t), 0, send_flag);
+       send_output("----------------\n", 0, send_flag);
+
        if (outbuf) {
                pid = fork();
                if (pid < 0) {
@@ -202,14 +317,15 @@ int main(int argc, char **argv)
                                       outfn);
                        exit(rc);
                }
+               setsid();       /* To avoid getting killed by init */
                while (outfd < 0) {
-                       outfd = open(outfn, O_CREAT|O_WRONLY|O_TRUNC, 0644);
+                       outfd = open(outfn, openflags, 0644);
                        sleep(1);
-               } 
-               write(outfd, outbuf, outbufsize);
+               }
+               write_all(outfd, outbuf, outbufsize);
                free(outbuf);
        }
        close(outfd);
-       
+
        exit(rc);
 }