Greetings all
One thing that is needed is a method of testing the exec utility. This
patch provides a step towards this goal by adding several command line
switches. The majority of these switches allow the utility to function
as a test target which will produce certain (controlled) behavior. The
behavior needed includes exiting with a particular status or signal,
masking (ignoring) a particular signal, and sleeping a certain amount of
time.
The -v switch increases the value of the verbosity counter variable
The -q switch sets the value of the verbosity counter variable to 0
The --exit switch causes the utility to exit with the value specified.
The --sleep switch causes the utility to sleep for the number of seconds
specified.
The --signal switch causes the utility to send itself the signal
name/number specified.
The --ignore switch causes the utility to ignore the signal name/number
specified.
--Andrew Black
Log:
2006-08-01 Andrew Black <[EMAIL PROTECTED]>
* exec.h (get_signo): Define macro for signal name to number conversion
* exec.cpp (get_signo): Implementation
* exec.cpp (signal_names): moved lookup table out of get_signame to
file scope
* cmdopt.h (verbose): Define global
* cmdopt.cpp (verbose): Instantiate global
* cmdopt.cpp (get_short_val, get_long_val, bad_option): Add helper
functions for option parsing
* cmdopt.cpp (eval_options): Use new functions, add -v, -q, --exit,
--sleep, --signal, --ignore switches
Index: exec.cpp
===================================================================
--- exec.cpp (revision 427578)
+++ exec.cpp (working copy)
@@ -58,192 +58,251 @@
static int alarm_timeout;
/**
- Translates a signal number into a human understandable name
-
- @param signo a signal number
- @returns the human understandable name for the signal (minus the SIG
- prefix), or "#n" if the the name for the number is unknown to the
- function, where n is signo
+ Utility macro to generate a signal number/name pair.
+
+ @parm val 'short' signal name (no leading SIG) to generate pair for.
+ @see signal_names []
*/
-const char*
-get_signame (int signo)
-{
- static const struct {
- int val;
- const char* str;
- } names [] = {
-
#undef SIGNAL
#define SIGNAL(val) { SIG ## val, #val }
+/**
+ Signal name/number translation table.
+
+ This table is populated using the SIGNAL helper macro to translate system SIG* macro values into name/value pairs.
+
+ @see SIGNAL ()
+*/
+static const struct {
+ int val; /**< Signal value for lookup pair */
+ const char* str; /**< Signal name for lookup pair */
+} signal_names [] = {
#ifdef SIGABRT
- SIGNAL (ABRT),
+ SIGNAL (ABRT),
#endif /* SIGABRT */
#ifdef SIGALRM
- SIGNAL (ALRM),
+ SIGNAL (ALRM),
#endif /* SIGALRM */
#ifdef SIGBUS
- SIGNAL (BUS),
+ SIGNAL (BUS),
#endif /* SIGBUS */
#ifdef SIGCANCEL
- SIGNAL (CANCEL),
+ SIGNAL (CANCEL),
#endif /* SIGCANCEL */
#ifdef SIGCHLD
- SIGNAL (CHLD),
+ SIGNAL (CHLD),
#endif /* SIGCHLD */
#ifdef SIGCKPT
- SIGNAL (CKPT),
+ SIGNAL (CKPT),
#endif /* SIGCKPT */
#ifdef SIGCLD
- SIGNAL (CLD),
+ SIGNAL (CLD),
#endif /* SIGCLD */
#ifdef SIGCONT
- SIGNAL (CONT),
+ SIGNAL (CONT),
#endif /* SIGCONT */
#ifdef SIGDIL
- SIGNAL (DIL),
+ SIGNAL (DIL),
#endif /* SIGDIL */
#ifdef SIGEMT
- SIGNAL (EMT),
+ SIGNAL (EMT),
#endif /* SIGEMT */
#ifdef SIGFPE
- SIGNAL (FPE),
+ SIGNAL (FPE),
#endif /* SIGFPE */
#ifdef SIGFREEZE
- SIGNAL (FREEZE),
+ SIGNAL (FREEZE),
#endif /* SIGFREEZE */
#ifdef SIGGFAULT
- SIGNAL (GFAULT),
+ SIGNAL (GFAULT),
#endif /* SIGGFAULT */
#ifdef SIGHUP
- SIGNAL (HUP),
+ SIGNAL (HUP),
#endif /* SIGHUP */
#ifdef SIGILL
- SIGNAL (ILL),
+ SIGNAL (ILL),
#endif /* SIGILL */
#ifdef SIGINFO
- SIGNAL (INFO),
+ SIGNAL (INFO),
#endif /* SIGINFO */
#ifdef SIGINT
- SIGNAL (INT),
+ SIGNAL (INT),
#endif /* SIGINT */
#ifdef SIGIO
- SIGNAL (IO),
+ SIGNAL (IO),
#endif /* SIGIO */
#ifdef SIGIOT
- SIGNAL (IOT),
+ SIGNAL (IOT),
#endif /* SIGIOT */
#ifdef SIGK32
- SIGNAL (K32),
+ SIGNAL (K32),
#endif /* SIGK32 */
#ifdef SIGKILL
- SIGNAL (KILL),
+ SIGNAL (KILL),
#endif /* SIGKILL */
#ifdef SIGLOST
- SIGNAL (LOST),
+ SIGNAL (LOST),
#endif /* SIGLOST */
#ifdef SIGLWP
- SIGNAL (LWP),
+ SIGNAL (LWP),
#endif /* SIGLWP */
#ifdef SIGPIPE
- SIGNAL (PIPE),
+ SIGNAL (PIPE),
#endif /* SIGPIPE */
#ifdef SIGPOLL
- SIGNAL (POLL),
+ SIGNAL (POLL),
#endif /* SIGPOLL */
#ifdef SIGPROF
- SIGNAL (PROF),
+ SIGNAL (PROF),
#endif /* SIGPROF */
#ifdef SIGPTINTR
- SIGNAL (PTINTR),
+ SIGNAL (PTINTR),
#endif /* SIGPTINTR */
#ifdef SIGPTRESCHED
- SIGNAL (PTRESCHED),
+ SIGNAL (PTRESCHED),
#endif /* SIGPTRESCHED */
#ifdef SIGPWR
- SIGNAL (PWR),
+ SIGNAL (PWR),
#endif /* SIGPWR */
#ifdef SIGQUIT
- SIGNAL (QUIT),
+ SIGNAL (QUIT),
#endif /* SIGQUIT */
#ifdef SIGRESTART
- SIGNAL (RESTART),
+ SIGNAL (RESTART),
#endif /* SIGRESTART */
#ifdef SIGRESV
- SIGNAL (RESV),
+ SIGNAL (RESV),
#endif /* SIGRESV */
#ifdef SIGSEGV
- SIGNAL (SEGV),
+ SIGNAL (SEGV),
#endif /* SIGSEGV */
#ifdef SIGSTKFLT
- SIGNAL (STKFLT),
+ SIGNAL (STKFLT),
#endif /* SIGSTKFLT */
#ifdef SIGSTOP
- SIGNAL (STOP),
+ SIGNAL (STOP),
#endif /* SIGSTOP */
#ifdef SIGSYS
- SIGNAL (SYS),
+ SIGNAL (SYS),
#endif /* SIGSYS */
#ifdef SIGTERM
- SIGNAL (TERM),
+ SIGNAL (TERM),
#endif /* SIGTERM */
#ifdef SIGTHAW
- SIGNAL (THAW),
+ SIGNAL (THAW),
#endif /* SIGTHAW */
#ifdef SIGTRAP
- SIGNAL (TRAP),
+ SIGNAL (TRAP),
#endif /* SIGTRAP */
#ifdef SIGTSTP
- SIGNAL (TSTP),
+ SIGNAL (TSTP),
#endif /* SIGTSTP */
#ifdef SIGTTIN
- SIGNAL (TTIN),
+ SIGNAL (TTIN),
#endif /* SIGTTIN */
#ifdef SIGTTOU
- SIGNAL (TTOU),
+ SIGNAL (TTOU),
#endif /* SIGTTOU */
#ifdef SIGUNUSED
- SIGNAL (UNUSED),
+ SIGNAL (UNUSED),
#endif /* SIGUNUSED */
#ifdef SIGURG
- SIGNAL (URG),
+ SIGNAL (URG),
#endif /* SIGURG */
#ifdef SIGUSR1
- SIGNAL (USR1),
+ SIGNAL (USR1),
#endif /* SIGUSR1 */
#ifdef SIGUSR2
- SIGNAL (USR2),
+ SIGNAL (USR2),
#endif /* SIGUSR2 */
#ifdef SIGVTALRM
- SIGNAL (VTALRM),
+ SIGNAL (VTALRM),
#endif /* SIGVTALRM */
#ifdef SIGWAITING
- SIGNAL (WAITING),
+ SIGNAL (WAITING),
#endif /* SIGWAITING */
#ifdef SIGWINCH
- SIGNAL (WINCH),
+ SIGNAL (WINCH),
#endif /* SIGWINCH */
#ifdef SIGWINDOW
- SIGNAL (WINDOW),
+ SIGNAL (WINDOW),
#endif /* SIGWINDOW */
#ifdef SIGXCPU
- SIGNAL (XCPU),
+ SIGNAL (XCPU),
#endif /* SIGXCPU */
#ifdef SIGXFSZ
- SIGNAL (XFSZ),
+ SIGNAL (XFSZ),
#endif /* SIGXFSZ */
#ifdef SIGXRES
- SIGNAL (XRES),
+ SIGNAL (XRES),
#endif /* SIGXRES */
- { -1, 0 }
- };
+ { -1, 0 }
+};
+/**
+ Index size for the signal_names array.
+
+ This array is semi-redundant, as the same check could be made looking for a null pointer in the str element of the structure.
+*/
+static const size_t name_count = sizeof signal_names / sizeof *signal_names;
+
+/**
+ Translates a human understandable signal name into a number usable by kill ().
+
+ This method understands several formats for signal names. They are as follows:
+ - SIG#n
+ - SIGn
+ - SIGFOO
+ - #n
+ - n
+ - FOO
+ In this list, n denotes a number and FOO denotes a short signal name.
+
+ @param signame a signal name to decode
+ @returns the signal number or -1 if a number couldn't be determined
+ @see signal_names []
+*/
+const int
+get_signo (char* signame)
+{
size_t i;
+
+ if ('S' == signame [0] && 'I' == signame [1] && 'G' == signame [2])
+ signame += 3;
+
+ if ('#' == signame [0])
+ ++signame;
+
+ if ('0' <= signame [0] && '9' >= signame [0])
+ return atoi (signame);
+
+ for (i = 0; i < name_count; ++i) {
+ if (0 == strcmp (signal_names [i].str, signame)) {
+ return signal_names [i].val;
+ }
+ }
+
+ return -1;
+}
+
+/**
+ Translates a signal number into a human understandable name
+
+ @param signo a signal number
+ @returns the human understandable name for the signal (minus the SIG
+ prefix), or "#n" if the the name for the number is unknown to the
+ function, where n is signo
+ @see signal_names []
+*/
+const char*
+get_signame (int signo)
+{
+ size_t i;
static char def [16];
- for (i = 0; i < sizeof names / sizeof *names; ++i) {
- if (names [i].val == signo) {
- return names [i].str;
+ for (i = 0; i < name_count; ++i) {
+ if (signal_names [i].val == signo) {
+ return signal_names [i].str;
}
}
Index: exec.h
===================================================================
--- exec.h (revision 427578)
+++ exec.h (working copy)
@@ -32,6 +32,8 @@
int killed;
};
+const int get_signo (char* const signame);
+
const char* get_signame (int signo);
struct exec_attrs exec_file (char** argv);
Index: cmdopt.cpp
===================================================================
--- cmdopt.cpp (revision 427578)
+++ cmdopt.cpp (working copy)
@@ -26,16 +26,20 @@
#include <assert.h>
#include <ctype.h> /* for isspace */
+#include <signal.h> /* for kill, SIG_IGN */
#include <stdio.h> /* for *printf, fputs */
#include <stdlib.h> /* for atoi, exit */
#include <string.h> /* for str* */
+#include <unistd.h> /* for getpid */
+#include "exec.h"
#include "util.h"
#include "cmdopt.h"
int timeout = 10; /**< Child process timeout. Default 10. */
int compat = 0; /**< Test compatability mode switch. Defaults to 0 (off). */
+unsigned verbose = 0;
const char* exe_opts = ""; /**< Global command line switches for child
processes. */
const char* in_root = ""; /**< Root directory for input/reference files. */
@@ -58,17 +62,80 @@
"processed after termination. If\n execution takes longer "
"than a certain (configurable) period of time, the\n process is "
"killed\n\n", stderr);
- fputs (" -d dir Root directory for output reference files\n"
- " -h, -? Display usage information and exit\n"
- " -t seconds Watchdog timeout before killing target (default is "
-"10 \n seconds)\n"
- " -x opts Command line options to pass to targets\n"
- " -- Terminate option processing and treat all "
- "following arguments\n as targets\n", stderr);
+ fputs (" -d dir Root directory for output reference files\n"
+ " -h, -? Display usage information and exit\n"
+ " -t seconds Watchdog timeout before killing target (default "
+ "is 10 \n seconds)\n"
+ " -q Set verbosity level to 0 (default)\n"
+ " -v Increase verbosity of output\n"
+ " -x opts Command line options to pass to targets\n",
+ stderr);
+ fputs (" -- Terminate option processing and treat all "
+ "following arguments\n as targets\n"
+ " --compat Use compatability mode test output parsing\n"
+ " --nocompat Use standard test output parsing (default)\n"
+ " --exit=val Exit (now) with a return code of val\n"
+ " --sleep=sec sleep() (now) for sec seconds\n"
+ " --signal=sig Send self signal sig (now)\n"
+ " --ignore=sig Ignore signal sig\n", stderr);
+ fputs ("\n"
+ " All short (single dash) options must be specified seperately.\n"
+ " If a short option takes a value, it may either be provided like"
+ "\n '-sval' or '-s val'\n"
+ " If a long option take a value, it may either be provided like\n"
+ " '--option=value' or '--option value'\n", stderr);
+
exit (status);
}
/**
+ Helper function to read the value for a short option
+
+ @param argv argument array
+ @param idx reference to index for option
+*/
+static char*
+get_short_val (char* const* argv, int* idx)
+{
+ if ('\0' == argv [*idx][2])
+ return argv [++(*idx)];
+ else
+ return argv [*idx] + 2;
+}
+
+/**
+ Helper function to read the value for a long option
+
+ @param argv argument array
+ @param idx reference to index for option
+ @param offset length of option name (including leading --)
+*/
+static char*
+get_long_val (char* const * argv, int* idx, unsigned offset)
+{
+ if ('\0' == argv [*idx][offset])
+ return argv [++(*idx)];
+ else if ('=' == argv [*idx][offset])
+ return argv [*idx] + offset + 1;
+ else
+ return (char*)0;
+}
+
+/**
+ Helper function to produce 'Unknown option' error message.
+
+ Terminates via show_usage.
+
+ @param opt name of option encountered
+*/
+static void
+bad_option (char* const opt)
+{
+ printf ("Unknown option: %s\n", opt);
+ show_usage (1);
+}
+
+/**
Parses command line arguments for switches and options.
@param argc number of command line arguments
@@ -101,29 +168,21 @@
++i; /* Ignore -r option (makefile compat) */
break;
case 't':
- if ('\0' == argv [i][2])
- val = argv [++i];
- else
- val = argv [i] + 2;
-
+ val = get_short_val (argv, &i);
timeout = atoi (val);
break;
case 'd':
- if ('\0' == argv [i][2])
- val = argv [++i];
- else
- val = argv [i] + 2;
-
- in_root = val;
+ in_root = get_short_val (argv, &i);
break;
case 'x':
- if ('\0' == argv [i][2])
- val = argv [++i];
- else
- val = argv [i] + 2;
-
- exe_opts = val;
+ exe_opts = get_short_val (argv, &i);
break;
+ case 'v':
+ ++verbose;
+ break;
+ case 'q':
+ verbose = 0;
+ break;
case '-':
{
const size_t arglen = strlen (argv [i]);
@@ -132,19 +191,70 @@
if ('\0' == argv [i][2])
return i+1;
- if (8 == arglen && 0 == memcmp ("--compat", argv [i], 8)) {
+ if (8 == arglen && 0 == memcmp ("--compat\0", argv [i], 9)) {
compat = 1;
break;
}
- else if (10 == arglen && 0 == memcmp ("--nocompat", argv [i], 10)) {
+ else if (10 == arglen && 0 == memcmp ("--nocompat\0", argv [i],
+ 11)) {
compat = 0;
break;
}
+ else if (6 <= arglen && 0 == memcmp ("--exit", argv [i], 6)) {
+ val = get_long_val (argv, &i, 6);
+ if (val)
+ exit (atoi (val));
+ else
+ bad_option (argv [i]);
+ }
+ else if (7 <= arglen && 0 == memcmp ("--sleep", argv [i], 7)) {
+ val = get_long_val (argv, &i, 7);
+ if (val)
+ sleep (atoi (val));
+ else
+ bad_option (argv [i]);
+ }
+ else if (8 <= arglen && 0 == memcmp ("--signal", argv [i], 8)) {
+ val = get_long_val (argv, &i, 8);
+ if (val) {
+ int sig = get_signo (val);
+ if (0 > sig)
+ terminate (1, "Unknown signal name for --signal: "
+ "%s\n", val);
+
+ /* Ignore kill errors (what should we do with them?) */
+ (void)kill (getpid (), sig);
+
+ /* Not certain what we should do if we don't terminate by
+ signal */
+ }
+ else
+ bad_option (argv [i]);
+ }
+ else if (8 <= arglen && 0 == memcmp ("--ignore", argv [i], 8)) {
+ val = get_long_val (argv, &i, 8);
+ if (val) {
+ struct sigaction act;
+ int sig = get_signo (val);
+ if (0 > sig)
+ terminate (1, "Unknown signal name for --ignore: "
+ "%s\n", val);
+
+ memset (&act, 0, sizeof act);
+ act.sa_handler = SIG_IGN;
+ (void)sigaction (sig, &act, 0);
+ /* Ignore sigaction errors (what should we do with them?)
+ */
+ break;
+ }
+ else
+ bad_option (argv [i]);
+ }
+ else
+ bad_option (argv [i]);
}
- /* Intentionally falling through */
default:
- fprintf (stderr, "Unknown option: %s\n", argv [i]);
- show_usage (1);
+ bad_option (argv [i]);
}
}
Index: cmdopt.h
===================================================================
--- cmdopt.h (revision 427578)
+++ cmdopt.h (working copy)
@@ -29,6 +29,7 @@
extern int timeout;
extern int compat;
+extern unsigned verbose; /**< Verbose output mode switch. Defaults to 0 (off) */
extern const char* exe_opts;
extern const char* in_root;
extern const char* exe_name;