[mod.sources] v07i032: Limit a program's execution time

sources-request@mirror.UUCP (10/16/86)

Submitted by: ihnp4!aicchi!mdb
Mod.sources: Volume 7, Issue 32
Archive-name: safe

[ Between an amazingly massive work crunch, and the replacement or exchange
  of both our minicomputers, there has been no mod.sources postings for almost
  a month.  Sorry.  For this program, I wrote a Makefile and tweaked the
  manpage a bit.  --r$ ]

I thought I'd send this in since there has been some discussion about this
sort of program.  I have tested/used it on SYS V r2.  It *should* be portable,
though.

					Mike Blackwell
					...!ihnp4!aicchi!mdb	(USENET)

#!/bin/sh
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
# If all goes well, you will see the message "No problems found."

# Exit status; set to 1 on "wc" errors or if would overwrite.
STATUS=0
# Contents:  Makefile safe.1 safe.c
 
echo x - Makefile
if test -f Makefile ; then
    echo Makefile exists, putting output in $$Makefile
    OUT=$$Makefile
    STATUS=1
else
    OUT=Makefile
fi
sed 's/^X//' > $OUT <<'@//E*O*F Makefile//'
X##  MAKEFILE FOR 'SAFE'

XCFLAGS	= -O

X##  THIS PROGRAM USES GETOPT; TWEAK THE NEXT LINE AS NECESSARY FOR YOU
X#GETOPT	= -lgetopt

Xsafe:	safe.c
X	cc $(CFLAGS) -o safe $(GETOPT)


Xinstall:
X	@echo Copy safe and the manpage to wherever is appropriate
@//E*O*F Makefile//
chmod u=rw,g=rw,o=rw $OUT
 
echo x - safe.1
if test -f safe.1 ; then
    echo safe.1 exists, putting output in $$safe.1
    OUT=$$safe.1
    STATUS=1
else
    OUT=safe.1
fi
sed 's/^X//' > $OUT <<'@//E*O*F safe.1//'
X.TH SAFE 1L
X.SH NAME
Xsafe \- kill a process after specified time.
X.SH SYNOPSIS
X.B safe -d <delay> -w <warning> -b command_line
X.SH DESCRIPTION
X.I Safe
Xexecutes the given
X.BR command_line ,
Xkilling the process if it is still running after
X.B delay
Xseconds.
XIf the -w option is specified, a warning will be given
X.B warning
Xseconds before the process is to be terminated.
XThe -b option supresses the text of the warning message and only beeps the
Xterminal; this is useful if you are in a screen oriented program.
X.PP
XI wrote this program to make it easier to test a program that was doing
Xsome strange ioctls.
XHowever it seems to have many uses, including
Xcontrolling netnews addiction.
X.SH AUTHOR
XMike Blackwell  -  USENET:  ...!ihnp4!aicchi!mdb
X.SH NOTES
XThe program traps SIGINT and uses it to terminate the process.
XI haven't run into any problems with this, but it could be a problem with
Xsome programs.

@//E*O*F safe.1//
chmod u=rw,g=rw,o=rw $OUT
 
echo x - safe.c
if test -f safe.c ; then
    echo safe.c exists, putting output in $$safe.c
    OUT=$$safe.c
    STATUS=1
else
    OUT=safe.c
fi
sed 's/^X//' > $OUT <<'@//E*O*F safe.c//'
X/* safe - Mike Blackwell - Aug 1986 */
X/* safe.c - safeguard a program: kill it after `n` seconds if its still alive */

X#include <signal.h>
X#include <stdio.h>

X/* delay constants */
X#define MINDELAY	10
X#define MAXDELAY	60*60
X#define DEFDELAY	60
X#define DLYMSG		"safe: <delay> must be between %d and %d seconds\n"
X#define WARNING		"\007\007safe: killing process %d in %d seconds\n"
X#define BELL		"\007\007"
X#define USAGE		"Usage:\n\tsafe -d <delay> -b -w <warning>\n"

Xint pid;

Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X	int done(),maim();
X	unsigned int delay = DEFDELAY;
X	unsigned int warndelay = 0;
X	int opt;
X	extern char *optarg;
X	extern int optind;
X	short int bell = 0;

X	while ((opt = getopt(argc,argv,"d:bw:")) != EOF) {
X		switch (opt) {
X		case 'd':
X			sscanf(optarg,"%d",&delay);
X			if (delay < MINDELAY || delay > MAXDELAY) {
X				fprintf(stderr,DLYMSG,MINDELAY,MAXDELAY);
X				exit(-1);
X			}
X			break;
X		case 'b':
X			bell = 1;
X			break;
X		case 'w':
X			sscanf(optarg,"%d",&warndelay);
X			break;
X		case '?':
X			fprintf(stderr,USAGE);
X			exit(-1);
X			break;
X		}
X	}

X	if (argv[optind] == NULL) {
X		fprintf(stderr,"safe: no program to execute\n");
X		exit(1);
X	}

X	if (warndelay >= delay) {
X		fprintf(stderr,
X	  "safe: delay less than warning time, no warning will be given\n");
X		warndelay = 0;
X	}

X	if (delay > warndelay) {
X		delay -= warndelay;
X	}

X	pid = fork();
X	if (pid == -1) {
X		fprintf(stderr,"safe: Can't fork\n");
X		perror("safe");
X		exit(-1);
X	}
X	if (pid == 0) {		/* child process */
X		if (execvp(argv[optind],&argv[optind]) == -1) {
X			perror("safe");
X			exit(-1);
X		}
X	} else {		/* parent - monitor and kill */
X		signal(SIGCLD,done);
X		signal(SIGINT,maim);
X		sleep(delay);
X		if (warndelay != 0) {
X			if (bell)
X				fprintf(stderr,BELL);
X			else
X				fprintf(stderr,WARNING,pid,warndelay);
X			sleep(warndelay);
X		}
X		maim();
X		exit(1);
X	}
X}

Xmaim()
X{
X	signal(SIGCLD,SIG_IGN);
X	kill(pid,SIGKILL);
X	fprintf(stderr,"safe: Process %d killed \n",pid);
X	exit(1);
X}

Xdone()
X{
X	fprintf(stderr,"safe: Process terminated\n");
X	exit(0);
X}
@//E*O*F safe.c//
chmod u=rw,g=rw,o=rw $OUT
 
echo Inspecting for damage in transit...
temp=/tmp/sharin$$; dtemp=/tmp/sharout$$
trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
cat > $temp <<\!!!
      13      41     245 Makefile
      29     159     908 safe.1
     106     269    2041 safe.c
     148     469    3194 total
!!!
wc  Makefile safe.1 safe.c | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
if test -s $dtemp ; then
    echo "Ouch [diff of wc output]:"
    cat $dtemp
    STATUS=1
elif test $STATUS = 0 ; then
    echo "No problems found."
else
    echo "WARNING -- PROBLEMS WERE FOUND..."
fi
exit $STATUS