diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-07-17 18:40:06 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-07-17 18:42:03 +0300 |
commit | 6efb45e5ff89896727a0946218b3d5efb08aac1e (patch) | |
tree | 61075cf96cf15e46c3f7476ea757c12b4599838e /t | |
parent | db60fd0122ec26a7ff354c395590abf919274181 (diff) | |
download | runcap-6efb45e5ff89896727a0946218b3d5efb08aac1e.tar.gz runcap-6efb45e5ff89896727a0946218b3d5efb08aac1e.tar.bz2 |
Write a test tool
* runcap.c (timeval_after): Fix typo.
* t/rt.c: New file.
Diffstat (limited to 't')
-rw-r--r-- | t/rt.c | 227 |
1 files changed, 227 insertions, 0 deletions
@@ -0,0 +1,227 @@ +/* runcap - run program and capture its output + Copyright (C) 2017 Sergey Poznyakoff + + Runcap is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + Runcap is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Runcap. If not, see <http://www.gnu.org/licenses/>. */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include "runcap.h" + +static char *progname; + +void +error(char const *fmt, ...) +{ + va_list ap; + + fprintf(stderr, "%s: ", progname); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fputc('\n', stderr); +} + +void +usage(int code) +{ + FILE *fp = code ? stderr : stdout; + fprintf(fp, "%s [OPTIONS] COMMAND [ARG...]\n", progname); + fprintf(fp, "OPTIONS are:\n\n"); + fprintf(fp, " -S all|stderr|stdout selects capture for the next -m or -s option\n"); + fprintf(fp, " -f FILE reads stdin from FILE\n"); + fprintf(fp, " -i inline read (use before -f)\n"); + fprintf(fp, " -m monitors each line recevied from the program (see -S)\n"); + fprintf(fp, " -p PROGNAME sets program name to use instead of COMMAND\n"); + fprintf(fp, " -s SIZE sets capture size (see -S)\n"); + fprintf(fp, " -t SECONDS sets execution timeout\n"); + fputc('\n', fp); + exit(code); +} + +#define WA_STDOUT 0x01 +#define WA_STDERR 0x02 +#define WA_ALL (WA_STDOUT|WA_STDERR) + +static int +whatarg(char const *arg) +{ + if (strcmp(arg, "all") == 0) + return WA_ALL; + else if (strcmp(arg, "stdout") == 0) + return WA_STDOUT; + else if (strcmp(arg, "stderr") == 0) + return WA_STDERR; + error("unreconginzed option argument: %s", arg); + exit(1); +} + +static void +linemon(const char *ptr, size_t len, void *data) +{ + fprintf(stdout, "[%s]: ", (char*) data); + fwrite(ptr, len-1, 1, stdout); + fputc('\n', stdout); +} + +int +main(int argc, char **argv) +{ + struct runcap rc; + int rcf = 0; + int what = WA_ALL; + int inopt = 0; + + int c; + int fd; + unsigned long size; + + progname = strrchr(argv[0], '/'); + if (progname) + progname++; + else + progname = argv[0]; + while ((c = getopt(argc, argv, "?f:imp:S:s:t:")) != EOF) { + switch (c) { + case 'f': + fd = open(optarg, O_RDONLY); + if (fd == -1) { + error("can't open \"%s\": %s", + optarg, strerror(errno)); + exit(1); + } + if (inopt) { + struct stat st; + char *buffer; + if (fstat(fd, &st)) { + error("can't fstat \"%s\": %s", + optarg, strerror(errno)); + exit(1); + } + size = st.st_size; + buffer = malloc(size + 1); + if (!buffer) { + error("not enough memory"); + exit(1); + } + + rc.rc_cap[RUNCAP_STDIN].fc_size = size; + rc.rc_cap[RUNCAP_STDIN].fc_base = buffer; + while (size) { + ssize_t n = read(fd, buffer, size); + if (n < 0) { + error("error reading from \"%s\": %s", + optarg, strerror(errno)); + exit(1); + } + if (n == 0) { + error("unexpected eof on \"%s\"", + optarg); + exit(1); + } + size -= n; + buffer += n; + } + close(fd); + rc.rc_cap[RUNCAP_STDIN].fc_fd = -1; + } else { + rc.rc_cap[RUNCAP_STDIN].fc_fd = fd; + rc.rc_cap[RUNCAP_STDIN].fc_size = 0; + } + rcf |= RCF_STDIN; + break; + case 'i': + inopt = 1; + break; + case 'S': + what = whatarg(optarg); + break; + case 'm': + if (what & WA_STDOUT) { + rc.rc_cap[RUNCAP_STDOUT].fc_linemon = linemon; + rc.rc_cap[RUNCAP_STDOUT].fc_monarg = "stdout"; + rcf |= RCF_STDOUT_LINEMON; + } + if (what & WA_STDERR) { + rc.rc_cap[RUNCAP_STDERR].fc_linemon = linemon; + rc.rc_cap[RUNCAP_STDERR].fc_monarg = "stderr"; + rcf |= RCF_STDERR_LINEMON; + } + break; + case 'p': + rc.rc_program = optarg; + rcf |= RCF_PROGRAM; + break; + case 's': + size = strtoul(optarg, NULL, 10); + if (what & WA_STDOUT) { + rc.rc_cap[RUNCAP_STDOUT].fc_size = size; + rcf |= RCF_STDOUT_SIZE; + } + if (what & WA_STDERR) { + rc.rc_cap[RUNCAP_STDERR].fc_size = size; + rcf |= RCF_STDERR_SIZE; + } + break; + case 't': + rc.rc_timeout = strtoul(optarg, NULL, 10); + rcf |= RCF_TIMEOUT; + break; + default: + usage(optopt != '?'); + } + } + + if (argc == optind) { + static char *xargv[2]; + if (rcf & RCF_PROGRAM) { + xargv[0] = rc.rc_program; + xargv[1] = NULL; + rc.rc_argv = xargv; + } else + usage(1); + } else + rc.rc_argv = argv + optind; + + c = runcap(&rc, rcf); + + printf("res=%d\n", c); + if (c) { + error("system error: %s", strerror(rc.rc_errno)); + exit(1); + } + + if (WIFEXITED(rc.rc_status)) { + printf("exit code: %d\n", WEXITSTATUS(rc.rc_status)); + } else if (WIFSIGNALED(rc.rc_status)) { + printf("got signal: %d\n", WTERMSIG(rc.rc_status)); + } else if (WIFSTOPPED(rc.rc_status)) { + printf("stopped by signal %d\n", WSTOPSIG(rc.rc_status)); + } else + printf("unrecognized status: %d\n", rc.rc_status); + + printf("stdout: %zu lines, %zu bytes\n", + rc.rc_cap[RUNCAP_STDOUT].fc_nlines, + rc.rc_cap[RUNCAP_STDOUT].fc_leng); + printf("stderr: %zu lines, %zu bytes\n", + rc.rc_cap[RUNCAP_STDERR].fc_nlines, + rc.rc_cap[RUNCAP_STDERR].fc_leng); + + return 0; +} |