From d8ffb1d8f28c456bee59730816a5ee276da76399 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Sun, 3 Jun 2001 20:35:19 +0000 Subject: [PATCH] Added interactive testing. --- Makefile | 7 ++- TODO | 3 + bin/lib | 42 ++++++++++++- config | 3 + src/iwrapper.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 219 insertions(+), 3 deletions(-) create mode 100644 src/iwrapper.c diff --git a/Makefile b/Makefile index 9d2b0e2..6681c0f 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,14 @@ #DEBUG=-ggdb CFLAGS=-O2 -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes -Winline $(DEBUG) -all: bin/box +all: bin/box bin/iwrapper bin/box: src/box.o $(CC) $(LDFLAGS) -o $@ $< +bin/iwrapper: src/iwrapper.o + $(CC) $(LDFLAGS) -o $@ $< + clean: rm -f `find . -name "*~" -or -name "*.[oa]" -or -name "\#*\#" -or -name TAGS -or -name core` - rm -f bin/box + rm -f bin/box bin/iwrapper diff --git a/TODO b/TODO index c20c426..7187e09 100644 --- a/TODO +++ b/TODO @@ -3,6 +3,9 @@ Evaluator mo-install: don't copy private test data to public lepsi time limity zkopirovat *.ok i kdyz program spadne na run-time error +submit: do real test? + +giant: sample input? Environment ~~~~~~~~~~~ diff --git a/bin/lib b/bin/lib index aa7b4cf..ccb0b9c 100644 --- a/bin/lib +++ b/bin/lib @@ -151,9 +151,16 @@ function compile pend "OK" } -# Running of test program with file input/output +# Running of test program according to current task type function test-run +{ + test-run-$TASK_TYPE +} + +# Running of test program with file input/output + +function test-run-file { pcont " " box-clean @@ -190,6 +197,38 @@ function test-run cp $BOXDIR/$PROBLEM.out $TDIR/$TEST.out } +# Running of interactive test programs + +function test-run-interactive +{ + pcont " " + box-clean + echo "Executable file: $TDIR/$PROBLEM" + cp $TDIR/$PROBLEM $BOXDIR/ + echo "Input: $TDIR/$PROBLEM" + ln $PDIR/$TEST.in $TDIR/$TEST.in + cp $PDIR/$TEST.in $BOXDIR/$PROBLEM.in + echo "Input files:" + ls -Al $BOXDIR + + pcont " " + echo "Timeout: $TIME_LIMIT s" + echo "Memory: $MEM_LIMIT KB" + BOXOPTS="`eval echo $TEST_SANDBOX_OPTS`" + echo "Sandbox options: $BOXOPTS" + ICCMD="`eval echo $IA_CHECK`" + echo "Interactive checker: $ICCMD" + if ! bin/iwrapper $BOXCMD $BOXOPTS -- ./$PROBLEM @@ $ICCMD 2>$TDIR/exec.out ; then + TEST_MSG="`cat $TDIR/exec.out`" + pend "$TEST_MSG" + echo "$TEST_MSG" + echo >>$PTSFILE "0 $TEST_MSG" + return 1 + fi + cat $TDIR/exec.out + rm $TDIR/exec.out +} + # Syntax checks function syntax-check @@ -209,6 +248,7 @@ function syntax-check function output-check { + [ -n "$OUTPUT_CHECK" ] || return 0 pcont " " ln $PDIR/$TEST.out $TDIR/$TEST.ok OCHECK="`eval echo $OUTPUT_CHECK`" diff --git a/config b/config index 50ed700..84bf889 100644 --- a/config +++ b/config @@ -16,6 +16,9 @@ TEST_USER=${TEST_USER:mo-test1} ### all of the following variables can be overriden in per-task config file +# Default task type (file or interactive) +TASK_TYPE=file + # Known source file extensions EXTENSIONS="c C cpp p pas" diff --git a/src/iwrapper.c b/src/iwrapper.c new file mode 100644 index 0000000..19435e8 --- /dev/null +++ b/src/iwrapper.c @@ -0,0 +1,167 @@ +/* + * A Wrapper for Interactive Tests + * + * (c) 2001 Martin Mares + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NONRET __attribute__((noreturn)) +#define UNUSED __attribute__((unused)) + +static void NONRET __attribute__((format(printf,1,2))) +die(char *msg, ...) +{ + va_list args; + va_start(args, msg); + vfprintf(stderr, msg, args); + fputc('\n', stderr); + exit(1); +} + +static void +copy(int fd) +{ + char buf[4096]; + int c; + + while (c = read(fd, buf, sizeof(buf))) + write(2, buf, c); +} + +int +main(int argc, char **argv) +{ + int sep, nbox, nchk; + char **abox, **achk; + pid_t pbox, pchk; + int inpipe[2], outpipe[2], boxepipe[2], chkepipe[2]; + int exited = 0, sbox, schk; + + for (sep=1; sep < argc; sep++) + if (!strcmp(argv[sep], "@@")) + break; + if (sep >= argc - 1) + die("Usage: iwrapper @@ "); + nbox = sep - 1; + abox = alloca((nbox+1) * sizeof(char *)); + memcpy(abox, argv+1, nbox*sizeof(char *)); + abox[nbox] = NULL; + nchk = argc - sep - 1; + achk = alloca((nchk+1) * sizeof(char *)); + memcpy(achk, argv+sep+1, nchk*sizeof(char *)); + achk[nchk] = NULL; + + if (pipe(inpipe) < 0 || + pipe(outpipe) < 0 || + pipe(boxepipe) < 0 || + pipe(chkepipe) < 0) + die("pipe: %m"); + + pbox = fork(); + if (pbox < 0) + die("fork: %m"); + if (!pbox) + { + close(inpipe[1]); + close(0); + dup(inpipe[0]); + close(inpipe[0]); + close(outpipe[0]); + close(1); + dup(outpipe[1]); + close(outpipe[1]); + close(boxepipe[0]); + close(2); + dup(boxepipe[1]); + close(boxepipe[1]); + close(chkepipe[0]); + close(chkepipe[1]); + execv(abox[0], abox); + die("exec: %m"); + } + + pchk = fork(); + if (pchk < 0) + die("fork: %m"); + if (!pchk) + { + close(inpipe[0]); + close(1); + dup(inpipe[1]); + close(inpipe[1]); + close(outpipe[1]); + close(0); + dup(outpipe[0]); + close(outpipe[0]); + close(chkepipe[0]); + close(2); + dup(chkepipe[1]); + close(chkepipe[1]); + close(boxepipe[0]); + close(boxepipe[1]); + execv(achk[0], achk); + die("exec: %m"); + } + + close(inpipe[0]); + close(inpipe[1]); + close(outpipe[0]); + close(outpipe[1]); + close(chkepipe[1]); + close(boxepipe[1]); + + sbox = schk = 0; + while (exited != 3) + { + int st; + pid_t p = wait(&st); + if (p < 0) + die("wait: %m"); + if (p == pbox) + { + exited |= 1; + sbox = st; + } + else if (p == pchk) + { + exited |= 2; + schk = st; + } + else + die("Unknown process %d died", p); + } + + if (!WIFEXITED(sbox)) + die("Sandbox fault, status=%x", sbox); + if (!WIFEXITED(schk)) + die("Checker fault, status=%x", schk); + if (WEXITSTATUS(sbox)) + { + copy(boxepipe[0]); + return 1; + } + else if (WEXITSTATUS(schk)) + { + copy(chkepipe[0]); + return 1; + } + copy(boxepipe[0]); + return 0; +} -- 2.39.2