summaryrefslogtreecommitdiff
path: root/test/run
diff options
context:
space:
mode:
Diffstat (limited to 'test/run')
-rw-r--r--test/run193
1 files changed, 153 insertions, 40 deletions
diff --git a/test/run b/test/run
index 1b7287a..c4d017a 100644
--- a/test/run
+++ b/test/run
@@ -1,11 +1,23 @@
-#!/usr/bin/perl
+#!/usr/bin/perl -w -U
+
+#
+# Possible improvements:
+#
+# - distinguish stdout and stderr output
+# - add environment variable like assignments
+# - run up to a specific line
+# - resume at a specific line
+#
use strict;
use FileHandle;
-use POSIX qw(geteuid getegid isatty);
+use Getopt::Std;
+use POSIX qw(isatty setuid);
+use vars qw($opt_v);
+
+no warnings qw(taint);
-my $owner = getpwuid(geteuid());
-my $group = getgrgid(getegid());
+getopts('v');
my ($OK, $FAILED) = ("ok", "failed");
if (isatty(fileno(STDOUT))) {
@@ -13,19 +25,61 @@ if (isatty(fileno(STDOUT))) {
$FAILED = "\033[31m\033[1m" . $FAILED . "\033[m";
}
+sub exec_test($$);
+
my ($prog, $in, $out) = ([], [], []);
-my $line = 0;
+my $line_number = 0;
my $prog_line;
-my ($tests, $failed);
+my ($tests, $failed) = (0,0);
for (;;) {
- my $script = <>; $line++;
- $script =~ s/\@OWNER\@/$owner/g;
- $script =~ s/\@GROUP\@/$group/g;
- next if (defined($script) && $script =~ /^!/);
- if (!defined($script) || $script =~ s/^\$ ?//) {
- if (@$prog) {
- #print "[$prog_line] \$ ", join(' ', @$prog), " -- ";
+ my $line = <>; $line_number++;
+ if (defined $line) {
+ # Substitute %VAR and %{VAR} with environment variables.
+ $line =~ s[%(?:(\w+)|\{(\w+)\})][$ENV{"$1$2"}]eg;
+ }
+ if (defined $line) {
+ if ($line =~ s/^\s*< ?//) {
+ push @$in, $line;
+ } elsif ($line =~ s/^\s*> ?//) {
+ push @$out, $line;
+ } else {
+ process_test($prog, $prog_line, $in, $out);
+
+ $prog = [];
+ $prog_line = 0;
+ }
+ if ($line =~ s/^\s*\$ ?//) {
+ $line =~ s/\s+#.*//; # remove comments here...
+ $prog = [ map { s/\\(.)/$1/g; $_ } split /(?<!\\)\s+/, $line ];
+ $prog_line = $line_number;
+ $in = [];
+ $out = [];
+ }
+ } else {
+ process_test($prog, $prog_line, $in, $out);
+ last;
+ }
+}
+
+my $status = sprintf("%d commands (%d passed, %d failed)",
+ $tests, $tests-$failed, $failed);
+if (isatty(fileno(STDOUT))) {
+ if ($failed) {
+ $status = "\033[31m\033[1m" . $status . "\033[m";
+ } else {
+ $status = "\033[32m" . $status . "\033[m";
+ }
+}
+print $status, "\n";
+exit $failed ? 1 : 0;
+
+
+sub process_test($$$$) {
+ my ($prog, $prog_line, $in, $out) = @_;
+
+ return unless @$prog;
+
my $p = [ @$prog ];
print "[$prog_line] \$ ", join(' ',
map { s/\s/\\$&/g; $_ } @$p), " -- ";
@@ -36,9 +90,6 @@ for (;;) {
if (!defined($out->[$n]) || !defined($result->[$n]) ||
$out->[$n] ne $result->[$n]) {
$good = 0;
- #chomp $out->[$n];
- #chomp $result->[$n];
- #print "$out->[$n] != $result->[$n]";
}
}
$tests++;
@@ -50,37 +101,88 @@ for (;;) {
chomp $l;
my $r = defined($result->[$n]) ? $result->[$n] : "~";
chomp $r;
- print sprintf("%-37s | %-39s\n", $l, $r);
+ print sprintf("%-37s %s %-39s\n", $l, $l eq $r ? "|" : "?", $r);
}
+ } elsif ($opt_v) {
+ print join('', @$result);
}
+}
+
+
+sub su($) {
+ my ($user) = @_;
+
+ $user ||= "root";
+
+ my ($login, $pass, $uid, $gid) = getpwnam($user)
+ or return [ "su: user $user does not exist\n" ];
+ my @groups = ();
+ my $fh = new FileHandle("/etc/group")
+ or return [ "opening /etc/group: $!\n" ];
+ while (<$fh>) {
+ chomp;
+ my ($group, $passwd, $gid, $users) = split /:/;
+ foreach my $u (split /,/, $users) {
+ push @groups, $gid
+ if ($user eq $u);
}
- #$prog = [ split /\s+/, $script ] if $script;
- $prog = [ map { s/\\(.)/$1/g; $_ } split /(?<!\\)\s+/, $script ] if $script;
- $prog_line = $line;
- $in = [];
- $out = [];
- } elsif ($script =~ s/^> ?//) {
- push @$in, $script;
- } else {
- push @$out, $script;
}
- last unless defined($script);
+ $fh->close;
+
+ my $groups = join(" ", ($gid, $gid, @groups));
+ #print STDERR "[[$groups]]\n";
+ $! = 0; # reset errno
+ $> = 0;
+ $( = $gid;
+ $) = $groups;
+ if ($!) {
+ return [ "su: $!\n" ];
+ }
+ if ($uid != 0) {
+ $> = $uid;
+ #$< = $uid;
+ if ($!) {
+ return [ "su: $prog->[1]: $!\n" ];
+ }
+ }
+ #print STDERR "[($>,$<)($(,$))]";
+ return [];
}
-my $status = sprintf("%d commands (%d passed, %d failed)",
- $tests, $tests-$failed, $failed);
-if (isatty(fileno(STDOUT))) {
- if ($failed) {
- $status = "\033[31m\033[1m" . $status . "\033[m";
- } else {
- $status = "\033[32m" . $status . "\033[m";
- }
+
+
+sub sg($) {
+ my ($group) = @_;
+
+ my $gid = getgrnam($group)
+ or return [ "sg: group $group does not exist\n" ];
+ my %groups = map { $_ eq $gid ? () : ($_ => 1) } (split /\s/, $));
+
+ #print STDERR "<<", join("/", keys %groups), ">>\n";
+ my $groups = join(" ", ($gid, $gid, keys %groups));
+ #print STDERR "[[$groups]]\n";
+ $! = 0; # reset errno
+ if ($> != 0) {
+ my $uid = $>;
+ $> = 0;
+ $( = $gid;
+ $) = $groups;
+ $> = $uid;
+ } else {
+ $( = $gid;
+ $) = $groups;
+ }
+ if ($!) {
+ return [ "sg: $!\n" ];
+ }
+ print STDERR "[($>,$<)($(,$))]";
+ return [];
}
-print $status, "\n";
-exit $failed ? 1 : 0;
+
sub exec_test($$) {
my ($prog, $in) = @_;
local (*IN, *IN_DUP, *IN2, *OUT_DUP, *OUT, *OUT2);
+ my $needs_shell = (join('', @$prog) =~ /[][|<>"'`\$\*\?]/);
if ($prog->[0] eq "umask") {
umask oct $prog->[1];
@@ -90,6 +192,10 @@ sub exec_test($$) {
return [ "chdir: $prog->[1]: $!\n" ];
}
return [];
+ } elsif ($prog->[0] eq "su") {
+ return su($prog->[1]);
+ } elsif ($prog->[0] eq "sg") {
+ return sg($prog->[1]);
}
pipe *IN2, *OUT
@@ -134,11 +240,15 @@ sub exec_test($$) {
my $result = [];
while (<IN>) {
#print "< $_";
+ if ($needs_shell) {
+ s#^/bin/sh: line \d+: ##;
+ }
push @$result, $_;
}
return $result;
} else {
# Client
+ $< = $>;
close IN
or die "Can't close read end for input pipe: $!";
close OUT
@@ -151,9 +261,12 @@ sub exec_test($$) {
open STDERR, ">&STDOUT"
or die "Can't join STDOUT and STDERR: $!";
- #print ERR_DUP "<", join(' ', @$prog), ">\n";
- exec @$prog;
- print ERR_DUP $prog->[0], ": $!\n";
+ if ($needs_shell) {
+ exec ('/bin/sh', '-c', join(" ", @$prog));
+ } else {
+ exec @$prog;
+ }
+ print STDERR $prog->[0], ": $!\n";
exit;
}
}