| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#!perl |
|
2
|
7
|
|
|
7
|
|
35484
|
use strict; |
|
|
7
|
|
|
|
|
13
|
|
|
|
7
|
|
|
|
|
280
|
|
|
3
|
7
|
|
|
7
|
|
35
|
use warnings; |
|
|
7
|
|
|
|
|
11
|
|
|
|
7
|
|
|
|
|
412
|
|
|
4
|
|
|
|
|
|
|
|
|
5
|
7
|
|
|
7
|
|
3214
|
use App::RunStopRun; |
|
|
7
|
|
|
|
|
20
|
|
|
|
7
|
|
|
|
|
264
|
|
|
6
|
7
|
|
|
7
|
|
39
|
use Config; |
|
|
7
|
|
|
|
|
16
|
|
|
|
7
|
|
|
|
|
327
|
|
|
7
|
7
|
|
|
7
|
|
41
|
use File::Spec; |
|
|
7
|
|
|
|
|
11
|
|
|
|
7
|
|
|
|
|
204
|
|
|
8
|
7
|
|
|
7
|
|
5372
|
use Getopt::Long qw(:config bundling no_ignore_case require_order); |
|
|
7
|
|
|
|
|
123598
|
|
|
|
7
|
|
|
|
|
61
|
|
|
9
|
7
|
|
|
7
|
|
5558
|
use IO::Pty; |
|
|
7
|
|
|
|
|
197569
|
|
|
|
7
|
|
|
|
|
759
|
|
|
10
|
7
|
|
|
7
|
|
121
|
use List::Util qw(first uniq); |
|
|
7
|
|
|
|
|
15
|
|
|
|
7
|
|
|
|
|
1367
|
|
|
11
|
7
|
|
|
7
|
|
55
|
use POSIX qw(:unistd_h :sys_wait_h); |
|
|
7
|
|
|
|
|
16
|
|
|
|
7
|
|
|
|
|
53
|
|
|
12
|
7
|
|
|
7
|
|
23073
|
use Pod::Usage; |
|
|
7
|
|
|
|
|
567848
|
|
|
|
7
|
|
|
|
|
1344
|
|
|
13
|
7
|
|
|
7
|
|
4237
|
use Proc::ProcessTable; |
|
|
7
|
|
|
|
|
45352
|
|
|
|
7
|
|
|
|
|
478
|
|
|
14
|
7
|
|
|
7
|
|
4222
|
use Time::HiRes qw(sleep); |
|
|
7
|
|
|
|
|
11591
|
|
|
|
7
|
|
|
|
|
51
|
|
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
# NOTE: docs claim getpgrp($PID) isn't portable. Also, the POSIX module |
|
17
|
|
|
|
|
|
|
# doesn't provide a separate interface for getpgid, though it's part of the |
|
18
|
|
|
|
|
|
|
# standard and used internally. |
|
19
|
|
|
|
|
|
|
use constant HAS_PORTABLE_GETPGRP => |
|
20
|
7
|
|
|
7
|
|
1356
|
!! grep defined, @Config{qw( d_getpgid d_bsdgetpgrp d_getpgrp2 )}; |
|
|
7
|
|
|
|
|
16
|
|
|
|
7
|
|
|
|
|
36707
|
|
|
21
|
|
|
|
|
|
|
|
|
22
|
7
|
|
|
|
|
1219959
|
my $filename = (File::Spec->splitpath(__FILE__))[-1]; |
|
23
|
7
|
|
|
|
|
74
|
my @option = ( |
|
24
|
|
|
|
|
|
|
'verbose|v' => \my $verbose, |
|
25
|
|
|
|
|
|
|
'dry-run|n' => \my $dryrun, |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
'limit|l=f' => \my $limit, |
|
28
|
|
|
|
|
|
|
'pid|p=s' => \my @pid, |
|
29
|
|
|
|
|
|
|
'run|r=f' => \my $run, |
|
30
|
|
|
|
|
|
|
'stop|s=f' => \my $stop, |
|
31
|
|
|
|
|
|
|
'group|g' => \my $group, |
|
32
|
|
|
|
|
|
|
'nogroup|no-group|G' => \my $nogroup, |
|
33
|
|
|
|
|
|
|
'children|c' => \my $children, |
|
34
|
|
|
|
|
|
|
'notty|no-tty|T' => \my $notty, |
|
35
|
|
|
|
|
|
|
'tty|t+' => \my $tty, |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
'version|V' => \my $version, |
|
38
|
|
|
|
|
|
|
'help|h' => \my $help, |
|
39
|
|
|
|
|
|
|
'man|H' => \my $man, |
|
40
|
|
|
|
|
|
|
); |
|
41
|
7
|
|
|
|
|
23
|
my @getopt_msg; |
|
42
|
7
|
50
|
|
|
|
15
|
eval { |
|
43
|
7
|
|
|
0
|
|
89
|
local @SIG{qw(__DIE__ __WARN__)} = (sub { push @getopt_msg, $_[0] }) x 2; |
|
|
0
|
|
|
|
|
0
|
|
|
44
|
7
|
|
|
|
|
56
|
GetOptions(@option); |
|
45
|
|
|
|
|
|
|
} or usage(@getopt_msg); |
|
46
|
7
|
|
|
|
|
11392
|
@pid = uniq split /,/, join ',', @pid; |
|
47
|
|
|
|
|
|
|
|
|
48
|
7
|
50
|
|
|
|
27
|
usage() if $help; |
|
49
|
7
|
50
|
|
|
|
20
|
exit printf "$filename $App::RunStopRun::VERSION\n" if $version; |
|
50
|
7
|
50
|
|
|
|
19
|
pod2usage(-exitval => 0, -verbose => 2) if $man; |
|
51
|
7
|
50
|
33
|
|
|
45
|
usage('Missing command or PIDs') unless @pid or @ARGV; |
|
52
|
7
|
50
|
33
|
|
|
36
|
usage("Can't use both command and PIDs") if @pid and @ARGV; |
|
53
|
7
|
0
|
0
|
|
|
25
|
if (my @bad = grep { ! /^-?\d+$/ or 1 >= abs or ! kill 0, $_ } @pid) { |
|
|
0
|
50
|
|
|
|
0
|
|
|
54
|
0
|
0
|
|
|
|
0
|
usage(sprintf "Bad PID%s: %s", 1 < @bad ? 's' : '', join ',', @bad); |
|
55
|
|
|
|
|
|
|
} |
|
56
|
7
|
50
|
33
|
|
|
27
|
usage('--run must be >0') if defined $run and 0 >= $run; |
|
57
|
7
|
50
|
33
|
|
|
28
|
usage('--stop must be >0') if defined $stop and 0 >= $stop; |
|
58
|
7
|
0
|
33
|
|
|
24
|
usage("Can't use --limit with both --run and --stop") |
|
|
|
|
33
|
|
|
|
|
|
59
|
|
|
|
|
|
|
if defined $limit and defined $run and defined $stop; |
|
60
|
7
|
50
|
|
|
|
24
|
if (defined $limit) { |
|
61
|
0
|
0
|
0
|
|
|
0
|
$limit *= 100 if $limit and 1 > $limit; |
|
62
|
0
|
0
|
0
|
|
|
0
|
usage('--limit must be between 1..99') if 1 > $limit or 99 < $limit; |
|
63
|
|
|
|
|
|
|
} |
|
64
|
|
|
|
|
|
|
|
|
65
|
7
|
|
50
|
|
|
33
|
$limit ||= 50; |
|
66
|
7
|
|
50
|
|
|
62
|
$run ||= 1; |
|
67
|
7
|
|
33
|
|
|
72
|
$stop ||= 100 * $run / $limit - $run; |
|
68
|
|
|
|
|
|
|
|
|
69
|
7
|
|
|
|
|
13
|
my $status = 0; |
|
70
|
7
|
|
|
|
|
13
|
my @kill; |
|
71
|
7
|
|
|
|
|
102
|
my $isfg = (getpgrp == tcgetpgrp STDIN_FILENO); |
|
72
|
7
|
100
|
|
|
|
24
|
if ($verbose) { |
|
73
|
2
|
|
|
|
|
154
|
warn "Controller PID: $$\n"; |
|
74
|
2
|
50
|
|
|
|
14
|
warn "Controller is in the foreground\n" if $isfg; |
|
75
|
|
|
|
|
|
|
} |
|
76
|
|
|
|
|
|
|
|
|
77
|
7
|
|
|
|
|
14
|
my $sigint; |
|
78
|
|
|
|
|
|
|
$SIG{INT} = $SIG{TERM} = sub { |
|
79
|
0
|
|
|
0
|
|
0
|
$sigint = shift; |
|
80
|
0
|
0
|
|
|
|
0
|
warn "Received SIG$sigint\n" if $verbose; |
|
81
|
|
|
|
|
|
|
# Ensure END block is run. |
|
82
|
0
|
|
|
|
|
0
|
exit; |
|
83
|
7
|
|
|
|
|
151
|
}; |
|
84
|
|
|
|
|
|
|
$SIG{USR1} = sub { |
|
85
|
0
|
|
|
0
|
|
0
|
my $pids = join ',', sort { $a <=> $b } @pid; |
|
|
0
|
|
|
|
|
0
|
|
|
86
|
0
|
0
|
|
|
|
0
|
my $info = sprintf "Invoked on PID%s: %s\n", 1 < @pid ? 's' : '', $pids; |
|
87
|
0
|
|
|
|
|
0
|
my $kill = join ',', sort { $a <=> $b } @kill; |
|
|
0
|
|
|
|
|
0
|
|
|
88
|
0
|
0
|
|
|
|
0
|
$info .= sprintf "Signals to PID%s: %s\n", 1 < @kill ? 's' : '', $kill |
|
|
|
0
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
if $pids ne $kill; |
|
90
|
0
|
|
|
|
|
0
|
warn $info; |
|
91
|
7
|
|
|
|
|
129
|
}; |
|
92
|
|
|
|
|
|
|
# SIGINFO isn't standard. |
|
93
|
7
|
50
|
|
|
|
37
|
$SIG{INFO} = $SIG{USR1} if exists $SIG{INFO}; |
|
94
|
|
|
|
|
|
|
|
|
95
|
7
|
|
|
|
|
85
|
my $table = Proc::ProcessTable->new; |
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
# TODO: if ptrace is available, it might be possible to attach to the process |
|
98
|
|
|
|
|
|
|
# to do something with the file descriptors. |
|
99
|
7
|
50
|
|
|
|
9991
|
if (@pid) { |
|
100
|
0
|
|
|
|
|
0
|
@kill = get_kill_list(); |
|
101
|
0
|
0
|
|
|
|
0
|
exit printf "Would signal %s\n", join ',', @kill if $dryrun; |
|
102
|
0
|
|
|
|
|
0
|
run_stop_run() while kill 0, @kill; |
|
103
|
0
|
|
|
|
|
0
|
exit; |
|
104
|
|
|
|
|
|
|
} |
|
105
|
|
|
|
|
|
|
|
|
106
|
7
|
50
|
|
|
|
28
|
exit print "Would exec command: @ARGV\n" if $dryrun; |
|
107
|
|
|
|
|
|
|
|
|
108
|
7
|
50
|
|
|
|
280
|
pipe my ($parent_reader, $child_writer) or die "Can't pipe: $!"; |
|
109
|
|
|
|
|
|
|
|
|
110
|
7
|
|
|
|
|
25
|
my ($pty, $termios, $ttyfh); |
|
111
|
7
|
100
|
|
|
|
23
|
unless ($notty) { |
|
112
|
5
|
|
|
15
|
|
111
|
$ttyfh = first { isatty $_ } *STDIN, *STDERR, *STDOUT; |
|
|
15
|
|
|
|
|
2190
|
|
|
113
|
5
|
50
|
|
|
|
97
|
if (! $ttyfh) { |
|
114
|
5
|
100
|
|
|
|
145
|
warn "No attached terminal found\n" if $verbose; |
|
115
|
5
|
100
|
|
|
|
149
|
$tty = 0 if 1 == $tty; |
|
116
|
|
|
|
|
|
|
} |
|
117
|
0
|
|
0
|
|
|
0
|
else { $tty ||= 1 } |
|
118
|
5
|
50
|
|
|
|
25
|
if ($tty) { |
|
119
|
0
|
|
|
|
|
0
|
$pty = IO::Pty->new; |
|
120
|
0
|
0
|
|
|
|
0
|
warn sprintf "Opened pseudo-terminal: %s\n", $pty->ttyname if $verbose; |
|
121
|
0
|
0
|
|
|
|
0
|
if ($ttyfh) { |
|
122
|
0
|
0
|
|
|
|
0
|
warn sprintf "Using terminal attached to %s\n", |
|
123
|
|
|
|
|
|
|
[qw(STDIN STDERR STDOUT)]->[fileno $ttyfh] if $verbose; |
|
124
|
0
|
0
|
0
|
|
|
0
|
if (@ARGV and $isfg) { |
|
125
|
0
|
|
|
|
|
0
|
$termios = POSIX::Termios->new; |
|
126
|
0
|
0
|
|
|
|
0
|
$termios->getattr(fileno $ttyfh) or $termios = undef; |
|
127
|
|
|
|
|
|
|
} |
|
128
|
|
|
|
|
|
|
} |
|
129
|
|
|
|
|
|
|
} |
|
130
|
|
|
|
|
|
|
} |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
# Child |
|
133
|
7
|
100
|
|
|
|
16355
|
unless ($pid[0] = fork) { |
|
134
|
4
|
50
|
|
|
|
226
|
die "Can't fork: $!" unless defined $pid[0]; |
|
135
|
4
|
|
|
|
|
921
|
local @SIG{qw(INT TERM USR1)}; |
|
136
|
4
|
50
|
|
|
|
228
|
local $SIG{INFO} if exists $SIG{INFO}; |
|
137
|
|
|
|
|
|
|
|
|
138
|
4
|
|
|
|
|
230
|
close $parent_reader; |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
# Calls setsid(), so no need create a new process group with setpgrp(). |
|
141
|
4
|
50
|
|
|
|
251
|
if ($pty) { |
|
|
|
50
|
|
|
|
|
|
|
142
|
0
|
|
|
|
|
0
|
$pty->make_slave_controlling_terminal; |
|
143
|
0
|
|
|
|
|
0
|
my $slave = $pty->slave; |
|
144
|
0
|
|
|
|
|
0
|
close $pty; |
|
145
|
0
|
0
|
|
|
|
0
|
$slave->clone_winsize_from($ttyfh) if $ttyfh; |
|
146
|
0
|
|
|
|
|
0
|
$slave->set_raw; |
|
147
|
0
|
|
|
|
|
0
|
close $slave; |
|
148
|
|
|
|
|
|
|
} |
|
149
|
|
|
|
|
|
|
elsif (! $nogroup) { |
|
150
|
4
|
|
|
|
|
47
|
setpgrp; |
|
151
|
|
|
|
|
|
|
} |
|
152
|
|
|
|
|
|
|
|
|
153
|
4
|
|
|
|
|
155
|
syswrite $child_writer, "\0"; |
|
154
|
|
|
|
|
|
|
|
|
155
|
4
|
100
|
|
|
|
267
|
warn "Exec'ing command: @ARGV\n" if $verbose; |
|
156
|
4
|
0
|
|
|
|
41
|
exec { $ARGV[0] } @ARGV or exit $!; |
|
|
4
|
|
|
|
|
0
|
|
|
157
|
|
|
|
|
|
|
} |
|
158
|
|
|
|
|
|
|
|
|
159
|
3
|
|
|
|
|
195
|
close $child_writer; |
|
160
|
|
|
|
|
|
|
# Block until the child is ready. |
|
161
|
3
|
|
|
|
|
2135
|
sysread $parent_reader, my $ready, 1; |
|
162
|
3
|
|
|
|
|
143
|
close $parent_reader; |
|
163
|
|
|
|
|
|
|
|
|
164
|
3
|
50
|
|
|
|
89
|
if ($pty) { |
|
165
|
0
|
|
|
|
|
0
|
$pty->close_slave; |
|
166
|
0
|
|
|
|
|
0
|
$pty->set_raw; |
|
167
|
|
|
|
|
|
|
} |
|
168
|
|
|
|
|
|
|
|
|
169
|
3
|
|
|
|
|
47
|
$group = ! $nogroup; |
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
$SIG{CHLD} = sub { |
|
172
|
3
|
|
|
3
|
|
115
|
local ($!, $?); |
|
173
|
3
|
100
|
|
|
|
81
|
warn "Received SIGCHLD\n" if $verbose; |
|
174
|
3
|
|
|
|
|
213
|
while (0 < (my $pid = waitpid -1, WNOHANG)) { |
|
175
|
3
|
50
|
|
|
|
70
|
$status = WIFEXITED($?) ? WEXITSTATUS($?) |
|
|
|
100
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
: WIFSIGNALED($?) ? WTERMSIG($?) : $? >> 8; |
|
177
|
3
|
100
|
|
|
|
131
|
warn "Reaped $pid; exit($status)\n" if $verbose; |
|
178
|
|
|
|
|
|
|
} |
|
179
|
3
|
|
|
|
|
402
|
}; |
|
180
|
|
|
|
|
|
|
$SIG{TSTP} = sub { |
|
181
|
0
|
|
|
0
|
|
0
|
@kill = get_kill_list(); |
|
182
|
0
|
0
|
|
|
|
0
|
warn sprintf "Sending SIGTSTP to %s\n", join ',', @kill, $$ if $verbose; |
|
183
|
0
|
|
|
|
|
0
|
kill $_ => @kill for qw(TSTP STOP); |
|
184
|
0
|
|
|
|
|
0
|
kill STOP => $$; |
|
185
|
3
|
|
|
|
|
167
|
}; |
|
186
|
|
|
|
|
|
|
$SIG{CONT} = sub { |
|
187
|
0
|
0
|
|
0
|
|
0
|
warn sprintf "Sending SIGCONT to %s\n", join ',', @kill if $verbose; |
|
188
|
0
|
|
|
|
|
0
|
kill CONT => @kill; |
|
189
|
3
|
|
|
|
|
195
|
}; |
|
190
|
|
|
|
|
|
|
$SIG{WINCH} = sub { |
|
191
|
0
|
0
|
|
0
|
|
0
|
$pty->slave->clone_winsize_from($ttyfh) if $ttyfh; |
|
192
|
0
|
0
|
|
|
|
0
|
warn sprintf "Sending SIGWINCH to %s\n", join ',', @kill if $verbose; |
|
193
|
0
|
|
|
|
|
0
|
kill WINCH => @kill; |
|
194
|
3
|
|
|
|
|
129
|
}; |
|
195
|
|
|
|
|
|
|
|
|
196
|
3
|
|
|
|
|
230
|
run_stop_run() until waitpid $pid[0], WNOHANG; |
|
197
|
|
|
|
|
|
|
|
|
198
|
3
|
|
|
|
|
567
|
exit $status; |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
END { |
|
202
|
3
|
50
|
|
3
|
|
21
|
return unless @pid; |
|
203
|
|
|
|
|
|
|
|
|
204
|
3
|
50
|
|
|
|
37
|
close $pty if $pty; |
|
205
|
|
|
|
|
|
|
|
|
206
|
3
|
50
|
|
|
|
74
|
if (@kill) { |
|
207
|
|
|
|
|
|
|
# Ensure the processes aren't left stopped. |
|
208
|
0
|
0
|
|
|
|
0
|
warn sprintf "Sending SIGCONT to %s\n", join ',', @kill if $verbose; |
|
209
|
0
|
|
|
|
|
0
|
kill CONT => @kill; |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
# Controller process is in the foreground. |
|
212
|
0
|
0
|
0
|
|
|
0
|
if (@ARGV and $isfg) { |
|
213
|
0
|
0
|
|
|
|
0
|
warn sprintf "Sending SIGTERM to %s\n", join ',', @pid if $verbose; |
|
214
|
0
|
|
|
|
|
0
|
kill TERM => @pid; |
|
215
|
|
|
|
|
|
|
} |
|
216
|
|
|
|
|
|
|
} |
|
217
|
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
# Restore terminal settings. |
|
219
|
3
|
50
|
|
|
|
88
|
$termios->setattr(fileno $ttyfh, &POSIX::TCSANOW) if $termios; |
|
220
|
|
|
|
|
|
|
|
|
221
|
3
|
50
|
|
|
|
|
if ($sigint) { |
|
222
|
0
|
0
|
|
|
|
|
warn "Sending SIG$sigint to self\n" if $verbose; |
|
223
|
0
|
|
|
|
|
|
local @SIG{qw(INT TERM)}; |
|
224
|
0
|
|
|
|
|
|
kill $sigint => $$; |
|
225
|
|
|
|
|
|
|
} |
|
226
|
|
|
|
|
|
|
} |
|
227
|
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
sub run_stop_run { |
|
230
|
3
|
|
|
3
|
|
2402261
|
sleep $run; |
|
231
|
3
|
50
|
|
|
|
118
|
@kill = get_kill_list() or return; |
|
232
|
0
|
0
|
|
|
|
0
|
warn sprintf "Sending SIGSTOP to %s\n", join ',', @kill if $verbose; |
|
233
|
0
|
0
|
|
|
|
0
|
kill STOP => @kill or return; |
|
234
|
0
|
|
|
|
|
0
|
sleep $stop; |
|
235
|
0
|
0
|
|
|
|
0
|
warn sprintf "Sending SIGCONT to %s\n", join ',', @kill if $verbose; |
|
236
|
0
|
0
|
|
|
|
0
|
kill CONT => @kill or return; |
|
237
|
|
|
|
|
|
|
} |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
sub get_kill_list { |
|
241
|
3
|
0
|
33
|
3
|
|
26
|
return @pid if ! $group and ! $children; |
|
242
|
3
|
|
|
|
|
25
|
my @p = @pid; |
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
# Generating the process table is slow- avoid if possible. The runtime of |
|
245
|
|
|
|
|
|
|
# Proc::ProcessTable is similar to that of running `ps` and parsing it's |
|
246
|
|
|
|
|
|
|
# output. |
|
247
|
3
|
50
|
|
|
|
42
|
if (HAS_PORTABLE_GETPGRP and ! $children) { |
|
248
|
3
|
|
|
|
|
11
|
my %g; |
|
249
|
3
|
|
|
|
|
30
|
for my $p (@p) { |
|
250
|
3
|
50
|
|
|
|
41
|
if (0 > $p) { $g{$p} = undef } |
|
|
0
|
|
|
|
|
0
|
|
|
251
|
|
|
|
|
|
|
else { |
|
252
|
3
|
|
|
|
|
18
|
my $g = getpgrp $p; |
|
253
|
3
|
50
|
|
|
|
25
|
$g{ 0 - $g } = undef if 1 < $g; |
|
254
|
|
|
|
|
|
|
} |
|
255
|
|
|
|
|
|
|
} |
|
256
|
3
|
|
|
|
|
33
|
@p = keys %g; |
|
257
|
|
|
|
|
|
|
} |
|
258
|
|
|
|
|
|
|
else { |
|
259
|
0
|
|
|
|
|
0
|
my (%group, %child); |
|
260
|
0
|
|
|
|
|
0
|
for my $p (@{ $table->table }) { |
|
|
0
|
|
|
|
|
0
|
|
|
261
|
0
|
|
|
|
|
0
|
$group{$p->pid} = $p->pgrp; |
|
262
|
|
|
|
|
|
|
|
|
263
|
0
|
|
|
|
|
0
|
push @{ $child{ $p->ppid } }, $p->pid; |
|
|
0
|
|
|
|
|
0
|
|
|
264
|
|
|
|
|
|
|
# Detached process. |
|
265
|
0
|
0
|
0
|
|
|
0
|
push @{ $child{ $p->pgrp } }, $p->pid |
|
|
0
|
|
|
|
|
0
|
|
|
266
|
|
|
|
|
|
|
if 1 == $p->ppid and $p->pid != $p->pgrp; |
|
267
|
|
|
|
|
|
|
} |
|
268
|
|
|
|
|
|
|
|
|
269
|
0
|
0
|
|
|
|
0
|
if ($children) { |
|
270
|
0
|
|
|
|
|
0
|
my %g; @g{ grep { 0 > $_ } @p } = (); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
271
|
0
|
|
|
|
|
0
|
my @c = @p; |
|
272
|
0
|
0
|
|
|
|
0
|
while (@c = map { @{ $child{$_} || [] } } @c) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
273
|
|
|
|
|
|
|
# Don't include members of any given process group. |
|
274
|
0
|
|
|
|
|
0
|
push @p, grep { ! exists $g{$_} } @c; |
|
|
0
|
|
|
|
|
0
|
|
|
275
|
|
|
|
|
|
|
} |
|
276
|
|
|
|
|
|
|
} |
|
277
|
|
|
|
|
|
|
|
|
278
|
0
|
0
|
0
|
|
|
0
|
if ($group and ! $nogroup) { |
|
279
|
0
|
0
|
|
|
|
0
|
my %m; @m{ map { my $g = $group{$_}; $g ? 0 - $g : $_ } @p } = (); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
280
|
0
|
|
|
|
|
0
|
@p = keys %m; |
|
281
|
|
|
|
|
|
|
} |
|
282
|
|
|
|
|
|
|
} |
|
283
|
|
|
|
|
|
|
|
|
284
|
3
|
|
|
|
|
48
|
return @p; |
|
285
|
|
|
|
|
|
|
} |
|
286
|
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
sub usage { |
|
289
|
0
|
0
|
|
0
|
|
0
|
my @msg = grep { defined and length } @_; |
|
|
0
|
|
|
|
|
0
|
|
|
290
|
0
|
|
|
|
|
0
|
@msg = map { split "\n" } @msg; |
|
|
0
|
|
|
|
|
0
|
|
|
291
|
0
|
|
|
|
|
0
|
warn "$filename: $_\n" for @msg; |
|
292
|
0
|
0
|
|
|
|
0
|
warn "\n" if @_; |
|
293
|
|
|
|
|
|
|
|
|
294
|
0
|
|
|
|
|
0
|
print <<" END_OF_USAGE"; |
|
295
|
|
|
|
|
|
|
Usage: |
|
296
|
|
|
|
|
|
|
$filename [options] command [arguments] |
|
297
|
|
|
|
|
|
|
$filename [options] -p PID[,-PGID,...] |
|
298
|
|
|
|
|
|
|
END_OF_USAGE |
|
299
|
|
|
|
|
|
|
|
|
300
|
0
|
0
|
|
|
|
0
|
print <<' END_OF_OPTIONS' unless @_; |
|
301
|
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
Options: |
|
303
|
|
|
|
|
|
|
-v, --verbose Be verbose |
|
304
|
|
|
|
|
|
|
-n, --dry-run Dry run, don't run command or send signals |
|
305
|
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
-l, --limit PERCENT Limit runtime to between 1..99 (default: 50.0) |
|
307
|
|
|
|
|
|
|
-r, --run SECONDS Run the process for SECONDS (default: 1.0) |
|
308
|
|
|
|
|
|
|
-s, --stop SECONDS Stop the process for SECONDS |
|
309
|
|
|
|
|
|
|
-p, --pid PIDS Operate on PIDS |
|
310
|
|
|
|
|
|
|
-c, --children Operate also on all child processes of the PIDs |
|
311
|
|
|
|
|
|
|
-g, --group Operate on the process groups of the PIDs |
|
312
|
|
|
|
|
|
|
-G --no-group Don't create a new process group or determine PGIDs |
|
313
|
|
|
|
|
|
|
-T, --no-tty Disable pseudo-terminal allocation |
|
314
|
|
|
|
|
|
|
-t, --tty Force pseudo-terminal allocation |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
-V --version Display the version number |
|
317
|
|
|
|
|
|
|
-h, --help Display this help message |
|
318
|
|
|
|
|
|
|
-H, --man Display the complete documentation |
|
319
|
|
|
|
|
|
|
END_OF_OPTIONS |
|
320
|
|
|
|
|
|
|
|
|
321
|
0
|
0
|
|
|
|
0
|
exit(@_ ? 2 : 0); |
|
322
|
|
|
|
|
|
|
} |
|
323
|
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
__END__ |