Filename | /usr/share/perl/5.36/IPC/Cmd.pm |
Statements | Executed 173 statements in 5.64ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 27.8ms | 59.5ms | can_run | IPC::Cmd::
1 | 1 | 1 | 4.95ms | 10.8ms | BEGIN@5 | IPC::Cmd::
1 | 1 | 1 | 1.29ms | 9.34ms | BEGIN@61 | IPC::Cmd::
1 | 1 | 1 | 994µs | 2.20ms | BEGIN@59 | IPC::Cmd::
1 | 1 | 1 | 745µs | 819µs | BEGIN@60 | IPC::Cmd::
27 | 1 | 1 | 52µs | 52µs | CORE:ftdir (opcode) | IPC::Cmd::
1 | 1 | 1 | 8µs | 8µs | BEGIN@1873 | IPC::Cmd::
1 | 1 | 1 | 7µs | 31µs | BEGIN@1507 | IPC::Cmd::
1 | 1 | 1 | 7µs | 9µs | BEGIN@3 | IPC::Cmd::
1 | 1 | 1 | 7µs | 8µs | BEGIN@58 | IPC::Cmd::
1 | 1 | 1 | 7µs | 28µs | BEGIN@12 | IPC::Cmd::
1 | 1 | 1 | 6µs | 9µs | BEGIN@357 | IPC::Cmd::
1 | 1 | 1 | 5µs | 35µs | BEGIN@7 | IPC::Cmd::
1 | 1 | 1 | 5µs | 110µs | BEGIN@62 | IPC::Cmd::
1 | 1 | 1 | 5µs | 20µs | BEGIN@1874 | IPC::Cmd::
1 | 1 | 1 | 3µs | 16µs | BEGIN@9 | IPC::Cmd::
1 | 1 | 1 | 3µs | 16µs | BEGIN@10 | IPC::Cmd::
1 | 1 | 1 | 3µs | 53µs | BEGIN@16 | IPC::Cmd::
1 | 1 | 1 | 3µs | 18µs | BEGIN@8 | IPC::Cmd::
1 | 1 | 1 | 3µs | 16µs | BEGIN@13 | IPC::Cmd::
1 | 1 | 1 | 2µs | 15µs | BEGIN@11 | IPC::Cmd::
1 | 1 | 1 | 1µs | 1µs | BEGIN@15 | IPC::Cmd::
2 | 2 | 1 | 700ns | 700ns | __ANON__ (xsub) | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | __ANON__[:1276] | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | __ANON__[:1317] | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | __ANON__[:1327] | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | __ANON__[:1346] | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | __ANON__[:1428] | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | __ANON__[:1442] | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | __ANON__[:361] | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | __ANON__[:459] | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | __ANON__[:559] | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | __ANON__[:597] | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | __ANON__[:944] | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | __ANON__[:947] | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | __dup_fds | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | __fix_cmd_whitespace_and_special_chars | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | __reopen_fds | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | _debug | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | _ipc_run | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | _open3_run | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | _open3_run_win32 | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | _pp_child_error | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | _quote_args_vms | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | _split_like_shell_win32 | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | _system_run | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | adjust_monotonic_start_time | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | can_capture_buffer | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | can_use_ipc_open3 | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | can_use_ipc_run | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | can_use_run_forked | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | get_monotonic_time | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | install_layered_signal | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | kill_gently | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | open3_run | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | run | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | run_forked | IPC::Cmd::
0 | 0 | 0 | 0s | 0s | uninstall_signals | IPC::Cmd::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package IPC::Cmd; | ||||
2 | |||||
3 | 2 | 27µs | 2 | 10µs | # spent 9µs (7+1) within IPC::Cmd::BEGIN@3 which was called:
# once (7µs+1µs) by main::BEGIN@30 at line 3 # spent 9µs making 1 call to IPC::Cmd::BEGIN@3
# spent 1µs making 1 call to strict::import |
4 | |||||
5 | # spent 10.8ms (4.95+5.82) within IPC::Cmd::BEGIN@5 which was called:
# once (4.95ms+5.82ms) by main::BEGIN@30 at line 55 | ||||
6 | |||||
7 | 2 | 23µs | 2 | 64µs | # spent 35µs (5+29) within IPC::Cmd::BEGIN@7 which was called:
# once (5µs+29µs) by main::BEGIN@30 at line 7 # spent 35µs making 1 call to IPC::Cmd::BEGIN@7
# spent 29µs making 1 call to constant::import |
8 | 2 | 18µs | 2 | 33µs | # spent 18µs (3+15) within IPC::Cmd::BEGIN@8 which was called:
# once (3µs+15µs) by main::BEGIN@30 at line 8 # spent 18µs making 1 call to IPC::Cmd::BEGIN@8
# spent 15µs making 1 call to constant::import |
9 | 2 | 23µs | 2 | 28µs | # spent 16µs (3+13) within IPC::Cmd::BEGIN@9 which was called:
# once (3µs+13µs) by main::BEGIN@30 at line 9 # spent 16µs making 1 call to IPC::Cmd::BEGIN@9
# spent 13µs making 1 call to constant::import |
10 | 2 | 16µs | 2 | 30µs | # spent 16µs (3+13) within IPC::Cmd::BEGIN@10 which was called:
# once (3µs+13µs) by main::BEGIN@30 at line 10 # spent 16µs making 1 call to IPC::Cmd::BEGIN@10
# spent 13µs making 1 call to constant::import |
11 | 2 | 16µs | 2 | 28µs | # spent 15µs (2+13) within IPC::Cmd::BEGIN@11 which was called:
# once (2µs+13µs) by main::BEGIN@30 at line 11 # spent 15µs making 1 call to IPC::Cmd::BEGIN@11
# spent 13µs making 1 call to constant::import |
12 | 2 | 20µs | 2 | 48µs | # spent 28µs (7+21) within IPC::Cmd::BEGIN@12 which was called:
# once (7µs+21µs) by main::BEGIN@30 at line 12 # spent 28µs making 1 call to IPC::Cmd::BEGIN@12
# spent 21µs making 1 call to constant::import |
13 | 2 | 12µs | 2 | 30µs | # spent 16µs (3+14) within IPC::Cmd::BEGIN@13 which was called:
# once (3µs+14µs) by main::BEGIN@30 at line 13 # spent 16µs making 1 call to IPC::Cmd::BEGIN@13
# spent 14µs making 1 call to constant::import |
14 | |||||
15 | 2 | 24µs | 1 | 1µs | # spent 1µs within IPC::Cmd::BEGIN@15 which was called:
# once (1µs+0s) by main::BEGIN@30 at line 15 # spent 1µs making 1 call to IPC::Cmd::BEGIN@15 |
16 | 1 | 2µs | 1 | 50µs | # spent 53µs (3+50) within IPC::Cmd::BEGIN@16 which was called:
# once (3µs+50µs) by main::BEGIN@30 at line 20 # spent 50µs making 1 call to vars::import |
17 | $USE_IPC_RUN $USE_IPC_OPEN3 $CAN_USE_RUN_FORKED $WARN | ||||
18 | $INSTANCES $ALLOW_NULL_ARGS | ||||
19 | $HAVE_MONOTONIC | ||||
20 | 1 | 123µs | 1 | 53µs | ]; # spent 53µs making 1 call to IPC::Cmd::BEGIN@16 |
21 | |||||
22 | 1 | 200ns | $VERSION = '1.04'; | ||
23 | 1 | 200ns | $VERBOSE = 0; | ||
24 | 1 | 0s | $DEBUG = 0; | ||
25 | 1 | 100ns | $WARN = 1; | ||
26 | 1 | 0s | $USE_IPC_RUN = IS_WIN32 && !IS_WIN98; | ||
27 | 1 | 200ns | $USE_IPC_OPEN3 = not IS_VMS; | ||
28 | 1 | 0s | $ALLOW_NULL_ARGS = 0; | ||
29 | |||||
30 | 1 | 100ns | $CAN_USE_RUN_FORKED = 0; | ||
31 | 1 | 200ns | eval { | ||
32 | 2 | 2µs | 1 | 4.66ms | require POSIX; POSIX->import(); # spent 4.66ms making 1 call to POSIX::import |
33 | 2 | 92µs | 1 | 13µs | require IPC::Open3; IPC::Open3->import(); # spent 13µs making 1 call to Exporter::import |
34 | 2 | 50µs | 1 | 7µs | require IO::Select; IO::Select->import(); # spent 7µs making 1 call to Exporter::import |
35 | 2 | 1µs | 1 | 4µs | require IO::Handle; IO::Handle->import(); # spent 4µs making 1 call to Exporter::import |
36 | 2 | 73µs | 1 | 198µs | require FileHandle; FileHandle->import(); # spent 198µs making 1 call to FileHandle::import |
37 | 1 | 96µs | require Socket; | ||
38 | 2 | 3µs | 1 | 44µs | require Time::HiRes; Time::HiRes->import(); # spent 44µs making 1 call to Time::HiRes::import |
39 | 1 | 500ns | require Win32 if IS_WIN32; | ||
40 | }; | ||||
41 | 1 | 700ns | $CAN_USE_RUN_FORKED = $@ || !IS_VMS && !IS_WIN32; | ||
42 | |||||
43 | 1 | 300ns | eval { | ||
44 | 1 | 7µs | 2 | 13µs | my $wait_start_time = Time::HiRes::clock_gettime(&Time::HiRes::CLOCK_MONOTONIC); # spent 10µs making 1 call to Time::HiRes::AUTOLOAD
# spent 2µs making 1 call to Time::HiRes::clock_gettime |
45 | }; | ||||
46 | 1 | 300ns | if ($@) { | ||
47 | $HAVE_MONOTONIC = 0; | ||||
48 | } | ||||
49 | else { | ||||
50 | 1 | 200ns | $HAVE_MONOTONIC = 1; | ||
51 | } | ||||
52 | |||||
53 | 1 | 5µs | @ISA = qw[Exporter]; | ||
54 | 1 | 3µs | @EXPORT_OK = qw[can_run run run_forked QUOTE]; | ||
55 | 1 | 39µs | 1 | 10.8ms | } # spent 10.8ms making 1 call to IPC::Cmd::BEGIN@5 |
56 | |||||
57 | 1 | 600ns | require Carp; | ||
58 | 2 | 21µs | 2 | 8µs | # spent 8µs (7+300ns) within IPC::Cmd::BEGIN@58 which was called:
# once (7µs+300ns) by main::BEGIN@30 at line 58 # spent 8µs making 1 call to IPC::Cmd::BEGIN@58
# spent 300ns making 1 call to IPC::Cmd::__ANON__ |
59 | 2 | 99µs | 2 | 2.22ms | # spent 2.20ms (994µs+1.20) within IPC::Cmd::BEGIN@59 which was called:
# once (994µs+1.20ms) by main::BEGIN@30 at line 59 # spent 2.20ms making 1 call to IPC::Cmd::BEGIN@59
# spent 20µs making 1 call to Exporter::import |
60 | 2 | 91µs | 1 | 819µs | # spent 819µs (745+74) within IPC::Cmd::BEGIN@60 which was called:
# once (745µs+74µs) by main::BEGIN@30 at line 60 # spent 819µs making 1 call to IPC::Cmd::BEGIN@60 |
61 | 2 | 107µs | 2 | 9.36ms | # spent 9.34ms (1.29+8.05) within IPC::Cmd::BEGIN@61 which was called:
# once (1.29ms+8.05ms) by main::BEGIN@30 at line 61 # spent 9.34ms making 1 call to IPC::Cmd::BEGIN@61
# spent 21µs making 1 call to Exporter::import |
62 | 2 | 306µs | 2 | 214µs | # spent 110µs (5+105) within IPC::Cmd::BEGIN@62 which was called:
# once (5µs+105µs) by main::BEGIN@30 at line 62 # spent 110µs making 1 call to IPC::Cmd::BEGIN@62
# spent 105µs making 1 call to Locale::Maketext::Simple::import |
63 | |||||
64 | 1 | 300ns | local $Module::Load::Conditional::FORCE_SAFE_INC = 1; | ||
65 | |||||
66 | =pod | ||||
67 | |||||
68 | =head1 NAME | ||||
69 | |||||
70 | IPC::Cmd - finding and running system commands made easy | ||||
71 | |||||
72 | =head1 SYNOPSIS | ||||
73 | |||||
74 | use IPC::Cmd qw[can_run run run_forked]; | ||||
75 | |||||
76 | my $full_path = can_run('wget') or warn 'wget is not installed!'; | ||||
77 | |||||
78 | ### commands can be arrayrefs or strings ### | ||||
79 | my $cmd = "$full_path -b theregister.co.uk"; | ||||
80 | my $cmd = [$full_path, '-b', 'theregister.co.uk']; | ||||
81 | |||||
82 | ### in scalar context ### | ||||
83 | my $buffer; | ||||
84 | if( scalar run( command => $cmd, | ||||
85 | verbose => 0, | ||||
86 | buffer => \$buffer, | ||||
87 | timeout => 20 ) | ||||
88 | ) { | ||||
89 | print "fetched webpage successfully: $buffer\n"; | ||||
90 | } | ||||
91 | |||||
92 | |||||
93 | ### in list context ### | ||||
94 | my( $success, $error_message, $full_buf, $stdout_buf, $stderr_buf ) = | ||||
95 | run( command => $cmd, verbose => 0 ); | ||||
96 | |||||
97 | if( $success ) { | ||||
98 | print "this is what the command printed:\n"; | ||||
99 | print join "", @$full_buf; | ||||
100 | } | ||||
101 | |||||
102 | ### run_forked example ### | ||||
103 | my $result = run_forked("$full_path -q -O - theregister.co.uk", {'timeout' => 20}); | ||||
104 | if ($result->{'exit_code'} eq 0 && !$result->{'timeout'}) { | ||||
105 | print "this is what wget returned:\n"; | ||||
106 | print $result->{'stdout'}; | ||||
107 | } | ||||
108 | |||||
109 | ### check for features | ||||
110 | print "IPC::Open3 available: " . IPC::Cmd->can_use_ipc_open3; | ||||
111 | print "IPC::Run available: " . IPC::Cmd->can_use_ipc_run; | ||||
112 | print "Can capture buffer: " . IPC::Cmd->can_capture_buffer; | ||||
113 | |||||
114 | ### don't have IPC::Cmd be verbose, ie don't print to stdout or | ||||
115 | ### stderr when running commands -- default is '0' | ||||
116 | $IPC::Cmd::VERBOSE = 0; | ||||
117 | |||||
118 | |||||
119 | =head1 DESCRIPTION | ||||
120 | |||||
121 | IPC::Cmd allows you to run commands platform independently, | ||||
122 | interactively if desired, but have them still work. | ||||
123 | |||||
124 | The C<can_run> function can tell you if a certain binary is installed | ||||
125 | and if so where, whereas the C<run> function can actually execute any | ||||
126 | of the commands you give it and give you a clear return value, as well | ||||
127 | as adhere to your verbosity settings. | ||||
128 | |||||
129 | =head1 CLASS METHODS | ||||
130 | |||||
131 | =head2 $ipc_run_version = IPC::Cmd->can_use_ipc_run( [VERBOSE] ) | ||||
132 | |||||
133 | Utility function that tells you if C<IPC::Run> is available. | ||||
134 | If the C<verbose> flag is passed, it will print diagnostic messages | ||||
135 | if L<IPC::Run> can not be found or loaded. | ||||
136 | |||||
137 | =cut | ||||
138 | |||||
139 | |||||
140 | sub can_use_ipc_run { | ||||
141 | my $self = shift; | ||||
142 | my $verbose = shift || 0; | ||||
143 | |||||
144 | ### IPC::Run doesn't run on win98 | ||||
145 | return if IS_WIN98; | ||||
146 | |||||
147 | ### if we don't have ipc::run, we obviously can't use it. | ||||
148 | return unless can_load( | ||||
149 | modules => { 'IPC::Run' => '0.55' }, | ||||
150 | verbose => ($WARN && $verbose), | ||||
151 | ); | ||||
152 | |||||
153 | ### otherwise, we're good to go | ||||
154 | return $IPC::Run::VERSION; | ||||
155 | } | ||||
156 | |||||
157 | =head2 $ipc_open3_version = IPC::Cmd->can_use_ipc_open3( [VERBOSE] ) | ||||
158 | |||||
159 | Utility function that tells you if C<IPC::Open3> is available. | ||||
160 | If the verbose flag is passed, it will print diagnostic messages | ||||
161 | if C<IPC::Open3> can not be found or loaded. | ||||
162 | |||||
163 | =cut | ||||
164 | |||||
165 | |||||
166 | sub can_use_ipc_open3 { | ||||
167 | my $self = shift; | ||||
168 | my $verbose = shift || 0; | ||||
169 | |||||
170 | ### IPC::Open3 is not working on VMS because of a lack of fork. | ||||
171 | return if IS_VMS; | ||||
172 | |||||
173 | ### IPC::Open3 works on every non-VMS platform, but it can't | ||||
174 | ### capture buffers on win32 :( | ||||
175 | return unless can_load( | ||||
176 | modules => { map {$_ => '0.0'} qw|IPC::Open3 IO::Select Symbol| }, | ||||
177 | verbose => ($WARN && $verbose), | ||||
178 | ); | ||||
179 | |||||
180 | return $IPC::Open3::VERSION; | ||||
181 | } | ||||
182 | |||||
183 | =head2 $bool = IPC::Cmd->can_capture_buffer | ||||
184 | |||||
185 | Utility function that tells you if C<IPC::Cmd> is capable of | ||||
186 | capturing buffers in it's current configuration. | ||||
187 | |||||
188 | =cut | ||||
189 | |||||
190 | sub can_capture_buffer { | ||||
191 | my $self = shift; | ||||
192 | |||||
193 | return 1 if $USE_IPC_RUN && $self->can_use_ipc_run; | ||||
194 | return 1 if $USE_IPC_OPEN3 && $self->can_use_ipc_open3; | ||||
195 | return; | ||||
196 | } | ||||
197 | |||||
198 | =head2 $bool = IPC::Cmd->can_use_run_forked | ||||
199 | |||||
200 | Utility function that tells you if C<IPC::Cmd> is capable of | ||||
201 | providing C<run_forked> on the current platform. | ||||
202 | |||||
203 | =head1 FUNCTIONS | ||||
204 | |||||
205 | =head2 $path = can_run( PROGRAM ); | ||||
206 | |||||
207 | C<can_run> takes only one argument: the name of a binary you wish | ||||
208 | to locate. C<can_run> works much like the unix binary C<which> or the bash | ||||
209 | command C<type>, which scans through your path, looking for the requested | ||||
210 | binary. | ||||
211 | |||||
212 | Unlike C<which> and C<type>, this function is platform independent and | ||||
213 | will also work on, for example, Win32. | ||||
214 | |||||
215 | If called in a scalar context it will return the full path to the binary | ||||
216 | you asked for if it was found, or C<undef> if it was not. | ||||
217 | |||||
218 | If called in a list context and the global variable C<$INSTANCES> is a true | ||||
219 | value, it will return a list of the full paths to instances | ||||
220 | of the binary where found in C<PATH>, or an empty list if it was not found. | ||||
221 | |||||
222 | =cut | ||||
223 | |||||
224 | # spent 59.5ms (27.8+31.7) within IPC::Cmd::can_run which was called:
# once (27.8ms+31.7ms) by main::BEGIN@51 at line 29 of /home/hejohns/documentsNoSync/22f/490/gradescope-utils/lib/Gradescope/Color.pm | ||||
225 | 1 | 300ns | my $command = shift; | ||
226 | |||||
227 | # a lot of VMS executables have a symbol defined | ||||
228 | # check those first | ||||
229 | 1 | 900ns | if ( $^O eq 'VMS' ) { | ||
230 | require VMS::DCLsym; | ||||
231 | my $syms = VMS::DCLsym->new; | ||||
232 | return $command if scalar $syms->getsym( uc $command ); | ||||
233 | } | ||||
234 | |||||
235 | 1 | 400ns | require File::Spec; | ||
236 | 1 | 98µs | require ExtUtils::MakeMaker; | ||
237 | |||||
238 | 1 | 300ns | my @possibles; | ||
239 | |||||
240 | 1 | 3µs | 1 | 6µs | if( File::Spec->file_name_is_absolute($command) ) { # spent 6µs making 1 call to File::Spec::Unix::file_name_is_absolute |
241 | return MM->maybe_command($command); | ||||
242 | |||||
243 | } else { | ||||
244 | 1 | 4µs | 1 | 12µs | for my $dir ( # spent 12µs making 1 call to File::Spec::Unix::path |
245 | File::Spec->path, | ||||
246 | ( IS_WIN32 ? File::Spec->curdir : () ) | ||||
247 | ) { | ||||
248 | 27 | 70µs | 27 | 52µs | next if ! $dir || ! -d $dir; # spent 52µs making 27 calls to IPC::Cmd::CORE:ftdir, avg 2µs/call |
249 | 27 | 105µs | 108 | 121µs | my $abs = File::Spec->catfile( IS_WIN32 ? Win32::GetShortPathName( $dir ) : $dir, $command); # spent 82µs making 27 calls to File::Spec::Unix::catfile, avg 3µs/call
# spent 30µs making 27 calls to File::Spec::Unix::catdir, avg 1µs/call
# spent 9µs making 54 calls to File::Spec::Unix::canonpath, avg 169ns/call |
250 | 27 | 19µs | 27 | 94µs | push @possibles, $abs if $abs = MM->maybe_command($abs); # spent 94µs making 27 calls to ExtUtils::MM_Unix::maybe_command, avg 3µs/call |
251 | } | ||||
252 | } | ||||
253 | 1 | 400ns | return @possibles if wantarray and $INSTANCES; | ||
254 | 1 | 3µs | return shift @possibles; | ||
255 | } | ||||
256 | |||||
257 | =head2 $ok | ($ok, $err, $full_buf, $stdout_buff, $stderr_buff) = run( command => COMMAND, [verbose => BOOL, buffer => \$SCALAR, timeout => DIGIT] ); | ||||
258 | |||||
259 | C<run> takes 4 arguments: | ||||
260 | |||||
261 | =over 4 | ||||
262 | |||||
263 | =item command | ||||
264 | |||||
265 | This is the command to execute. It may be either a string or an array | ||||
266 | reference. | ||||
267 | This is a required argument. | ||||
268 | |||||
269 | See L<"Caveats"> for remarks on how commands are parsed and their | ||||
270 | limitations. | ||||
271 | |||||
272 | =item verbose | ||||
273 | |||||
274 | This controls whether all output of a command should also be printed | ||||
275 | to STDOUT/STDERR or should only be trapped in buffers (NOTE: buffers | ||||
276 | require L<IPC::Run> to be installed, or your system able to work with | ||||
277 | L<IPC::Open3>). | ||||
278 | |||||
279 | It will default to the global setting of C<$IPC::Cmd::VERBOSE>, | ||||
280 | which by default is 0. | ||||
281 | |||||
282 | =item buffer | ||||
283 | |||||
284 | This will hold all the output of a command. It needs to be a reference | ||||
285 | to a scalar. | ||||
286 | Note that this will hold both the STDOUT and STDERR messages, and you | ||||
287 | have no way of telling which is which. | ||||
288 | If you require this distinction, run the C<run> command in list context | ||||
289 | and inspect the individual buffers. | ||||
290 | |||||
291 | Of course, this requires that the underlying call supports buffers. See | ||||
292 | the note on buffers above. | ||||
293 | |||||
294 | =item timeout | ||||
295 | |||||
296 | Sets the maximum time the command is allowed to run before aborting, | ||||
297 | using the built-in C<alarm()> call. If the timeout is triggered, the | ||||
298 | C<errorcode> in the return value will be set to an object of the | ||||
299 | C<IPC::Cmd::TimeOut> class. See the L<"error message"> section below for | ||||
300 | details. | ||||
301 | |||||
302 | Defaults to C<0>, meaning no timeout is set. | ||||
303 | |||||
304 | =back | ||||
305 | |||||
306 | C<run> will return a simple C<true> or C<false> when called in scalar | ||||
307 | context. | ||||
308 | In list context, you will be returned a list of the following items: | ||||
309 | |||||
310 | =over 4 | ||||
311 | |||||
312 | =item success | ||||
313 | |||||
314 | A simple boolean indicating if the command executed without errors or | ||||
315 | not. | ||||
316 | |||||
317 | =item error message | ||||
318 | |||||
319 | If the first element of the return value (C<success>) was 0, then some | ||||
320 | error occurred. This second element is the error message the command | ||||
321 | you requested exited with, if available. This is generally a pretty | ||||
322 | printed value of C<$?> or C<$@>. See C<perldoc perlvar> for details on | ||||
323 | what they can contain. | ||||
324 | If the error was a timeout, the C<error message> will be prefixed with | ||||
325 | the string C<IPC::Cmd::TimeOut>, the timeout class. | ||||
326 | |||||
327 | =item full_buffer | ||||
328 | |||||
329 | This is an array reference containing all the output the command | ||||
330 | generated. | ||||
331 | Note that buffers are only available if you have L<IPC::Run> installed, | ||||
332 | or if your system is able to work with L<IPC::Open3> -- see below). | ||||
333 | Otherwise, this element will be C<undef>. | ||||
334 | |||||
335 | =item out_buffer | ||||
336 | |||||
337 | This is an array reference containing all the output sent to STDOUT the | ||||
338 | command generated. The notes from L<"full_buffer"> apply. | ||||
339 | |||||
340 | =item error_buffer | ||||
341 | |||||
342 | This is an arrayreference containing all the output sent to STDERR the | ||||
343 | command generated. The notes from L<"full_buffer"> apply. | ||||
344 | |||||
345 | |||||
346 | =back | ||||
347 | |||||
348 | See the L<"HOW IT WORKS"> section below to see how C<IPC::Cmd> decides | ||||
349 | what modules or function calls to use when issuing a command. | ||||
350 | |||||
351 | =cut | ||||
352 | |||||
353 | 2 | 900ns | { my @acc = qw[ok error _fds]; | ||
354 | |||||
355 | ### autogenerate accessors ### | ||||
356 | 1 | 500ns | for my $key ( @acc ) { | ||
357 | 2 | 2.71ms | 2 | 13µs | # spent 9µs (6+4) within IPC::Cmd::BEGIN@357 which was called:
# once (6µs+4µs) by main::BEGIN@30 at line 357 # spent 9µs making 1 call to IPC::Cmd::BEGIN@357
# spent 4µs making 1 call to strict::unimport |
358 | *{__PACKAGE__."::$key"} = sub { | ||||
359 | $_[0]->{$key} = $_[1] if @_ > 1; | ||||
360 | return $_[0]->{$key}; | ||||
361 | } | ||||
362 | 3 | 6µs | } | ||
363 | } | ||||
364 | |||||
365 | sub can_use_run_forked { | ||||
366 | return $CAN_USE_RUN_FORKED eq "1"; | ||||
367 | } | ||||
368 | |||||
369 | sub get_monotonic_time { | ||||
370 | if ($HAVE_MONOTONIC) { | ||||
371 | return Time::HiRes::clock_gettime(&Time::HiRes::CLOCK_MONOTONIC); | ||||
372 | } | ||||
373 | else { | ||||
374 | return time(); | ||||
375 | } | ||||
376 | } | ||||
377 | |||||
378 | sub adjust_monotonic_start_time { | ||||
379 | my ($ref_vars, $now, $previous) = @_; | ||||
380 | |||||
381 | # workaround only for those systems which don't have | ||||
382 | # Time::HiRes::CLOCK_MONOTONIC (Mac OSX in particular) | ||||
383 | return if $HAVE_MONOTONIC; | ||||
384 | |||||
385 | # don't have previous monotonic value (only happens once | ||||
386 | # in the beginning of the program execution) | ||||
387 | return unless $previous; | ||||
388 | |||||
389 | my $time_diff = $now - $previous; | ||||
390 | |||||
391 | # adjust previously saved time with the skew value which is | ||||
392 | # either negative when clock moved back or more than 5 seconds -- | ||||
393 | # assuming that event loop does happen more often than once | ||||
394 | # per five seconds, which might not be always true (!) but | ||||
395 | # hopefully that's ok, because it's just a workaround | ||||
396 | if ($time_diff > 5 || $time_diff < 0) { | ||||
397 | foreach my $ref_var (@{$ref_vars}) { | ||||
398 | if (defined($$ref_var)) { | ||||
399 | $$ref_var = $$ref_var + $time_diff; | ||||
400 | } | ||||
401 | } | ||||
402 | } | ||||
403 | } | ||||
404 | |||||
405 | sub uninstall_signals { | ||||
406 | return unless defined($IPC::Cmd::{'__old_signals'}); | ||||
407 | |||||
408 | foreach my $sig_name (keys %{$IPC::Cmd::{'__old_signals'}}) { | ||||
409 | $SIG{$sig_name} = $IPC::Cmd::{'__old_signals'}->{$sig_name}; | ||||
410 | } | ||||
411 | } | ||||
412 | |||||
413 | # incompatible with POSIX::SigAction | ||||
414 | # | ||||
415 | sub install_layered_signal { | ||||
416 | my ($s, $handler_code) = @_; | ||||
417 | |||||
418 | my %available_signals = map {$_ => 1} keys %SIG; | ||||
419 | |||||
420 | Carp::confess("install_layered_signal got nonexistent signal name [$s]") | ||||
421 | unless defined($available_signals{$s}); | ||||
422 | Carp::confess("install_layered_signal expects coderef") | ||||
423 | if !ref($handler_code) || ref($handler_code) ne 'CODE'; | ||||
424 | |||||
425 | $IPC::Cmd::{'__old_signals'} = {} | ||||
426 | unless defined($IPC::Cmd::{'__old_signals'}); | ||||
427 | $IPC::Cmd::{'__old_signals'}->{$s} = $SIG{$s}; | ||||
428 | |||||
429 | my $previous_handler = $SIG{$s}; | ||||
430 | |||||
431 | my $sig_handler = sub { | ||||
432 | my ($called_sig_name, @sig_param) = @_; | ||||
433 | |||||
434 | # $s is a closure referring to real signal name | ||||
435 | # for which this handler is being installed. | ||||
436 | # it is used to distinguish between | ||||
437 | # real signal handlers and aliased signal handlers | ||||
438 | my $signal_name = $s; | ||||
439 | |||||
440 | # $called_sig_name is a signal name which | ||||
441 | # was passed to this signal handler; | ||||
442 | # it doesn't equal $signal_name in case | ||||
443 | # some signal handlers in %SIG point | ||||
444 | # to other signal handler (CHLD and CLD, | ||||
445 | # ABRT and IOT) | ||||
446 | # | ||||
447 | # initial signal handler for aliased signal | ||||
448 | # calls some other signal handler which | ||||
449 | # should not execute the same handler_code again | ||||
450 | if ($called_sig_name eq $signal_name) { | ||||
451 | $handler_code->($signal_name); | ||||
452 | } | ||||
453 | |||||
454 | # run original signal handler if any (including aliased) | ||||
455 | # | ||||
456 | if (ref($previous_handler)) { | ||||
457 | $previous_handler->($called_sig_name, @sig_param); | ||||
458 | } | ||||
459 | }; | ||||
460 | |||||
461 | $SIG{$s} = $sig_handler; | ||||
462 | } | ||||
463 | |||||
464 | # give process a chance sending TERM, | ||||
465 | # waiting for a while (2 seconds) | ||||
466 | # and killing it with KILL | ||||
467 | sub kill_gently { | ||||
468 | my ($pid, $opts) = @_; | ||||
469 | |||||
470 | require POSIX; | ||||
471 | |||||
472 | $opts = {} unless $opts; | ||||
473 | $opts->{'wait_time'} = 2 unless defined($opts->{'wait_time'}); | ||||
474 | $opts->{'first_kill_type'} = 'just_process' unless $opts->{'first_kill_type'}; | ||||
475 | $opts->{'final_kill_type'} = 'just_process' unless $opts->{'final_kill_type'}; | ||||
476 | |||||
477 | if ($opts->{'first_kill_type'} eq 'just_process') { | ||||
478 | kill(15, $pid); | ||||
479 | } | ||||
480 | elsif ($opts->{'first_kill_type'} eq 'process_group') { | ||||
481 | kill(-15, $pid); | ||||
482 | } | ||||
483 | |||||
484 | my $do_wait = 1; | ||||
485 | my $child_finished = 0; | ||||
486 | |||||
487 | my $wait_start_time = get_monotonic_time(); | ||||
488 | my $now; | ||||
489 | my $previous_monotonic_value; | ||||
490 | |||||
491 | while ($do_wait) { | ||||
492 | $previous_monotonic_value = $now; | ||||
493 | $now = get_monotonic_time(); | ||||
494 | |||||
495 | adjust_monotonic_start_time([\$wait_start_time], $now, $previous_monotonic_value); | ||||
496 | |||||
497 | if ($now > $wait_start_time + $opts->{'wait_time'}) { | ||||
498 | $do_wait = 0; | ||||
499 | next; | ||||
500 | } | ||||
501 | |||||
502 | my $waitpid = waitpid($pid, POSIX::WNOHANG); | ||||
503 | |||||
504 | if ($waitpid eq -1) { | ||||
505 | $child_finished = 1; | ||||
506 | $do_wait = 0; | ||||
507 | next; | ||||
508 | } | ||||
509 | |||||
510 | Time::HiRes::usleep(250000); # quarter of a second | ||||
511 | } | ||||
512 | |||||
513 | if (!$child_finished) { | ||||
514 | if ($opts->{'final_kill_type'} eq 'just_process') { | ||||
515 | kill(9, $pid); | ||||
516 | } | ||||
517 | elsif ($opts->{'final_kill_type'} eq 'process_group') { | ||||
518 | kill(-9, $pid); | ||||
519 | } | ||||
520 | } | ||||
521 | } | ||||
522 | |||||
523 | sub open3_run { | ||||
524 | my ($cmd, $opts) = @_; | ||||
525 | |||||
526 | $opts = {} unless $opts; | ||||
527 | |||||
528 | my $child_in = FileHandle->new; | ||||
529 | my $child_out = FileHandle->new; | ||||
530 | my $child_err = FileHandle->new; | ||||
531 | $child_out->autoflush(1); | ||||
532 | $child_err->autoflush(1); | ||||
533 | |||||
534 | my $pid = open3($child_in, $child_out, $child_err, $cmd); | ||||
535 | Time::HiRes::usleep(1) if IS_HPUX; | ||||
536 | |||||
537 | # will consider myself orphan if my ppid changes | ||||
538 | # from this one: | ||||
539 | my $original_ppid = $opts->{'original_ppid'}; | ||||
540 | |||||
541 | # push my child's pid to our parent | ||||
542 | # so in case i am killed parent | ||||
543 | # could stop my child (search for | ||||
544 | # child_child_pid in parent code) | ||||
545 | if ($opts->{'parent_info'}) { | ||||
546 | my $ps = $opts->{'parent_info'}; | ||||
547 | print $ps "spawned $pid\n"; | ||||
548 | } | ||||
549 | |||||
550 | if ($child_in && $child_out->opened && $opts->{'child_stdin'}) { | ||||
551 | # If the child process dies for any reason, | ||||
552 | # the next write to CHLD_IN is likely to generate | ||||
553 | # a SIGPIPE in the parent, which is fatal by default. | ||||
554 | # So you may wish to handle this signal. | ||||
555 | # | ||||
556 | # from http://perldoc.perl.org/IPC/Open3.html, | ||||
557 | # absolutely needed to catch piped commands errors. | ||||
558 | # | ||||
559 | local $SIG{'PIPE'} = sub { 1; }; | ||||
560 | |||||
561 | print $child_in $opts->{'child_stdin'}; | ||||
562 | } | ||||
563 | close($child_in); | ||||
564 | |||||
565 | my $child_output = { | ||||
566 | 'out' => $child_out->fileno, | ||||
567 | 'err' => $child_err->fileno, | ||||
568 | $child_out->fileno => { | ||||
569 | 'parent_socket' => $opts->{'parent_stdout'}, | ||||
570 | 'scalar_buffer' => "", | ||||
571 | 'child_handle' => $child_out, | ||||
572 | 'block_size' => ($child_out->stat)[11] || 1024, | ||||
573 | }, | ||||
574 | $child_err->fileno => { | ||||
575 | 'parent_socket' => $opts->{'parent_stderr'}, | ||||
576 | 'scalar_buffer' => "", | ||||
577 | 'child_handle' => $child_err, | ||||
578 | 'block_size' => ($child_err->stat)[11] || 1024, | ||||
579 | }, | ||||
580 | }; | ||||
581 | |||||
582 | my $select = IO::Select->new(); | ||||
583 | $select->add($child_out, $child_err); | ||||
584 | |||||
585 | # pass any signal to the child | ||||
586 | # effectively creating process | ||||
587 | # strongly attached to the child: | ||||
588 | # it will terminate only after child | ||||
589 | # has terminated (except for SIGKILL, | ||||
590 | # which is specially handled) | ||||
591 | SIGNAL: foreach my $s (keys %SIG) { | ||||
592 | next SIGNAL if $s eq '__WARN__' or $s eq '__DIE__'; # Skip and don't clobber __DIE__ & __WARN__ | ||||
593 | my $sig_handler; | ||||
594 | $sig_handler = sub { | ||||
595 | kill("$s", $pid); | ||||
596 | $SIG{$s} = $sig_handler; | ||||
597 | }; | ||||
598 | $SIG{$s} = $sig_handler; | ||||
599 | } | ||||
600 | |||||
601 | my $child_finished = 0; | ||||
602 | |||||
603 | my $real_exit; | ||||
604 | my $exit_value; | ||||
605 | |||||
606 | while(!$child_finished) { | ||||
607 | |||||
608 | # parent was killed otherwise we would have got | ||||
609 | # the same signal as parent and process it same way | ||||
610 | if (getppid() != $original_ppid) { | ||||
611 | |||||
612 | # end my process group with all the children | ||||
613 | # (i am the process group leader, so my pid | ||||
614 | # equals to the process group id) | ||||
615 | # | ||||
616 | # same thing which is done | ||||
617 | # with $opts->{'clean_up_children'} | ||||
618 | # in run_forked | ||||
619 | # | ||||
620 | kill(-9, $$); | ||||
621 | |||||
622 | POSIX::_exit 1; | ||||
623 | } | ||||
624 | |||||
625 | my $waitpid = waitpid($pid, POSIX::WNOHANG); | ||||
626 | |||||
627 | # child finished, catch it's exit status | ||||
628 | if ($waitpid ne 0 && $waitpid ne -1) { | ||||
629 | $real_exit = $?; | ||||
630 | $exit_value = $? >> 8; | ||||
631 | } | ||||
632 | |||||
633 | if ($waitpid eq -1) { | ||||
634 | $child_finished = 1; | ||||
635 | } | ||||
636 | |||||
637 | |||||
638 | my $ready_fds = []; | ||||
639 | push @{$ready_fds}, $select->can_read(1/100); | ||||
640 | |||||
641 | READY_FDS: while (scalar(@{$ready_fds})) { | ||||
642 | my $fd = shift @{$ready_fds}; | ||||
643 | $ready_fds = [grep {$_ ne $fd} @{$ready_fds}]; | ||||
644 | |||||
645 | my $str = $child_output->{$fd->fileno}; | ||||
646 | Carp::confess("child stream not found: $fd") unless $str; | ||||
647 | |||||
648 | my $data; | ||||
649 | my $count = $fd->sysread($data, $str->{'block_size'}); | ||||
650 | |||||
651 | if ($count) { | ||||
652 | if ($str->{'parent_socket'}) { | ||||
653 | my $ph = $str->{'parent_socket'}; | ||||
654 | print $ph $data; | ||||
655 | } | ||||
656 | else { | ||||
657 | $str->{'scalar_buffer'} .= $data; | ||||
658 | } | ||||
659 | } | ||||
660 | elsif ($count eq 0) { | ||||
661 | $select->remove($fd); | ||||
662 | $fd->close(); | ||||
663 | } | ||||
664 | else { | ||||
665 | Carp::confess("error during sysread: " . $!); | ||||
666 | } | ||||
667 | |||||
668 | push @{$ready_fds}, $select->can_read(1/100) if $child_finished; | ||||
669 | } | ||||
670 | |||||
671 | Time::HiRes::usleep(1); | ||||
672 | } | ||||
673 | |||||
674 | # since we've successfully reaped the child, | ||||
675 | # let our parent know about this. | ||||
676 | # | ||||
677 | if ($opts->{'parent_info'}) { | ||||
678 | my $ps = $opts->{'parent_info'}; | ||||
679 | |||||
680 | # child was killed, inform parent | ||||
681 | if ($real_exit & 127) { | ||||
682 | print $ps "$pid killed with " . ($real_exit & 127) . "\n"; | ||||
683 | } | ||||
684 | |||||
685 | print $ps "reaped $pid\n"; | ||||
686 | } | ||||
687 | |||||
688 | if ($opts->{'parent_stdout'} || $opts->{'parent_stderr'}) { | ||||
689 | return $exit_value; | ||||
690 | } | ||||
691 | else { | ||||
692 | return { | ||||
693 | 'stdout' => $child_output->{$child_output->{'out'}}->{'scalar_buffer'}, | ||||
694 | 'stderr' => $child_output->{$child_output->{'err'}}->{'scalar_buffer'}, | ||||
695 | 'exit_code' => $exit_value, | ||||
696 | }; | ||||
697 | } | ||||
698 | } | ||||
699 | |||||
700 | =head2 $hashref = run_forked( COMMAND, { child_stdin => SCALAR, timeout => DIGIT, stdout_handler => CODEREF, stderr_handler => CODEREF} ); | ||||
701 | |||||
702 | C<run_forked> is used to execute some program or a coderef, | ||||
703 | optionally feed it with some input, get its return code | ||||
704 | and output (both stdout and stderr into separate buffers). | ||||
705 | In addition, it allows to terminate the program | ||||
706 | if it takes too long to finish. | ||||
707 | |||||
708 | The important and distinguishing feature of run_forked | ||||
709 | is execution timeout which at first seems to be | ||||
710 | quite a simple task but if you think | ||||
711 | that the program which you're spawning | ||||
712 | might spawn some children itself (which | ||||
713 | in their turn could do the same and so on) | ||||
714 | it turns out to be not a simple issue. | ||||
715 | |||||
716 | C<run_forked> is designed to survive and | ||||
717 | successfully terminate almost any long running task, | ||||
718 | even a fork bomb in case your system has the resources | ||||
719 | to survive during given timeout. | ||||
720 | |||||
721 | This is achieved by creating separate watchdog process | ||||
722 | which spawns the specified program in a separate | ||||
723 | process session and supervises it: optionally | ||||
724 | feeds it with input, stores its exit code, | ||||
725 | stdout and stderr, terminates it in case | ||||
726 | it runs longer than specified. | ||||
727 | |||||
728 | Invocation requires the command to be executed or a coderef and optionally a hashref of options: | ||||
729 | |||||
730 | =over | ||||
731 | |||||
732 | =item C<timeout> | ||||
733 | |||||
734 | Specify in seconds how long to run the command before it is killed with SIG_KILL (9), | ||||
735 | which effectively terminates it and all of its children (direct or indirect). | ||||
736 | |||||
737 | =item C<child_stdin> | ||||
738 | |||||
739 | Specify some text that will be passed into the C<STDIN> of the executed program. | ||||
740 | |||||
741 | =item C<stdout_handler> | ||||
742 | |||||
743 | Coderef of a subroutine to call when a portion of data is received on | ||||
744 | STDOUT from the executing program. | ||||
745 | |||||
746 | =item C<stderr_handler> | ||||
747 | |||||
748 | Coderef of a subroutine to call when a portion of data is received on | ||||
749 | STDERR from the executing program. | ||||
750 | |||||
751 | =item C<wait_loop_callback> | ||||
752 | |||||
753 | Coderef of a subroutine to call inside of the main waiting loop | ||||
754 | (while C<run_forked> waits for the external to finish or fail). | ||||
755 | It is useful to stop running external process before it ends | ||||
756 | by itself, e.g. | ||||
757 | |||||
758 | my $r = run_forked("some external command", { | ||||
759 | 'wait_loop_callback' => sub { | ||||
760 | if (condition) { | ||||
761 | kill(1, $$); | ||||
762 | } | ||||
763 | }, | ||||
764 | 'terminate_on_signal' => 'HUP', | ||||
765 | }); | ||||
766 | |||||
767 | Combined with C<stdout_handler> and C<stderr_handler> allows terminating | ||||
768 | external command based on its output. Could also be used as a timer | ||||
769 | without engaging with L<alarm> (signals). | ||||
770 | |||||
771 | Remember that this code could be called every millisecond (depending | ||||
772 | on the output which external command generates), so try to make it | ||||
773 | as lightweight as possible. | ||||
774 | |||||
775 | =item C<discard_output> | ||||
776 | |||||
777 | Discards the buffering of the standard output and standard errors for return by run_forked(). | ||||
778 | With this option you have to use the std*_handlers to read what the command outputs. | ||||
779 | Useful for commands that send a lot of output. | ||||
780 | |||||
781 | =item C<terminate_on_parent_sudden_death> | ||||
782 | |||||
783 | Enable this option if you wish all spawned processes to be killed if the initially spawned | ||||
784 | process (the parent) is killed or dies without waiting for child processes. | ||||
785 | |||||
786 | =back | ||||
787 | |||||
788 | C<run_forked> will return a HASHREF with the following keys: | ||||
789 | |||||
790 | =over | ||||
791 | |||||
792 | =item C<exit_code> | ||||
793 | |||||
794 | The exit code of the executed program. | ||||
795 | |||||
796 | =item C<timeout> | ||||
797 | |||||
798 | The number of seconds the program ran for before being terminated, or 0 if no timeout occurred. | ||||
799 | |||||
800 | =item C<stdout> | ||||
801 | |||||
802 | Holds the standard output of the executed command (or empty string if | ||||
803 | there was no STDOUT output or if C<discard_output> was used; it's always defined!) | ||||
804 | |||||
805 | =item C<stderr> | ||||
806 | |||||
807 | Holds the standard error of the executed command (or empty string if | ||||
808 | there was no STDERR output or if C<discard_output> was used; it's always defined!) | ||||
809 | |||||
810 | =item C<merged> | ||||
811 | |||||
812 | Holds the standard output and error of the executed command merged into one stream | ||||
813 | (or empty string if there was no output at all or if C<discard_output> was used; it's always defined!) | ||||
814 | |||||
815 | =item C<err_msg> | ||||
816 | |||||
817 | Holds some explanation in the case of an error. | ||||
818 | |||||
819 | =back | ||||
820 | |||||
821 | =cut | ||||
822 | |||||
823 | sub run_forked { | ||||
824 | ### container to store things in | ||||
825 | my $self = bless {}, __PACKAGE__; | ||||
826 | |||||
827 | if (!can_use_run_forked()) { | ||||
828 | Carp::carp("run_forked is not available: $CAN_USE_RUN_FORKED"); | ||||
829 | return; | ||||
830 | } | ||||
831 | |||||
832 | require POSIX; | ||||
833 | |||||
834 | my ($cmd, $opts) = @_; | ||||
835 | if (ref($cmd) eq 'ARRAY') { | ||||
836 | $cmd = join(" ", @{$cmd}); | ||||
837 | } | ||||
838 | |||||
839 | if (!$cmd) { | ||||
840 | Carp::carp("run_forked expects command to run"); | ||||
841 | return; | ||||
842 | } | ||||
843 | |||||
844 | $opts = {} unless $opts; | ||||
845 | $opts->{'timeout'} = 0 unless $opts->{'timeout'}; | ||||
846 | $opts->{'terminate_wait_time'} = 2 unless defined($opts->{'terminate_wait_time'}); | ||||
847 | |||||
848 | # turned on by default | ||||
849 | $opts->{'clean_up_children'} = 1 unless defined($opts->{'clean_up_children'}); | ||||
850 | |||||
851 | # sockets to pass child stdout to parent | ||||
852 | my $child_stdout_socket; | ||||
853 | my $parent_stdout_socket; | ||||
854 | |||||
855 | # sockets to pass child stderr to parent | ||||
856 | my $child_stderr_socket; | ||||
857 | my $parent_stderr_socket; | ||||
858 | |||||
859 | # sockets for child -> parent internal communication | ||||
860 | my $child_info_socket; | ||||
861 | my $parent_info_socket; | ||||
862 | |||||
863 | socketpair($child_stdout_socket, $parent_stdout_socket, &Socket::AF_UNIX, &Socket::SOCK_STREAM, &Socket::PF_UNSPEC) || | ||||
864 | Carp::confess ("socketpair: $!"); | ||||
865 | socketpair($child_stderr_socket, $parent_stderr_socket, &Socket::AF_UNIX, &Socket::SOCK_STREAM, &Socket::PF_UNSPEC) || | ||||
866 | Carp::confess ("socketpair: $!"); | ||||
867 | socketpair($child_info_socket, $parent_info_socket, &Socket::AF_UNIX, &Socket::SOCK_STREAM, &Socket::PF_UNSPEC) || | ||||
868 | Carp::confess ("socketpair: $!"); | ||||
869 | |||||
870 | $child_stdout_socket->autoflush(1); | ||||
871 | $parent_stdout_socket->autoflush(1); | ||||
872 | $child_stderr_socket->autoflush(1); | ||||
873 | $parent_stderr_socket->autoflush(1); | ||||
874 | $child_info_socket->autoflush(1); | ||||
875 | $parent_info_socket->autoflush(1); | ||||
876 | |||||
877 | my $start_time = get_monotonic_time(); | ||||
878 | |||||
879 | my $pid; | ||||
880 | my $ppid = $$; | ||||
881 | if ($pid = fork) { | ||||
882 | |||||
883 | # we are a parent | ||||
884 | close($parent_stdout_socket); | ||||
885 | close($parent_stderr_socket); | ||||
886 | close($parent_info_socket); | ||||
887 | |||||
888 | my $flags; | ||||
889 | |||||
890 | # prepare sockets to read from child | ||||
891 | |||||
892 | $flags = fcntl($child_stdout_socket, POSIX::F_GETFL, 0) || Carp::confess "can't fnctl F_GETFL: $!"; | ||||
893 | $flags |= POSIX::O_NONBLOCK; | ||||
894 | fcntl($child_stdout_socket, POSIX::F_SETFL, $flags) || Carp::confess "can't fnctl F_SETFL: $!"; | ||||
895 | |||||
896 | $flags = fcntl($child_stderr_socket, POSIX::F_GETFL, 0) || Carp::confess "can't fnctl F_GETFL: $!"; | ||||
897 | $flags |= POSIX::O_NONBLOCK; | ||||
898 | fcntl($child_stderr_socket, POSIX::F_SETFL, $flags) || Carp::confess "can't fnctl F_SETFL: $!"; | ||||
899 | |||||
900 | $flags = fcntl($child_info_socket, POSIX::F_GETFL, 0) || Carp::confess "can't fnctl F_GETFL: $!"; | ||||
901 | $flags |= POSIX::O_NONBLOCK; | ||||
902 | fcntl($child_info_socket, POSIX::F_SETFL, $flags) || Carp::confess "can't fnctl F_SETFL: $!"; | ||||
903 | |||||
904 | # print "child $pid started\n"; | ||||
905 | |||||
906 | my $child_output = { | ||||
907 | $child_stdout_socket->fileno => { | ||||
908 | 'scalar_buffer' => "", | ||||
909 | 'child_handle' => $child_stdout_socket, | ||||
910 | 'block_size' => ($child_stdout_socket->stat)[11] || 1024, | ||||
911 | 'protocol' => 'stdout', | ||||
912 | }, | ||||
913 | $child_stderr_socket->fileno => { | ||||
914 | 'scalar_buffer' => "", | ||||
915 | 'child_handle' => $child_stderr_socket, | ||||
916 | 'block_size' => ($child_stderr_socket->stat)[11] || 1024, | ||||
917 | 'protocol' => 'stderr', | ||||
918 | }, | ||||
919 | $child_info_socket->fileno => { | ||||
920 | 'scalar_buffer' => "", | ||||
921 | 'child_handle' => $child_info_socket, | ||||
922 | 'block_size' => ($child_info_socket->stat)[11] || 1024, | ||||
923 | 'protocol' => 'info', | ||||
924 | }, | ||||
925 | }; | ||||
926 | |||||
927 | my $select = IO::Select->new(); | ||||
928 | $select->add($child_stdout_socket, $child_stderr_socket, $child_info_socket); | ||||
929 | |||||
930 | my $child_timedout = 0; | ||||
931 | my $child_finished = 0; | ||||
932 | my $child_stdout = ''; | ||||
933 | my $child_stderr = ''; | ||||
934 | my $child_merged = ''; | ||||
935 | my $child_exit_code = 0; | ||||
936 | my $child_killed_by_signal = 0; | ||||
937 | my $parent_died = 0; | ||||
938 | |||||
939 | my $last_parent_check = 0; | ||||
940 | my $got_sig_child = 0; | ||||
941 | my $got_sig_quit = 0; | ||||
942 | my $orig_sig_child = $SIG{'CHLD'}; | ||||
943 | |||||
944 | $SIG{'CHLD'} = sub { $got_sig_child = get_monotonic_time(); }; | ||||
945 | |||||
946 | if ($opts->{'terminate_on_signal'}) { | ||||
947 | install_layered_signal($opts->{'terminate_on_signal'}, sub { $got_sig_quit = time(); }); | ||||
948 | } | ||||
949 | |||||
950 | my $child_child_pid; | ||||
951 | my $now; | ||||
952 | my $previous_monotonic_value; | ||||
953 | |||||
954 | while (!$child_finished) { | ||||
955 | $previous_monotonic_value = $now; | ||||
956 | $now = get_monotonic_time(); | ||||
957 | |||||
958 | adjust_monotonic_start_time([\$start_time, \$last_parent_check, \$got_sig_child], $now, $previous_monotonic_value); | ||||
959 | |||||
960 | if ($opts->{'terminate_on_parent_sudden_death'}) { | ||||
961 | # check for parent once each five seconds | ||||
962 | if ($now > $last_parent_check + 5) { | ||||
963 | if (getppid() eq "1") { | ||||
964 | kill_gently ($pid, { | ||||
965 | 'first_kill_type' => 'process_group', | ||||
966 | 'final_kill_type' => 'process_group', | ||||
967 | 'wait_time' => $opts->{'terminate_wait_time'} | ||||
968 | }); | ||||
969 | $parent_died = 1; | ||||
970 | } | ||||
971 | |||||
972 | $last_parent_check = $now; | ||||
973 | } | ||||
974 | } | ||||
975 | |||||
976 | # user specified timeout | ||||
977 | if ($opts->{'timeout'}) { | ||||
978 | if ($now > $start_time + $opts->{'timeout'}) { | ||||
979 | kill_gently ($pid, { | ||||
980 | 'first_kill_type' => 'process_group', | ||||
981 | 'final_kill_type' => 'process_group', | ||||
982 | 'wait_time' => $opts->{'terminate_wait_time'} | ||||
983 | }); | ||||
984 | $child_timedout = 1; | ||||
985 | } | ||||
986 | } | ||||
987 | |||||
988 | # give OS 10 seconds for correct return of waitpid, | ||||
989 | # kill process after that and finish wait loop; | ||||
990 | # shouldn't ever happen -- remove this code? | ||||
991 | if ($got_sig_child) { | ||||
992 | if ($now > $got_sig_child + 10) { | ||||
993 | print STDERR "waitpid did not return -1 for 10 seconds after SIG_CHLD, killing [$pid]\n"; | ||||
994 | kill (-9, $pid); | ||||
995 | $child_finished = 1; | ||||
996 | } | ||||
997 | } | ||||
998 | |||||
999 | if ($got_sig_quit) { | ||||
1000 | kill_gently ($pid, { | ||||
1001 | 'first_kill_type' => 'process_group', | ||||
1002 | 'final_kill_type' => 'process_group', | ||||
1003 | 'wait_time' => $opts->{'terminate_wait_time'} | ||||
1004 | }); | ||||
1005 | $child_finished = 1; | ||||
1006 | } | ||||
1007 | |||||
1008 | my $waitpid = waitpid($pid, POSIX::WNOHANG); | ||||
1009 | |||||
1010 | # child finished, catch it's exit status | ||||
1011 | if ($waitpid ne 0 && $waitpid ne -1) { | ||||
1012 | $child_exit_code = $? >> 8; | ||||
1013 | } | ||||
1014 | |||||
1015 | if ($waitpid eq -1) { | ||||
1016 | $child_finished = 1; | ||||
1017 | } | ||||
1018 | |||||
1019 | my $ready_fds = []; | ||||
1020 | push @{$ready_fds}, $select->can_read(1/100); | ||||
1021 | |||||
1022 | READY_FDS: while (scalar(@{$ready_fds})) { | ||||
1023 | my $fd = shift @{$ready_fds}; | ||||
1024 | $ready_fds = [grep {$_ ne $fd} @{$ready_fds}]; | ||||
1025 | |||||
1026 | my $str = $child_output->{$fd->fileno}; | ||||
1027 | Carp::confess("child stream not found: $fd") unless $str; | ||||
1028 | |||||
1029 | my $data = ""; | ||||
1030 | my $count = $fd->sysread($data, $str->{'block_size'}); | ||||
1031 | |||||
1032 | if ($count) { | ||||
1033 | # extract all the available lines and store the rest in temporary buffer | ||||
1034 | if ($data =~ /(.+\n)([^\n]*)/so) { | ||||
1035 | $data = $str->{'scalar_buffer'} . $1; | ||||
1036 | $str->{'scalar_buffer'} = $2 || ""; | ||||
1037 | } | ||||
1038 | else { | ||||
1039 | $str->{'scalar_buffer'} .= $data; | ||||
1040 | $data = ""; | ||||
1041 | } | ||||
1042 | } | ||||
1043 | elsif ($count eq 0) { | ||||
1044 | $select->remove($fd); | ||||
1045 | $fd->close(); | ||||
1046 | if ($str->{'scalar_buffer'}) { | ||||
1047 | $data = $str->{'scalar_buffer'} . "\n"; | ||||
1048 | } | ||||
1049 | } | ||||
1050 | else { | ||||
1051 | Carp::confess("error during sysread on [$fd]: " . $!); | ||||
1052 | } | ||||
1053 | |||||
1054 | # $data contains only full lines (or last line if it was unfinished read | ||||
1055 | # or now new-line in the output of the child); dat is processed | ||||
1056 | # according to the "protocol" of socket | ||||
1057 | if ($str->{'protocol'} eq 'info') { | ||||
1058 | if ($data =~ /^spawned ([0-9]+?)\n(.*?)/so) { | ||||
1059 | $child_child_pid = $1; | ||||
1060 | $data = $2; | ||||
1061 | } | ||||
1062 | if ($data =~ /^reaped ([0-9]+?)\n(.*?)/so) { | ||||
1063 | $child_child_pid = undef; | ||||
1064 | $data = $2; | ||||
1065 | } | ||||
1066 | if ($data =~ /^[\d]+ killed with ([0-9]+?)\n(.*?)/so) { | ||||
1067 | $child_killed_by_signal = $1; | ||||
1068 | $data = $2; | ||||
1069 | } | ||||
1070 | |||||
1071 | # we don't expect any other data in info socket, so it's | ||||
1072 | # some strange violation of protocol, better know about this | ||||
1073 | if ($data) { | ||||
1074 | Carp::confess("info protocol violation: [$data]"); | ||||
1075 | } | ||||
1076 | } | ||||
1077 | if ($str->{'protocol'} eq 'stdout') { | ||||
1078 | if (!$opts->{'discard_output'}) { | ||||
1079 | $child_stdout .= $data; | ||||
1080 | $child_merged .= $data; | ||||
1081 | } | ||||
1082 | |||||
1083 | if ($opts->{'stdout_handler'} && ref($opts->{'stdout_handler'}) eq 'CODE') { | ||||
1084 | $opts->{'stdout_handler'}->($data); | ||||
1085 | } | ||||
1086 | } | ||||
1087 | if ($str->{'protocol'} eq 'stderr') { | ||||
1088 | if (!$opts->{'discard_output'}) { | ||||
1089 | $child_stderr .= $data; | ||||
1090 | $child_merged .= $data; | ||||
1091 | } | ||||
1092 | |||||
1093 | if ($opts->{'stderr_handler'} && ref($opts->{'stderr_handler'}) eq 'CODE') { | ||||
1094 | $opts->{'stderr_handler'}->($data); | ||||
1095 | } | ||||
1096 | } | ||||
1097 | |||||
1098 | # process may finish (waitpid returns -1) before | ||||
1099 | # we've read all of its output because of buffering; | ||||
1100 | # so try to read all the way it is possible to read | ||||
1101 | # in such case - this shouldn't be too much (unless | ||||
1102 | # the buffer size is HUGE -- should introduce | ||||
1103 | # another counter in such case, maybe later) | ||||
1104 | # | ||||
1105 | push @{$ready_fds}, $select->can_read(1/100) if $child_finished; | ||||
1106 | } | ||||
1107 | |||||
1108 | if ($opts->{'wait_loop_callback'} && ref($opts->{'wait_loop_callback'}) eq 'CODE') { | ||||
1109 | $opts->{'wait_loop_callback'}->(); | ||||
1110 | } | ||||
1111 | |||||
1112 | Time::HiRes::usleep(1); | ||||
1113 | } | ||||
1114 | |||||
1115 | # $child_pid_pid is not defined in two cases: | ||||
1116 | # * when our child was killed before | ||||
1117 | # it had chance to tell us the pid | ||||
1118 | # of the child it spawned. we can do | ||||
1119 | # nothing in this case :( | ||||
1120 | # * our child successfully reaped its child, | ||||
1121 | # we have nothing left to do in this case | ||||
1122 | # | ||||
1123 | # defined $child_pid_pid means child's child | ||||
1124 | # has not died but nobody is waiting for it, | ||||
1125 | # killing it brutally. | ||||
1126 | # | ||||
1127 | if ($child_child_pid) { | ||||
1128 | kill_gently($child_child_pid); | ||||
1129 | } | ||||
1130 | |||||
1131 | # in case there are forks in child which | ||||
1132 | # do not forward or process signals (TERM) correctly | ||||
1133 | # kill whole child process group, effectively trying | ||||
1134 | # not to return with some children or their parts still running | ||||
1135 | # | ||||
1136 | # to be more accurate -- we need to be sure | ||||
1137 | # that this is process group created by our child | ||||
1138 | # (and not some other process group with the same pgid, | ||||
1139 | # created just after death of our child) -- fortunately | ||||
1140 | # this might happen only when process group ids | ||||
1141 | # are reused quickly (there are lots of processes | ||||
1142 | # spawning new process groups for example) | ||||
1143 | # | ||||
1144 | if ($opts->{'clean_up_children'}) { | ||||
1145 | kill(-9, $pid); | ||||
1146 | } | ||||
1147 | |||||
1148 | # print "child $pid finished\n"; | ||||
1149 | |||||
1150 | close($child_stdout_socket); | ||||
1151 | close($child_stderr_socket); | ||||
1152 | close($child_info_socket); | ||||
1153 | |||||
1154 | my $o = { | ||||
1155 | 'stdout' => $child_stdout, | ||||
1156 | 'stderr' => $child_stderr, | ||||
1157 | 'merged' => $child_merged, | ||||
1158 | 'timeout' => $child_timedout ? $opts->{'timeout'} : 0, | ||||
1159 | 'exit_code' => $child_exit_code, | ||||
1160 | 'parent_died' => $parent_died, | ||||
1161 | 'killed_by_signal' => $child_killed_by_signal, | ||||
1162 | 'child_pgid' => $pid, | ||||
1163 | 'cmd' => $cmd, | ||||
1164 | }; | ||||
1165 | |||||
1166 | my $err_msg = ''; | ||||
1167 | if ($o->{'exit_code'}) { | ||||
1168 | $err_msg .= "exited with code [$o->{'exit_code'}]\n"; | ||||
1169 | } | ||||
1170 | if ($o->{'timeout'}) { | ||||
1171 | $err_msg .= "ran more than [$o->{'timeout'}] seconds\n"; | ||||
1172 | } | ||||
1173 | if ($o->{'parent_died'}) { | ||||
1174 | $err_msg .= "parent died\n"; | ||||
1175 | } | ||||
1176 | if ($o->{'stdout'} && !$opts->{'non_empty_stdout_ok'}) { | ||||
1177 | $err_msg .= "stdout:\n" . $o->{'stdout'} . "\n"; | ||||
1178 | } | ||||
1179 | if ($o->{'stderr'}) { | ||||
1180 | $err_msg .= "stderr:\n" . $o->{'stderr'} . "\n"; | ||||
1181 | } | ||||
1182 | if ($o->{'killed_by_signal'}) { | ||||
1183 | $err_msg .= "killed by signal [" . $o->{'killed_by_signal'} . "]\n"; | ||||
1184 | } | ||||
1185 | $o->{'err_msg'} = $err_msg; | ||||
1186 | |||||
1187 | if ($orig_sig_child) { | ||||
1188 | $SIG{'CHLD'} = $orig_sig_child; | ||||
1189 | } | ||||
1190 | else { | ||||
1191 | delete($SIG{'CHLD'}); | ||||
1192 | } | ||||
1193 | |||||
1194 | uninstall_signals(); | ||||
1195 | |||||
1196 | return $o; | ||||
1197 | } | ||||
1198 | else { | ||||
1199 | Carp::confess("cannot fork: $!") unless defined($pid); | ||||
1200 | |||||
1201 | # create new process session for open3 call, | ||||
1202 | # so we hopefully can kill all the subprocesses | ||||
1203 | # which might be spawned in it (except for those | ||||
1204 | # which do setsid theirselves -- can't do anything | ||||
1205 | # with those) | ||||
1206 | |||||
1207 | POSIX::setsid() == -1 and Carp::confess("Error running setsid: " . $!); | ||||
1208 | |||||
1209 | if ($opts->{'child_BEGIN'} && ref($opts->{'child_BEGIN'}) eq 'CODE') { | ||||
1210 | $opts->{'child_BEGIN'}->(); | ||||
1211 | } | ||||
1212 | |||||
1213 | close($child_stdout_socket); | ||||
1214 | close($child_stderr_socket); | ||||
1215 | close($child_info_socket); | ||||
1216 | |||||
1217 | my $child_exit_code; | ||||
1218 | |||||
1219 | # allow both external programs | ||||
1220 | # and internal perl calls | ||||
1221 | if (!ref($cmd)) { | ||||
1222 | $child_exit_code = open3_run($cmd, { | ||||
1223 | 'parent_info' => $parent_info_socket, | ||||
1224 | 'parent_stdout' => $parent_stdout_socket, | ||||
1225 | 'parent_stderr' => $parent_stderr_socket, | ||||
1226 | 'child_stdin' => $opts->{'child_stdin'}, | ||||
1227 | 'original_ppid' => $ppid, | ||||
1228 | }); | ||||
1229 | } | ||||
1230 | elsif (ref($cmd) eq 'CODE') { | ||||
1231 | # reopen STDOUT and STDERR for child code: | ||||
1232 | # https://rt.cpan.org/Ticket/Display.html?id=85912 | ||||
1233 | open STDOUT, '>&', $parent_stdout_socket || Carp::confess("Unable to reopen STDOUT: $!\n"); | ||||
1234 | open STDERR, '>&', $parent_stderr_socket || Carp::confess("Unable to reopen STDERR: $!\n"); | ||||
1235 | |||||
1236 | $child_exit_code = $cmd->({ | ||||
1237 | 'opts' => $opts, | ||||
1238 | 'parent_info' => $parent_info_socket, | ||||
1239 | 'parent_stdout' => $parent_stdout_socket, | ||||
1240 | 'parent_stderr' => $parent_stderr_socket, | ||||
1241 | 'child_stdin' => $opts->{'child_stdin'}, | ||||
1242 | }); | ||||
1243 | } | ||||
1244 | else { | ||||
1245 | print $parent_stderr_socket "Invalid command reference: " . ref($cmd) . "\n"; | ||||
1246 | $child_exit_code = 1; | ||||
1247 | } | ||||
1248 | |||||
1249 | close($parent_stdout_socket); | ||||
1250 | close($parent_stderr_socket); | ||||
1251 | close($parent_info_socket); | ||||
1252 | |||||
1253 | if ($opts->{'child_END'} && ref($opts->{'child_END'}) eq 'CODE') { | ||||
1254 | $opts->{'child_END'}->(); | ||||
1255 | } | ||||
1256 | |||||
1257 | $| = 1; | ||||
1258 | POSIX::_exit $child_exit_code; | ||||
1259 | } | ||||
1260 | } | ||||
1261 | |||||
1262 | sub run { | ||||
1263 | ### container to store things in | ||||
1264 | my $self = bless {}, __PACKAGE__; | ||||
1265 | |||||
1266 | my %hash = @_; | ||||
1267 | |||||
1268 | ### if the user didn't provide a buffer, we'll store it here. | ||||
1269 | my $def_buf = ''; | ||||
1270 | |||||
1271 | my($verbose,$cmd,$buffer,$timeout); | ||||
1272 | my $tmpl = { | ||||
1273 | verbose => { default => $VERBOSE, store => \$verbose }, | ||||
1274 | buffer => { default => \$def_buf, store => \$buffer }, | ||||
1275 | command => { required => 1, store => \$cmd, | ||||
1276 | allow => sub { !ref($_[0]) or ref($_[0]) eq 'ARRAY' }, | ||||
1277 | }, | ||||
1278 | timeout => { default => 0, store => \$timeout }, | ||||
1279 | }; | ||||
1280 | |||||
1281 | unless( check( $tmpl, \%hash, $VERBOSE ) ) { | ||||
1282 | Carp::carp( loc( "Could not validate input: %1", | ||||
1283 | Params::Check->last_error ) ); | ||||
1284 | return; | ||||
1285 | }; | ||||
1286 | |||||
1287 | $cmd = _quote_args_vms( $cmd ) if IS_VMS; | ||||
1288 | |||||
1289 | ### strip any empty elements from $cmd if present | ||||
1290 | if ( $ALLOW_NULL_ARGS ) { | ||||
1291 | $cmd = [ grep { defined } @$cmd ] if ref $cmd; | ||||
1292 | } | ||||
1293 | else { | ||||
1294 | $cmd = [ grep { defined && length } @$cmd ] if ref $cmd; | ||||
1295 | } | ||||
1296 | |||||
1297 | my $pp_cmd = (ref $cmd ? "@$cmd" : $cmd); | ||||
1298 | print loc("Running [%1]...\n", $pp_cmd ) if $verbose; | ||||
1299 | |||||
1300 | ### did the user pass us a buffer to fill or not? if so, set this | ||||
1301 | ### flag so we know what is expected of us | ||||
1302 | ### XXX this is now being ignored. in the future, we could add diagnostic | ||||
1303 | ### messages based on this logic | ||||
1304 | #my $user_provided_buffer = $buffer == \$def_buf ? 0 : 1; | ||||
1305 | |||||
1306 | ### buffers that are to be captured | ||||
1307 | my( @buffer, @buff_err, @buff_out ); | ||||
1308 | |||||
1309 | ### capture STDOUT | ||||
1310 | my $_out_handler = sub { | ||||
1311 | my $buf = shift; | ||||
1312 | return unless defined $buf; | ||||
1313 | |||||
1314 | print STDOUT $buf if $verbose; | ||||
1315 | push @buffer, $buf; | ||||
1316 | push @buff_out, $buf; | ||||
1317 | }; | ||||
1318 | |||||
1319 | ### capture STDERR | ||||
1320 | my $_err_handler = sub { | ||||
1321 | my $buf = shift; | ||||
1322 | return unless defined $buf; | ||||
1323 | |||||
1324 | print STDERR $buf if $verbose; | ||||
1325 | push @buffer, $buf; | ||||
1326 | push @buff_err, $buf; | ||||
1327 | }; | ||||
1328 | |||||
1329 | |||||
1330 | ### flag to indicate we have a buffer captured | ||||
1331 | my $have_buffer = $self->can_capture_buffer ? 1 : 0; | ||||
1332 | |||||
1333 | ### flag indicating if the subcall went ok | ||||
1334 | my $ok; | ||||
1335 | |||||
1336 | ### don't look at previous errors: | ||||
1337 | local $?; | ||||
1338 | local $@; | ||||
1339 | local $!; | ||||
1340 | |||||
1341 | ### we might be having a timeout set | ||||
1342 | eval { | ||||
1343 | local $SIG{ALRM} = sub { die bless sub { | ||||
1344 | ALARM_CLASS . | ||||
1345 | qq[: Command '$pp_cmd' aborted by alarm after $timeout seconds] | ||||
1346 | }, ALARM_CLASS } if $timeout; | ||||
1347 | alarm $timeout || 0; | ||||
1348 | |||||
1349 | ### IPC::Run is first choice if $USE_IPC_RUN is set. | ||||
1350 | if( !IS_WIN32 and $USE_IPC_RUN and $self->can_use_ipc_run( 1 ) ) { | ||||
1351 | ### ipc::run handlers needs the command as a string or an array ref | ||||
1352 | |||||
1353 | $self->_debug( "# Using IPC::Run. Have buffer: $have_buffer" ) | ||||
1354 | if $DEBUG; | ||||
1355 | |||||
1356 | $ok = $self->_ipc_run( $cmd, $_out_handler, $_err_handler ); | ||||
1357 | |||||
1358 | ### since IPC::Open3 works on all platforms, and just fails on | ||||
1359 | ### win32 for capturing buffers, do that ideally | ||||
1360 | } elsif ( $USE_IPC_OPEN3 and $self->can_use_ipc_open3( 1 ) ) { | ||||
1361 | |||||
1362 | $self->_debug("# Using IPC::Open3. Have buffer: $have_buffer") | ||||
1363 | if $DEBUG; | ||||
1364 | |||||
1365 | ### in case there are pipes in there; | ||||
1366 | ### IPC::Open3 will call exec and exec will do the right thing | ||||
1367 | |||||
1368 | my $method = IS_WIN32 ? '_open3_run_win32' : '_open3_run'; | ||||
1369 | |||||
1370 | $ok = $self->$method( | ||||
1371 | $cmd, $_out_handler, $_err_handler, $verbose | ||||
1372 | ); | ||||
1373 | |||||
1374 | ### if we are allowed to run verbose, just dispatch the system command | ||||
1375 | } else { | ||||
1376 | $self->_debug( "# Using system(). Have buffer: $have_buffer" ) | ||||
1377 | if $DEBUG; | ||||
1378 | $ok = $self->_system_run( $cmd, $verbose ); | ||||
1379 | } | ||||
1380 | |||||
1381 | alarm 0; | ||||
1382 | }; | ||||
1383 | |||||
1384 | ### restore STDIN after duping, or STDIN will be closed for | ||||
1385 | ### this current perl process! | ||||
1386 | $self->__reopen_fds( @{ $self->_fds} ) if $self->_fds; | ||||
1387 | |||||
1388 | my $err; | ||||
1389 | unless( $ok ) { | ||||
1390 | ### alarm happened | ||||
1391 | if ( $@ and ref $@ and $@->isa( ALARM_CLASS ) ) { | ||||
1392 | $err = $@->(); # the error code is an expired alarm | ||||
1393 | |||||
1394 | ### another error happened, set by the dispatchub | ||||
1395 | } else { | ||||
1396 | $err = $self->error; | ||||
1397 | } | ||||
1398 | } | ||||
1399 | |||||
1400 | ### fill the buffer; | ||||
1401 | $$buffer = join '', @buffer if @buffer; | ||||
1402 | |||||
1403 | ### return a list of flags and buffers (if available) in list | ||||
1404 | ### context, or just a simple 'ok' in scalar | ||||
1405 | return wantarray | ||||
1406 | ? $have_buffer | ||||
1407 | ? ($ok, $err, \@buffer, \@buff_out, \@buff_err) | ||||
1408 | : ($ok, $err ) | ||||
1409 | : $ok | ||||
1410 | |||||
1411 | |||||
1412 | } | ||||
1413 | |||||
1414 | sub _open3_run_win32 { | ||||
1415 | my $self = shift; | ||||
1416 | my $cmd = shift; | ||||
1417 | my $outhand = shift; | ||||
1418 | my $errhand = shift; | ||||
1419 | |||||
1420 | require Socket; | ||||
1421 | |||||
1422 | my $pipe = sub { | ||||
1423 | socketpair($_[0], $_[1], &Socket::AF_UNIX, &Socket::SOCK_STREAM, &Socket::PF_UNSPEC) | ||||
1424 | or return undef; | ||||
1425 | shutdown($_[0], 1); # No more writing for reader | ||||
1426 | shutdown($_[1], 0); # No more reading for writer | ||||
1427 | return 1; | ||||
1428 | }; | ||||
1429 | |||||
1430 | my $open3 = sub { | ||||
1431 | local (*TO_CHLD_R, *TO_CHLD_W); | ||||
1432 | local (*FR_CHLD_R, *FR_CHLD_W); | ||||
1433 | local (*FR_CHLD_ERR_R, *FR_CHLD_ERR_W); | ||||
1434 | |||||
1435 | $pipe->(*TO_CHLD_R, *TO_CHLD_W ) or die $^E; | ||||
1436 | $pipe->(*FR_CHLD_R, *FR_CHLD_W ) or die $^E; | ||||
1437 | $pipe->(*FR_CHLD_ERR_R, *FR_CHLD_ERR_W) or die $^E; | ||||
1438 | |||||
1439 | my $pid = IPC::Open3::open3('>&TO_CHLD_R', '<&FR_CHLD_W', '<&FR_CHLD_ERR_W', @_); | ||||
1440 | |||||
1441 | return ( $pid, *TO_CHLD_W, *FR_CHLD_R, *FR_CHLD_ERR_R ); | ||||
1442 | }; | ||||
1443 | |||||
1444 | $cmd = [ grep { defined && length } @$cmd ] if ref $cmd; | ||||
1445 | $cmd = $self->__fix_cmd_whitespace_and_special_chars( $cmd ); | ||||
1446 | |||||
1447 | my ($pid, $to_chld, $fr_chld, $fr_chld_err) = | ||||
1448 | $open3->( ( ref $cmd ? @$cmd : $cmd ) ); | ||||
1449 | |||||
1450 | my $in_sel = IO::Select->new(); | ||||
1451 | my $out_sel = IO::Select->new(); | ||||
1452 | |||||
1453 | my %objs; | ||||
1454 | |||||
1455 | $objs{ fileno( $fr_chld ) } = $outhand; | ||||
1456 | $objs{ fileno( $fr_chld_err ) } = $errhand; | ||||
1457 | $in_sel->add( $fr_chld ); | ||||
1458 | $in_sel->add( $fr_chld_err ); | ||||
1459 | |||||
1460 | close($to_chld); | ||||
1461 | |||||
1462 | while ($in_sel->count() + $out_sel->count()) { | ||||
1463 | my ($ins, $outs) = IO::Select::select($in_sel, $out_sel, undef); | ||||
1464 | |||||
1465 | for my $fh (@$ins) { | ||||
1466 | my $obj = $objs{ fileno($fh) }; | ||||
1467 | my $buf; | ||||
1468 | my $bytes_read = sysread($fh, $buf, 64*1024 ); #, length($buf)); | ||||
1469 | if (!$bytes_read) { | ||||
1470 | $in_sel->remove($fh); | ||||
1471 | } | ||||
1472 | else { | ||||
1473 | $obj->( "$buf" ); | ||||
1474 | } | ||||
1475 | } | ||||
1476 | |||||
1477 | for my $fh (@$outs) { | ||||
1478 | } | ||||
1479 | } | ||||
1480 | |||||
1481 | waitpid($pid, 0); | ||||
1482 | |||||
1483 | ### some error occurred | ||||
1484 | if( $? ) { | ||||
1485 | $self->error( $self->_pp_child_error( $cmd, $? ) ); | ||||
1486 | $self->ok( 0 ); | ||||
1487 | return; | ||||
1488 | } else { | ||||
1489 | return $self->ok( 1 ); | ||||
1490 | } | ||||
1491 | } | ||||
1492 | |||||
1493 | sub _open3_run { | ||||
1494 | my $self = shift; | ||||
1495 | my $cmd = shift; | ||||
1496 | my $_out_handler = shift; | ||||
1497 | my $_err_handler = shift; | ||||
1498 | my $verbose = shift || 0; | ||||
1499 | |||||
1500 | ### Following code are adapted from Friar 'abstracts' in the | ||||
1501 | ### Perl Monastery (http://www.perlmonks.org/index.pl?node_id=151886). | ||||
1502 | ### XXX that code didn't work. | ||||
1503 | ### we now use the following code, thanks to theorbtwo | ||||
1504 | |||||
1505 | ### define them beforehand, so we always have defined FH's | ||||
1506 | ### to read from. | ||||
1507 | 2 | 897µs | 2 | 55µs | # spent 31µs (7+24) within IPC::Cmd::BEGIN@1507 which was called:
# once (7µs+24µs) by main::BEGIN@30 at line 1507 # spent 31µs making 1 call to IPC::Cmd::BEGIN@1507
# spent 24µs making 1 call to Exporter::import |
1508 | my $kidout = Symbol::gensym(); | ||||
1509 | my $kiderror = Symbol::gensym(); | ||||
1510 | |||||
1511 | ### Dup the filehandle so we can pass 'our' STDIN to the | ||||
1512 | ### child process. This stops us from having to pump input | ||||
1513 | ### from ourselves to the childprocess. However, we will need | ||||
1514 | ### to revive the FH afterwards, as IPC::Open3 closes it. | ||||
1515 | ### We'll do the same for STDOUT and STDERR. It works without | ||||
1516 | ### duping them on non-unix derivatives, but not on win32. | ||||
1517 | my @fds_to_dup = ( IS_WIN32 && !$verbose | ||||
1518 | ? qw[STDIN STDOUT STDERR] | ||||
1519 | : qw[STDIN] | ||||
1520 | ); | ||||
1521 | $self->_fds( \@fds_to_dup ); | ||||
1522 | $self->__dup_fds( @fds_to_dup ); | ||||
1523 | |||||
1524 | ### pipes have to come in a quoted string, and that clashes with | ||||
1525 | ### whitespace. This sub fixes up such commands so they run properly | ||||
1526 | $cmd = $self->__fix_cmd_whitespace_and_special_chars( $cmd ); | ||||
1527 | |||||
1528 | ### don't stringify @$cmd, so spaces in filenames/paths are | ||||
1529 | ### treated properly | ||||
1530 | my $pid = eval { | ||||
1531 | IPC::Open3::open3( | ||||
1532 | '<&STDIN', | ||||
1533 | (IS_WIN32 ? '>&STDOUT' : $kidout), | ||||
1534 | (IS_WIN32 ? '>&STDERR' : $kiderror), | ||||
1535 | ( ref $cmd ? @$cmd : $cmd ), | ||||
1536 | ); | ||||
1537 | }; | ||||
1538 | |||||
1539 | ### open3 error occurred | ||||
1540 | if( $@ and $@ =~ /^open3:/ ) { | ||||
1541 | $self->ok( 0 ); | ||||
1542 | $self->error( $@ ); | ||||
1543 | return; | ||||
1544 | }; | ||||
1545 | |||||
1546 | ### use OUR stdin, not $kidin. Somehow, | ||||
1547 | ### we never get the input.. so jump through | ||||
1548 | ### some hoops to do it :( | ||||
1549 | my $selector = IO::Select->new( | ||||
1550 | (IS_WIN32 ? \*STDERR : $kiderror), | ||||
1551 | \*STDIN, | ||||
1552 | (IS_WIN32 ? \*STDOUT : $kidout) | ||||
1553 | ); | ||||
1554 | |||||
1555 | STDOUT->autoflush(1); STDERR->autoflush(1); STDIN->autoflush(1); | ||||
1556 | $kidout->autoflush(1) if UNIVERSAL::can($kidout, 'autoflush'); | ||||
1557 | $kiderror->autoflush(1) if UNIVERSAL::can($kiderror, 'autoflush'); | ||||
1558 | |||||
1559 | ### add an explicit break statement | ||||
1560 | ### code courtesy of theorbtwo from #london.pm | ||||
1561 | my $stdout_done = 0; | ||||
1562 | my $stderr_done = 0; | ||||
1563 | OUTER: while ( my @ready = $selector->can_read ) { | ||||
1564 | |||||
1565 | for my $h ( @ready ) { | ||||
1566 | my $buf; | ||||
1567 | |||||
1568 | ### $len is the amount of bytes read | ||||
1569 | my $len = sysread( $h, $buf, 4096 ); # try to read 4096 bytes | ||||
1570 | |||||
1571 | ### see perldoc -f sysread: it returns undef on error, | ||||
1572 | ### so bail out. | ||||
1573 | if( not defined $len ) { | ||||
1574 | warn(loc("Error reading from process: %1", $!)); | ||||
1575 | last OUTER; | ||||
1576 | } | ||||
1577 | |||||
1578 | ### check for $len. it may be 0, at which point we're | ||||
1579 | ### done reading, so don't try to process it. | ||||
1580 | ### if we would print anyway, we'd provide bogus information | ||||
1581 | $_out_handler->( "$buf" ) if $len && $h == $kidout; | ||||
1582 | $_err_handler->( "$buf" ) if $len && $h == $kiderror; | ||||
1583 | |||||
1584 | ### Wait till child process is done printing to both | ||||
1585 | ### stdout and stderr. | ||||
1586 | $stdout_done = 1 if $h == $kidout and $len == 0; | ||||
1587 | $stderr_done = 1 if $h == $kiderror and $len == 0; | ||||
1588 | last OUTER if ($stdout_done && $stderr_done); | ||||
1589 | } | ||||
1590 | } | ||||
1591 | |||||
1592 | waitpid $pid, 0; # wait for it to die | ||||
1593 | |||||
1594 | ### restore STDIN after duping, or STDIN will be closed for | ||||
1595 | ### this current perl process! | ||||
1596 | ### done in the parent call now | ||||
1597 | # $self->__reopen_fds( @fds_to_dup ); | ||||
1598 | |||||
1599 | ### some error occurred | ||||
1600 | if( $? ) { | ||||
1601 | $self->error( $self->_pp_child_error( $cmd, $? ) ); | ||||
1602 | $self->ok( 0 ); | ||||
1603 | return; | ||||
1604 | } else { | ||||
1605 | return $self->ok( 1 ); | ||||
1606 | } | ||||
1607 | } | ||||
1608 | |||||
1609 | ### Text::ParseWords::shellwords() uses unix semantics. that will break | ||||
1610 | ### on win32 | ||||
1611 | 1 | 8µs | 1 | 2µs | { my $parse_sub = IS_WIN32 # spent 2µs making 1 call to UNIVERSAL::can |
1612 | ? __PACKAGE__->can('_split_like_shell_win32') | ||||
1613 | : Text::ParseWords->can('shellwords'); | ||||
1614 | |||||
1615 | sub _ipc_run { | ||||
1616 | my $self = shift; | ||||
1617 | my $cmd = shift; | ||||
1618 | my $_out_handler = shift; | ||||
1619 | my $_err_handler = shift; | ||||
1620 | |||||
1621 | STDOUT->autoflush(1); STDERR->autoflush(1); | ||||
1622 | |||||
1623 | ### a command like: | ||||
1624 | # [ | ||||
1625 | # '/usr/bin/gzip', | ||||
1626 | # '-cdf', | ||||
1627 | # '/Users/kane/sources/p4/other/archive-extract/t/src/x.tgz', | ||||
1628 | # '|', | ||||
1629 | # '/usr/bin/tar', | ||||
1630 | # '-tf -' | ||||
1631 | # ] | ||||
1632 | ### needs to become: | ||||
1633 | # [ | ||||
1634 | # ['/usr/bin/gzip', '-cdf', | ||||
1635 | # '/Users/kane/sources/p4/other/archive-extract/t/src/x.tgz'] | ||||
1636 | # '|', | ||||
1637 | # ['/usr/bin/tar', '-tf -'] | ||||
1638 | # ] | ||||
1639 | |||||
1640 | |||||
1641 | my @command; | ||||
1642 | my $special_chars; | ||||
1643 | |||||
1644 | my $re = do { my $x = join '', SPECIAL_CHARS; qr/([$x])/ }; | ||||
1645 | if( ref $cmd ) { | ||||
1646 | my $aref = []; | ||||
1647 | for my $item (@$cmd) { | ||||
1648 | if( $item =~ $re ) { | ||||
1649 | push @command, $aref, $item; | ||||
1650 | $aref = []; | ||||
1651 | $special_chars .= $1; | ||||
1652 | } else { | ||||
1653 | push @$aref, $item; | ||||
1654 | } | ||||
1655 | } | ||||
1656 | push @command, $aref; | ||||
1657 | } else { | ||||
1658 | @command = map { if( $_ =~ $re ) { | ||||
1659 | $special_chars .= $1; $_; | ||||
1660 | } else { | ||||
1661 | # [ split /\s+/ ] | ||||
1662 | [ map { m/[ ]/ ? qq{'$_'} : $_ } $parse_sub->($_) ] | ||||
1663 | } | ||||
1664 | } split( /\s*$re\s*/, $cmd ); | ||||
1665 | } | ||||
1666 | |||||
1667 | ### if there's a pipe in the command, *STDIN needs to | ||||
1668 | ### be inserted *BEFORE* the pipe, to work on win32 | ||||
1669 | ### this also works on *nix, so we should do it when possible | ||||
1670 | ### this should *also* work on multiple pipes in the command | ||||
1671 | ### if there's no pipe in the command, append STDIN to the back | ||||
1672 | ### of the command instead. | ||||
1673 | ### XXX seems IPC::Run works it out for itself if you just | ||||
1674 | ### don't pass STDIN at all. | ||||
1675 | # if( $special_chars and $special_chars =~ /\|/ ) { | ||||
1676 | # ### only add STDIN the first time.. | ||||
1677 | # my $i; | ||||
1678 | # @command = map { ($_ eq '|' && not $i++) | ||||
1679 | # ? ( \*STDIN, $_ ) | ||||
1680 | # : $_ | ||||
1681 | # } @command; | ||||
1682 | # } else { | ||||
1683 | # push @command, \*STDIN; | ||||
1684 | # } | ||||
1685 | |||||
1686 | # \*STDIN is already included in the @command, see a few lines up | ||||
1687 | my $ok = eval { IPC::Run::run( @command, | ||||
1688 | fileno(STDOUT).'>', | ||||
1689 | $_out_handler, | ||||
1690 | fileno(STDERR).'>', | ||||
1691 | $_err_handler | ||||
1692 | ) | ||||
1693 | }; | ||||
1694 | |||||
1695 | ### all is well | ||||
1696 | if( $ok ) { | ||||
1697 | return $self->ok( $ok ); | ||||
1698 | |||||
1699 | ### some error occurred | ||||
1700 | } else { | ||||
1701 | $self->ok( 0 ); | ||||
1702 | |||||
1703 | ### if the eval fails due to an exception, deal with it | ||||
1704 | ### unless it's an alarm | ||||
1705 | if( $@ and not UNIVERSAL::isa( $@, ALARM_CLASS ) ) { | ||||
1706 | $self->error( $@ ); | ||||
1707 | |||||
1708 | ### if it *is* an alarm, propagate | ||||
1709 | } elsif( $@ ) { | ||||
1710 | die $@; | ||||
1711 | |||||
1712 | ### some error in the sub command | ||||
1713 | } else { | ||||
1714 | $self->error( $self->_pp_child_error( $cmd, $? ) ); | ||||
1715 | } | ||||
1716 | |||||
1717 | return; | ||||
1718 | } | ||||
1719 | } | ||||
1720 | } | ||||
1721 | |||||
1722 | 1 | 100ns | sub _system_run { | ||
1723 | my $self = shift; | ||||
1724 | my $cmd = shift; | ||||
1725 | my $verbose = shift || 0; | ||||
1726 | |||||
1727 | ### pipes have to come in a quoted string, and that clashes with | ||||
1728 | ### whitespace. This sub fixes up such commands so they run properly | ||||
1729 | $cmd = $self->__fix_cmd_whitespace_and_special_chars( $cmd ); | ||||
1730 | |||||
1731 | my @fds_to_dup = $verbose ? () : qw[STDOUT STDERR]; | ||||
1732 | $self->_fds( \@fds_to_dup ); | ||||
1733 | $self->__dup_fds( @fds_to_dup ); | ||||
1734 | |||||
1735 | ### system returns 'true' on failure -- the exit code of the cmd | ||||
1736 | $self->ok( 1 ); | ||||
1737 | system( ref $cmd ? @$cmd : $cmd ) == 0 or do { | ||||
1738 | $self->error( $self->_pp_child_error( $cmd, $? ) ); | ||||
1739 | $self->ok( 0 ); | ||||
1740 | }; | ||||
1741 | |||||
1742 | ### done in the parent call now | ||||
1743 | #$self->__reopen_fds( @fds_to_dup ); | ||||
1744 | |||||
1745 | return unless $self->ok; | ||||
1746 | return $self->ok; | ||||
1747 | } | ||||
1748 | |||||
1749 | 1 | 13µs | { my %sc_lookup = map { $_ => $_ } SPECIAL_CHARS; | ||
1750 | |||||
1751 | |||||
1752 | sub __fix_cmd_whitespace_and_special_chars { | ||||
1753 | my $self = shift; | ||||
1754 | my $cmd = shift; | ||||
1755 | |||||
1756 | ### command has a special char in it | ||||
1757 | if( ref $cmd and grep { $sc_lookup{$_} } @$cmd ) { | ||||
1758 | |||||
1759 | ### since we have special chars, we have to quote white space | ||||
1760 | ### this *may* conflict with the parsing :( | ||||
1761 | my $fixed; | ||||
1762 | my @cmd = map { / / ? do { $fixed++; QUOTE.$_.QUOTE } : $_ } @$cmd; | ||||
1763 | |||||
1764 | $self->_debug( "# Quoted $fixed arguments containing whitespace" ) | ||||
1765 | if $DEBUG && $fixed; | ||||
1766 | |||||
1767 | ### stringify it, so the special char isn't escaped as argument | ||||
1768 | ### to the program | ||||
1769 | $cmd = join ' ', @cmd; | ||||
1770 | } | ||||
1771 | |||||
1772 | return $cmd; | ||||
1773 | } | ||||
1774 | } | ||||
1775 | |||||
1776 | ### Command-line arguments (but not the command itself) must be quoted | ||||
1777 | ### to ensure case preservation. Borrowed from Module::Build with adaptations. | ||||
1778 | ### Patch for this supplied by Craig Berry, see RT #46288: [PATCH] Add argument | ||||
1779 | ### quoting for run() on VMS | ||||
1780 | 1 | 600ns | sub _quote_args_vms { | ||
1781 | ### Returns a command string with proper quoting so that the subprocess | ||||
1782 | ### sees this same list of args, or if we get a single arg that is an | ||||
1783 | ### array reference, quote the elements of it (except for the first) | ||||
1784 | ### and return the reference. | ||||
1785 | my @args = @_; | ||||
1786 | my $got_arrayref = (scalar(@args) == 1 | ||||
1787 | && UNIVERSAL::isa($args[0], 'ARRAY')) | ||||
1788 | ? 1 | ||||
1789 | : 0; | ||||
1790 | |||||
1791 | @args = split(/\s+/, $args[0]) unless $got_arrayref || scalar(@args) > 1; | ||||
1792 | |||||
1793 | my $cmd = $got_arrayref ? shift @{$args[0]} : shift @args; | ||||
1794 | |||||
1795 | ### Do not quote qualifiers that begin with '/' or previously quoted args. | ||||
1796 | map { if (/^[^\/\"]/) { | ||||
1797 | $_ =~ s/\"/""/g; # escape C<"> by doubling | ||||
1798 | $_ = q(").$_.q("); | ||||
1799 | } | ||||
1800 | } | ||||
1801 | ($got_arrayref ? @{$args[0]} | ||||
1802 | : @args | ||||
1803 | ); | ||||
1804 | |||||
1805 | $got_arrayref ? unshift(@{$args[0]}, $cmd) : unshift(@args, $cmd); | ||||
1806 | |||||
1807 | return $got_arrayref ? $args[0] | ||||
1808 | : join(' ', @args); | ||||
1809 | } | ||||
1810 | |||||
1811 | |||||
1812 | ### XXX this is cribbed STRAIGHT from M::B 0.30 here: | ||||
1813 | ### http://search.cpan.org/src/KWILLIAMS/Module-Build-0.30/lib/Module/Build/Platform/Windows.pm:split_like_shell | ||||
1814 | ### XXX this *should* be integrated into text::parsewords | ||||
1815 | sub _split_like_shell_win32 { | ||||
1816 | # As it turns out, Windows command-parsing is very different from | ||||
1817 | # Unix command-parsing. Double-quotes mean different things, | ||||
1818 | # backslashes don't necessarily mean escapes, and so on. So we | ||||
1819 | # can't use Text::ParseWords::shellwords() to break a command string | ||||
1820 | # into words. The algorithm below was bashed out by Randy and Ken | ||||
1821 | # (mostly Randy), and there are a lot of regression tests, so we | ||||
1822 | # should feel free to adjust if desired. | ||||
1823 | |||||
1824 | local $_ = shift; | ||||
1825 | |||||
1826 | my @argv; | ||||
1827 | return @argv unless defined() && length(); | ||||
1828 | |||||
1829 | my $arg = ''; | ||||
1830 | my( $i, $quote_mode ) = ( 0, 0 ); | ||||
1831 | |||||
1832 | while ( $i < length() ) { | ||||
1833 | |||||
1834 | my $ch = substr( $_, $i , 1 ); | ||||
1835 | my $next_ch = substr( $_, $i+1, 1 ); | ||||
1836 | |||||
1837 | if ( $ch eq '\\' && $next_ch eq '"' ) { | ||||
1838 | $arg .= '"'; | ||||
1839 | $i++; | ||||
1840 | } elsif ( $ch eq '\\' && $next_ch eq '\\' ) { | ||||
1841 | $arg .= '\\'; | ||||
1842 | $i++; | ||||
1843 | } elsif ( $ch eq '"' && $next_ch eq '"' && $quote_mode ) { | ||||
1844 | $quote_mode = !$quote_mode; | ||||
1845 | $arg .= '"'; | ||||
1846 | $i++; | ||||
1847 | } elsif ( $ch eq '"' && $next_ch eq '"' && !$quote_mode && | ||||
1848 | ( $i + 2 == length() || | ||||
1849 | substr( $_, $i + 2, 1 ) eq ' ' ) | ||||
1850 | ) { # for cases like: a"" => [ 'a' ] | ||||
1851 | push( @argv, $arg ); | ||||
1852 | $arg = ''; | ||||
1853 | $i += 2; | ||||
1854 | } elsif ( $ch eq '"' ) { | ||||
1855 | $quote_mode = !$quote_mode; | ||||
1856 | } elsif ( $ch eq ' ' && !$quote_mode ) { | ||||
1857 | push( @argv, $arg ) if defined( $arg ) && length( $arg ); | ||||
1858 | $arg = ''; | ||||
1859 | ++$i while substr( $_, $i + 1, 1 ) eq ' '; | ||||
1860 | } else { | ||||
1861 | $arg .= $ch; | ||||
1862 | } | ||||
1863 | |||||
1864 | $i++; | ||||
1865 | } | ||||
1866 | |||||
1867 | push( @argv, $arg ) if defined( $arg ) && length( $arg ); | ||||
1868 | return @argv; | ||||
1869 | } | ||||
1870 | |||||
- - | |||||
1873 | 2 | 19µs | 2 | 8µs | # spent 8µs (8+400ns) within IPC::Cmd::BEGIN@1873 which was called:
# once (8µs+400ns) by main::BEGIN@30 at line 1873 # spent 8µs making 1 call to IPC::Cmd::BEGIN@1873
# spent 400ns making 1 call to IPC::Cmd::__ANON__ |
1874 | 2 | 358µs | 2 | 35µs | # spent 20µs (5+15) within IPC::Cmd::BEGIN@1874 which was called:
# once (5µs+15µs) by main::BEGIN@30 at line 1874 # spent 20µs making 1 call to IPC::Cmd::BEGIN@1874
# spent 15µs making 1 call to Exporter::import |
1875 | |||||
1876 | 1 | 4µs | 3 | 8µs | my %Map = ( # spent 8µs making 3 calls to Symbol::gensym, avg 3µs/call |
1877 | STDOUT => [qw|>&|, \*STDOUT, Symbol::gensym() ], | ||||
1878 | STDERR => [qw|>&|, \*STDERR, Symbol::gensym() ], | ||||
1879 | STDIN => [qw|<&|, \*STDIN, Symbol::gensym() ], | ||||
1880 | ); | ||||
1881 | |||||
1882 | ### dups FDs and stores them in a cache | ||||
1883 | sub __dup_fds { | ||||
1884 | my $self = shift; | ||||
1885 | my @fds = @_; | ||||
1886 | |||||
1887 | __PACKAGE__->_debug( "# Closing the following fds: @fds" ) if $DEBUG; | ||||
1888 | |||||
1889 | for my $name ( @fds ) { | ||||
1890 | my($redir, $fh, $glob) = @{$Map{$name}} or ( | ||||
1891 | Carp::carp(loc("No such FD: '%1'", $name)), next ); | ||||
1892 | |||||
1893 | ### MUST use the 2-arg version of open for dup'ing for | ||||
1894 | ### 5.6.x compatibility. 5.8.x can use 3-arg open | ||||
1895 | ### see perldoc5.6.2 -f open for details | ||||
1896 | open $glob, $redir . fileno($fh) or ( | ||||
1897 | Carp::carp(loc("Could not dup '$name': %1", $!)), | ||||
1898 | return | ||||
1899 | ); | ||||
1900 | |||||
1901 | ### we should re-open this filehandle right now, not | ||||
1902 | ### just dup it | ||||
1903 | ### Use 2-arg version of open, as 5.5.x doesn't support | ||||
1904 | ### 3-arg version =/ | ||||
1905 | if( $redir eq '>&' ) { | ||||
1906 | open( $fh, '>' . File::Spec->devnull ) or ( | ||||
1907 | Carp::carp(loc("Could not reopen '$name': %1", $!)), | ||||
1908 | return | ||||
1909 | ); | ||||
1910 | } | ||||
1911 | } | ||||
1912 | |||||
1913 | return 1; | ||||
1914 | } | ||||
1915 | |||||
1916 | ### reopens FDs from the cache | ||||
1917 | sub __reopen_fds { | ||||
1918 | my $self = shift; | ||||
1919 | my @fds = @_; | ||||
1920 | |||||
1921 | __PACKAGE__->_debug( "# Reopening the following fds: @fds" ) if $DEBUG; | ||||
1922 | |||||
1923 | for my $name ( @fds ) { | ||||
1924 | my($redir, $fh, $glob) = @{$Map{$name}} or ( | ||||
1925 | Carp::carp(loc("No such FD: '%1'", $name)), next ); | ||||
1926 | |||||
1927 | ### MUST use the 2-arg version of open for dup'ing for | ||||
1928 | ### 5.6.x compatibility. 5.8.x can use 3-arg open | ||||
1929 | ### see perldoc5.6.2 -f open for details | ||||
1930 | open( $fh, $redir . fileno($glob) ) or ( | ||||
1931 | Carp::carp(loc("Could not restore '$name': %1", $!)), | ||||
1932 | return | ||||
1933 | ); | ||||
1934 | |||||
1935 | ### close this FD, we're not using it anymore | ||||
1936 | close $glob; | ||||
1937 | } | ||||
1938 | return 1; | ||||
1939 | |||||
1940 | } | ||||
1941 | } | ||||
1942 | |||||
1943 | 1 | 300ns | sub _debug { | ||
1944 | my $self = shift; | ||||
1945 | my $msg = shift or return; | ||||
1946 | my $level = shift || 0; | ||||
1947 | |||||
1948 | local $Carp::CarpLevel += $level; | ||||
1949 | Carp::carp($msg); | ||||
1950 | |||||
1951 | return 1; | ||||
1952 | } | ||||
1953 | |||||
1954 | sub _pp_child_error { | ||||
1955 | my $self = shift; | ||||
1956 | my $cmd = shift or return; | ||||
1957 | my $ce = shift or return; | ||||
1958 | my $pp_cmd = ref $cmd ? "@$cmd" : $cmd; | ||||
1959 | |||||
1960 | |||||
1961 | my $str; | ||||
1962 | if( $ce == -1 ) { | ||||
1963 | ### Include $! in the error message, so that the user can | ||||
1964 | ### see 'No such file or directory' versus 'Permission denied' | ||||
1965 | ### versus 'Cannot fork' or whatever the cause was. | ||||
1966 | $str = "Failed to execute '$pp_cmd': $!"; | ||||
1967 | |||||
1968 | } elsif ( $ce & 127 ) { | ||||
1969 | ### some signal | ||||
1970 | $str = loc( "'%1' died with signal %2, %3 coredump", | ||||
1971 | $pp_cmd, ($ce & 127), ($ce & 128) ? 'with' : 'without'); | ||||
1972 | |||||
1973 | } else { | ||||
1974 | ### Otherwise, the command run but gave error status. | ||||
1975 | $str = "'$pp_cmd' exited with value " . ($ce >> 8); | ||||
1976 | } | ||||
1977 | |||||
1978 | $self->_debug( "# Child error '$ce' translated to: $str" ) if $DEBUG; | ||||
1979 | |||||
1980 | return $str; | ||||
1981 | } | ||||
1982 | |||||
1983 | 1 | 8µs | 1; | ||
1984 | |||||
1985 | __END__ | ||||
# spent 52µs within IPC::Cmd::CORE:ftdir which was called 27 times, avg 2µs/call:
# 27 times (52µs+0s) by IPC::Cmd::can_run at line 248, avg 2µs/call | |||||
sub IPC::Cmd::__ANON__; # xsub |