Whamcloud - gitweb
probe.c: When revalidating a filesystem in the blkid library,
[tools/e2fsprogs.git] / misc / logsave.c
1 /*
2  * logsave.c --- A program which saves the output of a program until
3  *      /var/log is mounted.
4  *
5  * Copyright (C) 2003 Theodore Ts'o.
6  *
7  * %Begin-Header%
8  * This file may be redistributed under the terms of the GNU Public
9  * License.
10  * %End-Header%
11  */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <string.h>
17 #include <sys/types.h>
18 #include <sys/wait.h>
19 #include <fcntl.h>
20 #include <time.h>
21 #include <errno.h>
22 #ifdef HAVE_GETOPT_H
23 #include <getopt.h>
24 #else
25 extern char *optarg;
26 extern int optind;
27 #endif
28
29 int     outfd = -1;
30 int     outbufsize = 0;
31 void    *outbuf = 0;
32 int     verbose = 0;
33 int     do_skip = 0;
34 int     skip_mode = 0;
35
36 static void usage(char *progname)
37 {
38         printf("Usage: %s [-v] [-d dir] logfile program\n", progname);
39         exit(1);
40 }
41
42 #define SEND_LOG        0x01
43 #define SEND_CONSOLE    0x02
44 #define SEND_BOTH       0x03
45
46 static void send_output(const char *buffer, int c, int flag)
47 {
48         char    *n;
49         
50         if (c == 0)
51                 c = strlen(buffer);
52         
53         if (flag & SEND_CONSOLE)
54                 write(1, buffer, c);
55         if (!(flag & SEND_LOG))
56                 return;
57         if (outfd > 0)
58                 write(outfd, buffer, c);
59         else {
60                 n = realloc(outbuf, outbufsize + c);
61                 if (n) {
62                         outbuf = n;
63                         memcpy(((char *)outbuf)+outbufsize, buffer, c);
64                         outbufsize += c;
65                 }
66         }
67 }
68
69 static int do_read(int fd)
70 {
71         int     c;
72         char    buffer[4096], *cp, *sep;
73
74         c = read(fd, buffer, sizeof(buffer)-1);
75         if (c <= 0)
76                 return c;
77         if (do_skip) {
78                 send_output(buffer, c, SEND_CONSOLE);
79                 buffer[c] = 0;
80                 cp = buffer;
81                 while (*cp) {
82                         if (skip_mode) {
83                                 cp = strchr(cp, '\002');
84                                 if (!cp)
85                                         return 0;
86                                 cp++;
87                                 skip_mode = 0;
88                                 continue;
89                         }
90                         sep = strchr(cp, '\001');
91                         if (sep)
92                                 *sep = 0;
93                         send_output(cp, 0, SEND_LOG);
94                         if (sep) {
95                                 cp = sep + 1;
96                                 skip_mode = 1;
97                         } else
98                                 break;
99                 }
100         } else
101                 send_output(buffer, c, SEND_BOTH);
102         return c;
103 }
104
105 static int run_program(char **argv)
106 {
107         int     fds[2];
108         int     status, rc, pid;
109         char    buffer[80];
110
111         if (pipe(fds) < 0) {
112                 perror("pipe");
113                 exit(1);
114         }
115
116         pid = fork();
117         if (pid < 0) {
118                 perror("vfork");
119                 exit(1);
120         }
121         if (pid == 0) {
122                 dup2(fds[1],1);         /* fds[1] replaces stdout */
123                 dup2(fds[1],2);         /* fds[1] replaces stderr */
124                 close(fds[0]);  /* don't need this here */
125                 
126                 execvp(argv[0], argv);
127                 perror(argv[0]);
128                 exit(1);
129         }
130         close(fds[1]);
131
132         while (!(waitpid(pid, &status, WNOHANG ))) {
133                 do_read(fds[0]);
134         }
135         do_read(fds[0]);
136         close(fds[0]);
137
138         if ( WIFEXITED(status) ) {
139                 rc = WEXITSTATUS(status);
140                 if (rc) {
141                         send_output(argv[0], 0, SEND_BOTH);
142                         sprintf(buffer, " died with exit status %d", rc);
143                         send_output(buffer, 0, SEND_BOTH);
144                 }
145         } else {
146                 if (WIFSIGNALED(status)) {
147                         send_output(argv[0], 0, SEND_BOTH);
148                         sprintf(buffer, "died with signal %d",
149                                 WTERMSIG(status));
150                         send_output(buffer, 0, SEND_BOTH);
151                         rc = 1;
152                 }
153                 rc = 0;
154         }
155         return rc;
156 }
157
158 static int copy_from_stdin(void)
159 {
160         int     c, bad_read = 0;
161
162         while (1) {
163                 c = do_read(0);
164                 if ((c == 0 ) ||
165                     ((c < 0) && ((errno == EAGAIN) || (errno == EINTR)))) {
166                         if (bad_read++ > 3)
167                                 break;
168                         continue;
169                 }
170                 if (c < 0) {
171                         perror("read");
172                         exit(1);
173                 }
174                 bad_read = 0;
175         }
176         return 0;
177 }       
178         
179
180
181 int main(int argc, char **argv)
182 {
183         int     c, pid, rc;
184         char    *outfn, **cpp;
185         int     openflags = O_CREAT|O_WRONLY|O_TRUNC;
186         int     send_flag = SEND_LOG;
187         int     do_stdin;
188         time_t  t;
189         
190         while ((c = getopt(argc, argv, "+asv")) != EOF) {
191                 switch (c) {
192                 case 'a':
193                         openflags &= ~O_TRUNC;
194                         openflags |= O_APPEND;
195                         break;
196                 case 's':
197                         do_skip = 1;
198                         break;
199                 case 'v':
200                         verbose++;
201                         send_flag |= SEND_CONSOLE;
202                         break;
203                 }
204         }
205         if (optind == argc || optind+1 == argc)
206                 usage(argv[0]);
207         outfn = argv[optind];
208         optind++;
209         argv += optind;
210         argc -= optind;
211
212         outfd = open(outfn, openflags, 0644);
213         do_stdin = !strcmp(argv[0], "-");
214         
215         send_output("Log of ", 0, send_flag);
216         if (do_stdin)
217                 send_output("stdin", 0, send_flag);
218         else {
219                 for (cpp = argv; *cpp; cpp++) {
220                         send_output(*cpp, 0, send_flag);
221                         send_output(" ", 0, send_flag);
222                 }
223         }
224         send_output("\n", 0, send_flag);
225         t = time(0);
226         send_output(ctime(&t), 0, send_flag);
227         send_output("\n", 0, send_flag);
228
229         if (do_stdin)
230                 rc = copy_from_stdin();
231         else
232                 rc = run_program(argv);
233         
234         send_output("\n", 0, send_flag);
235         t = time(0);
236         send_output(ctime(&t), 0, send_flag);
237         send_output("----------------\n", 0, send_flag);
238
239         if (outbuf) {
240                 pid = fork();
241                 if (pid < 0) {
242                         perror("fork");
243                         exit(1);
244                 }
245                 if (pid) {
246                         if (verbose)
247                                 printf("Backgrounding to save %s later\n",
248                                        outfn);
249                         exit(rc);
250                 }
251                 while (outfd < 0) {
252                         outfd = open(outfn, openflags, 0644);
253                         sleep(1);
254                 } 
255                 write(outfd, outbuf, outbufsize);
256                 free(outbuf);
257         }
258         close(outfd);
259         
260         exit(rc);
261 }