| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#+############################################################################## |
|
2
|
|
|
|
|
|
|
# # |
|
3
|
|
|
|
|
|
|
# File: No/Worries/Proc.pm # |
|
4
|
|
|
|
|
|
|
# # |
|
5
|
|
|
|
|
|
|
# Description: process handling without worries # |
|
6
|
|
|
|
|
|
|
# # |
|
7
|
|
|
|
|
|
|
#-############################################################################## |
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
# |
|
10
|
|
|
|
|
|
|
# module definition |
|
11
|
|
|
|
|
|
|
# |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
package No::Worries::Proc; |
|
14
|
11
|
|
|
11
|
|
4805
|
use strict; |
|
|
11
|
|
|
|
|
42
|
|
|
|
11
|
|
|
|
|
424
|
|
|
15
|
11
|
|
|
11
|
|
84
|
use warnings; |
|
|
11
|
|
|
|
|
32
|
|
|
|
11
|
|
|
|
|
1289
|
|
|
16
|
11
|
|
|
11
|
|
258
|
use 5.005; # need the four-argument form of substr() |
|
|
11
|
|
|
|
|
63
|
|
|
17
|
|
|
|
|
|
|
our $VERSION = "1.5"; |
|
18
|
|
|
|
|
|
|
our $REVISION = sprintf("%d.%02d", q$Revision: 1.23 $ =~ /(\d+)\.(\d+)/); |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# |
|
21
|
|
|
|
|
|
|
# used modules |
|
22
|
|
|
|
|
|
|
# |
|
23
|
|
|
|
|
|
|
|
|
24
|
11
|
|
|
11
|
|
4259
|
use IO::Select qw(); |
|
|
11
|
|
|
|
|
23934
|
|
|
|
11
|
|
|
|
|
371
|
|
|
25
|
11
|
|
|
11
|
|
95
|
use No::Worries qw($_IntegerRegexp $_NumberRegexp); |
|
|
11
|
|
|
|
|
32
|
|
|
|
11
|
|
|
|
|
85
|
|
|
26
|
11
|
|
|
11
|
|
86
|
use No::Worries::Die qw(dief); |
|
|
11
|
|
|
|
|
41
|
|
|
|
11
|
|
|
|
|
106
|
|
|
27
|
11
|
|
|
11
|
|
4010
|
use No::Worries::Dir qw(dir_change); |
|
|
11
|
|
|
|
|
43
|
|
|
|
11
|
|
|
|
|
85
|
|
|
28
|
11
|
|
|
11
|
|
106
|
use No::Worries::Export qw(export_control); |
|
|
11
|
|
|
|
|
32
|
|
|
|
11
|
|
|
|
|
74
|
|
|
29
|
11
|
|
|
11
|
|
85
|
use Params::Validate qw(validate validate_with :types); |
|
|
11
|
|
|
|
|
42
|
|
|
|
11
|
|
|
|
|
2089
|
|
|
30
|
11
|
|
|
11
|
|
4835
|
use POSIX qw(:sys_wait_h :errno_h setsid); |
|
|
11
|
|
|
|
|
82359
|
|
|
|
11
|
|
|
|
|
105
|
|
|
31
|
11
|
|
|
11
|
|
30560
|
use Time::HiRes qw(); |
|
|
11
|
|
|
|
|
16159
|
|
|
|
11
|
|
|
|
|
28736
|
|
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# |
|
34
|
|
|
|
|
|
|
# global variables |
|
35
|
|
|
|
|
|
|
# |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
our($Transient); |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
# |
|
40
|
|
|
|
|
|
|
# check a command to be executed |
|
41
|
|
|
|
|
|
|
# |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
sub _chk_cmd (@) { |
|
44
|
54
|
|
|
54
|
|
301
|
my(@cmd) = @_; |
|
45
|
54
|
|
|
|
|
268
|
my($path); |
|
46
|
|
|
|
|
|
|
|
|
47
|
54
|
50
|
|
|
|
504
|
if ($cmd[0] =~ /\//) { |
|
48
|
54
|
50
|
33
|
|
|
1494
|
dief("invalid command: %s", $cmd[0]) unless -f $cmd[0] and -x _; |
|
49
|
|
|
|
|
|
|
} else { |
|
50
|
0
|
|
0
|
|
|
0
|
$path = $ENV{PATH} || "/usr/bin:/usr/sbin:/bin:/sbin"; |
|
51
|
0
|
|
|
|
|
0
|
foreach my $dir (split(/:/, $path)) { |
|
52
|
0
|
0
|
0
|
|
|
0
|
next unless length($dir) and -d $dir; |
|
53
|
0
|
0
|
0
|
|
|
0
|
next unless -f "$dir/$cmd[0]" and -x _; |
|
54
|
0
|
|
|
|
|
0
|
$cmd[0] = "$dir/$cmd[0]"; |
|
55
|
0
|
|
|
|
|
0
|
last; |
|
56
|
|
|
|
|
|
|
} |
|
57
|
0
|
0
|
|
|
|
0
|
dief("command not found: %s", $cmd[0]) unless $cmd[0] =~ /\//; |
|
58
|
|
|
|
|
|
|
} |
|
59
|
54
|
|
|
|
|
370
|
return(\@cmd); |
|
60
|
|
|
|
|
|
|
} |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
# |
|
63
|
|
|
|
|
|
|
# definition of the process structure |
|
64
|
|
|
|
|
|
|
# |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
my $nbre = "(\\d+\\.)?\\d+"; # fractional number pattern |
|
67
|
|
|
|
|
|
|
my $ksre = "([A-Z]+\\/${nbre}\\s+)*[A-Z]+\\/${nbre}"; # kill spec. pattern |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
my %proc_structure = ( |
|
70
|
|
|
|
|
|
|
# public |
|
71
|
|
|
|
|
|
|
command => { optional => 0, type => ARRAYREF }, |
|
72
|
|
|
|
|
|
|
pid => { optional => 0, type => SCALAR, regex => $_IntegerRegexp }, |
|
73
|
|
|
|
|
|
|
start => { optional => 0, type => SCALAR, regex => $_NumberRegexp }, |
|
74
|
|
|
|
|
|
|
stop => { optional => 1, type => SCALAR, regex => $_NumberRegexp }, |
|
75
|
|
|
|
|
|
|
status => { optional => 1, type => SCALAR, regex => qr/^-?\d+$/ }, |
|
76
|
|
|
|
|
|
|
timeout => { optional => 1, type => SCALAR, regex => $_NumberRegexp }, |
|
77
|
|
|
|
|
|
|
# private |
|
78
|
|
|
|
|
|
|
kill => { optional => 1, type => SCALAR, regex => qr/^${ksre}$/ }, |
|
79
|
|
|
|
|
|
|
maxtime => { optional => 1, type => SCALAR, regex => $_NumberRegexp }, |
|
80
|
|
|
|
|
|
|
fhin => { optional => 1, type => GLOBREF }, |
|
81
|
|
|
|
|
|
|
fhout => { optional => 1, type => GLOBREF }, |
|
82
|
|
|
|
|
|
|
fherr => { optional => 1, type => GLOBREF }, |
|
83
|
|
|
|
|
|
|
bufin => { optional => 1, type => SCALAR }, |
|
84
|
|
|
|
|
|
|
cbout => { optional => 1, type => CODEREF }, |
|
85
|
|
|
|
|
|
|
cberr => { optional => 1, type => CODEREF }, |
|
86
|
|
|
|
|
|
|
); |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
sub _chk_proc ($) { |
|
89
|
53
|
|
|
53
|
|
162
|
my($proc) = @_; |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
validate_with( |
|
92
|
|
|
|
|
|
|
params => $proc, |
|
93
|
|
|
|
|
|
|
spec => \%proc_structure, |
|
94
|
0
|
|
|
0
|
|
0
|
on_fail => sub { dief("invalid process structure: %s", $_[0]) }, |
|
95
|
53
|
|
|
|
|
5627
|
); |
|
96
|
53
|
|
|
|
|
6919
|
return(); # so that validate_with() is called in void context |
|
97
|
|
|
|
|
|
|
} |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
# |
|
100
|
|
|
|
|
|
|
# close a file handle used for IPC |
|
101
|
|
|
|
|
|
|
# |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
sub _close ($$$$) { |
|
104
|
65
|
|
|
65
|
|
218
|
my($proc, $fh, $what, $ios) = @_; |
|
105
|
|
|
|
|
|
|
|
|
106
|
65
|
100
|
|
|
|
575
|
$ios->remove($fh) if $ios; |
|
107
|
65
|
50
|
|
|
|
5034
|
close($fh) or dief("cannot close(): %s", $!); |
|
108
|
65
|
|
|
|
|
438
|
delete($proc->{"fh$what"}); |
|
109
|
65
|
|
|
|
|
847
|
delete($proc->{"cb$what"}); |
|
110
|
|
|
|
|
|
|
} |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
# |
|
113
|
|
|
|
|
|
|
# try to read from a dead process in case we called _is_alive() on it |
|
114
|
|
|
|
|
|
|
# before all its output pipes got emptied... |
|
115
|
|
|
|
|
|
|
# |
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
sub _read_zombie ($$$) { |
|
118
|
44
|
|
|
44
|
|
155
|
my($proc, $iosr, $iosw) = @_; |
|
119
|
44
|
|
|
|
|
122
|
my($fh, $buf, $done); |
|
120
|
|
|
|
|
|
|
|
|
121
|
44
|
|
|
|
|
245
|
foreach my $what (qw(in)) { |
|
122
|
44
|
50
|
33
|
|
|
384
|
next unless $proc->{"fh$what"} and $proc->{"cb$what"}; |
|
123
|
0
|
|
|
|
|
0
|
$fh = $proc->{"fh$what"}; |
|
124
|
|
|
|
|
|
|
# no write, simply close |
|
125
|
0
|
|
|
|
|
0
|
_close($proc, $fh, $what, $iosw); |
|
126
|
|
|
|
|
|
|
} |
|
127
|
44
|
|
|
|
|
183
|
foreach my $what (qw(out err)) { |
|
128
|
88
|
100
|
66
|
|
|
735
|
next unless $proc->{"fh$what"} and $proc->{"cb$what"}; |
|
129
|
43
|
|
|
|
|
234
|
$fh = $proc->{"fh$what"}; |
|
130
|
|
|
|
|
|
|
# read until EOF then close |
|
131
|
43
|
|
|
|
|
137
|
$done = 1; |
|
132
|
43
|
|
|
|
|
166
|
while ($done) { |
|
133
|
50
|
|
|
|
|
163
|
$buf = ""; |
|
134
|
50
|
|
|
|
|
478
|
$done = sysread($fh, $buf, 8192); |
|
135
|
50
|
50
|
|
|
|
204
|
dief("cannot sysread(): %s", $!) unless defined($done); |
|
136
|
50
|
|
|
|
|
295
|
$proc->{"cb$what"}($proc, $buf); |
|
137
|
|
|
|
|
|
|
} |
|
138
|
43
|
|
|
|
|
189
|
_close($proc, $fh, $what, $iosr); |
|
139
|
|
|
|
|
|
|
} |
|
140
|
|
|
|
|
|
|
} |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
# |
|
143
|
|
|
|
|
|
|
# check if a process is alive, record its status if not |
|
144
|
|
|
|
|
|
|
# |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
sub _is_alive ($$$) { |
|
147
|
2038
|
|
|
2038
|
|
9073
|
my($proc, $iosr, $iosw) = @_; |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
# check if it recently died |
|
150
|
2038
|
100
|
|
|
|
58671
|
if (waitpid($proc->{pid}, WNOHANG) == $proc->{pid}) { |
|
151
|
44
|
|
|
|
|
680
|
$proc->{status} = $?; |
|
152
|
44
|
|
|
|
|
410
|
$proc->{stop} = Time::HiRes::time(); |
|
153
|
44
|
|
|
|
|
154
|
delete($proc->{maxtime}); |
|
154
|
44
|
|
|
|
|
131
|
delete($proc->{kill}); |
|
155
|
44
|
|
|
|
|
299
|
_read_zombie($proc, $iosr, $iosw); |
|
156
|
44
|
|
|
|
|
298
|
return(0); # no |
|
157
|
|
|
|
|
|
|
} |
|
158
|
|
|
|
|
|
|
# check if we can kill it |
|
159
|
1994
|
50
|
33
|
|
|
45810
|
if (kill(0, $proc->{pid}) or $! == EPERM) { |
|
160
|
1994
|
|
|
|
|
13389
|
return(1); # yes |
|
161
|
|
|
|
|
|
|
} |
|
162
|
|
|
|
|
|
|
# ooops |
|
163
|
0
|
|
|
|
|
0
|
return(); # don't know |
|
164
|
|
|
|
|
|
|
} |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
# |
|
167
|
|
|
|
|
|
|
# prepare I/O before creating a process |
|
168
|
|
|
|
|
|
|
# |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
sub _prepare_stdin ($$) { |
|
171
|
54
|
|
|
54
|
|
254
|
my($proc, $stdin) = @_; |
|
172
|
54
|
|
|
|
|
158
|
my($ref, $rdrin, $wrtin); |
|
173
|
|
|
|
|
|
|
|
|
174
|
54
|
100
|
|
|
|
261
|
return() unless defined($stdin); |
|
175
|
11
|
|
|
|
|
44
|
$ref = ref($stdin); |
|
176
|
11
|
100
|
|
|
|
93
|
if ($ref eq "") { |
|
|
|
50
|
|
|
|
|
|
|
177
|
6
|
50
|
|
|
|
30
|
if ($stdin eq "") { |
|
178
|
0
|
|
|
|
|
0
|
dief("unexpected stdin: empty string"); |
|
179
|
|
|
|
|
|
|
} else { |
|
180
|
|
|
|
|
|
|
## no critic 'InputOutput::RequireBriefOpen' |
|
181
|
6
|
50
|
|
|
|
204
|
open($rdrin, "<", $stdin) |
|
182
|
|
|
|
|
|
|
or dief("cannot open(<, %s): %s", $stdin, $!); |
|
183
|
|
|
|
|
|
|
} |
|
184
|
|
|
|
|
|
|
} elsif ($ref eq "SCALAR") { |
|
185
|
5
|
50
|
|
|
|
145
|
pipe($rdrin, $wrtin) |
|
186
|
|
|
|
|
|
|
or dief("cannot pipe(): %s", $!); |
|
187
|
5
|
|
|
|
|
30
|
$proc->{fhin} = $wrtin; |
|
188
|
5
|
|
|
|
|
10
|
$proc->{bufin} = ${ $stdin }; |
|
|
5
|
|
|
|
|
20
|
|
|
189
|
|
|
|
|
|
|
} else { |
|
190
|
0
|
|
|
|
|
0
|
dief("unexpected stdin: ref(%s)", $ref); |
|
191
|
|
|
|
|
|
|
} |
|
192
|
11
|
|
|
|
|
67
|
return($rdrin, $wrtin); |
|
193
|
|
|
|
|
|
|
} |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
sub _prepare_stdout ($$) { |
|
196
|
54
|
|
|
54
|
|
174
|
my($proc, $stdout) = @_; |
|
197
|
54
|
|
|
|
|
150
|
my($ref, $rdrout, $wrtout); |
|
198
|
|
|
|
|
|
|
|
|
199
|
54
|
100
|
|
|
|
190
|
return() unless defined($stdout); |
|
200
|
52
|
|
|
|
|
179
|
$ref = ref($stdout); |
|
201
|
52
|
100
|
33
|
|
|
444
|
if ($ref eq "") { |
|
|
|
50
|
|
|
|
|
|
|
202
|
8
|
50
|
|
|
|
96
|
if ($stdout eq "") { |
|
203
|
0
|
|
|
|
|
0
|
dief("unexpected stdout: empty string"); |
|
204
|
|
|
|
|
|
|
} else { |
|
205
|
|
|
|
|
|
|
## no critic 'InputOutput::RequireBriefOpen' |
|
206
|
8
|
50
|
|
|
|
856
|
open($wrtout, ">", $stdout) |
|
207
|
|
|
|
|
|
|
or dief("cannot open(>, %s): %s", $stdout, $!); |
|
208
|
|
|
|
|
|
|
} |
|
209
|
|
|
|
|
|
|
} elsif ($ref eq "CODE" or $ref eq "SCALAR") { |
|
210
|
44
|
50
|
|
|
|
1337
|
pipe($rdrout, $wrtout) |
|
211
|
|
|
|
|
|
|
or dief("cannot pipe(): %s", $!); |
|
212
|
44
|
|
|
|
|
207
|
$proc->{fhout} = $rdrout; |
|
213
|
44
|
50
|
|
|
|
191
|
if ($ref eq "CODE") { |
|
214
|
0
|
|
|
|
|
0
|
$proc->{cbout} = $stdout; |
|
215
|
|
|
|
|
|
|
} else { |
|
216
|
44
|
|
|
|
|
84
|
${ $stdout } = ""; |
|
|
44
|
|
|
|
|
145
|
|
|
217
|
|
|
|
|
|
|
$proc->{cbout} = sub { |
|
218
|
66
|
|
|
66
|
|
257
|
my($_proc, $_buf) = @_; |
|
219
|
66
|
|
|
|
|
165
|
${ $stdout } .= $_buf; |
|
|
66
|
|
|
|
|
298
|
|
|
220
|
44
|
|
|
|
|
384
|
}; |
|
221
|
|
|
|
|
|
|
} |
|
222
|
|
|
|
|
|
|
} else { |
|
223
|
0
|
|
|
|
|
0
|
dief("unexpected stdout: ref(%s)", $ref); |
|
224
|
|
|
|
|
|
|
} |
|
225
|
52
|
|
|
|
|
351
|
return($rdrout, $wrtout); |
|
226
|
|
|
|
|
|
|
} |
|
227
|
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
sub _prepare_stderr ($$) { |
|
229
|
54
|
|
|
54
|
|
222
|
my($proc, $stderr) = @_; |
|
230
|
54
|
|
|
|
|
150
|
my($ref, $rdrerr, $wrterr, $merge); |
|
231
|
|
|
|
|
|
|
|
|
232
|
54
|
100
|
|
|
|
244
|
return() unless defined($stderr); |
|
233
|
39
|
|
|
|
|
123
|
$ref = ref($stderr); |
|
234
|
39
|
100
|
33
|
|
|
366
|
if ($ref eq "") { |
|
|
|
50
|
|
|
|
|
|
|
235
|
9
|
50
|
|
|
|
54
|
if ($stderr eq "") { |
|
236
|
|
|
|
|
|
|
# special case: stderr will be merged with stdout |
|
237
|
9
|
|
|
|
|
63
|
$merge = 1; |
|
238
|
|
|
|
|
|
|
} else { |
|
239
|
|
|
|
|
|
|
## no critic 'InputOutput::RequireBriefOpen' |
|
240
|
0
|
0
|
|
|
|
0
|
open($wrterr, ">", $stderr) |
|
241
|
|
|
|
|
|
|
or dief("cannot open(>, %s): %s", $stderr, $!); |
|
242
|
|
|
|
|
|
|
} |
|
243
|
|
|
|
|
|
|
} elsif ($ref eq "CODE" or $ref eq "SCALAR") { |
|
244
|
30
|
50
|
|
|
|
632
|
pipe($rdrerr, $wrterr) |
|
245
|
|
|
|
|
|
|
or dief("cannot pipe(): %s", $!); |
|
246
|
30
|
|
|
|
|
121
|
$proc->{fherr} = $rdrerr; |
|
247
|
30
|
50
|
|
|
|
97
|
if ($ref eq "CODE") { |
|
248
|
0
|
|
|
|
|
0
|
$proc->{cberr} = $stderr; |
|
249
|
|
|
|
|
|
|
} else { |
|
250
|
30
|
|
|
|
|
73
|
${ $stderr } = ""; |
|
|
30
|
|
|
|
|
564
|
|
|
251
|
|
|
|
|
|
|
$proc->{cberr} = sub { |
|
252
|
41
|
|
|
41
|
|
144
|
my($_proc, $_buf) = @_; |
|
253
|
41
|
|
|
|
|
105
|
${ $stderr } .= $_buf; |
|
|
41
|
|
|
|
|
209
|
|
|
254
|
30
|
|
|
|
|
277
|
}; |
|
255
|
|
|
|
|
|
|
} |
|
256
|
|
|
|
|
|
|
} else { |
|
257
|
0
|
|
|
|
|
0
|
dief("unexpected stderr: ref(%s)", $ref); |
|
258
|
|
|
|
|
|
|
} |
|
259
|
39
|
|
|
|
|
200
|
return($rdrerr, $wrterr, $merge); |
|
260
|
|
|
|
|
|
|
} |
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
# |
|
263
|
|
|
|
|
|
|
# redirect I/O after creating a process |
|
264
|
|
|
|
|
|
|
# |
|
265
|
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
sub _redirect_io ($$$$) { |
|
267
|
9
|
|
|
9
|
|
102
|
my($rdrin, $wrtout, $wrterr, $merge) = @_; |
|
268
|
9
|
|
|
|
|
181
|
my($fd); |
|
269
|
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
# handle stdin |
|
271
|
9
|
100
|
|
|
|
100
|
if ($rdrin) { |
|
272
|
2
|
|
|
|
|
19
|
$fd = fileno($rdrin); |
|
273
|
2
|
50
|
|
|
|
17
|
if (fileno(*STDIN) != $fd) { |
|
274
|
2
|
50
|
|
|
|
183
|
open(*STDIN, "<&=$fd") |
|
275
|
|
|
|
|
|
|
or dief("cannot redirect stdin: %s", $!); |
|
276
|
|
|
|
|
|
|
} |
|
277
|
|
|
|
|
|
|
} |
|
278
|
|
|
|
|
|
|
# handle stdout |
|
279
|
9
|
100
|
|
|
|
133
|
if ($wrtout) { |
|
280
|
8
|
|
|
|
|
69
|
$fd = fileno($wrtout); |
|
281
|
8
|
50
|
|
|
|
101
|
if (fileno(*STDOUT) != $fd) { |
|
282
|
8
|
50
|
|
|
|
972
|
open(*STDOUT, ">&=$fd") |
|
283
|
|
|
|
|
|
|
or dief("cannot redirect stdout: %s", $!); |
|
284
|
|
|
|
|
|
|
} |
|
285
|
|
|
|
|
|
|
} |
|
286
|
|
|
|
|
|
|
# handle stderr |
|
287
|
9
|
100
|
100
|
|
|
491
|
if ($wrterr or $merge) { |
|
288
|
6
|
100
|
|
|
|
81
|
$fd = $merge ? fileno(*STDOUT) : fileno($wrterr); |
|
289
|
6
|
50
|
|
|
|
64
|
if (fileno(*STDERR) != $fd) { |
|
290
|
6
|
50
|
|
|
|
280
|
open(*STDERR, ">&=$fd") |
|
291
|
|
|
|
|
|
|
or dief("cannot redirect stderr: %s", $!); |
|
292
|
|
|
|
|
|
|
} |
|
293
|
|
|
|
|
|
|
} |
|
294
|
|
|
|
|
|
|
} |
|
295
|
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
# |
|
297
|
|
|
|
|
|
|
# fork a new process, setup its environment and exec() the command |
|
298
|
|
|
|
|
|
|
# |
|
299
|
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
my %proc_create_options = ( |
|
301
|
|
|
|
|
|
|
command => { optional => 0, type => ARRAYREF }, |
|
302
|
|
|
|
|
|
|
cwd => { optional => 1, type => SCALAR }, |
|
303
|
|
|
|
|
|
|
timeout => { optional => 1, type => SCALAR, regex => $_NumberRegexp }, |
|
304
|
|
|
|
|
|
|
kill => { optional => 1, type => SCALAR, regex => qr/^${ksre}$/ }, |
|
305
|
|
|
|
|
|
|
stdin => { optional => 1, type => SCALAR | SCALARREF }, |
|
306
|
|
|
|
|
|
|
stdout => { optional => 1, type => SCALAR | SCALARREF | CODEREF }, |
|
307
|
|
|
|
|
|
|
stderr => { optional => 1, type => SCALAR | SCALARREF | CODEREF }, |
|
308
|
|
|
|
|
|
|
); |
|
309
|
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
sub proc_create (@) { |
|
311
|
54
|
|
|
54
|
1
|
4119
|
my(%option, %proc, $merge); |
|
312
|
54
|
|
|
|
|
0
|
my($rdrin, $wrtin, $rdrout, $wrtout, $rdrerr, $wrterr); |
|
313
|
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
# |
|
315
|
|
|
|
|
|
|
# preparation |
|
316
|
|
|
|
|
|
|
# |
|
317
|
|
|
|
|
|
|
|
|
318
|
54
|
|
|
|
|
3123
|
%option = validate(@_, \%proc_create_options); |
|
319
|
54
|
|
|
|
|
826
|
$proc{command} = _chk_cmd(@{ $option{command} }); |
|
|
54
|
|
|
|
|
496
|
|
|
320
|
|
|
|
|
|
|
# check the "current working directory" option |
|
321
|
54
|
50
|
|
|
|
252
|
if (defined($option{cwd})) { |
|
322
|
0
|
0
|
|
|
|
0
|
dief("invalid directory: %s", $option{cwd}) unless -d $option{cwd}; |
|
323
|
|
|
|
|
|
|
} |
|
324
|
|
|
|
|
|
|
# prepare I/O |
|
325
|
54
|
|
|
|
|
364
|
($rdrin, $wrtin) = _prepare_stdin(\%proc, $option{stdin}); |
|
326
|
54
|
|
|
|
|
318
|
($rdrout, $wrtout) = _prepare_stdout(\%proc, $option{stdout}); |
|
327
|
54
|
|
|
|
|
292
|
($rdrerr, $wrterr, $merge) = _prepare_stderr(\%proc, $option{stderr}); |
|
328
|
|
|
|
|
|
|
# fork |
|
329
|
54
|
|
|
|
|
55274
|
$proc{pid} = fork(); |
|
330
|
54
|
50
|
|
|
|
1416
|
dief("cannot fork(): %s", $!) unless defined($proc{pid}); |
|
331
|
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
# |
|
333
|
|
|
|
|
|
|
# handle the child |
|
334
|
|
|
|
|
|
|
# |
|
335
|
|
|
|
|
|
|
|
|
336
|
54
|
100
|
|
|
|
430
|
unless ($proc{pid}) { |
|
337
|
|
|
|
|
|
|
# we are about to exec() or die() |
|
338
|
9
|
|
|
|
|
556
|
$Transient = 1; |
|
339
|
|
|
|
|
|
|
# handle the "current working directory" |
|
340
|
9
|
50
|
|
|
|
284
|
dir_change($option{cwd}) if defined($option{cwd}); |
|
341
|
|
|
|
|
|
|
# make sure the STD* file handles are "normal" |
|
342
|
9
|
|
|
|
|
164
|
foreach my $glob (*STDIN, *STDOUT, *STDERR) { |
|
343
|
27
|
50
|
|
|
|
290
|
next unless tied($glob); |
|
344
|
11
|
|
|
11
|
|
131
|
no warnings qw(untie); ## no critic 'ProhibitNoWarnings' |
|
|
11
|
|
|
|
|
43
|
|
|
|
11
|
|
|
|
|
35838
|
|
|
345
|
0
|
|
|
|
|
0
|
untie($glob); |
|
346
|
|
|
|
|
|
|
} |
|
347
|
|
|
|
|
|
|
# handle the pipe ends to close |
|
348
|
9
|
|
|
|
|
51
|
foreach my $fh ($wrtin, $rdrout, $rdrerr) { |
|
349
|
27
|
100
|
|
|
|
290
|
next unless $fh; |
|
350
|
13
|
50
|
|
|
|
400
|
close($fh) or dief("cannot close pipe: %s", $!); |
|
351
|
|
|
|
|
|
|
} |
|
352
|
|
|
|
|
|
|
# redirect I/O |
|
353
|
9
|
|
|
|
|
707
|
_redirect_io($rdrin, $wrtout, $wrterr, $merge); |
|
354
|
|
|
|
|
|
|
# execute the command |
|
355
|
9
|
|
|
|
|
104
|
exec({ $proc{command}[0] } @{ $proc{command} }) |
|
|
9
|
|
|
|
|
0
|
|
|
356
|
9
|
0
|
|
|
|
92
|
or dief("cannot execute %s: %s", $proc{command}[0], $!); |
|
357
|
0
|
|
|
|
|
0
|
exit(-1); |
|
358
|
|
|
|
|
|
|
} |
|
359
|
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
# |
|
361
|
|
|
|
|
|
|
# handle the father |
|
362
|
|
|
|
|
|
|
# |
|
363
|
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
# record the "start" time |
|
365
|
45
|
|
|
|
|
1646
|
$proc{start} = Time::HiRes::time(); |
|
366
|
|
|
|
|
|
|
# record the maximum running time |
|
367
|
45
|
100
|
|
|
|
464
|
if (defined($option{timeout})) { |
|
368
|
6
|
|
|
|
|
342
|
$proc{maxtime} = $proc{start} + $option{timeout}; |
|
369
|
|
|
|
|
|
|
} |
|
370
|
|
|
|
|
|
|
# record the kill specification |
|
371
|
45
|
50
|
|
|
|
173
|
$proc{kill} = $option{kill} if $option{kill}; |
|
372
|
|
|
|
|
|
|
# handle the pipe ends to close |
|
373
|
45
|
|
|
|
|
821
|
foreach my $fh ($rdrin, $wrtout, $wrterr) { |
|
374
|
135
|
100
|
|
|
|
484
|
next unless $fh; |
|
375
|
78
|
50
|
|
|
|
1559
|
close($fh) or dief("cannot close pipe: %s", $!); |
|
376
|
|
|
|
|
|
|
} |
|
377
|
|
|
|
|
|
|
# so far so good |
|
378
|
45
|
|
|
|
|
3455
|
return(\%proc); |
|
379
|
|
|
|
|
|
|
} |
|
380
|
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
# |
|
382
|
|
|
|
|
|
|
# terminate a process |
|
383
|
|
|
|
|
|
|
# |
|
384
|
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
my %proc_terminate_options = ( |
|
386
|
|
|
|
|
|
|
kill => { optional => 1, type => SCALAR, regex => qr/^${ksre}$/ }, |
|
387
|
|
|
|
|
|
|
_iosr => { optional => 1, type => UNDEF|OBJECT }, |
|
388
|
|
|
|
|
|
|
_iosw => { optional => 1, type => UNDEF|OBJECT }, |
|
389
|
|
|
|
|
|
|
); |
|
390
|
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
sub proc_terminate ($@) { |
|
392
|
7
|
|
|
7
|
1
|
907220
|
my($proc, %option, $pid, $sig, $grace, $maxtime); |
|
393
|
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
# setup |
|
395
|
7
|
|
|
|
|
31
|
$proc = shift(@_); |
|
396
|
7
|
50
|
|
|
|
160
|
if (ref($proc) eq "") { |
|
|
|
50
|
|
|
|
|
|
|
397
|
0
|
0
|
|
|
|
0
|
dief("unexpected pid: %s", $proc) unless $proc =~ /^\d+$/; |
|
398
|
0
|
|
|
|
|
0
|
$proc = { pid => $proc }; |
|
399
|
|
|
|
|
|
|
} elsif (ref($proc) eq "HASH") { |
|
400
|
7
|
|
|
|
|
48
|
_chk_proc($proc); |
|
401
|
|
|
|
|
|
|
} else { |
|
402
|
0
|
|
|
|
|
0
|
dief("unexpected process: %s", $proc); |
|
403
|
|
|
|
|
|
|
} |
|
404
|
7
|
100
|
|
|
|
229
|
%option = validate(@_, \%proc_terminate_options) if @_; |
|
405
|
7
|
|
50
|
|
|
162
|
$option{kill} ||= $proc->{kill} || "TERM/1 INT/1 QUIT/1"; |
|
|
|
|
33
|
|
|
|
|
|
406
|
7
|
|
|
|
|
28
|
$pid = $proc->{pid}; |
|
407
|
|
|
|
|
|
|
# gentle kill |
|
408
|
7
|
|
|
|
|
84
|
foreach my $spec (split(/\s+/, $option{kill})) { |
|
409
|
7
|
50
|
|
|
|
2500
|
if ($spec =~ /^([A-Z]+)\/(${nbre})$/) { |
|
410
|
7
|
|
|
|
|
111
|
($sig, $grace) = ($1, $2); |
|
411
|
|
|
|
|
|
|
} else { |
|
412
|
0
|
|
|
|
|
0
|
dief("unexpected kill specification: %s", $spec); |
|
413
|
|
|
|
|
|
|
} |
|
414
|
7
|
50
|
|
|
|
1797
|
unless (kill($sig, $pid)) { |
|
415
|
0
|
0
|
|
|
|
0
|
dief("cannot kill(%s, %d): %s", $sig, $pid, $!) unless $! == ESRCH; |
|
416
|
|
|
|
|
|
|
} |
|
417
|
7
|
|
|
|
|
63
|
$maxtime = Time::HiRes::time() + $grace; |
|
418
|
7
|
|
|
|
|
61
|
while (Time::HiRes::time() < $maxtime) { |
|
419
|
14
|
100
|
|
|
|
130
|
return unless _is_alive($proc, $option{_iosr}, $option{_iosw}); |
|
420
|
7
|
|
|
|
|
71711
|
Time::HiRes::sleep(0.01); |
|
421
|
|
|
|
|
|
|
} |
|
422
|
0
|
0
|
|
|
|
0
|
return unless _is_alive($proc, $option{_iosr}, $option{_iosw}); |
|
423
|
|
|
|
|
|
|
} |
|
424
|
|
|
|
|
|
|
# hard kill |
|
425
|
0
|
|
|
|
|
0
|
$sig = "KILL"; |
|
426
|
0
|
0
|
|
|
|
0
|
unless (kill($sig, $pid)) { |
|
427
|
0
|
0
|
|
|
|
0
|
dief("cannot kill(%s, %d): %s", $sig, $pid, $!) unless $! == ESRCH; |
|
428
|
|
|
|
|
|
|
} |
|
429
|
|
|
|
|
|
|
} |
|
430
|
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
# |
|
432
|
|
|
|
|
|
|
# setup monitoring |
|
433
|
|
|
|
|
|
|
# |
|
434
|
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
sub _monitor_setup ($) { |
|
436
|
44
|
|
|
44
|
|
182
|
my($procs) = @_; |
|
437
|
44
|
|
|
|
|
193
|
my(%process, %map, $iosr, $iosw, $fh); |
|
438
|
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
# store the processes to monitor in a hash |
|
440
|
44
|
|
|
|
|
84
|
foreach my $proc (@{ $procs }) { |
|
|
44
|
|
|
|
|
267
|
|
|
441
|
46
|
|
|
|
|
416
|
_chk_proc($proc); |
|
442
|
46
|
|
|
|
|
269
|
$process{$proc->{pid}} = $proc; |
|
443
|
|
|
|
|
|
|
} |
|
444
|
|
|
|
|
|
|
# record the file handles to monitor |
|
445
|
44
|
|
|
|
|
1279
|
$iosr = IO::Select->new(); |
|
446
|
44
|
|
|
|
|
787
|
$iosw = IO::Select->new(); |
|
447
|
44
|
|
|
|
|
555
|
foreach my $proc (values(%process)) { |
|
448
|
46
|
|
|
|
|
112
|
foreach my $what (qw(in out err)) { |
|
449
|
138
|
|
|
|
|
449
|
$fh = $proc->{"fh$what"}; |
|
450
|
138
|
100
|
|
|
|
429
|
next unless $fh; |
|
451
|
65
|
100
|
|
|
|
186
|
if ($what eq "in") { |
|
452
|
4
|
|
|
|
|
56
|
$iosw->add($fh); |
|
453
|
|
|
|
|
|
|
} else { |
|
454
|
61
|
|
|
|
|
370
|
$iosr->add($fh); |
|
455
|
|
|
|
|
|
|
} |
|
456
|
65
|
|
|
|
|
5237
|
$map{"$fh"} = [ $proc->{pid}, $what ]; |
|
457
|
|
|
|
|
|
|
} |
|
458
|
|
|
|
|
|
|
} |
|
459
|
44
|
100
|
|
|
|
397
|
$iosr = undef unless $iosr->count(); |
|
460
|
44
|
100
|
|
|
|
416
|
$iosw = undef unless $iosw->count(); |
|
461
|
44
|
|
|
|
|
802
|
return(\%process, \%map, $iosr, $iosw); |
|
462
|
|
|
|
|
|
|
} |
|
463
|
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
# |
|
465
|
|
|
|
|
|
|
# monitor I/O |
|
466
|
|
|
|
|
|
|
# |
|
467
|
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
sub _monitor_reading ($$$$$) { |
|
469
|
1431
|
|
|
1431
|
|
9901
|
my($process, $map, $iosr, $bufsize, $timeout) = @_; |
|
470
|
1431
|
|
|
|
|
4882
|
my($buf, $done, $proc, $what); |
|
471
|
|
|
|
|
|
|
|
|
472
|
1431
|
|
|
|
|
8946
|
foreach my $fh ($iosr->can_read($timeout)) { |
|
473
|
57
|
|
|
|
|
21186
|
$timeout = 0; |
|
474
|
57
|
|
|
|
|
191
|
$buf = ""; |
|
475
|
57
|
|
|
|
|
600
|
$done = sysread($fh, $buf, $bufsize); |
|
476
|
57
|
50
|
|
|
|
214
|
dief("cannot sysread(): %s", $!) unless defined($done); |
|
477
|
57
|
|
|
|
|
325
|
$proc = $process->{$map->{"$fh"}[0]}; |
|
478
|
57
|
|
|
|
|
328
|
$what = $map->{"$fh"}[1]; |
|
479
|
57
|
|
|
|
|
371
|
$proc->{"cb$what"}($proc, $buf); |
|
480
|
57
|
100
|
|
|
|
213
|
unless ($done) { |
|
481
|
18
|
|
|
|
|
90
|
_close($proc, $fh, $what, $iosr); |
|
482
|
|
|
|
|
|
|
} |
|
483
|
|
|
|
|
|
|
} |
|
484
|
1431
|
|
|
|
|
14626283
|
return($timeout); |
|
485
|
|
|
|
|
|
|
} |
|
486
|
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
sub _monitor_writing ($$$$$) { |
|
488
|
8
|
|
|
8
|
|
88
|
my($process, $map, $iosw, $bufsize, $timeout) = @_; |
|
489
|
8
|
|
|
|
|
60
|
my($buf, $done, $proc, $what); |
|
490
|
|
|
|
|
|
|
|
|
491
|
8
|
|
|
|
|
140
|
foreach my $fh ($iosw->can_write($timeout)) { |
|
492
|
8
|
|
|
|
|
1100
|
$timeout = 0; |
|
493
|
8
|
|
|
|
|
80
|
$proc = $process->{$map->{"$fh"}[0]}; |
|
494
|
8
|
|
|
|
|
84
|
$what = $map->{"$fh"}[1]; |
|
495
|
8
|
|
|
|
|
100
|
$buf = $proc->{"buf$what"}; |
|
496
|
8
|
100
|
|
|
|
48
|
if (length($buf)) { |
|
497
|
4
|
|
|
|
|
144
|
$done = syswrite($fh, $buf, length($buf)); |
|
498
|
4
|
50
|
|
|
|
72
|
dief("cannot syswrite(): %s", $!) unless defined($done); |
|
499
|
4
|
|
|
|
|
52
|
substr($proc->{"buf$what"}, 0, $done, ""); |
|
500
|
|
|
|
|
|
|
} else { |
|
501
|
4
|
|
|
|
|
52
|
_close($proc, $fh, $what, $iosw); |
|
502
|
|
|
|
|
|
|
} |
|
503
|
|
|
|
|
|
|
} |
|
504
|
8
|
|
|
|
|
48
|
return($timeout); |
|
505
|
|
|
|
|
|
|
} |
|
506
|
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
# |
|
508
|
|
|
|
|
|
|
# monitor termination (death and timeout) |
|
509
|
|
|
|
|
|
|
# |
|
510
|
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
sub _monitor_termination ($$$$) { |
|
512
|
1984
|
|
|
1984
|
|
10571
|
my($process, $iosr, $iosw, $timeout) = @_; |
|
513
|
1984
|
|
|
|
|
5219
|
my($now); |
|
514
|
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
# check if some processes finished |
|
516
|
1984
|
|
|
|
|
6973
|
foreach my $proc (grep(!defined($_->{status}), values(%{ $process }))) { |
|
|
1984
|
|
|
|
|
20947
|
|
|
517
|
2024
|
100
|
|
|
|
11790
|
next if _is_alive($proc, $iosr, $iosw); |
|
518
|
37
|
|
|
|
|
137
|
$timeout = 0; |
|
519
|
|
|
|
|
|
|
} |
|
520
|
|
|
|
|
|
|
# check if some processes timed out |
|
521
|
1984
|
|
|
|
|
17481
|
$now = Time::HiRes::time(); |
|
522
|
1984
|
|
|
|
|
8025
|
foreach my $proc (grep($_->{maxtime}, values(%{ $process }))) { |
|
|
1984
|
|
|
|
|
13847
|
|
|
523
|
264
|
100
|
|
|
|
1566
|
next unless $now > $proc->{maxtime}; |
|
524
|
6
|
|
|
|
|
30
|
$timeout = 0; |
|
525
|
6
|
|
|
|
|
48
|
delete($proc->{maxtime}); |
|
526
|
6
|
|
|
|
|
30
|
$proc->{timeout} = $now; |
|
527
|
6
|
|
|
|
|
438
|
proc_terminate($proc, _iosr => $iosr, _iosw => $iosw); |
|
528
|
|
|
|
|
|
|
} |
|
529
|
1984
|
|
|
|
|
8018
|
return($timeout); |
|
530
|
|
|
|
|
|
|
} |
|
531
|
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
# |
|
533
|
|
|
|
|
|
|
# monitor one or more processes |
|
534
|
|
|
|
|
|
|
# |
|
535
|
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
my %proc_monitor_options = ( |
|
537
|
|
|
|
|
|
|
timeout => { optional => 1, type => SCALAR, regex => $_NumberRegexp }, |
|
538
|
|
|
|
|
|
|
bufsize => { optional => 1, type => SCALAR, regex => $_IntegerRegexp }, |
|
539
|
|
|
|
|
|
|
deaths => { optional => 1, type => SCALAR, regex => $_IntegerRegexp }, |
|
540
|
|
|
|
|
|
|
); |
|
541
|
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
sub proc_monitor ($@) { |
|
543
|
44
|
|
|
44
|
1
|
7840
|
my($procs, %option, $process, $map, $iosr, $iosw); |
|
544
|
44
|
|
|
|
|
0
|
my($maxtime, $timeout, $zombies); |
|
545
|
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
# |
|
547
|
|
|
|
|
|
|
# preparation |
|
548
|
|
|
|
|
|
|
# |
|
549
|
|
|
|
|
|
|
|
|
550
|
44
|
|
|
|
|
131
|
$procs = shift(@_); |
|
551
|
44
|
100
|
|
|
|
357
|
if (ref($procs) eq "HASH") { |
|
|
|
50
|
|
|
|
|
|
|
552
|
42
|
|
|
|
|
273
|
$procs = [ $procs ]; |
|
553
|
|
|
|
|
|
|
} elsif (ref($procs) ne "ARRAY") { |
|
554
|
0
|
|
|
|
|
0
|
dief("unexpected processes: %s", $procs); |
|
555
|
|
|
|
|
|
|
} |
|
556
|
44
|
100
|
|
|
|
347
|
%option = validate(@_, \%proc_monitor_options) if @_; |
|
557
|
44
|
|
50
|
|
|
973
|
$option{bufsize} ||= 8192; |
|
558
|
44
|
|
|
|
|
289
|
($process, $map, $iosr, $iosw) = _monitor_setup($procs); |
|
559
|
|
|
|
|
|
|
# count the number of processes which are already dead |
|
560
|
44
|
|
|
|
|
896
|
$zombies = grep(defined($_->{status}), values(%{ $process })); |
|
|
44
|
|
|
|
|
583
|
|
|
561
|
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
# |
|
563
|
|
|
|
|
|
|
# work |
|
564
|
|
|
|
|
|
|
# |
|
565
|
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
$maxtime = Time::HiRes::time() + $option{timeout} |
|
567
|
44
|
100
|
|
|
|
267
|
if defined($option{timeout}); |
|
568
|
44
|
|
66
|
|
|
295
|
while ($iosr or $iosw |
|
|
|
|
100
|
|
|
|
|
|
569
|
596
|
|
|
|
|
8706
|
or grep(!defined($_->{status}), values(%{ $process }))) { |
|
570
|
1984
|
|
|
|
|
7156
|
$timeout = 0.01; |
|
571
|
|
|
|
|
|
|
# read what can be read |
|
572
|
|
|
|
|
|
|
$timeout = _monitor_reading($process, $map, $iosr, $option{bufsize}, |
|
573
|
1984
|
100
|
|
|
|
15989
|
$timeout) if $iosr; |
|
574
|
|
|
|
|
|
|
# write what can be written |
|
575
|
|
|
|
|
|
|
$timeout = _monitor_writing($process, $map, $iosw, $option{bufsize}, |
|
576
|
1984
|
100
|
|
|
|
13610
|
$timeout) if $iosw; |
|
577
|
|
|
|
|
|
|
# check if some processes finished or timed out |
|
578
|
1984
|
|
|
|
|
12773
|
$timeout = _monitor_termination($process, $iosr, $iosw, $timeout); |
|
579
|
|
|
|
|
|
|
# or if we timed out |
|
580
|
1984
|
50
|
33
|
|
|
11114
|
last if $maxtime and Time::HiRes::time() > $maxtime; |
|
581
|
|
|
|
|
|
|
# or if enough processes died |
|
582
|
|
|
|
|
|
|
last if $option{deaths} |
|
583
|
40
|
|
|
|
|
487
|
and grep(defined($_->{status}), values(%{ $process })) |
|
584
|
1984
|
100
|
100
|
|
|
10622
|
>= $zombies + $option{deaths}; |
|
585
|
|
|
|
|
|
|
# sleep a bit if needed (= if we have not worked before in the loop) |
|
586
|
1983
|
100
|
|
|
|
19977863
|
Time::HiRes::sleep($timeout) if $timeout; |
|
587
|
|
|
|
|
|
|
# update the IO::Select objects |
|
588
|
1983
|
100
|
100
|
|
|
45211
|
$iosr = undef unless $iosr and $iosr->count(); |
|
589
|
1983
|
100
|
100
|
|
|
45421
|
$iosw = undef unless $iosw and $iosw->count(); |
|
590
|
|
|
|
|
|
|
} |
|
591
|
|
|
|
|
|
|
} |
|
592
|
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
# |
|
594
|
|
|
|
|
|
|
# run the given command |
|
595
|
|
|
|
|
|
|
# |
|
596
|
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
sub proc_run (@) { |
|
598
|
49
|
|
|
49
|
1
|
48238
|
my(@args) = @_; |
|
599
|
49
|
|
|
|
|
119
|
my($proc); |
|
600
|
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
# create the process |
|
602
|
49
|
|
|
|
|
234
|
$proc = proc_create(@args); |
|
603
|
|
|
|
|
|
|
# monitor it until it ends |
|
604
|
42
|
|
|
|
|
710
|
proc_monitor($proc); |
|
605
|
|
|
|
|
|
|
# return what is expected |
|
606
|
42
|
100
|
|
|
|
260
|
return(%{ $proc }) if wantarray(); |
|
|
6
|
|
|
|
|
144
|
|
|
607
|
36
|
|
|
|
|
814
|
return($proc->{status}); |
|
608
|
|
|
|
|
|
|
} |
|
609
|
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
# |
|
611
|
|
|
|
|
|
|
# execute the given command, check its status and return its output |
|
612
|
|
|
|
|
|
|
# |
|
613
|
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
sub proc_output (@) { |
|
615
|
4
|
|
|
4
|
1
|
10580
|
my(@command) = @_; |
|
616
|
4
|
|
|
|
|
12
|
my($output, $status); |
|
617
|
|
|
|
|
|
|
|
|
618
|
4
|
|
|
|
|
12
|
$output = ""; |
|
619
|
4
|
|
|
|
|
20
|
$status = proc_run(command => \@command, stdout => \$output); |
|
620
|
3
|
50
|
|
|
|
42
|
dief("%s failed: %d", $command[0], $status) if $status; |
|
621
|
3
|
|
|
|
|
45
|
return($output); |
|
622
|
|
|
|
|
|
|
} |
|
623
|
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
# |
|
625
|
|
|
|
|
|
|
# detach ourself and go in the background |
|
626
|
|
|
|
|
|
|
# |
|
627
|
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
my %proc_detach_options = ( |
|
629
|
|
|
|
|
|
|
callback => { optional => 1, type => CODEREF }, |
|
630
|
|
|
|
|
|
|
); |
|
631
|
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
sub proc_detach (@) { |
|
633
|
0
|
|
|
0
|
1
|
0
|
my(%option, $pid, $sid); |
|
634
|
|
|
|
|
|
|
|
|
635
|
0
|
0
|
|
|
|
0
|
%option = validate(@_, \%proc_detach_options) if @_; |
|
636
|
|
|
|
|
|
|
# change directory to a known place |
|
637
|
0
|
|
|
|
|
0
|
dir_change("/"); |
|
638
|
|
|
|
|
|
|
# fork and let dad die |
|
639
|
0
|
|
|
|
|
0
|
$pid = fork(); |
|
640
|
0
|
0
|
|
|
|
0
|
dief("cannot fork(): %s", $!) unless defined($pid); |
|
641
|
0
|
0
|
|
|
|
0
|
if ($pid) { |
|
642
|
|
|
|
|
|
|
# we are about to exit() |
|
643
|
0
|
|
|
|
|
0
|
$Transient = 1; |
|
644
|
0
|
0
|
|
|
|
0
|
$option{callback}->($pid) if $option{callback}; |
|
645
|
0
|
|
|
|
|
0
|
exit(0); |
|
646
|
|
|
|
|
|
|
} |
|
647
|
|
|
|
|
|
|
# create a new session |
|
648
|
0
|
|
|
|
|
0
|
$sid = setsid(); |
|
649
|
0
|
0
|
|
|
|
0
|
dief("cannot setsid(): %s", $!) if $sid == -1; |
|
650
|
|
|
|
|
|
|
# detach std* from anything but plain files (i.e. allow: cmd --detach > log) |
|
651
|
0
|
0
|
|
|
|
0
|
unless (-f STDIN) { |
|
652
|
0
|
0
|
|
|
|
0
|
open(STDIN, "<", "/dev/null") |
|
653
|
|
|
|
|
|
|
or dief("cannot re-open stdin: %s", $!); |
|
654
|
|
|
|
|
|
|
} |
|
655
|
0
|
0
|
|
|
|
0
|
unless (-f STDOUT) { |
|
656
|
0
|
0
|
|
|
|
0
|
open(STDOUT, ">", "/dev/null") |
|
657
|
|
|
|
|
|
|
or dief("cannot re-open stdout: %s", $!); |
|
658
|
|
|
|
|
|
|
} |
|
659
|
0
|
0
|
|
|
|
0
|
unless (-f STDERR) { |
|
660
|
0
|
0
|
|
|
|
0
|
open(STDERR, ">", "/dev/null") |
|
661
|
|
|
|
|
|
|
or dief("cannot re-open stderr: %s", $!); |
|
662
|
|
|
|
|
|
|
} |
|
663
|
|
|
|
|
|
|
} |
|
664
|
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
# |
|
666
|
|
|
|
|
|
|
# export control |
|
667
|
|
|
|
|
|
|
# |
|
668
|
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
sub import : method { |
|
670
|
11
|
|
|
11
|
|
193
|
my($pkg, %exported); |
|
671
|
|
|
|
|
|
|
|
|
672
|
11
|
|
|
|
|
43
|
$pkg = shift(@_); |
|
673
|
11
|
|
|
|
|
154
|
grep($exported{$_}++, |
|
674
|
|
|
|
|
|
|
map("proc_$_", qw(create detach monitor output terminate run))); |
|
675
|
11
|
|
|
|
|
99
|
export_control(scalar(caller()), $pkg, \%exported, @_); |
|
676
|
|
|
|
|
|
|
} |
|
677
|
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
1; |
|
679
|
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
__DATA__ |