timelimit-1.5/000075500000000000000000000000001213266431100133515ustar00rootroot00000000000000timelimit-1.5/ChangeLog000064400000000000000000000044211213266431100151240ustar00rootroot00000000000000Change log for timelimit, the process time limit tool 1.5 2009/10/30 - add the '__dead2' definition for no-return functions - add the '-p' flag to propagate information about the child process being terminated by a signal [teddy, roam] 1.4 2008/11/12 - correct options parsing on GNU systems - do not let timelimit grab the option arguments passed to the executed program Debian: #505140, reported by John Hasler 1.3 2008/09/03 - fix the $Ringlet VCS keyword in the source files [roam] 1.2 2008/08/22 - return the child process exit code instead of always exiting with 0 [cberg, roam] - define _GNU_SOURCE to properly use the Linux header files [roam] 1.1 2007/12/07 - move the manual page from section 8 to section 1 [mario] 1.0 2007/11/28 - add an 'install' target to the Makefile [roam] - build and install the gzipped manual page, too [roam] - remove the TARGETS file that was never used as intended [roam] - break the web-visible documentation out of the source tree [roam] - add a two-clause BSD copyright to all files [roam] - style fixes to the manual page [roam] - attempt to create the installation directories [roam] 1.0pre3 2001/06/09 - actually add the -q flag to the getopt() arguments (ARGH!) [roam] - use envopts[] for time/sig variable setting (both env and cmdline) [roam] - warn when no time/sig arguments specified, as suggested by alpha [roam] - silence a few gcc warnings [roam] - removed CC, CFLAGS initial settings from Makefile [alpha] 1.0pre2 2001/05/21 - added the '-q' flag to not output messages about signals sent to the child process [roam] - changed the execv() call to execvp(), so PATH is searched for the specified command, as suggested by alpha [roam] - changed the default compiler to gcc, as suggested by alpha [roam] - added timelimit.8 manpage [roam/alpha] - added killtime/warntime/killsig/warnsig defaults [alpha] 1.0pre1 2001/05/16 - first rolled-together prerelease. Name tags: roam Peter Pentchev alpha Karsten W Rohrbach mario Mario Iseli cberg Christoph Berg teddy Teddy Hogeborn Comments: Peter Pentchev $Ringlet: ChangeLog 4182 2009-10-30 15:46:15Z roam $ timelimit-1.5/Makefile000064400000000000000000000053341213266431100150160ustar00rootroot00000000000000# Copyright (c) 2001, 2007 Peter Pentchev # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $Ringlet: Makefile 2544 2008-09-03 13:24:36Z roam $ CC?= gcc CFLAGS?= -O -pipe LDFLAGS?= LFLAGS?= ${LDFLAGS} LIBS?= RM= rm -f MKDIR?= mkdir -p PROG= timelimit OBJS= timelimit.o SRCS= timelimit.c MAN1= timelimit.1 MAN1GZ= ${MAN1}.gz LOCALBASE?= /usr/local PREFIX?= ${LOCALBASE} BINDIR?= ${PREFIX}/bin MANDIR?= ${PREFIX}/man/man BINOWN?= root BINGRP?= wheel BINMODE?= 555 MANOWN?= root MANGRP?= wheel MANMODE?= 644 # comment this if you do not have err(3) and errx(3) (most BSD systems do) CFLAGS+= -DHAVE_ERR # comment this if you do not have the sysexits.h header file (most systems do) CFLAGS+= -DHAVE_SYSEXITS_H # comment this if you do not have the errno.h header file (most systems do) CFLAGS+= -DHAVE_ERRNO_H # comment this if you do not have sigaction(2) (most systems do) CFLAGS+= -DHAVE_SIGACTION # development/debugging flags, you may safely ignore them #CFLAGS+= ${BDECFLAGS} #CFLAGS+= -ggdb -g3 all: ${PROG} ${MAN1GZ} clean: ${RM} ${PROG} ${OBJS} ${MAN1GZ} ${PROG}: ${OBJS} ${CC} ${LFLAGS} -o ${PROG} ${OBJS} timelimit.o: timelimit.c config.h ${CC} ${CFLAGS} -c timelimit.c ${MAN1GZ}: ${MAN1} gzip -c9 ${MAN1} > ${MAN1GZ}.tmp mv ${MAN1GZ}.tmp ${MAN1GZ} install: all -${MKDIR} ${DESTDIR}${BINDIR} -${MKDIR} ${DESTDIR}${MANDIR}1 install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} ${PROG} ${DESTDIR}${BINDIR}/ install -c -o ${MANOWN} -g ${MANGRP} -m ${MANMODE} ${MAN1GZ} ${DESTDIR}${MANDIR}1/ timelimit-1.5/config.h000064400000000000000000000062061213266431100147730ustar00rootroot00000000000000#ifndef _INCLUDED_TIMELIMIT_CONFIG_H #define _INCLUDED_TIMELIMIT_CONFIG_H /*- * Copyright (c) 2001, 2007 - 2009 Peter Pentchev * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Ringlet: config.h 4172 2009-10-30 10:24:40Z roam $ */ #define _GNU_SOURCE /* we hope all OS's have those..*/ #include #include #include #include #include #include #include #include #include #ifdef HAVE_ERRNO_H #include #endif /* HAVE_ERRNO_H */ #ifdef HAVE_ERR #include #endif /* HAVE_ERR */ #ifdef HAVE_SYSEXITS_H #include #else #define EX_OK 0 /* successful termination */ #define EX__BASE 64 /* base value for error messages */ #define EX_USAGE 64 /* command line usage error */ #define EX_DATAERR 65 /* data format error */ #define EX_NOINPUT 66 /* cannot open input */ #define EX_NOUSER 67 /* addressee unknown */ #define EX_NOHOST 68 /* host name unknown */ #define EX_UNAVAILABLE 69 /* service unavailable */ #define EX_SOFTWARE 70 /* internal software error */ #define EX_OSERR 71 /* system error (e.g., can't fork) */ #define EX_OSFILE 72 /* critical OS file missing */ #define EX_CANTCREAT 73 /* can't create (user) output file */ #define EX_IOERR 74 /* input/output error */ #define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */ #define EX_PROTOCOL 76 /* remote error in protocol */ #define EX_NOPERM 77 /* permission denied */ #define EX_CONFIG 78 /* configuration error */ #define EX__MAX 78 /* maximum listed value */ #endif /* HAVE_SYSEXITS_H */ #ifndef __unused #ifdef __GNUC__ #define __unused __attribute__((unused)) #else /* __GNUC__ */ #define __unused #endif /* __GNUC__ */ #endif /* __unused */ #ifndef __dead2 #ifdef __GNUC__ #define __dead2 __attribute__((noreturn)) #else /* __GNUC__ */ #define __dead2 #endif /* __GNUC__ */ #endif /* __dead2 */ #endif /* _INCLUDED */ timelimit-1.5/timelimit.1000064400000000000000000000133621213266431100154350ustar00rootroot00000000000000.\" Copyright (c) 2001, 2007 - 2009 Peter Pentchev .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $Ringlet: timelimit.1 4173 2009-10-30 10:27:16Z roam $ .\" .Dd October 30, 2009 .Dt TIMELIMIT 1 .Os .Sh NAME .Nm timelimit .Nd effectively limit the absolute execution time of a process .Sh SYNOPSIS .Nm .Op Fl pq .Op Fl S Ar killsig .Op Fl s Ar warnsig .Op Fl T Ar killtime .Op Fl t Ar warntime .Ar command .Op Ar arguments ... .Sh DESCRIPTION The .Nm utility executes a given .Ar command with the supplied .Ar arguments and terminates the spawned process after a given time with a given signal. If the process exits before the time limit has elapsed, .Nm will silently exit, too. .Pp Options: .Bl -tag -width indent .It Fl p If the child process is terminated by a signal, .Nm propagates this condition, i.e. sends the same signal to itself. This allows the program executing .Nm to determine whether the child process was terminated by a signal or actually exited with an exit code larger than 128. .It Fl q Quiet operation - .Nm does not output diagnostic messages about signals sent to the child process. .It Fl S Ar killsig Specify the number of the signal to be sent to the process .Ar killtime seconds after .Ar warntime has expired. Defaults to 9 (SIGKILL). .It Fl s Ar warnsig Specify the number of the signal to be sent to the process .Ar warntime seconds after it has been started. Defaults to 15 (SIGTERM). .It Fl T Ar killtime Specify the maximum execution time of the process before sending .Ar killsig after .Ar warnsig has been sent. Defaults to 120 seconds. .It Fl t Ar warntime Specify the maximum execution time of the process in seconds before sending .Ar warnsig . Defaults to 3600 seconds. .El .Sh ENVIRONMENT .Bl -tag -width indent .It Ev KILLSIG The .Ar killsig to use if the .Fl S option was not specified. .It Ev KILLTIME The .Ar killtime to use if the .Fl T option was not specified. .It Ev WARNSIG The .Ar warnsig to use if the .Fl s option was not specified. .It Ev WARNTIME The .Ar warntime to use if the .Fl t option was not specified. .El .Sh EXIT STATUS If the child process exits normally, the .Nm utility will pass its exit code on up. If the child process is terminated by a signal and the .Fl p flag was not specified, the .Nm utility's exit status is 128 plus the signal number, similar to .Xr sh 1 . If the .Fl p flag was specified, the .Nm utility will raise the signal itself so that its own parent process may in turn reliably distinguish between a signal and a larger than 128 exit code. .Pp In rare cases, the .Nm utility may encounter a system or user error; then, its exit status is one of the standard .Xr sysexits 3 values: .Bl -tag -width indent .It Dv EX_USAGE The command-line parameters and options were incorrectly specified. .It Dv EX_SOFTWARE The .Nm utility itself received an unexpected signal while waiting for the child process to terminate. .It Dv EX_OSERR The .Nm utility was unable to execute the child process, wait for it to terminate, or examine its exit status. .El .Sh EXAMPLES .Pp The following examples are shown as given to the shell: .Pp .Dl timelimit -p /usr/local/bin/rsync rsync://some.host/dir /opt/mirror .Pp Run the rsync program to mirror a WWW or FTP site and kill it if it runs longer than 1 hour (that is 3600 seconds) with SIGTERM. If the rsync process does not exit after receiving the SIGTERM, .Nm issues a SIGKILL 120 seconds after the SIGTERM. If the rsync process is terminated by a signal, .Nm will itself raise this signal. .Pp .Dl tcpserver 0 8888 timelimit -t600 -T300 /opt/services/chat/stats .Pp Start a .Xr tcpserver n process listening on tcp port 8888; each client connection shall invoke an instance of an IRC statistics tool under .Pa /opt/services/chat and kill it after 600 seconds have elapsed. If the stats process is still running after the SIGTERM, it will be killed by a SIGKILL sent 300 seconds later. .Pp .Dl env WARNTIME=600 WARNSIG=1 KILLTIME=30 timelimit sh stats.sh .Pp Start a shell script and kill it with a SIGHUP in 600 seconds. If the shell gets stuck and does not respond to the SIGHUP, kill it with the default SIGKILL after 30 more seconds. .Sh SEE ALSO .Xr kill 1 , .Xr rsync 1 , .Xr signal 3 , .Xr tcpserver n .Sh STANDARDS No standards documentation was harmed in the process of creating .Nm . .Sh BUGS Please report any bugs in .Nm to the author. .Sh AUTHOR The .Nm utility was conceived and written by .An Peter Pentchev Aq roam@ringlet.net with contributions by .An Karsten W Rohrbach Aq karsten@rohrbach.de and .An Teddy Hogeborn Aq teddy@fukt.bsnet.se . timelimit-1.5/timelimit.c000064400000000000000000000166341213266431100155240ustar00rootroot00000000000000/*- * Copyright (c) 2001, 2007 - 2009 Peter Pentchev * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "config.h" #define PARSE_CMDLINE unsigned long warntime, killtime; unsigned long warnsig, killsig; volatile int fdone, falarm, fsig, sigcaught; int propagate, quiet; static const char cvs_id[] = "$Ringlet: timelimit.c 4174 2009-10-30 10:34:13Z roam $"; static struct { const char *name, opt; unsigned long *var; } envopts[] = { {"KILLSIG", 'S', &killsig}, {"KILLTIME", 'T', &killtime}, {"WARNSIG", 's', &warnsig}, {"WARNTIME", 't', &warntime}, {NULL, 0, NULL} }; #ifndef HAVE_ERR static void err(int, const char *, ...); static void errx(int, const char *, ...); #endif /* !HAVE_ERR */ static void usage(void); static void init(int, char *[]); static pid_t doit(char *[]); static void child(char *[]); static void raisesignal(int) __dead2; static void setsig_fatal(int, void (*)(int)); static void setsig_fatal_gen(int, void (*)(int), int, const char *); static void terminated(const char *); #ifndef HAVE_ERR static void err(int code, const char *fmt, ...) { va_list v; va_start(v, fmt); vfprintf(stderr, fmt, v); va_end(v); fprintf(stderr, ": %s\n", strerror(errno)); exit(code); } static void errx(int code, const char *fmt, ...) { va_list v; va_start(v, fmt); vfprintf(stderr, fmt, v); va_end(v); fprintf(stderr, "\n"); exit(code); } static void warn(const char *fmt, ...) { va_list v; va_start(v, fmt); vfprintf(stderr, fmt, v); va_end(v); fprintf(stderr, ": %s\n", strerror(errno)); } static void warnx(const char *fmt, ...) { va_list v; va_start(v, fmt); vfprintf(stderr, fmt, v); va_end(v); fprintf(stderr, "\n"); } #endif /* !HAVE_ERR */ static void usage(void) { errx(EX_USAGE, "usage: timelimit [-pq] [-S ksig] [-s wsig] " "[-T ktime] [-t wtime] command"); } static unsigned long atou_fatal(const char *s) { unsigned long v; const char *p; v = 0; for (p = s; (*p >= '0') && (*p <= '9'); p++) v = v * 10 + *p - '0'; if (*p != '\0') usage(); return (v); } static void init(int argc, char *argv[]) { #ifdef PARSE_CMDLINE int ch; #endif int optset; unsigned i; char *s; /* defaults */ quiet = 0; warnsig = SIGTERM; killsig = SIGKILL; warntime = 3600; killtime = 120; optset = 0; /* process environment variables first */ for (i = 0; envopts[i].name != NULL; i++) if ((s = getenv(envopts[i].name)) != NULL) { *envopts[i].var = atou_fatal(s); optset = 1; } #ifdef PARSE_CMDLINE while ((ch = getopt(argc, argv, "+qpS:s:T:t:")) != EOF) { switch (ch) { case 'p': propagate = 1; break; case 'q': quiet = 1; break; default: /* check if it's a recognized option */ for (i = 0; envopts[i].name != NULL; i++) if (ch == envopts[i].opt) { *envopts[i].var = atou_fatal(optarg); optset = 1; break; } if (envopts[i].name == NULL) usage(); } } #else optind = 1; #endif if (!optset) /* && !quiet? */ warnx("using defaults: warntime=%lu, warnsig=%lu, " "killtime=%lu, killsig=%lu", warntime, warnsig, killtime, killsig); argc -= optind; argv += optind; if (argc == 0) usage(); /* sanity checks */ if ((warntime == 0) || (killtime == 0)) usage(); } static void sigchld(int sig __unused) { fdone = 1; } static void sigalrm(int sig __unused) { falarm = 1; } static void sighandler(int sig) { sigcaught = sig; fsig = 1; } static void setsig_fatal(int sig, void (*handler)(int)) { setsig_fatal_gen(sig, handler, 1, "setting"); } static void setsig_fatal_gen(int sig, void (*handler)(int), int nocld, const char *what) { #ifdef HAVE_SIGACTION struct sigaction act; memset(&act, 0, sizeof(act)); act.sa_handler = handler; act.sa_flags = 0; #ifdef SA_NOCLDSTOP if (nocld) act.sa_flags |= SA_NOCLDSTOP; #endif /* SA_NOCLDSTOP */ if (sigaction(sig, &act, NULL) < 0) err(EX_OSERR, "%s signal handler for %d", what, sig); #else /* HAVE_SIGACTION */ if (signal(sig, handler) == SIG_ERR) err(EX_OSERR, "%s signal handler for %d", what, sig); #endif /* HAVE_SIGACTION */ } static pid_t doit(char *argv[]) { pid_t pid; /* install signal handlers */ fdone = falarm = fsig = sigcaught = 0; setsig_fatal(SIGALRM, sigalrm); setsig_fatal(SIGCHLD, sigchld); setsig_fatal(SIGTERM, sighandler); setsig_fatal(SIGHUP, sighandler); setsig_fatal(SIGINT, sighandler); setsig_fatal(SIGQUIT, sighandler); /* fork off the child process */ if ((pid = fork()) < 0) err(EX_OSERR, "fork"); if (pid == 0) child(argv); /* sleep for the allowed time */ alarm(warntime); while (!(fdone || falarm || fsig)) pause(); alarm(0); /* send the warning signal */ if (fdone) return (pid); if (fsig) terminated("run"); falarm = 0; if (!quiet) warnx("sending warning signal %lu", warnsig); kill(pid, (int) warnsig); #ifndef HAVE_SIGACTION /* reset our signal handlers, just in case */ setsig_fatal(SIGALRM, sigalrm); setsig_fatal(SIGCHLD, sigchld); setsig_fatal(SIGTERM, sighandler); setsig_fatal(SIGHUP, sighandler); setsig_fatal(SIGINT, sighandler); setsig_fatal(SIGQUIT, sighandler); #endif /* HAVE_SIGACTION */ /* sleep for the grace time */ alarm(killtime); while (!(fdone || falarm || fsig)) pause(); alarm(0); /* send the kill signal */ if (fdone) return (pid); if (fsig) terminated("grace"); if (!quiet) warnx("sending kill signal %lu", killsig); kill(pid, (int) killsig); return (pid); } static void terminated(const char *period) { errx(EX_SOFTWARE, "terminated by signal %d during the %s period", sigcaught, period); } static void child(char *argv[]) { execvp(argv[0], argv); err(EX_OSERR, "executing %s", argv[0]); } static __dead2 void raisesignal (int sig) { setsig_fatal_gen(sig, SIG_DFL, 0, "restoring"); raise(sig); while (1) pause(); /* NOTREACHED */ } int main(int argc, char *argv[]) { pid_t pid; int status; init(argc, argv); argc -= optind; argv += optind; pid = doit(argv); if (waitpid(pid, &status, 0) == -1) errx(EX_OSERR, "could not get the exit status for process %ld", (long)pid); if (WIFEXITED(status)) return (WEXITSTATUS(status)); else if (!WIFSIGNALED(status)) return (EX_OSERR); if (propagate) raisesignal(WTERMSIG(status)); else return (WTERMSIG(status) + 128); }