[BACK]Return to pipeio.c CVS log [TXT][DIR] Up to [Development] / projects / ltp / tests

File: [Development] / projects / ltp / tests / pipeio.c (download)

Revision 1.1, Thu Nov 16 17:35:59 2000 UTC (16 years, 11 months ago) by nstraz
Branch: MAIN
CVS Tags: HEAD

Adding pipeio, which is a tool that creates children which write to a pipe
while the parent reads everything off, checking for data errors.  I've included
8 command line examples in a new pan file.
TODO: Handle EAGAIN errors

/* $Header: /oss/CVS/cvs/projects/ltp/tests/pipeio.c,v 1.1 2000/11/16 17:35:59 nstraz Exp $ */
/*
 *  (c) Copyright Cray Research, Inc.  Unpublished Proprietary Information.
 *  All Rights Reserved.
 */
/*
 *  This tool can be used to beat on system or named pipes.
 *  See the help() function below for user information.
 */
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>

#include "tlibio.h"

#if defined(linux)
# define NBPW sizeof(int)
#endif


#define PPATH "tpipe"
#define OCTAL	'o'
#define HEX	'x'
#define DECIMAL	'd'
#define ASCII	'a'
#define NO_OUT	'n'

#define PIPE_NAMED	"named pipe,"
#define PIPE_UNNAMED	"sys pipe,"

#define BLOCKING_IO	"blking,"
#define NON_BLOCKING_IO	"non-blking,"
#define UNNAMED_IO	""

void sig_handler(), help(), usage(), prt_buf(), prt_examples();
void sig_child();

extern int errno;

char *Progname;
int count = 0;
int Nchildcomplete = 0;

/*
 * Ensure PATH_MAX is define
 */
#ifndef PATH_MAX
#ifdef MAXPATHLEN
#define PATH_MAX MAXPATHLEN
#else
#define PATH_MAX 1024
#endif /* ! MAXPATHLEN */
#endif /* PATH_MAX */

int
main(ac,av)
int ac;
char *av[];
{
	int i,j,c,error = 0;
	int n;
	int nb;			/* number of bytes read */
	int num_wrters=1;	/* number of writers */
	int num_writes=1;	/* number of writes per child */
	int loop=0;		/* loop indefinitely */
	int exit_error = 1;	/* exit on error #, zero means no exit */
	int size=327;		/* default size */
	int unpipe = 0;		/* un-named pipe if non-zero */
	int verbose=0;		/* verbose mode if set */
	int quiet=0;		/* quiet mode if set */
	int num_rpt=0;		/* ping number, how often to print message */
	int chld_wait = 0;	/* max time to wait between writes, 1 == no wait */
	int parent_wait = 0;	/* max time to wait between reads, 1 == no wait*/
	int ndelay = O_NDELAY;	/* additional flag to open */
	long clock;
	char *writebuf;
	char *readbuf;
	double d;
	char   *cp;
        extern char *optarg;
	char pname[PATH_MAX];	/* contains the name of the unamed pipe */
	char dir[PATH_MAX];	/* directory to create pipe in		*/
	char *blk_type;		/* blocking i/o or not */
	char *pipe_type;	/* type of pipe under test */
	int fds[2];		/* un-named pipe fds */
	int read_fd;
	int write_fd;
	int empty_read = 0;	/* counter for the number of empty reads */
	time_t stime, ctime, dtime;	/* start time, current time, diff of times */
	int *count_word;	/* holds address where to write writers count */
	int *pid_word;		/* holds address where to write writers pid */
	int format;
	int format_size = -1;
	int background = 0;	/* if set, put process in background */
	struct stat stbuf;
        int iotype = 0;		/* sync io */
	char *toutput;		/* for getenv() */

	format = HEX;
	blk_type = NON_BLOCKING_IO;
	dir[0] = '\0';
	sprintf(pname,"%s.%d",PPATH,getpid());

	if ((Progname = (char *)strrchr(av[0],'/')) == NULL)
                Progname = av[0];
        else
                ++Progname;

	if( (toutput=getenv("TOUTPUT")) != NULL ) {
	    if( strcmp( toutput, "NOPASS") == 0 ) {
		quiet=1;
	    }
	}

        while ((c=getopt (ac, av, "BbCc:D:d:he:Ef:i:I:ln:p:qs:uvW:w:P:")) != EOF) {
	    switch (c) {
		case 'h':
			help();
			exit(0);
			break;
		case 'd':	/* dir name */
			strcpy(dir, optarg);
			break;
		case 'D':	/* pipe name */
			strcpy(pname, optarg);
			break;
		case 'B':	/* background */
			background=1;
			break;
		case 'b':	/* blocked */
			ndelay=0;
			blk_type = BLOCKING_IO;
			break;
		case 'C':
			fprintf(stderr,
			    "%s: --C option not supported on this architecture\n",
			    Progname);
			exit(1);
			break;
		case 'c':	/* number childern */
			if (sscanf(optarg, "%d", &num_wrters) != 1) {
				fprintf(stderr,"%s: --c option invalid arg '%s'.\n",
					Progname,optarg);
				usage();
				exit(1);
			}
			else if ( num_wrters <= 0 ) {
				fprintf(stderr,
				    "%s: --c option must be greater than zero.\n",
				    Progname);
				usage();
				exit(1);
			}
			break;
		case 'e':	/* exit on error # */
			if (sscanf(optarg, "%d", &exit_error) != 1) {
				fprintf(stderr,"%s: --e option invalid arg '%s'.\n",
					Progname,optarg);
				usage();
				exit(1);
			}
			else if ( exit_error < 0 ) {
				fprintf(stderr,
				    "%s: --e option must be greater than zero.\n",
				    Progname);
				usage();
				exit(1);
			}
			break;

		case 'E':
			prt_examples();
			exit(0);
			break;
		case 'f':	/* format of buffer on error */
			switch(optarg[0]) {
			case 'x':
			case 'X':
				format = HEX;
				break;
			case 'o':
			case 'O':
				format = OCTAL;
				break;
			case 'd':
			case 'D':
				format = DECIMAL;
				break;
			case 'a':
			case 'A':
				format = ASCII;
				break;
			case 'n':		/* not output */
			case 'N':
				format = NO_OUT;
				break;

			default :
				fprintf(stderr,"%s: --f option invalid arg '%s'.\n",
					Progname,optarg);
				fprintf(stderr,
				    "\tIt must be x(hex), o(octal), d(decimal), a(ascii) or n(none) with opt sz\n");
				exit(1);
				break;
			}
			cp = optarg;
			cp++;
			if ( *cp ) {
			    if ( sscanf(cp, "%i", &format_size) != 1 ) {
				fprintf(stderr,"%s: --f option invalid arg '%s'.\n",
					Progname,optarg);
				fprintf(stderr,
				    "\tIt must be x(hex), o(octal), d(decimal), a(ascii) or n(none) with opt sz\n");
				exit(1);
				break;
			    }
			}
			break;

    		case 'I':
     			if((iotype=lio_parse_io_arg1(optarg)) == -1 ) {
         		    fprintf(stderr,
             			"%s: --I arg is invalid, must be s, p, f, a, l, L or r.\n",
             			Progname);
         		    exit(1);
     			}
			break;

		case 'l':	/* loop forever */
			++loop;
			break;

		case 'i':
		case 'n':	/* number writes per child */
			if (sscanf(optarg, "%d", &num_writes) != 1) {
				fprintf(stderr,"%s: --i/n option invalid arg '%s'.\n",
					Progname,optarg);
				usage();
				exit(1);
			}
			else if ( num_writes < 0 ) {
				fprintf(stderr,
				    "%s: --i/n option must be greater than equal to zero.\n", 
				    Progname);
				usage();
				exit(1);
			}

			if (num_writes == 0)	/* loop forever */
				++loop;

			break;
		case 'P':	/* panic flag */
			fprintf(stderr, "%s: --P not supported on this architecture\n",
			    Progname);
			exit(1);
			break;
		case 'p':	/* ping */
			if (sscanf(optarg, "%d", &num_rpt) != 1) {
				fprintf(stderr,"%s: --p option invalid arg '%s'.\n",
					Progname,optarg);
				usage();
				exit(1);
			}
			else if ( num_rpt < 0 ) {
				fprintf(stderr,
					"%s: --p option must be greater than equal to zero.\n",
					Progname);
				usage();
				exit(1);
			}
			break;
	        case 'q':	/* Quiet - NOPASS */
			quiet=1;
			break;
		case 's':	/* size */
			if (sscanf(optarg, "%d", &size) != 1) {
				fprintf(stderr,"%s: --s option invalid arg '%s'.\n",
					Progname,optarg);
				usage();
				exit(1);
			}
			else if ( size <= 0 ) {
				fprintf(stderr,
				    "%s: --s option must be greater than zero.\n",
				    Progname);
				usage();
				exit(1);
			}
			break;
		case 'u':
			unpipe=1;	/* un-named pipe */
			break;
		case 'v':	/* verbose */
			verbose=1;
			break;
		case 'W':	/* max wait time between writes */
			d = strtod(optarg, &cp);
			if (*cp != '\0') {
				fprintf(stderr,"%s: --w option invalid arg '%s'.\n",
					Progname,optarg);
				usage();
				exit(1);
			}
			else if ( d < 0 ) {
				fprintf(stderr,
				    "%s: --w option must be greater than zero.\n",
				    Progname);
				usage();
				exit(1);
			}
			parent_wait = (int)(d * 1000000.0);
			break;
		case 'w':	/* max wait time between writes */
			d = strtod(optarg, &cp);
			if (*cp != '\0') {
				fprintf(stderr,"%s: --w option invalid arg '%s'.\n",
					Progname,optarg);
				usage();
				exit(1);
			}
			else if ( d < 0 ) {
				fprintf(stderr,
				    "%s: --w option must be greater than zero.\n",
				    Progname);
				usage();
				exit(1);
			}
			chld_wait = (int)(d * 1000000.0);
			break;
		case '?':
			usage();
			exit (1);
			break;
	    }
	}

	if ( format_size == -1 )
		format_size = size;

	/*
	 * 
	 * If there is more than one writer, all writes and reads
	 * must be the same size.  Only writes of a size <= PIPE_BUF
	 * are atomic.  T
	 * Therefore, if size is greater than PIPE_BUF, we will break
	 * the writes into PIPE_BUF chunks.  We will also increase the
	 * number of writes to ensure the same (or more) amount of 
	 * data is written.  This is the same as erroring and telling
	 * the user the new cmd line to do the same thing.
	 * Example:
	 *	pipeio -s 5000 -n 10 -c 5
	 *	(each child will write at least 50000 bytes, since all
	 *	writes have to be in 4096 chuncks or 13*4096 (53248)
	 *	bytes will be written.)  This is the same as:
	 *      pipeio -s 4096 -n 13 -c 5
	 */
	if ( size > PIPE_BUF && num_wrters > 1 ) {
	    if ( ! loop ) {
		j=(num_writes*size)/PIPE_BUF;
		if ( (num_writes*size)%PIPE_BUF ) 
		    j++;
		num_writes=j;
	        printf("%s: adjusting i/o size to %d, and # of writes to %d\n",
		    Progname, PIPE_BUF, num_writes);
	    }
	    else {
		printf("%s: adjusting i/o size to %d\n", Progname, PIPE_BUF);
	    }
	    size=PIPE_BUF;
	
	}

	if ((writebuf = (char *) malloc(size)) == NULL ||
	    (readbuf = (char *) malloc(size)) == NULL) {
		perror("malloc() failed:");
		
		exit(1);
	}

	memset(writebuf,'Z',size);

	writebuf[size-1] = 'A';	/* to detect partial read/write problem */

	if ( background ) {
	    if ( (n=fork() ) == -1 ) {
		fprintf(stderr,"%s: fork failed, errno:%d\n", Progname, errno);
		exit(1);
	    }
	    else if ( n != 0 ) /* parent */
		exit(0);
	}

	if ( unpipe ) {
		if ( pipe(fds) == -1 ) {
			fprintf(stderr,"%s: ERROR could not create un-named pipe\n",Progname);
			perror("pipe");
			fflush(stderr);
			exit(1);
		}
		read_fd = fds[0];
		write_fd = fds[1];
		pipe_type = PIPE_UNNAMED;
		blk_type = UNNAMED_IO;
	} else {
		if (strlen(dir) && chdir(dir) == -1) {
			fprintf(stderr, "%s:  ERROR could not chdir to %s",
				Progname, dir);
			perror("chdir");
			fflush(stderr);
			exit(1);
		}

		if ( stat(pname, &stbuf) == -1 ) {

		    if ( mkfifo(pname,0777) == -1 ) {
			fprintf(stderr,"%s: ERROR could not create pipe %s\n",Progname,pname);
			fprintf(stderr,"mkfifo(%s,0777) failed, errno:%d %s\n",
			    pname, errno, strerror(errno));
			fflush(stderr);
			exit(1);
		    }
		}
		pipe_type = PIPE_NAMED;
	}

	stime=time(0);

#if DEBUG
printf("num_wrters = %d\n", num_wrters);
#endif

	for (i=num_wrters; i > 0; --i) {
		if ((c=fork()) < 0) {
			fprintf(stderr,"%s: ERROR could not fork\n",Progname);
			perror("fork() failed:");
			exit(1);
		}
		if (c == 0) break;	/* stop child from forking */
	}
	if (c == 0) {	/***** if child *****/
#if DEBUG
printf("child after fork pid = %d\n", getpid());
#endif
		if ( ! unpipe ) {
			if (ndelay) sleep(1);
			if ((write_fd = open(pname,O_WRONLY|ndelay)) == -1) {
				fprintf(stderr,"%s: ERROR child could not open pipe %s\n",
					Progname,pname);
				fprintf(stderr, "open(%s, %#o) failed, errno:%d %s\n",
				    pname, O_WRONLY|ndelay, errno, 
				    strerror(errno));
				fflush(stderr);
				exit(1);
			}
		}
		else {
			close(read_fd);
		}

		pid_word = (int *)&writebuf[0];
		count_word = (int *)&writebuf[NBPW];

		for (j=0; j < num_writes || loop; ++j) {

			/* writes are only in one unit when the size of the write
			 * is <= PIPE_BUF.
			 * Therefore, if size is greater than PIPE_BUF, we will break
			 * the writes into PIPE_BUF chunks.
			 * All writes and read need to be same size.
			 */

			/*
			 * write pid and count in first two
			 * words of buffer
			 */

			*count_word = j;
			*pid_word = getpid();
			
                        if ((nb = lio_write_buffer(write_fd, iotype, writebuf, size,
                                                        SIGUSR1, &cp, 0)) == -1 ) {
                                fprintf(stderr, "%s: cnt:%d %s\n", Progname, j, cp);
                                fflush(stderr);
                                exit(1);
                        }
			if ( ndelay && nb == 0 ) {
				j--;
			}
			/*
			 * If lio_write_buffer returns a negative number,
			 * the return will be -errno.
			 */
			else if (nb < 0 )
				fprintf(stdout,
					"%s: ERROR write count %d: %s\n",
					Progname,j,cp);
			else if (nb != size ) {
				fprintf(stdout,
					"%s: ERROR write count %d, wrote only wrote %d and expected %d.\n",
					Progname,j,nb,size);
			}
		        if (verbose)
				fprintf(stdout,
					"%s: %d write count %d,wrote %d bytes expected %d bytes\n",
					Progname,getpid(),j,nb,size);
			
			if (chld_wait) {
                		clock=time(0);
               			srand48(clock);
                		n = lrand48() % chld_wait;
				usleep(n); 
			}
			fflush(stderr);
		}
	}
	if (c > 0) {	/***** if parent *****/
#ifdef linux
		signal(SIGCHLD, sig_child);
		signal(SIGHUP, sig_handler);
		signal(SIGINT, sig_handler);
		signal(SIGQUIT, sig_handler);
#ifdef SIGRECOVERY
		signal(SIGRECOVERY, sig_handler);
#endif /* SIGRECOVERY */
#else
		sigset(SIGCHLD, sig_child);
		sigset(SIGHUP, sig_handler);
		sigset(SIGINT, sig_handler);
		sigset(SIGQUIT, sig_handler);
#ifdef SIGRECOVERY
		sigset(SIGRECOVERY, sig_handler);
#endif /* SIGRECOVERY */
#endif /* linux */

		if ( ! unpipe ) {
			if ((read_fd = open(pname,O_RDONLY|ndelay)) == -1) {
				fprintf(stderr,"%s: ERROR parent could not open pipe %s\n",
					Progname,pname);
				fprintf(stderr, "open(%s, %#o) failed, errno:%d %s\n",
				    pname, O_RDONLY|ndelay, errno, 
				    strerror(errno));
				fflush(stderr);
				exit(1);
			}
		}
		else {
			close(write_fd);
		}

		for (i=num_wrters*num_writes; i > 0 || loop; --i) {
			if ( Nchildcomplete >= num_wrters ) {
				break; /* All children have died */
			}
			if (parent_wait) {
                		clock=time(0);
                		srand48(clock);
                		n = lrand48() % parent_wait;
				usleep(n);
			}
			++count;
			if ((nb = lio_read_buffer(read_fd, iotype, readbuf, size,
                   					SIGUSR1, &cp, 0)) == -1 ) {
				fprintf(stderr, "%s: cnt:%d %s\n", 
				     Progname, count, cp);
				fflush(stderr);
				exit(1);
			}
                        /*
                         * If lio_read_buffer returns a negative number,
                         * the return will be -errno.
                         */
                        else if (nb < 0 ) {
			    fprintf(stdout,
					"%s: ERROR read count %d: %s\n",
					Progname,i,cp);
			    ++i;
			    count--;
			    continue;

 			} else {
				if (nb == 0) {
					empty_read++;
/*
					fprintf(stdout,
						"%s: Nothing on the pipe (%d),read count %d (read not counted)\n",
						Progname,empty_read,count);
 */
					fflush(stdout);
					++i;
					count--;
					continue;
				} else if (nb < size && size <= PIPE_BUF) {
					fprintf(stdout,
						"%s: partial read from the pipe: read %d bytes, expected %d, read count %d\n",
						Progname,nb, size, count);
					fflush(stdout);
					++error;
				} else if (nb == size) {
					for (j=2*NBPW;j < size; ++j) {
						if (writebuf[j] != readbuf[j]) {
							++error;
							fprintf(stdout,"%s 1 FAIL data error on byte %d\n",
								Progname,j);
							fprintf(stdout,
							"%s: rd# %d, sz= %d, %s %s empty_reads= %d, err= %d\n",
							Progname,count,size,pipe_type,blk_type,
							empty_read,error);
							prt_buf(&readbuf,readbuf,format_size,format);
							fflush(stdout);
							if ( exit_error && exit_error == error )
								goto output;

							else 
								break;
						}
					}
				} 
				if (verbose || (num_rpt && !(count % num_rpt))) {
					ctime = time(0);
					dtime = ctime - stime;	/* elapsed time */
					fprintf(stdout,
						"%s:(%d) rd# %d, sz= %d, %s %s empty_reads= %d, err= %d\n",
						Progname,(int)dtime,count,size,pipe_type,
						blk_type,empty_read,error);
					fflush(stdout);
				}
			}
		}
output:
		if (error)
			fprintf(stdout,
				"%s 1 FAIL %d data errors on pipe, read size = %d, %s %s\n",
				Progname,error,size,pipe_type,blk_type);
		else
			if( !quiet )
				fprintf(stdout,
					"%s 1 PASS %d pipe reads complete, read size = %d, %s %s\n",
					Progname,count+1,size,pipe_type,blk_type);
		fflush(stdout);

		if (!unpipe)
			unlink(pname);
	}
	return 0;
}

void
usage ()
{
	fprintf(stderr, "Usage: %s [-BbCEv][-c #writers][-D pname][-d dir][-h][-e exit_num][-f fmt][-l][-i #writes][-n #writes][-p num_rpt]\n\t[-s size][-W max_wait][-w max_wait][-u]\n",Progname);
	fflush(stderr);

}

void
help()
{
        usage();

    printf("  -B           - execute actions in background\n\
  -b           - blocking reads and writes. default non-block\n\
  -c #writers  - number of writers (childern)\n\
  -D pname     - name of fifo (def tpipe<pid>)\n\
  -d dir       - cd to dir before creating named pipe\n\
               - (silently ignored if used with -u)\n\
  -h           - print this help message\n\
  -e exit_num  - exit on error exit_num, 0 is ignore errors, 1 is default.\n\
  -E           - print cmd line examples and exit\n\
  -f format    - define format of bad buffer: h(hex), o(octal)\n\
                 d(decimal), a(ascii), n (none). hex is default\n\
	         option size can be added to control output\n\
  -i #writes   - number write per child, zero means forever.\n\
  -I io_type   - Specifies io type: s - sync, p - polled async, a - async (def s)\n\
                 l - listio sync, L - listio async, r - random\n\
  -l           - loop forever (implied by -n 0).\n\
  -n #writes   - same as -i (for compatability).\n\
  -p num_rpt   - number of reads before a report\n\
  -q           - quiet mode, no PASS results are printed\n\
  -s size      - size of read and write (def 327)\n\
                 if size >= 4096, i/o will be in 4096 chuncks\n\
  -w max_wait  - max time (seconds) for sleep between writes.\n\
                 max_wait is interpreted as a double with ms accuracy.\n\
  -W max_wait  - max time (seconds) for sleep between reads\n\
                 max_wait is interpreted as a double with ms accuracy.\n\
  -u           - un-named pipe instead of named pipe\n\
  -v           - verbose mode, all writes/reads resutlts printed\n");

	fflush(stdout);
        
}

void
prt_buf(long addr, char * buf, int length, int format)
{

	int i;
	int num_words = length/NBPW;  /* given length in bytes, get length in words */
	int width;		/* number of columns */
	int extra_words;	/* odd or even number of words */
	char *a = buf;
	char b[NBPW];
	char c[NBPW*2];
	char *p;
	long *word;

	if ( format == NO_OUT )		/* if no output wanted, return */
		return;

	if (length % NBPW) ++num_words; /* is length in full words? */
	if (format == ASCII) {
	 	width = 3;
	} else {
		width = 2;
	    /* do we have an odd number of words? */
		extra_words = num_words%width;
	}
	for(i=0; i < num_words; ++i, a += NBPW, addr++) {
		word = (long *) a;
		if (!(i%width)) {
			if (i > 0 && format != ASCII) {
		   	  /*
		    	   * print the ascii equivalent of the data
			   * before beginning the next line of output.
			   */
				bzero(c,width*NBPW);
			   /*
			    * get the last 2 words printed 
			    */
				bcopy(a-(width*NBPW),c,width*NBPW);
				for (p = c; (p-c) < width*NBPW; ++p) {
					if (*p < '!' || *p > '~')
						*p = '.';
				}
				printf("\t%16.16s",c);
			}
			printf("\n%7lo: ",addr);
			/***printf("\n%7o (%d): ",addr,i);***/
		}

		switch (format) {
			case HEX:
				printf("%16.16lx ",*word);
				break;
			case DECIMAL:
				printf("%10.10ld ",*word);
				break;
			case ASCII:
				bcopy(a,b,NBPW);
				for (p = b; (p-b) < NBPW; ++p) {
					if (*p < '!' || *p > '~')
						*p = '.';
				}
				printf("%8.8s ",b);
				break;
			default:
				printf("%22.22lo ",*word);
				break;
		}
	}
	if (format != ASCII) {
   	  /*
    	   * print the ascii equivalent of the last words in the buffer
	   * before returning.
	   */
		bzero(c,width*NBPW);
		if (extra_words) width = extra_words; /* odd number of words */
		bcopy(a-(width*NBPW),c,width*NBPW);
		for (p = c; (p-c) < width*NBPW; ++p) {
			if (*p < '!' || *p > '~')
				*p = '.';
		}
		if (width == 2) 
			printf("\t%16.16s",c);
		else
			printf("\t\t%16.8s",c);
	}
	printf("\n");
	fflush(stdout);
}

void
prt_examples()
{
    printf("%s -c 5 -i 0 -s 4090 -b\n", Progname);
    printf("%s -c 5 -i 0 -s 4090 -b -u \n", Progname);
    printf("%s -c 5 -i 0 -s 4090 -b -W 3 -w 3 \n", Progname);

}

void
sig_child(int sig)
{
    int status;

    Nchildcomplete++;
#if DEBUG
printf("parent: received SIGCHLD\n");
#endif
    waitpid(-1, &status, WNOHANG);
#if linux
    signal(SIGCHLD, sig_child);
#else
    sigset(SIGCHLD, sig_child);
#endif
}

void
sig_handler(int sig)
{
#ifdef SIGRECOVERY
    if ( sig == SIGRECOVERY) {
	printf("%s: received SIGRECOVERY, count = %d\n", Progname, count);
        fflush(stdout);
#ifdef linux
	signal(sig, sig_handler);
#else
	sigset(sig, sig_handler);
#endif
	return;
    }
#endif
    printf("%s: received unexpected signal: %d\n", Progname, sig);
    fflush(stdout);
    exit(3);

}