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   297440 use strict;
  547         1684  
  547         16394  
21 547     547   2732 use warnings;
  547         568  
  547         26840  
22              
23             our $VERSION = '1.02';
24             our @EXPORT = qw(
25             spawn
26             wait_child
27             );
28              
29 547     547   2756 use Carp;
  547         1118  
  547         28674  
30 547     547   2823 use Exporter qw(import);
  547         812  
  547         13313  
31              
32 547     547   4933 use Dpkg::ErrorHandling;
  547         591  
  547         59168  
33 547     547   3924 use Dpkg::Gettext;
  547         1093  
  547         956514  
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   504531 my (%opts) = @_;
150              
151             croak 'exec parameter is mandatory in spawn()'
152 133939 50       605209 unless $opts{exec};
153              
154 133939         391164 my $to = my $error_to = my $from = 0;
155 133939         389506 foreach my $thing (qw(file handle string pipe)) {
156 535756 100       1549700 $to++ if $opts{"to_$thing"};
157 535756 100       1336929 $error_to++ if $opts{"error_to_$thing"};
158 535756 100       1357258 $from++ if $opts{"from_$thing"};
159             }
160 133939 50       428583 croak 'not more than one of to_* parameters is allowed'
161             if $to > 1;
162 133939 50       369289 croak 'not more than one of error_to_* parameters is allowed'
163             if $error_to > 1;
164 133939 50       497838 croak 'not more than one of from_* parameters is allowed'
165             if $from > 1;
166              
167 133939         393419 foreach my $param (qw(to_string error_to_string from_string)) {
168 401817 50 33     3273957 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         439189 foreach my $param (qw(to_pipe error_to_pipe from_pipe)) {
175 401817 50 33     1046021 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     525890 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     475380 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     1314249 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     599145 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     464066 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         450532 return %opts;
205             }
206              
207             sub spawn {
208 133939     133939 1 987754 my (%opts) = @_;
209 133939         275046 my @prog;
210              
211 133939         813773 _sanity_check_opts(%opts);
212 133939   50     2123758 $opts{close_in_child} //= [];
213 133939 100       2780790 if (ref($opts{exec}) =~ /ARRAY/) {
    50          
214 133927         453098 push @prog, @{$opts{exec}};
  133927         683843  
215             } elsif (not ref($opts{exec})) {
216 12         36 push @prog, $opts{exec};
217             } else {
218 0         0 croak 'invalid exec parameter in spawn()';
219             }
220 133939         379099 my ($from_string_pipe, $to_string_pipe, $error_to_string_pipe);
221 133939 100       3624559 if ($opts{to_string}) {
222 10         32 $opts{to_pipe} = \$to_string_pipe;
223 10         33 $opts{wait_child} = 1;
224             }
225 133939 100       463908 if ($opts{error_to_string}) {
226 133907         487042 $opts{error_to_pipe} = \$error_to_string_pipe;
227 133907         305398 $opts{wait_child} = 1;
228             }
229 133939 100       450048 if ($opts{from_string}) {
230 5         5 $opts{from_pipe} = \$from_string_pipe;
231             }
232             # Create pipes if needed
233 133939         357173 my ($input_pipe, $output_pipe, $error_pipe);
234 133939 100       349312 if ($opts{from_pipe}) {
235 18 50       840 pipe($opts{from_handle}, $input_pipe)
236             or syserr(g_('pipe for %s'), "@prog");
237 18         70 ${$opts{from_pipe}} = $input_pipe;
  18         84  
238 18         33 push @{$opts{close_in_child}}, $input_pipe;
  18         59  
239             }
240 133939 100       404176 if ($opts{to_pipe}) {
241             pipe($output_pipe, $opts{to_handle})
242 19 50       1467 or syserr(g_('pipe for %s'), "@prog");
243 19         59 ${$opts{to_pipe}} = $output_pipe;
  19         69  
244 19         39 push @{$opts{close_in_child}}, $output_pipe;
  19         73  
245             }
246 133939 100       313519 if ($opts{error_to_pipe}) {
247             pipe($error_pipe, $opts{error_to_handle})
248 133907 50       7222496 or syserr(g_('pipe for %s'), "@prog");
249 133907         534589 ${$opts{error_to_pipe}} = $error_pipe;
  133907         508396  
250 133907         1092452 push @{$opts{close_in_child}}, $error_pipe;
  133907         520383  
251             }
252             # Fork and exec
253 133939         122549990 my $pid = fork();
254 133939 50       2665584 syserr(g_('cannot fork for %s'), "@prog") unless defined $pid;
255 133939 100       394592 if (not $pid) {
256             # Define environment variables
257 528 100       55342 if ($opts{env}) {
258 2         13 foreach (keys %{$opts{env}}) {
  2         139  
259 6         243 $ENV{$_} = $opts{env}{$_};
260             }
261             }
262 528 100       21699 if ($opts{delete_env}) {
263 2         33 delete $ENV{$_} foreach (@{$opts{delete_env}});
  2         81  
264             }
265             # Define signal dispositions.
266 528 50       21671 if ($opts{sig}) {
267 0         0 foreach (keys %{$opts{sig}}) {
  0         0  
268 0         0 $SIG{$_} = $opts{sig}{$_};
269             }
270             }
271 528 50       12429 if ($opts{delete_sig}) {
272 0         0 delete $SIG{$_} foreach (@{$opts{delete_sig}});
  0         0  
273             }
274             # Change the current directory
275 528 100       14386 if ($opts{chdir}) {
276 2 50       236 chdir($opts{chdir}) or syserr(g_('chdir to %s'), $opts{chdir});
277             }
278             # Redirect STDIN if needed
279 528 100       20930 if ($opts{from_file}) {
    100          
280             open(STDIN, '<', $opts{from_file})
281 3 50       544 or syserr(g_('cannot open %s'), $opts{from_file});
282             } elsif ($opts{from_handle}) {
283             open(STDIN, '<&', $opts{from_handle})
284 8 50       1229 or syserr(g_('reopen stdin'));
285             # has been duped, can be closed
286 8         12708 push @{$opts{close_in_child}}, $opts{from_handle};
  8         200  
287             }
288             # Redirect STDOUT if needed
289 528 100       17146 if ($opts{to_file}) {
    100          
290             open(STDOUT, '>', $opts{to_file})
291 3 50       323 or syserr(g_('cannot write %s'), $opts{to_file});
292             } elsif ($opts{to_handle}) {
293             open(STDOUT, '>&', $opts{to_handle})
294 8 50       480 or syserr(g_('reopen stdout'));
295             # has been duped, can be closed
296 8         101 push @{$opts{close_in_child}}, $opts{to_handle};
  8         65  
297             }
298             # Redirect STDERR if needed
299 528 50       20235 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       94688 or syserr(g_('reopen stdout'));
305             # has been duped, can be closed
306 518         6941 push @{$opts{close_in_child}}, $opts{error_to_handle};
  518         13169  
307             }
308             # Close some inherited filehandles
309 528         2588 close($_) foreach (@{$opts{close_in_child}});
  528         22583  
310             # Execute the program
311 528 0       6902 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       527453 close($opts{from_handle}) if exists $opts{from_handle};
315 133411 100       487138 close($opts{to_handle}) if exists $opts{to_handle};
316 133411 100       6715962 close($opts{error_to_handle}) if exists $opts{error_to_handle};
317              
318 133411 100       670404 if ($opts{from_string}) {
319 4         60 print { $from_string_pipe } ${$opts{from_string}};
  4         88  
  4         84  
320 4         76 close($from_string_pipe);
321             }
322 133411 100       412784 if ($opts{to_string}) {
323 7         344 local $/ = undef;
324 7         441 ${$opts{to_string}} = readline($to_string_pipe);
  7         4913782  
325             }
326 133411 100       2861957 if ($opts{error_to_string}) {
327 133389         10682756 local $/ = undef;
328 133389         448126 ${$opts{error_to_string}} = readline($error_to_string_pipe);
  133389         112481985559  
329             }
330 133411 100       2260935 if ($opts{wait_child}) {
331 133396         2870288 my $cmdline = "@prog";
332 133396 100       1028801 if ($opts{env}) {
333 3         13 foreach (keys %{$opts{env}}) {
  3         68  
334 9         74 $cmdline = "$_=\"" . $opts{env}{$_} . "\" $cmdline";
335             }
336             }
337             wait_child($pid, nocheck => $opts{nocheck},
338 133396         5221186 timeout => $opts{timeout}, cmdline => $cmdline);
339 133395         15612659 return 1;
340             }
341              
342 15         2999 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 5917961 my ($pid, %opts) = @_;
379 133411   66     945539 $opts{cmdline} //= g_('child process');
380 133411 50       607248 croak 'no PID set, cannot wait end of process' unless $pid;
381 133411         790840 eval {
382 133411     1   9717221 local $SIG{ALRM} = sub { die "alarm\n" };
  1         73  
383 133411 100       858954 alarm($opts{timeout}) if defined($opts{timeout});
384 133411 50       13060078 $pid == waitpid($pid, 0) or syserr(g_('wait for %s'), $opts{cmdline});
385 133410 100       3194501 alarm(0) if defined($opts{timeout});
386             };
387 133411 100       796894 if ($@) {
388 1 50       29 die $@ unless $@ eq "alarm\n";
389 1         73 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         56 $opts{cmdline}, $opts{timeout});
394             }
395 133410 100       936981 unless ($opts{nocheck}) {
396 16 50       337 subprocerr($opts{cmdline}) if $?;
397             }
398             }
399              
400             1;
401             __END__