2 * logsave.c --- A program which saves the output of a program until
5 * Copyright (C) 2003 Theodore Ts'o.
8 * This file may be redistributed under the terms of the GNU Public
13 #define _XOPEN_SOURCE 600 /* for inclusion of sa_handler in Solaris */
20 #include <sys/types.h>
35 static int outfd
= -1;
36 static int outbufsize
= 0;
37 static void *outbuf
= 0;
38 static int verbose
= 0;
39 static int do_skip
= 0;
40 static int skip_mode
= 0;
41 static pid_t child_pid
= -1;
43 static void usage(char *progname
)
45 printf("Usage: %s [-asv] logfile program\n", progname
);
50 #define SEND_CONSOLE 0x02
51 #define SEND_BOTH 0x03
54 * Helper function that does the right thing if write returns a
55 * partial write, or an EAGAIN/EINTR error.
57 static int write_all(int fd
, const char *buf
, size_t count
)
63 ret
= write(fd
, buf
, count
);
65 if ((errno
== EAGAIN
) || (errno
== EINTR
))
76 static void send_output(const char *buffer
, int c
, int flag
)
85 if (flag
& SEND_CONSOLE
) {
90 for (d
=0; d
< cnt
; d
++) {
92 (cp
[d
] == '\001' || cp
[d
] == '\002')) {
104 if (!(flag
& SEND_LOG
))
107 write_all(outfd
, buffer
, c
);
109 n
= realloc(outbuf
, outbufsize
+ c
);
112 memcpy(((char *)outbuf
)+outbufsize
, buffer
, c
);
118 static int do_read(int fd
)
121 char buffer
[4096], *cp
, *sep
;
123 c
= read(fd
, buffer
, sizeof(buffer
)-1);
127 send_output(buffer
, c
, SEND_CONSOLE
);
132 cp
= strchr(cp
, '\002');
139 sep
= strchr(cp
, '\001');
142 send_output(cp
, 0, SEND_LOG
);
150 send_output(buffer
, c
, SEND_BOTH
);
154 static void signal_term(int sig
)
157 kill(child_pid
, sig
);
160 static int run_program(char **argv
)
175 memset(&sa
, 0, sizeof(struct sigaction
));
176 sa
.sa_handler
= signal_term
;
177 sigaction(SIGINT
, &sa
, 0);
178 sigaction(SIGTERM
, &sa
, 0);
180 sa
.sa_flags
= SA_RESTART
;
190 dup2(fds
[1],1); /* fds[1] replaces stdout */
191 dup2(fds
[1],2); /* fds[1] replaces stderr */
192 close(fds
[0]); /* don't need this here */
195 execvp(argv
[0], argv
);
202 while (!(waitpid(pid
, &status
, WNOHANG
))) {
209 if ( WIFEXITED(status
) ) {
210 rc
= WEXITSTATUS(status
);
212 send_output(argv
[0], 0, SEND_BOTH
);
213 sprintf(buffer
, " exited with status code %d\n", rc
);
214 send_output(buffer
, 0, SEND_BOTH
);
217 if (WIFSIGNALED(status
)) {
218 send_output(argv
[0], 0, SEND_BOTH
);
219 sprintf(buffer
, "died with signal %d\n",
221 send_output(buffer
, 0, SEND_BOTH
);
229 static int copy_from_stdin(void)
236 ((c
< 0) && ((errno
== EAGAIN
) || (errno
== EINTR
)))) {
252 int main(int argc
, char **argv
)
256 int openflags
= O_CREAT
|O_WRONLY
|O_TRUNC
;
257 int send_flag
= SEND_LOG
;
261 while ((c
= getopt(argc
, argv
, "+asv")) != EOF
) {
264 openflags
&= ~O_TRUNC
;
265 openflags
|= O_APPEND
;
272 send_flag
|= SEND_CONSOLE
;
276 if (optind
== argc
|| optind
+1 == argc
)
278 outfn
= argv
[optind
];
283 outfd
= open(outfn
, openflags
, 0644);
284 do_stdin
= !strcmp(argv
[0], "-");
286 send_output("Log of ", 0, send_flag
);
288 send_output("stdin", 0, send_flag
);
290 for (cpp
= argv
; *cpp
; cpp
++) {
291 send_output(*cpp
, 0, send_flag
);
292 send_output(" ", 0, send_flag
);
295 send_output("\n", 0, send_flag
);
297 send_output(ctime(&t
), 0, send_flag
);
298 send_output("\n", 0, send_flag
);
301 rc
= copy_from_stdin();
303 rc
= run_program(argv
);
305 send_output("\n", 0, send_flag
);
307 send_output(ctime(&t
), 0, send_flag
);
308 send_output("----------------\n", 0, send_flag
);
318 printf("Backgrounding to save %s later\n",
322 setsid(); /* To avoid getting killed by init */
324 outfd
= open(outfn
, openflags
, 0644);
327 write_all(outfd
, outbuf
, outbufsize
);