1 # Copyright © 2008-2009 Raphaël Hertzog <hertzog@debian.org>
2 # Copyright © 2008 Frank Lichtenheld <djpig@debian.org>
3 # Copyright © 2008-2010, 2012-2015 Guillem Jover <guillem@debian.org>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <https://www.gnu.org/licenses/>.
23 our $VERSION = '1.02';
30 use Exporter qw(import);
32 use Dpkg::ErrorHandling;
39 Dpkg::IPC - helper functions for IPC
43 Dpkg::IPC offers helper functions to allow you to execute
44 other programs in an easy, yet flexible way, while hiding
45 all the gory details of IPC (Inter-Process Communication)
52 =item $pid = spawn(%opts)
54 Creates a child process and executes another program in it.
55 The arguments are interpreted as a hash of options, specifying
56 how to handle the in and output of the program to execute.
57 Returns the pid of the child process (unless the wait_child
60 Any error will cause the function to exit with one of the
61 Dpkg::ErrorHandling functions.
69 Can be either a scalar, i.e. the name of the program to be
70 executed, or an array reference, i.e. the name of the program
71 plus additional arguments. Note that the program will never be
72 executed via the shell, so you can't specify additional arguments
73 in the scalar string and you can't use any shell facilities like
78 =item from_file, to_file, error_to_file
80 Filename as scalar. Standard input/output/error of the
81 child process will be redirected to the file specified.
83 =item from_handle, to_handle, error_to_handle
85 Filehandle. Standard input/output/error of the child process will be
86 dup'ed from the handle.
88 =item from_pipe, to_pipe, error_to_pipe
90 Scalar reference or object based on IO::Handle. A pipe will be opened for
91 each of the two options and either the reading (C<to_pipe> and
92 C<error_to_pipe>) or the writing end (C<from_pipe>) will be returned in
93 the referenced scalar. Standard input/output/error of the child process
94 will be dup'ed to the other ends of the pipes.
96 =item from_string, to_string, error_to_string
98 Scalar reference. Standard input/output/error of the child
99 process will be redirected to the string given as reference. Note
100 that it wouldn't be strictly necessary to use a scalar reference
101 for C<from_string>, as the string is not modified in any way. This was
102 chosen only for reasons of symmetry with C<to_string> and
103 C<error_to_string>. C<to_string> and C<error_to_string> imply the
104 C<wait_child> option.
108 Scalar. If containing a true value, wait_child() will be called before
109 returning. The return value of spawn() will be a true value, not the pid.
113 Scalar. Option of the wait_child() call.
117 Scalar. Option of the wait_child() call.
121 Scalar. The child process will chdir in the indicated directory before
126 Hash reference. The child process will populate %ENV with the items of the
127 hash before calling exec. This allows exporting environment variables.
131 Array reference. The child process will remove all environment variables
132 listed in the array before calling exec.
136 Hash reference. The child process will populate %SIG with the items of the
137 hash before calling exec. This allows setting signal dispositions.
141 Array reference. The child process will reset all signals listed in the
142 array to their default dispositions before calling exec.
148 sub _sanity_check_opts {
151 croak 'exec parameter is mandatory in spawn()'
154 my $to = my $error_to = my $from = 0;
155 foreach my $thing (qw(file handle string pipe)) {
156 $to++ if $opts{"to_$thing"};
157 $error_to++ if $opts{"error_to_$thing"};
158 $from++ if $opts{"from_$thing"};
160 croak 'not more than one of to_* parameters is allowed'
162 croak 'not more than one of error_to_* parameters is allowed'
164 croak 'not more than one of from_* parameters is allowed'
167 foreach my $param (qw(to_string error_to_string from_string)) {
168 if (exists $opts{$param} and
169 (not ref $opts{$param} or ref $opts{$param} ne 'SCALAR')) {
170 croak "parameter $param must be a scalar reference";
174 foreach my $param (qw(to_pipe error_to_pipe from_pipe)) {
175 if (exists $opts{$param} and
176 (not ref $opts{$param} or (ref $opts{$param} ne 'SCALAR' and
177 not $opts{$param}->isa('IO::Handle')))) {
178 croak "parameter $param must be a scalar reference or " .
179 'an IO::Handle object';
183 if (exists $opts{timeout} and defined($opts{timeout}) and
184 $opts{timeout} !~ /^\d+$/) {
185 croak 'parameter timeout must be an integer';
188 if (exists $opts{env} and ref($opts{env}) ne 'HASH') {
189 croak 'parameter env must be a hash reference';
192 if (exists $opts{delete_env} and ref($opts{delete_env}) ne 'ARRAY') {
193 croak 'parameter delete_env must be an array reference';
196 if (exists $opts{sig} and ref($opts{sig}) ne 'HASH') {
197 croak 'parameter sig must be a hash reference';
200 if (exists $opts{delete_sig} and ref($opts{delete_sig}) ne 'ARRAY') {
201 croak 'parameter delete_sig must be an array reference';
211 _sanity_check_opts(%opts);
212 $opts{close_in_child} //= [];
213 if (ref($opts{exec}) =~ /ARRAY/) {
214 push @prog, @{$opts{exec}};
215 } elsif (not ref($opts{exec})) {
216 push @prog, $opts{exec};
218 croak 'invalid exec parameter in spawn()';
220 my ($from_string_pipe, $to_string_pipe, $error_to_string_pipe);
221 if ($opts{to_string}) {
222 $opts{to_pipe} = \$to_string_pipe;
223 $opts{wait_child} = 1;
225 if ($opts{error_to_string}) {
226 $opts{error_to_pipe} = \$error_to_string_pipe;
227 $opts{wait_child} = 1;
229 if ($opts{from_string}) {
230 $opts{from_pipe} = \$from_string_pipe;
232 # Create pipes if needed
233 my ($input_pipe, $output_pipe, $error_pipe);
234 if ($opts{from_pipe}) {
235 pipe($opts{from_handle}, $input_pipe)
236 or syserr(g_('pipe for %s'), "@prog");
237 ${$opts{from_pipe}} = $input_pipe;
238 push @{$opts{close_in_child}}, $input_pipe;
240 if ($opts{to_pipe}) {
241 pipe($output_pipe, $opts{to_handle})
242 or syserr(g_('pipe for %s'), "@prog");
243 ${$opts{to_pipe}} = $output_pipe;
244 push @{$opts{close_in_child}}, $output_pipe;
246 if ($opts{error_to_pipe}) {
247 pipe($error_pipe, $opts{error_to_handle})
248 or syserr(g_('pipe for %s'), "@prog");
249 ${$opts{error_to_pipe}} = $error_pipe;
250 push @{$opts{close_in_child}}, $error_pipe;
254 syserr(g_('cannot fork for %s'), "@prog") unless defined $pid;
256 # Define environment variables
258 foreach (keys %{$opts{env}}) {
259 $ENV{$_} = $opts{env}{$_};
262 if ($opts{delete_env}) {
263 delete $ENV{$_} foreach (@{$opts{delete_env}});
265 # Define signal dispositions.
267 foreach (keys %{$opts{sig}}) {
268 $SIG{$_} = $opts{sig}{$_};
271 if ($opts{delete_sig}) {
272 delete $SIG{$_} foreach (@{$opts{delete_sig}});
274 # Change the current directory
276 chdir($opts{chdir}) or syserr(g_('chdir to %s'), $opts{chdir});
278 # Redirect STDIN if needed
279 if ($opts{from_file}) {
280 open(STDIN, '<', $opts{from_file})
281 or syserr(g_('cannot open %s'), $opts{from_file});
282 } elsif ($opts{from_handle}) {
283 open(STDIN, '<&', $opts{from_handle})
284 or syserr(g_('reopen stdin'));
285 # has been duped, can be closed
286 push @{$opts{close_in_child}}, $opts{from_handle};
288 # Redirect STDOUT if needed
289 if ($opts{to_file}) {
290 open(STDOUT, '>', $opts{to_file})
291 or syserr(g_('cannot write %s'), $opts{to_file});
292 } elsif ($opts{to_handle}) {
293 open(STDOUT, '>&', $opts{to_handle})
294 or syserr(g_('reopen stdout'));
295 # has been duped, can be closed
296 push @{$opts{close_in_child}}, $opts{to_handle};
298 # Redirect STDERR if needed
299 if ($opts{error_to_file}) {
300 open(STDERR, '>', $opts{error_to_file})
301 or syserr(g_('cannot write %s'), $opts{error_to_file});
302 } elsif ($opts{error_to_handle}) {
303 open(STDERR, '>&', $opts{error_to_handle})
304 or syserr(g_('reopen stdout'));
305 # has been duped, can be closed
306 push @{$opts{close_in_child}}, $opts{error_to_handle};
308 # Close some inherited filehandles
309 close($_) foreach (@{$opts{close_in_child}});
310 # Execute the program
311 exec({ $prog[0] } @prog) or syserr(g_('unable to execute %s'), "@prog");
313 # Close handle that we can't use any more
314 close($opts{from_handle}) if exists $opts{from_handle};
315 close($opts{to_handle}) if exists $opts{to_handle};
316 close($opts{error_to_handle}) if exists $opts{error_to_handle};
318 if ($opts{from_string}) {
319 print { $from_string_pipe } ${$opts{from_string}};
320 close($from_string_pipe);
322 if ($opts{to_string}) {
324 ${$opts{to_string}} = readline($to_string_pipe);
326 if ($opts{error_to_string}) {
328 ${$opts{error_to_string}} = readline($error_to_string_pipe);
330 if ($opts{wait_child}) {
331 my $cmdline = "@prog";
333 foreach (keys %{$opts{env}}) {
334 $cmdline = "$_=\"" . $opts{env}{$_} . "\" $cmdline";
337 wait_child($pid, nocheck => $opts{nocheck},
338 timeout => $opts{timeout}, cmdline => $cmdline);
346 =item wait_child($pid, %opts)
348 Takes as first argument the pid of the process to wait for.
349 Remaining arguments are taken as a hash of options. Returns
350 nothing. Fails if the child has been ended by a signal or
351 if it exited non-zero.
359 String to identify the child process in error messages.
360 Defaults to "child process".
364 If true do not check the return status of the child (and thus
365 do not fail it has been killed or if it exited with a
366 non-zero return code).
370 Set a maximum time to wait for the process, after that kill the process and
371 fail with an error message.
378 my ($pid, %opts) = @_;
379 $opts{cmdline} //= g_('child process');
380 croak 'no PID set, cannot wait end of process' unless $pid;
382 local $SIG{ALRM} = sub { die "alarm\n" };
383 alarm($opts{timeout}) if defined($opts{timeout});
384 $pid == waitpid($pid, 0) or syserr(g_('wait for %s'), $opts{cmdline});
385 alarm(0) if defined($opts{timeout});
388 die $@ unless $@ eq "alarm\n";
390 error(P_("%s didn't complete in %d second",
391 "%s didn't complete in %d seconds",
393 $opts{cmdline}, $opts{timeout});
395 unless ($opts{nocheck}) {
396 subprocerr($opts{cmdline}) if $?;
407 =head2 Version 1.02 (dpkg 1.18.0)
409 Change options: wait_child() now kills the process when reaching the 'timeout'.
411 =head2 Version 1.01 (dpkg 1.17.11)
413 New options: spawn() now accepts 'sig' and 'delete_sig'.
415 =head2 Version 1.00 (dpkg 1.15.6)
417 Mark the module as public.
421 Dpkg, Dpkg::ErrorHandling