blob: 7dfbe447f5d7d5d123dc94b89a1859993071790c [file] [log] [blame]
/*
* Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* Further, this software is distributed without any warranty that it is
* free of the rightful claim of any third person regarding infringement
* or the like. Any license provided herein, whether implied or
* otherwise, applies only to this software file. Patent licenses, if
* any, provided herein do not apply to combinations of this program with
* other software, or any other product whatsoever.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
* Mountain View, CA 94043, or:
*
* http://www.sgi.com
*
* For further information regarding this notice, see:
*
* http://oss.sgi.com/projects/GenInfo/NoticeExplan/
*
*/
/* $Header: /cvsroot/ltp/ltp/testcases/kernel/ipc/pipeio/pipeio.c,v 1.18 2009/03/19 07:10:02 subrata_modak Exp $ */
/*
* 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 <time.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/sem.h>
#include "tlibio.h"
#include "test.h"
char *TCID = "pipeio"; /* Test program identifier. */
int TST_TOTAL = 1; /* Total number of test cases. */
#define SAFE_FREE(p) { if (p) { free(p); (p)=NULL; } }
/* To avoid extensive modifications to the code, use this bodge */
#define exit(x) myexit(x)
void myexit(int x)
{
if (x)
tst_resm(TFAIL, "Test failed");
else
tst_resm(TPASS, "Test passed");
tst_exit();
}
#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 ""
#define MAX_ERRS 16
#define MAX_EMPTY 256
void sig_handler(), help(), usage(), prt_buf(), prt_examples();
void sig_child();
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 = NULL;
char *readbuf = NULL;
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 = 0;
int write_fd = 0;
int empty_read = 0;
time_t start_time, current_time, diff_time; /* 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() */
int sem_id;
struct sembuf sem_op;
union semun { /* for semctl() */
int val;
struct semid_ds *buf;
unsigned short int *array;
} u;
unsigned int uwait_iter = 1000;
unsigned int uwait_total = 5000000;
u.val = 0;
format = HEX;
blk_type = NON_BLOCKING_IO;
dir[0] = '\0';
sprintf(pname, "%s.%d", PPATH, getpid());
if ((toutput = getenv("TOUTPUT")) != NULL) {
if (strcmp(toutput, "NOPASS") == 0) {
quiet = 1;
}
}
while ((c =
getopt(ac, av,
"T:BbCc:D:d:he:Ef:i:I:ln:p:qs:uvW:w:P:")) != EOF) {
switch (c) {
case 'T':
TCID = optarg;
break;
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",
TCID);
exit(1);
break;
case 'c': /* number childern */
if (sscanf(optarg, "%d", &num_wrters) != 1) {
fprintf(stderr,
"%s: --c option invalid arg '%s'.\n",
TCID, optarg);
usage();
exit(1);
} else if (num_wrters <= 0) {
fprintf(stderr,
"%s: --c option must be greater than zero.\n",
TCID);
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",
TCID, optarg);
usage();
exit(1);
} else if (exit_error < 0) {
fprintf(stderr,
"%s: --e option must be greater than zero.\n",
TCID);
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",
TCID, 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",
TCID, 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",
TCID);
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",
TCID, optarg);
usage();
exit(1);
} else if (num_writes < 0) {
fprintf(stderr,
"%s: --i/n option must be greater than equal to zero.\n",
TCID);
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",
TCID);
exit(1);
break;
case 'p': /* ping */
if (sscanf(optarg, "%d", &num_rpt) != 1) {
fprintf(stderr,
"%s: --p option invalid arg '%s'.\n",
TCID, optarg);
usage();
exit(1);
} else if (num_rpt < 0) {
fprintf(stderr,
"%s: --p option must be greater than equal to zero.\n",
TCID);
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",
TCID, optarg);
usage();
exit(1);
} else if (size <= 0) {
fprintf(stderr,
"%s: --s option must be greater than zero.\n",
TCID);
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",
TCID, optarg);
usage();
exit(1);
} else if (d < 0) {
fprintf(stderr,
"%s: --w option must be greater than zero.\n",
TCID);
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",
TCID, optarg);
usage();
exit(1);
} else if (d < 0) {
fprintf(stderr,
"%s: --w option must be greater than zero.\n",
TCID);
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) {
/* we must set num_writes s.t. num_writes*num_wrters doesn't overflow later */
num_writes =
MIN(((long long)num_writes * size + PIPE_BUF -
1) / PIPE_BUF, INT_MAX / num_wrters);
tst_resm(TINFO,
"adjusting i/o size to %d, and # of writes to %d",
PIPE_BUF, num_writes);
} else {
tst_resm(TINFO, "adjusting i/o size to %d", PIPE_BUF);
}
size = PIPE_BUF;
}
if ((writebuf = (char *)malloc(size)) == NULL ||
(readbuf = (char *)malloc(size)) == NULL) {
tst_resm(TFAIL | TERRNO, "malloc() failed");
SAFE_FREE(writebuf);
SAFE_FREE(readbuf);
exit(1);
}
memset(writebuf, 'Z', size);
writebuf[size - 1] = 'A'; /* to detect partial read/write problem */
if ((sem_id = semget(IPC_PRIVATE, 2, IPC_CREAT | S_IRWXU)) == -1) {
tst_brkm(TBROK | TERRNO, NULL, "Couldn't allocate semaphore");
}
if (semctl(sem_id, 0, SETVAL, u) == -1)
tst_brkm(TBROK | TERRNO, NULL,
"Couldn't initialize semaphore 0 value");
/* semaphore to hold off children from exiting until open() completes */
if (semctl(sem_id, 1, SETVAL, u) == -1)
tst_brkm(TBROK | TERRNO, NULL,
"Couldn't initialize semaphore 1 value");
if (background) {
if ((n = fork()) == -1) {
tst_resm(TFAIL | TERRNO, "fork() failed");
exit(1);
} else if (n != 0) /* parent */
exit(0);
}
if (unpipe) {
if (pipe(fds) == -1) {
tst_resm(TFAIL | TERRNO,
"pipe() failed to create un-named pipe");
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) {
tst_resm(TFAIL | TERRNO, "chdir(%s) failed", dir);
exit(1);
}
if (stat(pname, &stbuf) == -1) {
if (mkfifo(pname, 0777) == -1) {
tst_resm(TFAIL | TERRNO,
"mkfifo(%s,0777) failed", pname);
exit(1);
}
}
pipe_type = PIPE_NAMED;
}
start_time = time(0);
#if DEBUG
printf("num_wrters = %d\n", num_wrters);
#endif
#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 */
for (i = num_wrters; i > 0; --i) {
if ((c = fork()) < 0) {
tst_resm(TFAIL | TERRNO, "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 ((write_fd = open(pname, O_WRONLY)) == -1) {
tst_resm(TFAIL | TERRNO,
"child pipe open(%s, %#o) failed",
pname, O_WRONLY | ndelay);
exit(1);
}
if (ndelay
&& fcntl(write_fd, F_SETFL, O_NONBLOCK) == -1) {
tst_brkm(TBROK | TERRNO, NULL,
"Failed setting the pipe to nonblocking mode");
}
} else {
close(read_fd);
}
sem_op = (struct sembuf) {
.sem_num = 0,.sem_op = 1,.sem_flg = 0};
if (semop(sem_id, &sem_op, 1) == -1)
tst_brkm(TBROK | TERRNO, NULL,
"Couldn't raise the semaphore 0");
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)) < 0) {
/*
* If lio_write_buffer returns a negative number,
* the return will be -errno.
*/
tst_resm(TFAIL,
"pass %d: lio_write_buffer(%s) failed; it returned %d: %s",
j, cp, nb, strerror(-nb));
exit(1);
} else if (nb != size) {
tst_resm(TFAIL,
"pass %d: lio_write_buffer(%s) failed, write count %d, but expected to write %d",
j, cp, nb, size);
}
if (verbose)
tst_resm(TINFO,
"pass %d: pid %d: wrote %d bytes, expected %d bytes",
j, getpid(), nb, size);
if (chld_wait) {
clock = time(0);
srand48(clock);
n = lrand48() % chld_wait;
usleep(n);
}
fflush(stderr);
}
/* child waits until parent completes open() */
sem_op = (struct sembuf) {
.sem_num = 1,.sem_op = -1,.sem_flg = 0};
if (semop(sem_id, &sem_op, 1) == -1)
tst_brkm(TBROK | TERRNO, NULL,
"Couldn't lower the semaphore 1");
}
if (c > 0) { /***** if parent *****/
if (!unpipe) {
if ((read_fd = open(pname, O_RDONLY)) == -1) {
tst_resm(TFAIL | TERRNO,
"parent pipe open(%s, %#o) failed",
pname, O_RDONLY);
exit(1);
}
if (ndelay && fcntl(read_fd, F_SETFL, O_NONBLOCK) == -1) {
tst_brkm(TBROK | TERRNO, NULL,
"Failed setting the pipe to nonblocking mode");
}
} else {
close(write_fd);
}
/* raise semaphore so children can exit */
sem_op = (struct sembuf) {
.sem_num = 1,.sem_op = num_wrters,.sem_flg = 0};
if (semop(sem_id, &sem_op, 1) == -1)
tst_brkm(TBROK | TERRNO, NULL,
"Couldn't raise the semaphore 1");
sem_op = (struct sembuf) {
.sem_num = 0,.sem_op = -num_wrters,.sem_flg = 0};
while (Nchildcomplete < num_wrters
&& semop(sem_id, &sem_op, 1) == -1) {
if (errno == EINTR) {
continue;
}
tst_brkm(TBROK | TERRNO, NULL,
"Couldn't wait on semaphore 0");
}
for (i = num_wrters * num_writes; i > 0 || loop; --i) {
if (error >= MAX_ERRS || empty_read >= MAX_EMPTY)
break;
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)) < 0) {
/*
* If lio_read_buffer returns a negative number,
* the return will be -errno.
*/
tst_resm(TFAIL,
"pass %d: lio_read_buffer(%s) failed; it returned %d: %s",
i, cp, nb, strerror(-nb));
++i;
count--;
error++;
continue;
} else {
if (nb == 0) {
if (Nchildcomplete >= num_wrters) {
if (!loop)
tst_resm(TWARN,
"The children have died prematurely");
break; /* All children have died */
}
empty_read++;
/*
fprintf(stdout,
"%s: Nothing on the pipe (%d),read count %d (read not counted)\n",
TCID,empty_read,count);
fflush(stdout);
*/
++i;
count--;
continue;
} else if (nb < size && size <= PIPE_BUF) {
tst_resm(TFAIL,
"pass %d: partial read from the pipe: read %d bytes, expected %d, read count %d",
i, nb, size, count);
++error;
} else if (nb == size) {
for (j = 2 * NBPW; j < size; ++j) {
if (writebuf[j] != readbuf[j]) {
++error;
tst_resm(TFAIL,
"1 FAIL data error on byte %d; rd# %d, sz= %d, %s %s empty_reads= %d, err= %d",
j, 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))) {
current_time = time(0);
diff_time = current_time - start_time; /* elapsed time */
tst_resm(TFAIL,
"(%d) rd# %d, sz= %d, %s %s empty_reads= %d, err= %d\n",
(int)diff_time, count, size,
pipe_type, blk_type,
empty_read, error);
fflush(stdout);
}
}
}
if (empty_read)
tst_resm(TWARN, "%d empty reads", empty_read);
output:
if (error)
tst_resm(TFAIL,
"1 FAIL %d data errors on pipe, read size = %d, %s %s",
error, size, pipe_type, blk_type);
else if (!quiet)
tst_resm(TPASS,
"1 PASS %d pipe reads complete, read size = %d, %s %s",
count + 1, size, pipe_type, blk_type);
/* wait for all children to finish, timeout after uwait_total
semtimedop might not be available everywhere */
for (i = 0; i < uwait_total; i += uwait_iter) {
if (semctl(sem_id, 1, GETVAL) == 0) {
break;
}
usleep(uwait_iter);
}
if (i > uwait_total) {
tst_resm(TWARN,
"Timed out waiting for child processes to exit");
}
semctl(sem_id, 0, IPC_RMID);
if (!unpipe)
unlink(pname);
}
SAFE_FREE(writebuf);
SAFE_FREE(readbuf);
return (error);
}
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",
TCID);
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 = 0; /* 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.
*/
memset(c, 0x00, width * NBPW);
/*
* get the last 2 words printed
*/
memcpy(c, a - (width * NBPW), 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:
memcpy(b, a, 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.
*/
memset(c, 0x00, width * NBPW);
if (extra_words)
width = extra_words; /* odd number of words */
memcpy(c, a - (width * NBPW), 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", TCID);
printf("%s -c 5 -i 0 -s 4090 -b -u \n", TCID);
printf("%s -c 5 -i 0 -s 4090 -b -W 3 -w 3 \n", TCID);
}
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", TCID, count);
fflush(stdout);
#ifdef linux
signal(sig, sig_handler);
#else
sigset(sig, sig_handler);
#endif
return;
}
#endif
printf("%s: received unexpected signal: %d\n", TCID, sig);
fflush(stdout);
exit(3);
}