Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100755 65 lines (60 sloc) 1.872 kB
6e06544 @apenwarr Add and use 'runtee' to avoid hangs due to long-running subprocesses.
authored
1 #!/usr/bin/perl -w
2 #
3 # A variant of 'tee' that runs a command and stops when that command finishes.
4 # This is needed instead of 'tee' because sometimes, the command ends up
5 # (probably accidentally) forking more subprocesses, which might continue
6 # living beyond the lifetime of the original process we started. But 'tee'
7 # will keep on going until *all* the processes die that have stdout connected
8 # to its stdin pipe, which is no good.
9 #
10 # runtee starts its own subprocess, so it can monitor to see when that
11 # subprocess dies, and clean up accordingly at that time.
12 #
13 # Like 'tee', we write to the given file *and* to stdout. Unlike 'tee',
14 # we capture both stdout and stderr from the program.
15 #
16 use strict;
17 use IO::Select;
18 use POSIX ":sys_wait_h";
19 $| = 1;
20
21 if (@ARGV < 2) {
22 print STDERR "Usage: $0 <logfile> <command line...>\n";
23 exit 127;
24 }
25
26 my $logname = shift @ARGV;
27 open(my $log, ">$logname") or die("Can't open $logname: $!\n");
28
29 my $pid = open(my $fh, "-|");
30 my $done = 0;
31 if ($pid) {
32 # parent
33 local $SIG{INT} = sub { kill 2, $pid; };
34 local $SIG{TERM} = sub { kill 15, $pid; };
35 local $SIG{CHLD} = sub {
36 $done = 1;
37 };
38 my $s = IO::Select->new($fh);
39 while (1) {
40 if ($s->can_read($done ? 0 : 5)) {
41 my $buf;
42 my $len = sysread($fh, $buf, 1024);
43 last if ($len == 0); # EOF, definitely done
44 print STDOUT $buf;
45 print $log $buf;
46 } elsif ($done) {
47 # only honour $done if the input buffer is empty
48 last;
49 }
50 }
51 my $newpid = waitpid($pid, 0);
52 if ($newpid != $pid) {
53 die("waitpid returned '$newpid', expected '$pid'\n");
54 }
55 exit $? >> 8;
56 } else {
57 # child
58 open STDERR, '>&STDOUT' or die("Can't dup stdout: $!\n");
59 exec(@ARGV);
60 exit 126; # just in case
61 }
62
63 # NOTREACHED
64 exit 125;
Something went wrong with that request. Please try again.