File Coverage

blib/lib/Dpkg/IPC.pm
Criterion Covered Total %
statement 146 160 91.2
branch 91 124 73.3
condition 19 35 54.2
subroutine 10 10 100.0
pod 2 2 100.0
total 268 331 80.9


line stmt bran cond sub pod time code
1             # Copyright © 2008-2009 Raphaël Hertzog
2             # Copyright © 2008 Frank Lichtenheld
3             # Copyright © 2008-2010, 2012-2015 Guillem Jover
4             #
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.
9             #
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.
14             #
15             # You should have received a copy of the GNU General Public License
16             # along with this program. If not, see .
17              
18             package Dpkg::IPC;
19              
20 547     547   310999 use strict;
  547         1611  
  547         16919  
21 547     547   2724 use warnings;
  547         1086  
  547         44408  
22              
23             our $VERSION = '1.02';
24             our @EXPORT = qw(
25             spawn
26             wait_child
27             );
28              
29 547     547   3270 use Carp;
  547         1090  
  547         32768  
30 547     547   3338 use Exporter qw(import);
  547         576  
  547         14493  
31              
32 547     547   5097 use Dpkg::ErrorHandling;
  547         1107  
  547         54531  
33 547     547   3869 use Dpkg::Gettext;
  547         594  
  547         982181  
34              
35             =encoding utf8
36              
37             =head1 NAME
38              
39             Dpkg::IPC - helper functions for IPC
40              
41             =head1 DESCRIPTION
42              
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)
46             from you.
47              
48             =head1 FUNCTIONS
49              
50             =over 4
51              
52             =item $pid = spawn(%opts)
53              
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
58             option was given).
59              
60             Any error will cause the function to exit with one of the
61             Dpkg::ErrorHandling functions.
62              
63             Options:
64              
65             =over 4
66              
67             =item exec
68              
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
74             globbing.
75              
76             Mandatory Option.
77              
78             =item from_file, to_file, error_to_file
79              
80             Filename as scalar. Standard input/output/error of the
81             child process will be redirected to the file specified.
82              
83             =item from_handle, to_handle, error_to_handle
84              
85             Filehandle. Standard input/output/error of the child process will be
86             dup'ed from the handle.
87              
88             =item from_pipe, to_pipe, error_to_pipe
89              
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 and
92             C) or the writing end (C) 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.
95              
96             =item from_string, to_string, error_to_string
97              
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, as the string is not modified in any way. This was
102             chosen only for reasons of symmetry with C and
103             C. C and C imply the
104             C option.
105              
106             =item wait_child
107              
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.
110              
111             =item nocheck
112              
113             Scalar. Option of the wait_child() call.
114              
115             =item timeout
116              
117             Scalar. Option of the wait_child() call.
118              
119             =item chdir
120              
121             Scalar. The child process will chdir in the indicated directory before
122             calling exec.
123              
124             =item env
125              
126             Hash reference. The child process will populate %ENV with the items of the
127             hash before calling exec. This allows exporting environment variables.
128              
129             =item delete_env
130              
131             Array reference. The child process will remove all environment variables
132             listed in the array before calling exec.
133              
134             =item sig
135              
136             Hash reference. The child process will populate %SIG with the items of the
137             hash before calling exec. This allows setting signal dispositions.
138              
139             =item delete_sig
140              
141             Array reference. The child process will reset all signals listed in the
142             array to their default dispositions before calling exec.
143              
144             =back
145              
146             =cut
147              
148             sub _sanity_check_opts {
149 133939     133939   672703 my (%opts) = @_;
150              
151             croak 'exec parameter is mandatory in spawn()'
152 133939 50       568970 unless $opts{exec};
153              
154 133939         453210 my $to = my $error_to = my $from = 0;
155 133939         384333 foreach my $thing (qw(file handle string pipe)) {
156 535756 100       1259519 $to++ if $opts{"to_$thing"};
157 535756 100       1186927 $error_to++ if $opts{"error_to_$thing"};
158 535756 100       1267725 $from++ if $opts{"from_$thing"};
159             }
160 133939 50       370519 croak 'not more than one of to_* parameters is allowed'
161             if $to > 1;
162 133939 50       373298 croak 'not more than one of error_to_* parameters is allowed'
163             if $error_to > 1;
164 133939 50       424832 croak 'not more than one of from_* parameters is allowed'
165             if $from > 1;
166              
167 133939         341552 foreach my $param (qw(to_string error_to_string from_string)) {
168 401817 50 33     3001771 if (exists $opts{$param} and
      66        
169             (not ref $opts{$param} or ref $opts{$param} ne 'SCALAR')) {
170 0         0 croak "parameter $param must be a scalar reference";
171             }
172             }
173              
174 133939         370746 foreach my $param (qw(to_pipe error_to_pipe from_pipe)) {
175 401817 50 33     915701 if (exists $opts{$param} and
      66        
176             (not ref $opts{$param} or (ref $opts{$param} ne 'SCALAR' and
177             not $opts{$param}->isa('IO::Handle')))) {
178 0         0 croak "parameter $param must be a scalar reference or " .
179             'an IO::Handle object';
180             }
181             }
182              
183 133939 50 66     615894 if (exists $opts{timeout} and defined($opts{timeout}) and
      66        
184             $opts{timeout} !~ /^\d+$/) {
185 0         0 croak 'parameter timeout must be an integer';
186             }
187              
188 133939 50 66     502239 if (exists $opts{env} and ref($opts{env}) ne 'HASH') {
189 0         0 croak 'parameter env must be a hash reference';
190             }
191              
192 133939 50 66     443467 if (exists $opts{delete_env} and ref($opts{delete_env}) ne 'ARRAY') {
193 0         0 croak 'parameter delete_env must be an array reference';
194             }
195              
196 133939 50 33     447706 if (exists $opts{sig} and ref($opts{sig}) ne 'HASH') {
197 0         0 croak 'parameter sig must be a hash reference';
198             }
199              
200 133939 50 33     430110 if (exists $opts{delete_sig} and ref($opts{delete_sig}) ne 'ARRAY') {
201 0         0 croak 'parameter delete_sig must be an array reference';
202             }
203              
204 133939         382626 return %opts;
205             }
206              
207             sub spawn {
208 133939     133939 1 1084245 my (%opts) = @_;
209 133939         236246 my @prog;
210              
211 133939         1417276 _sanity_check_opts(%opts);
212 133939   50     2015046 $opts{close_in_child} //= [];
213 133939 100       2463038 if (ref($opts{exec}) =~ /ARRAY/) {
    50          
214 133927         413157 push @prog, @{$opts{exec}};
  133927         566589  
215             } elsif (not ref($opts{exec})) {
216 12         32 push @prog, $opts{exec};
217             } else {
218 0         0 croak 'invalid exec parameter in spawn()';
219             }
220 133939         365139 my ($from_string_pipe, $to_string_pipe, $error_to_string_pipe);
221 133939 100       436417 if ($opts{to_string}) {
222 10         23 $opts{to_pipe} = \$to_string_pipe;
223 10         25 $opts{wait_child} = 1;
224             }
225 133939 100       416116 if ($opts{error_to_string}) {
226 133907         595115 $opts{error_to_pipe} = \$error_to_string_pipe;
227 133907         360949 $opts{wait_child} = 1;
228             }
229 133939 100       471245 if ($opts{from_string}) {
230 5         10 $opts{from_pipe} = \$from_string_pipe;
231             }
232             # Create pipes if needed
233 133939         271917 my ($input_pipe, $output_pipe, $error_pipe);
234 133939 100       430491 if ($opts{from_pipe}) {
235 18 50       918 pipe($opts{from_handle}, $input_pipe)
236             or syserr(g_('pipe for %s'), "@prog");
237 18         62 ${$opts{from_pipe}} = $input_pipe;
  18         61  
238 18         42 push @{$opts{close_in_child}}, $input_pipe;
  18         79  
239             }
240 133939 100       468236 if ($opts{to_pipe}) {
241             pipe($output_pipe, $opts{to_handle})
242 19 50       780 or syserr(g_('pipe for %s'), "@prog");
243 19         58 ${$opts{to_pipe}} = $output_pipe;
  19         69  
244 19         38 push @{$opts{close_in_child}}, $output_pipe;
  19         64  
245             }
246 133939 100       376821 if ($opts{error_to_pipe}) {
247             pipe($error_pipe, $opts{error_to_handle})
248 133907 50       6750731 or syserr(g_('pipe for %s'), "@prog");
249 133907         481903 ${$opts{error_to_pipe}} = $error_pipe;
  133907         1155828  
250 133907         438447 push @{$opts{close_in_child}}, $error_pipe;
  133907         506100  
251             }
252             # Fork and exec
253 133939         115721644 my $pid = fork();
254 133939 50       3376459 syserr(g_('cannot fork for %s'), "@prog") unless defined $pid;
255 133939 100       483906 if (not $pid) {
256             # Define environment variables
257 528 100       50906 if ($opts{env}) {
258 2         26 foreach (keys %{$opts{env}}) {
  2         163  
259 6         268 $ENV{$_} = $opts{env}{$_};
260             }
261             }
262 528 100       14367 if ($opts{delete_env}) {
263 2         5 delete $ENV{$_} foreach (@{$opts{delete_env}});
  2         93  
264             }
265             # Define signal dispositions.
266 528 50       13024 if ($opts{sig}) {
267 0         0 foreach (keys %{$opts{sig}}) {
  0         0  
268 0         0 $SIG{$_} = $opts{sig}{$_};
269             }
270             }
271 528 50       17122 if ($opts{delete_sig}) {
272 0         0 delete $SIG{$_} foreach (@{$opts{delete_sig}});
  0         0  
273             }
274             # Change the current directory
275 528 100       5233 if ($opts{chdir}) {
276 2 50       212 chdir($opts{chdir}) or syserr(g_('chdir to %s'), $opts{chdir});
277             }
278             # Redirect STDIN if needed
279 528 100       29977 if ($opts{from_file}) {
    100          
280             open(STDIN, '<', $opts{from_file})
281 3 50       542 or syserr(g_('cannot open %s'), $opts{from_file});
282             } elsif ($opts{from_handle}) {
283             open(STDIN, '<&', $opts{from_handle})
284 8 50       1194 or syserr(g_('reopen stdin'));
285             # has been duped, can be closed
286 8         84 push @{$opts{close_in_child}}, $opts{from_handle};
  8         11604  
287             }
288             # Redirect STDOUT if needed
289 528 100       23548 if ($opts{to_file}) {
    100          
290             open(STDOUT, '>', $opts{to_file})
291 3 50       280 or syserr(g_('cannot write %s'), $opts{to_file});
292             } elsif ($opts{to_handle}) {
293             open(STDOUT, '>&', $opts{to_handle})
294 8 50       473 or syserr(g_('reopen stdout'));
295             # has been duped, can be closed
296 8         151 push @{$opts{close_in_child}}, $opts{to_handle};
  8         76  
297             }
298             # Redirect STDERR if needed
299 528 50       13008 if ($opts{error_to_file}) {
    100          
300             open(STDERR, '>', $opts{error_to_file})
301 0 0       0 or syserr(g_('cannot write %s'), $opts{error_to_file});
302             } elsif ($opts{error_to_handle}) {
303             open(STDERR, '>&', $opts{error_to_handle})
304 518 50       79813 or syserr(g_('reopen stdout'));
305             # has been duped, can be closed
306 518         2038 push @{$opts{close_in_child}}, $opts{error_to_handle};
  518         16982  
307             }
308             # Close some inherited filehandles
309 528         2372 close($_) foreach (@{$opts{close_in_child}});
  528         21855  
310             # Execute the program
311 528 0       2520 exec({ $prog[0] } @prog) or syserr(g_('unable to execute %s'), "@prog");
  528         0  
312             }
313             # Close handle that we can't use any more
314 133411 100       515286 close($opts{from_handle}) if exists $opts{from_handle};
315 133411 100       425244 close($opts{to_handle}) if exists $opts{to_handle};
316 133411 100       6433559 close($opts{error_to_handle}) if exists $opts{error_to_handle};
317              
318 133411 100       631417 if ($opts{from_string}) {
319 4         76 print { $from_string_pipe } ${$opts{from_string}};
  4         88  
  4         112  
320 4         100 close($from_string_pipe);
321             }
322 133411 100       511187 if ($opts{to_string}) {
323 7         324 local $/ = undef;
324 7         441 ${$opts{to_string}} = readline($to_string_pipe);
  7         4897416  
325             }
326 133411 100       2604740 if ($opts{error_to_string}) {
327 133389         6843115 local $/ = undef;
328 133389         361696 ${$opts{error_to_string}} = readline($error_to_string_pipe);
  133389         116860515296  
329             }
330 133411 100       2061166 if ($opts{wait_child}) {
331 133396         2550376 my $cmdline = "@prog";
332 133396 100       795531 if ($opts{env}) {
333 3         12 foreach (keys %{$opts{env}}) {
  3         50  
334 9         64 $cmdline = "$_=\"" . $opts{env}{$_} . "\" $cmdline";
335             }
336             }
337             wait_child($pid, nocheck => $opts{nocheck},
338 133396         5279278 timeout => $opts{timeout}, cmdline => $cmdline);
339 133395         13804071 return 1;
340             }
341              
342 15         2768 return $pid;
343             }
344              
345              
346             =item wait_child($pid, %opts)
347              
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.
352              
353             Options:
354              
355             =over 4
356              
357             =item cmdline
358              
359             String to identify the child process in error messages.
360             Defaults to "child process".
361              
362             =item nocheck
363              
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).
367              
368             =item timeout
369              
370             Set a maximum time to wait for the process, after that kill the process and
371             fail with an error message.
372              
373             =back
374              
375             =cut
376              
377             sub wait_child {
378 133411     133411 1 4893158 my ($pid, %opts) = @_;
379 133411   66     1091293 $opts{cmdline} //= g_('child process');
380 133411 50       516780 croak 'no PID set, cannot wait end of process' unless $pid;
381 133411         630355 eval {
382 133411     1   9773422 local $SIG{ALRM} = sub { die "alarm\n" };
  1         55  
383 133411 100       933539 alarm($opts{timeout}) if defined($opts{timeout});
384 133411 50       12855593 $pid == waitpid($pid, 0) or syserr(g_('wait for %s'), $opts{cmdline});
385 133410 100       3227287 alarm(0) if defined($opts{timeout});
386             };
387 133411 100       710661 if ($@) {
388 1 50       16 die $@ unless $@ eq "alarm\n";
389 1         57 kill 'TERM', $pid;
390             error(P_("%s didn't complete in %d second",
391             "%s didn't complete in %d seconds",
392             $opts{timeout}),
393 1         53 $opts{cmdline}, $opts{timeout});
394             }
395 133410 100       877496 unless ($opts{nocheck}) {
396 16 50       387 subprocerr($opts{cmdline}) if $?;
397             }
398             }
399              
400             1;
401             __END__