mirror of
https://github.com/pragma-/pbot.git
synced 2024-12-23 11:12:42 +01:00
755d7bd6c0
general.debugcontext: filter out cmdlist and arglist Core/Applets: log applet start/stop and duration Core/ProcessManager: fix potential race-condition with $context object Core/Interpreter: * expand pronouns before command-substitution * attempt to find current channel's factoid instance for metadata * remove duplication of command history in command-substition * terminate pipe/substitution processing when protecting self Core/Factoids: limit -url contents to 250kb
144 lines
3.8 KiB
Perl
144 lines
3.8 KiB
Perl
# File: ProcessManager.pm
|
|
#
|
|
# Purpose: Registers commands for listing and killing running PBot processes.
|
|
|
|
# SPDX-FileCopyrightText: 2020-2023 Pragmatic Software <pragma78@gmail.com>
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
package PBot::Core::Commands::ProcessManager;
|
|
|
|
use PBot::Imports;
|
|
use parent 'PBot::Core::Class';
|
|
|
|
use Time::Duration qw/concise duration/;
|
|
use Time::HiRes qw/gettimeofday/;
|
|
|
|
sub initialize($self, %conf) {
|
|
# process manager bot commands
|
|
$self->{pbot}->{commands}->register(sub { $self->cmd_ps(@_) }, 'ps', 0);
|
|
$self->{pbot}->{commands}->register(sub { $self->cmd_kill(@_) }, 'kill', 1);
|
|
|
|
# give admin capability group the can-kill capability
|
|
$self->{pbot}->{capabilities}->add('admin', 'can-kill', 1);
|
|
}
|
|
|
|
sub cmd_ps($self, $context) {
|
|
my $usage = 'Usage: ps [-atu]; -a show all information; -t show running time; -u show user/channel';
|
|
|
|
my ($show_all, $show_user, $show_running_time);
|
|
|
|
my %opts = (
|
|
all => \$show_all,
|
|
user => \$show_user,
|
|
time => \$show_running_time,
|
|
);
|
|
|
|
my ($opt_args, $opt_error) = $self->{pbot}->{interpreter}->getopt(
|
|
$context->{arguments},
|
|
\%opts,
|
|
['bundling'],
|
|
'all|a',
|
|
'user|u',
|
|
'time|t',
|
|
);
|
|
|
|
return "$opt_error; $usage" if defined $opt_error;
|
|
|
|
my @processes;
|
|
|
|
foreach my $pid (sort keys %{$self->{pbot}->{process_manager}->{processes}}) {
|
|
push @processes, $self->{pbot}->{process_manager}->{processes}->{$pid};
|
|
}
|
|
|
|
if (not @processes) {
|
|
return "No running processes.";
|
|
}
|
|
|
|
my $result = @processes == 1 ? 'One process: ' : @processes . ' processes: ';
|
|
|
|
my @entries;
|
|
|
|
foreach my $process (@processes) {
|
|
my $entry = "$process->{pid}: $process->{command}";
|
|
|
|
if ($show_running_time or $show_all) {
|
|
my $duration = concise duration (gettimeofday - $process->{start});
|
|
$entry .= " [$duration]";
|
|
}
|
|
|
|
if ($show_user or $show_all) {
|
|
$entry .= " ($process->{nick} in $process->{from})";
|
|
}
|
|
|
|
push @entries, $entry;
|
|
}
|
|
|
|
$result .= join '; ', @entries;
|
|
|
|
return $result;
|
|
}
|
|
|
|
sub cmd_kill($self, $context) {
|
|
my $usage = 'Usage: kill [-a] [-t <seconds>] [-s <signal>] [pids...]; -a kill all processes; -t <seconds> kill processes running longer than <seconds>; -s send <signal> to processes';
|
|
|
|
my ($kill_all, $kill_time, $signal);
|
|
|
|
my %opts = (
|
|
all => \$kill_all,
|
|
time => \$kill_time,
|
|
signal => \$signal,
|
|
);
|
|
|
|
my ($opt_args, $opt_error) = $self->{pbot}->{interpreter}->getopt(
|
|
$context->{arguments},
|
|
\%opts,
|
|
['bundling'],
|
|
'all|a',
|
|
'time|t=i',
|
|
'signal|s=s',
|
|
);
|
|
|
|
return "$opt_error; $usage" if defined $opt_error;
|
|
|
|
if (not $kill_all and not $kill_time and not @$opt_args) {
|
|
return "Must specify PIDs to kill unless options -a or -t are provided.";
|
|
}
|
|
|
|
if (defined $signal) {
|
|
$signal = uc $signal;
|
|
} else {
|
|
$signal = 'INT';
|
|
}
|
|
|
|
my @pids;
|
|
|
|
if (defined $kill_all or defined $kill_time) {
|
|
my $now = time;
|
|
|
|
foreach my $pid (sort keys %{$self->{pbot}->{process_manager}->{processes}}) {
|
|
my $process = $self->{pbot}->{process_manager}->{processes}->{$pid};
|
|
next if defined $kill_time and $now - $process->{start} < $kill_time;
|
|
push @pids, $pid;
|
|
}
|
|
} else {
|
|
foreach my $pid (@$opt_args) {
|
|
return "No such pid $pid." if not exists $self->{pbot}->{process_manager}->{processes}->{$pid};
|
|
push @pids, $pid;
|
|
}
|
|
}
|
|
|
|
return "No matching process." if not @pids;
|
|
|
|
my $ret = eval { kill $signal, @pids };
|
|
|
|
if ($@) {
|
|
my $error = $@;
|
|
$error =~ s/ at PBot.*//;
|
|
return $error;
|
|
}
|
|
|
|
return "[$ret] Sent signal " . $signal . ' to ' . join ', ', @pids;
|
|
}
|
|
|
|
1;
|