Whamcloud - gitweb
Remove trailing whitespace for the entire source tree
[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 #define _XOPEN_SOURCE 600 /* for inclusion of sa_handler in Solaris */
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <string.h>
19 #include <sys/types.h>
20 #include <sys/wait.h>
21 #include <fcntl.h>
22 #include <time.h>
23 #include <errno.h>
24 #ifdef HAVE_SIGNAL_H
25 #include <signal.h>
26 #endif
27 #ifdef HAVE_GETOPT_H
28 #include <getopt.h>
29 #else
30 extern char *optarg;
31 extern int optind;
32 #endif
33
34 int     outfd = -1;
35 int     outbufsize = 0;
36 void    *outbuf = 0;
37 int     verbose = 0;
38 int     do_skip = 0;
39 int     skip_mode = 0;
40 pid_t   child_pid = -1;
41
42 static void usage(char *progname)
43 {
44         printf("Usage: %s [-v] [-d dir] logfile program\n", progname);
45         exit(1);
46 }
47
48 #define SEND_LOG        0x01
49 #define SEND_CONSOLE    0x02
50 #define SEND_BOTH       0x03
51
52 static void send_output(const char *buffer, int c, int flag)
53 {
54         char    *n;
55
56         if (c == 0)
57                 c = strlen(buffer);
58
59         if (flag & SEND_CONSOLE)
60                 write(1, buffer, c);
61         if (!(flag & SEND_LOG))
62                 return;
63         if (outfd > 0)
64                 write(outfd, buffer, c);
65         else {
66                 n = realloc(outbuf, outbufsize + c);
67                 if (n) {
68                         outbuf = n;
69                         memcpy(((char *)outbuf)+outbufsize, buffer, c);
70                         outbufsize += c;
71                 }
72         }
73 }
74
75 static int do_read(int fd)
76 {
77         int     c;
78         char    buffer[4096], *cp, *sep;
79
80         c = read(fd, buffer, sizeof(buffer)-1);
81         if (c <= 0)
82                 return c;
83         if (do_skip) {
84                 send_output(buffer, c, SEND_CONSOLE);
85                 buffer[c] = 0;
86                 cp = buffer;
87                 while (*cp) {
88                         if (skip_mode) {
89                                 cp = strchr(cp, '\002');
90                                 if (!cp)
91                                         return 0;
92                                 cp++;
93                                 skip_mode = 0;
94                                 continue;
95                         }
96                         sep = strchr(cp, '\001');
97                         if (sep)
98                                 *sep = 0;
99                         send_output(cp, 0, SEND_LOG);
100                         if (sep) {
101                                 cp = sep + 1;
102                                 skip_mode = 1;
103                         } else
104                                 break;
105                 }
106         } else
107                 send_output(buffer, c, SEND_BOTH);
108         return c;
109 }
110
111 static void signal_term(int sig)
112 {
113         if (child_pid > 0)
114                 kill(child_pid, sig);
115 }
116
117 static int run_program(char **argv)
118 {
119         int     fds[2];
120         int     status, rc, pid;
121         char    buffer[80];
122 #ifdef HAVE_SIGNAL_H
123         struct sigaction        sa;
124 #endif
125
126         if (pipe(fds) < 0) {
127                 perror("pipe");
128                 exit(1);
129         }
130
131 #ifdef HAVE_SIGNAL_H
132         memset(&sa, 0, sizeof(struct sigaction));
133         sa.sa_handler = signal_term;
134         sigaction(SIGINT, &sa, 0);
135         sigaction(SIGTERM, &sa, 0);
136 #ifdef SA_RESTART
137         sa.sa_flags = SA_RESTART;
138 #endif
139 #endif
140
141         pid = fork();
142         if (pid < 0) {
143                 perror("vfork");
144                 exit(1);
145         }
146         if (pid == 0) {
147                 dup2(fds[1],1);         /* fds[1] replaces stdout */
148                 dup2(fds[1],2);         /* fds[1] replaces stderr */
149                 close(fds[0]);  /* don't need this here */
150
151                 execvp(argv[0], argv);
152                 perror(argv[0]);
153                 exit(1);
154         }
155         child_pid = pid;
156         close(fds[1]);
157
158         while (!(waitpid(pid, &status, WNOHANG ))) {
159                 do_read(fds[0]);
160         }
161         child_pid = -1;
162         do_read(fds[0]);
163         close(fds[0]);
164
165         if ( WIFEXITED(status) ) {
166                 rc = WEXITSTATUS(status);
167                 if (rc) {
168                         send_output(argv[0], 0, SEND_BOTH);
169                         sprintf(buffer, " died with exit status %d\n", rc);
170                         send_output(buffer, 0, SEND_BOTH);
171                 }
172         } else {
173                 if (WIFSIGNALED(status)) {
174                         send_output(argv[0], 0, SEND_BOTH);
175                         sprintf(buffer, "died with signal %d\n",
176                                 WTERMSIG(status));
177                         send_output(buffer, 0, SEND_BOTH);
178                         rc = 1;
179                 }
180                 rc = 0;
181         }
182         return rc;
183 }
184
185 static int copy_from_stdin(void)
186 {
187         int     c, bad_read = 0;
188
189         while (1) {
190                 c = do_read(0);
191                 if ((c == 0 ) ||
192                     ((c < 0) && ((errno == EAGAIN) || (errno == EINTR)))) {
193                         if (bad_read++ > 3)
194                                 break;
195                         continue;
196                 }
197                 if (c < 0) {
198                         perror("read");
199                         exit(1);
200                 }
201                 bad_read = 0;
202         }
203         return 0;
204 }
205
206
207
208 int main(int argc, char **argv)
209 {
210         int     c, pid, rc;
211         char    *outfn, **cpp;
212         int     openflags = O_CREAT|O_WRONLY|O_TRUNC;
213         int     send_flag = SEND_LOG;
214         int     do_stdin;
215         time_t  t;
216
217         while ((c = getopt(argc, argv, "+asv")) != EOF) {
218                 switch (c) {
219                 case 'a':
220                         openflags &= ~O_TRUNC;
221                         openflags |= O_APPEND;
222                         break;
223                 case 's':
224                         do_skip = 1;
225                         break;
226                 case 'v':
227                         verbose++;
228                         send_flag |= SEND_CONSOLE;
229                         break;
230                 }
231         }
232         if (optind == argc || optind+1 == argc)
233                 usage(argv[0]);
234         outfn = argv[optind];
235         optind++;
236         argv += optind;
237         argc -= optind;
238
239         outfd = open(outfn, openflags, 0644);
240         do_stdin = !strcmp(argv[0], "-");
241
242         send_output("Log of ", 0, send_flag);
243         if (do_stdin)
244                 send_output("stdin", 0, send_flag);
245         else {
246                 for (cpp = argv; *cpp; cpp++) {
247                         send_output(*cpp, 0, send_flag);
248                         send_output(" ", 0, send_flag);
249                 }
250         }
251         send_output("\n", 0, send_flag);
252         t = time(0);
253         send_output(ctime(&t), 0, send_flag);
254         send_output("\n", 0, send_flag);
255
256         if (do_stdin)
257                 rc = copy_from_stdin();
258         else
259                 rc = run_program(argv);
260
261         send_output("\n", 0, send_flag);
262         t = time(0);
263         send_output(ctime(&t), 0, send_flag);
264         send_output("----------------\n", 0, send_flag);
265
266         if (outbuf) {
267                 pid = fork();
268                 if (pid < 0) {
269                         perror("fork");
270                         exit(1);
271                 }
272                 if (pid) {
273                         if (verbose)
274                                 printf("Backgrounding to save %s later\n",
275                                        outfn);
276                         exit(rc);
277                 }
278                 setsid();       /* To avoid getting killed by init */
279                 while (outfd < 0) {
280                         outfd = open(outfn, openflags, 0644);
281                         sleep(1);
282                 }
283                 write(outfd, outbuf, outbufsize);
284                 free(outbuf);
285         }
286         close(outfd);
287
288         exit(rc);
289 }