2015-01-15 06:51:17 +01:00
|
|
|
#!/usr/bin/perl
|
|
|
|
|
2021-07-11 00:00:22 +02:00
|
|
|
# SPDX-FileCopyrightText: 2021 Pragmatic Software <pragma78@gmail.com>
|
|
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
|
2019-06-13 06:35:04 +02:00
|
|
|
package _default;
|
|
|
|
|
2015-01-15 06:51:17 +01:00
|
|
|
use warnings;
|
|
|
|
use strict;
|
|
|
|
|
2019-06-13 06:35:04 +02:00
|
|
|
use IPC::Run qw/run timeout/;
|
2022-02-06 20:33:21 +01:00
|
|
|
|
2019-06-13 06:35:04 +02:00
|
|
|
use Data::Dumper;
|
2015-01-15 06:51:17 +01:00
|
|
|
|
2022-02-06 20:33:21 +01:00
|
|
|
$Data::Dumper::Terse = 1;
|
|
|
|
$Data::Dumper::Sortkeys = 1;
|
|
|
|
$Data::Dumper::Useqq = 1;
|
|
|
|
|
2015-01-15 06:51:17 +01:00
|
|
|
sub new {
|
2022-02-06 20:33:21 +01:00
|
|
|
my ($class, %conf) = @_;
|
|
|
|
my $self = bless {}, $class;
|
|
|
|
|
|
|
|
$self->{debug} = $conf{debug} // 0;
|
|
|
|
$self->{sourcefile} = $conf{sourcefile};
|
|
|
|
$self->{execfile} = $conf{execfile};
|
|
|
|
$self->{code} = $conf{code};
|
|
|
|
$self->{cmdline} = $conf{cmdline};
|
|
|
|
$self->{input} = $conf{input};
|
|
|
|
$self->{date} = $conf{date};
|
|
|
|
$self->{arguments} = $conf{arguments};
|
|
|
|
$self->{factoid} = $conf{factoid};
|
|
|
|
$self->{'persist-key'} = $conf{'persist-key'};
|
|
|
|
|
|
|
|
$self->initialize(%conf);
|
|
|
|
return $self;
|
2015-01-15 06:51:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sub initialize {
|
2022-02-06 20:33:21 +01:00
|
|
|
my ($self, %conf) = @_;
|
2015-01-15 06:51:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sub preprocess {
|
2022-02-06 20:33:21 +01:00
|
|
|
my $self = shift;
|
2015-01-15 06:51:17 +01:00
|
|
|
|
2022-02-06 20:33:21 +01:00
|
|
|
open(my $fh, '>', $self->{sourcefile}) or die $!;
|
|
|
|
binmode($fh, ':utf8');
|
|
|
|
print $fh $self->{code} . "\n";
|
|
|
|
close $fh;
|
2019-05-31 20:07:05 +02:00
|
|
|
|
2022-02-06 20:33:21 +01:00
|
|
|
my $quoted_args = '';
|
2019-05-31 20:07:05 +02:00
|
|
|
|
2022-02-06 20:33:21 +01:00
|
|
|
if (length $self->{arguments}) {
|
|
|
|
my @args = $self->split_line($self->{arguments}, strip_quotes => 1, preserve_escapes => 0);
|
2022-02-06 09:24:04 +01:00
|
|
|
|
2022-02-06 20:33:21 +01:00
|
|
|
foreach my $arg (@args) {
|
|
|
|
$arg =~ s/'/'"'"'/g;
|
|
|
|
$quoted_args .= "'$arg' ";
|
|
|
|
}
|
|
|
|
}
|
2022-02-06 09:24:04 +01:00
|
|
|
|
2022-02-06 20:33:21 +01:00
|
|
|
$self->{input} = "ulimit -f 2000; ulimit -t 8; ulimit -u 200; $self->{cmdline} $quoted_args";
|
2022-02-06 09:24:04 +01:00
|
|
|
|
2022-02-06 20:33:21 +01:00
|
|
|
my ($retval, $stdout, $stderr) = $self->execute(60, $self->{input}, '/bin/sh');
|
2022-02-06 09:24:04 +01:00
|
|
|
|
2022-02-06 20:33:21 +01:00
|
|
|
$self->{output} = $stderr;
|
|
|
|
$self->{output} .= ' ' if length $self->{output};
|
|
|
|
$self->{output} .= $stdout;
|
|
|
|
$self->{error} = $retval;
|
2015-01-15 06:51:17 +01:00
|
|
|
}
|
|
|
|
|
2022-02-06 20:33:21 +01:00
|
|
|
sub postprocess {}
|
2015-01-15 06:51:17 +01:00
|
|
|
|
|
|
|
sub execute {
|
2022-02-06 20:33:21 +01:00
|
|
|
my ($self, $timeout, $stdin, @cmdline) = @_;
|
2015-01-15 06:51:17 +01:00
|
|
|
|
2022-02-06 20:33:21 +01:00
|
|
|
$stdin //= '';
|
2015-01-15 06:51:17 +01:00
|
|
|
|
2022-02-13 01:06:04 +01:00
|
|
|
print STDERR "execute ($timeout) [$stdin] @cmdline\n";
|
2015-01-15 06:51:17 +01:00
|
|
|
|
2022-02-06 20:33:21 +01:00
|
|
|
my ($exitval, $stdout, $stderr) = eval {
|
|
|
|
my ($stdout, $stderr);
|
|
|
|
run \@cmdline, \$stdin, \$stdout, \$stderr, timeout($timeout);
|
|
|
|
my $exitval = $? >> 8;
|
|
|
|
return ($exitval, $stdout, $stderr);
|
|
|
|
};
|
2019-06-13 06:35:04 +02:00
|
|
|
|
2022-02-06 20:33:21 +01:00
|
|
|
if (my $exception = $@) {
|
|
|
|
$exception = "[Timed-out]" if $exception =~ m/timeout on timer/;
|
|
|
|
($exitval, $stdout, $stderr) = (-1, '', $exception);
|
|
|
|
}
|
|
|
|
|
|
|
|
$Data::Dumper::Indent = 0;
|
2022-02-13 01:06:04 +01:00
|
|
|
print STDERR "exitval $exitval stderr [", Dumper($stderr), "] stdout [", Dumper($stdout), "]\n";
|
2022-02-06 20:33:21 +01:00
|
|
|
$Data::Dumper::Indent = 1;
|
|
|
|
|
|
|
|
return ($exitval, $stdout, $stderr);
|
2019-06-13 06:35:04 +02:00
|
|
|
}
|
2015-01-15 06:51:17 +01:00
|
|
|
|
2019-06-26 08:21:15 +02:00
|
|
|
# splits line into quoted arguments while preserving quotes.
|
|
|
|
# a string is considered quoted only if they are surrounded by
|
|
|
|
# whitespace or json separators.
|
|
|
|
# handles unbalanced quotes gracefully by treating them as
|
|
|
|
# part of the argument they were found within.
|
2019-06-13 06:35:04 +02:00
|
|
|
sub split_line {
|
2022-02-06 20:33:21 +01:00
|
|
|
my ($self, $line, %opts) = @_;
|
|
|
|
|
|
|
|
my %default_opts = (
|
|
|
|
strip_quotes => 0,
|
|
|
|
keep_spaces => 0,
|
|
|
|
preserve_escapes => 1,
|
|
|
|
);
|
|
|
|
|
|
|
|
%opts = (%default_opts, %opts);
|
|
|
|
|
|
|
|
my @chars = split //, $line;
|
|
|
|
|
|
|
|
my @args;
|
|
|
|
my $escaped = 0;
|
|
|
|
my $quote;
|
|
|
|
my $token = '';
|
|
|
|
my $ch = ' ';
|
|
|
|
my $last_ch;
|
|
|
|
my $next_ch;
|
|
|
|
my $i = 0;
|
|
|
|
my $pos;
|
|
|
|
my $ignore_quote = 0;
|
|
|
|
my $spaces = 0;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
$last_ch = $ch;
|
|
|
|
|
|
|
|
if ($i >= @chars) {
|
|
|
|
if (defined $quote) {
|
|
|
|
# reached end, but unbalanced quote... reset to beginning of quote and ignore it
|
|
|
|
$i = $pos;
|
|
|
|
$ignore_quote = 1;
|
|
|
|
$quote = undef;
|
|
|
|
$last_ch = ' ';
|
|
|
|
$token = '';
|
|
|
|
} else {
|
|
|
|
# add final token and exit
|
|
|
|
push @args, $token if length $token;
|
|
|
|
last;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$ch = $chars[$i++];
|
|
|
|
$next_ch = $chars[$i];
|
|
|
|
|
|
|
|
$spaces = 0 if $ch ne ' ';
|
|
|
|
|
|
|
|
if ($escaped) {
|
|
|
|
if ($opts{preserve_escapes}) {
|
|
|
|
$token .= "\\$ch";
|
|
|
|
} else {
|
|
|
|
$token .= $ch;
|
|
|
|
}
|
|
|
|
$escaped = 0;
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($ch eq '\\') {
|
|
|
|
$escaped = 1;
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (defined $quote) {
|
|
|
|
if ($ch eq $quote and (not defined $next_ch or $next_ch =~ /[\s,:;})\].+=]/)) {
|
|
|
|
# closing quote
|
|
|
|
$token .= $ch unless $opts{strip_quotes};
|
|
|
|
push @args, $token;
|
|
|
|
$quote = undef;
|
|
|
|
$token = '';
|
|
|
|
} else {
|
|
|
|
# still within quoted argument
|
|
|
|
$token .= $ch;
|
|
|
|
}
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (($last_ch =~ /[\s:{(\[.+=]/) and not defined $quote and ($ch eq "'" or $ch eq '"')) {
|
|
|
|
if ($ignore_quote) {
|
|
|
|
# treat unbalanced quote as part of this argument
|
|
|
|
$token .= $ch;
|
|
|
|
$ignore_quote = 0;
|
|
|
|
} else {
|
|
|
|
# begin potential quoted argument
|
|
|
|
$pos = $i - 1;
|
|
|
|
$quote = $ch;
|
|
|
|
$token .= $ch unless $opts{strip_quotes};
|
|
|
|
}
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($ch eq ' ') {
|
|
|
|
if (++$spaces > 1 and $opts{keep_spaces}) {
|
|
|
|
$token .= $ch;
|
|
|
|
next;
|
|
|
|
} else {
|
|
|
|
push @args, $token if length $token;
|
|
|
|
$token = '';
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
}
|
2015-01-15 06:51:17 +01:00
|
|
|
|
2019-06-25 04:01:38 +02:00
|
|
|
$token .= $ch;
|
2015-01-15 06:51:17 +01:00
|
|
|
}
|
|
|
|
|
2022-02-06 20:33:21 +01:00
|
|
|
return @args;
|
2015-01-15 06:51:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
1;
|