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__ |