This file is indexed.

/usr/share/perl5/Lintian/Command/Simple.pm is in lintian 2.5.43.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# Copyright (C) 2010 Raphael Geissert <atomo64@gmail.com>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program.  If not, see <http://www.gnu.org/licenses/>.

package Lintian::Command::Simple;

use strict;
use warnings;
use autodie qw(open close chdir);

use Exporter qw(import);
use POSIX qw(:sys_wait_h);

our @EXPORT_OK = qw(rundir background wait_any kill_all);

=head1 NAME

Lintian::Command::Simple - Run commands without pipes

=head1 SYNOPSIS

    use Lintian::Command::Simple qw(background rundir);

    Lintian::Command::Simple::rundir ('./some-dir/', 'echo', 'hello world');

    # Start a command in the background:
    Lintian::Command::Simple::background('sleep', 10);
    print wait() > 0 ? 'success' : 'failure';


=head1 DESCRIPTION

Lintian::Command::Simple allows running commands with the capability of
running them "in the background" (asynchronously.)

Pipes are not handled at all, except for those handled internally by
the shell. See 'perldoc -f exec's note about shell metacharacters.
If you want to pipe to/from Perl, look at Lintian::Command instead.

=over 4

=item rundir(dir, command, argument  [, ...])

Executes the given C<command> with the given arguments and in C<dir>
returns the status code as one would see it from a shell script.

Being fair, the only advantage of this function over the
CORE::system() function is the way the return status is reported
and the chdir support.

=cut

sub rundir {
    my $pid;
    my $res;

    $pid = fork();
    if (not defined($pid)) {
        # failed
        $res = -1;
    } elsif ($pid > 0) {
        # parent
        waitpid($pid, 0);
        $res = $? >> 8;
    } else {
        # child
        my $dir = shift;
        close(STDIN);
        open(STDIN, '<', '/dev/null');
        chdir($dir);
        CORE::exec @_ or die("Failed to exec '$_[0]': $!\n");
    }

    return $res;
}

=item background(command, argument  [, ...])

Executes the given C<command> with the given arguments asynchronously
and returns the process id of the child process.

A return value of -1 indicates an error. This can either be a problem
when calling CORE::fork() or when trying to run another command before
calling wait() to reap the previous command.

=cut

sub background {
    my $pid = fork();

    if (not defined($pid)) {
        # failed
        return -1;
    } elsif ($pid > 0) {
        # parent
        return $pid;
    } else {
        # child
        close(STDIN);
        open(STDIN, '<', '/dev/null');

        CORE::exec @_ or die("Failed to exec '$_[0]': $!\n");
    }
}

=item wait_any (hashref[, nohang])

When starting multiple processes asynchronously, it is common to wait
until the first is done. While the CORE::wait() function is usually
used for that very purpose, it does not provide the desired results
when the processes were started via the OO interface.

To help with this task, wait_any() can take a hash ref where the key
of each entry is the pid of that command.  There are no requirements
for the value (which can be used for any application specific
purpose).

Under this mode, wait_any() waits until any child process is done.
The key (and value) associated the pid of the reaped child will then
be removed from the hashref.  The exitcode of the child is available
via C<$?> as usual.

The results and return value are undefined when under this mode
wait_any() "accidentally" reaps a process not listed in the hashref.

The return value in scalar context is value associated with the pid of
the reaped processed.  In list context, the pid and value are returned
as a pair.

Whenever waitpid() would return -1, wait_any() returns undef or a null
value so that it is safe to:

    while($cmd = wait_any(\%hash)) { something; }

The same is true whenever the hash reference points to an empty hash.

If C<nohang> is also given, wait_any will attempt to reap any child
process non-blockingly.  If no child can be reaped, it will
immediately return (like there were no more processes left) instead of
waiting.

=cut

sub wait_any {
    my ($jobs, $nohang) = @_;
    my $reaped_pid;
    my $extra;

    $nohang = WNOHANG if $nohang;
    $nohang //= 0;

    return unless scalar keys %$jobs;

    $reaped_pid = waitpid(-1, $nohang);

    if ($reaped_pid == -1 or ($nohang and $reaped_pid == 0)) {
        return;
    }

    # Did we reap some other pid?
    return unless exists $jobs->{$reaped_pid};

    $extra = delete $jobs->{$reaped_pid};
    return ($reaped_pid, $extra) if wantarray;
    return $extra;
}

=item kill_all(hashref[, signal])

In a similar way to wait_any(), it is possible to pass a hash
reference to kill_all().  It will then kill all of the processes
(default signal being "TERM") followed by a reaping of the processes.
All reaped processes (and their values) will be removed from the set.

Any entries remaining in the hashref are processes that did not
terminate (or did not terminate yet).

=cut

sub kill_all {
    my ($jobs, $signal) = @_;
    my $count = 0;
    my @jobs;

    $signal //= 'TERM';

    foreach my $pid (keys %$jobs) {
        push @jobs, $pid if kill $signal, $pid;
    }

    foreach my $pid (@jobs) {
        if (waitpid($pid, 0) == $pid) {
            $count++;
            delete $jobs->{$pid};
        }
    }

    return scalar @jobs;
}

1;

__END__

=back

=head1 TODO

Provide the necessary methods to modify the environment variables of
the to-be-executed commands.  This would let us drop C<system_env> (from
Lintian::Util) and make C<run> more useful.

=head1 NOTES

Unless specified by prefixing the package name, every reference to a
function/method in this documentation refers to the functions/methods
provided by this package itself.

=head1 CAVEATS

Combining asynchronous jobs (e.g. via Lintian::Command) and calls to
wait_any() can lead to unexpected results.

=head1 AUTHOR

Originally written by Raphael Geissert <atomo64@gmail.com> for Lintian.

=cut

# Local Variables:
# indent-tabs-mode: nil
# cperl-indent-level: 4
# End:
# vim: syntax=perl sw=4 sts=4 sr et