Home | History | Annotate | Download | only in pipeio
      1 /*
      2  * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
      3  *
      4  * This program is free software; you can redistribute it and/or modify it
      5  * under the terms of version 2 of the GNU General Public License as
      6  * published by the Free Software Foundation.
      7  *
      8  * This program is distributed in the hope that it would be useful, but
      9  * WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     11  *
     12  * Further, this software is distributed without any warranty that it is
     13  * free of the rightful claim of any third person regarding infringement
     14  * or the like.  Any license provided herein, whether implied or
     15  * otherwise, applies only to this software file.  Patent licenses, if
     16  * any, provided herein do not apply to combinations of this program with
     17  * other software, or any other product whatsoever.
     18  *
     19  * You should have received a copy of the GNU General Public License along
     20  * with this program; if not, write the Free Software Foundation, Inc.,
     21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     22  *
     23  * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
     24  * Mountain View, CA  94043, or:
     25  *
     26  * http://www.sgi.com
     27  *
     28  * For further information regarding this notice, see:
     29  *
     30  * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
     31  *
     32  */
     33 /* $Header: /cvsroot/ltp/ltp/testcases/kernel/ipc/pipeio/pipeio.c,v 1.18 2009/03/19 07:10:02 subrata_modak Exp $ */
     34 /*
     35  *  This tool can be used to beat on system or named pipes.
     36  *  See the help() function below for user information.
     37  */
     38 #include <stdio.h>
     39 #include <fcntl.h>
     40 #include <stdlib.h>
     41 #include <unistd.h>
     42 #include <sys/types.h>
     43 #include <sys/param.h>
     44 #include <sys/wait.h>
     45 #include <time.h>
     46 #include <errno.h>
     47 #include <string.h>
     48 #include <signal.h>
     49 #include <sys/stat.h>
     50 #include <sys/sem.h>
     51 
     52 #include "tlibio.h"
     53 
     54 #include "test.h"
     55 #include "safe_macros.h"
     56 #include "lapi/semun.h"
     57 
     58 char *TCID = "pipeio";
     59 int TST_TOTAL = 1;
     60 
     61 #define SAFE_FREE(p) { if (p) { free(p); (p)=NULL; } }
     62 
     63 #if defined(__linux__)
     64 #define NBPW sizeof(int)
     65 #endif
     66 
     67 #define OCTAL	'o'
     68 #define HEX	'x'
     69 #define DECIMAL	'd'
     70 #define ASCII	'a'
     71 #define NO_OUT	'n'
     72 
     73 #define PIPE_NAMED	"named pipe,"
     74 #define PIPE_UNNAMED	"sys pipe,"
     75 
     76 #define BLOCKING_IO	"blking,"
     77 #define NON_BLOCKING_IO	"non-blking,"
     78 #define UNNAMED_IO	""
     79 
     80 #define MAX_ERRS 16
     81 #define MAX_EMPTY 256
     82 
     83 static int parse_options(int argc, char *argv[]);
     84 static void setup(int argc, char *argv[]);
     85 static void cleanup(void);
     86 
     87 static void do_child(void);
     88 static void do_parent(void);
     89 
     90 static void help(void), usage(void), prt_examples(void);
     91 static void prt_buf(char **addr, char *buf, int length, int format);
     92 static void sig_child(int sig);
     93 static int check_rw_buf(void);
     94 
     95 static volatile sig_atomic_t nchildcompleted;
     96 
     97 /* variables may be modified in setup() */
     98 static int num_writers = 1;	/* number of writers */
     99 static int num_writes = 1;	/* number of writes per child */
    100 static int loop;		/* loop indefinitely */
    101 static int exit_error = 1;	/* exit on error #, zero means no exit */
    102 static int size = 327;		/* default size */
    103 static int unpipe;		/* un-named pipe if non-zero */
    104 static int verbose;		/* verbose mode if set */
    105 static int quiet;		/* quiet mode if set */
    106 static int num_rpt;		/* ping number, how often to print message */
    107 static int chld_wait;	/* max time to wait between writes, 1 == no wait */
    108 static int parent_wait;	/* max time to wait between reads, 1 == no wait */
    109 static int ndelay = O_NDELAY;	/* additional flag to open */
    110 static char *writebuf;
    111 static char *readbuf;
    112 static char pname[PATH_MAX];	/* contains the name of the named pipe */
    113 static char *blk_type = NON_BLOCKING_IO; /* blocking i/o or not */
    114 static char *pipe_type;		/* type of pipe under test */
    115 static int format = HEX;
    116 static int format_size = -1;
    117 static int iotype;		/* sync io */
    118 
    119 /* variables will be modified in running */
    120 static int error;
    121 static int count;
    122 static int read_fd;
    123 static int write_fd;
    124 static int empty_read;
    125 static int sem_id;
    126 
    127 static union semun u;
    128 
    129 int main(int ac, char *av[])
    130 {
    131 	int i;
    132 	unsigned int j;
    133 	unsigned int uwait_iter = 1000, uwait_total = 5000000;
    134 	pid_t child;
    135 
    136 	setup(ac, av);
    137 
    138 	for (i = num_writers; i > 0; --i) {
    139 
    140 		child = tst_fork();
    141 		switch (child) {
    142 		case -1:
    143 			tst_brkm(TBROK | TERRNO, cleanup, "fork() failed");
    144 		case 0:
    145 			do_child();
    146 			exit(0);
    147 		default:
    148 			break;
    149 		}
    150 	}
    151 
    152 	do_parent();
    153 
    154 	if (empty_read)
    155 		tst_resm(TWARN, "%d empty reads", empty_read);
    156 
    157 	if (error) {
    158 		tst_resm(TFAIL, "%d data errors on pipe, read size = %d, %s %s",
    159 			 error, size, pipe_type, blk_type);
    160 	} else if (!quiet) {
    161 		tst_resm(TPASS, "%d pipe reads complete, read size = %d, %s %s",
    162 			 count + 1, size, pipe_type, blk_type);
    163 	}
    164 
    165 	/*
    166 	 * wait for all children to finish, timeout after uwait_total
    167 	 * semtimedop might not be available everywhere
    168 	 */
    169 	for (j = 0; j < uwait_total; j += uwait_iter) {
    170 		if (semctl(sem_id, 1, GETVAL) == 0)
    171 			break;
    172 		usleep(uwait_iter);
    173 	}
    174 
    175 	if (j >= uwait_total) {
    176 		tst_resm(TWARN,
    177 			 "Timed out waiting for child processes to exit");
    178 	}
    179 
    180 	cleanup();
    181 	tst_exit();
    182 }
    183 
    184 static int parse_options(int argc, char *argv[])
    185 {
    186 	char *cp;
    187 	int c;
    188 	int ret = 0;
    189 	static double d;
    190 
    191 	while ((c = getopt(argc, argv, "T:bc:D:he:Ef:i:I:ln:p:qs:uvW:w:"))
    192 	       != -1) {
    193 		switch (c) {
    194 		case 'T':
    195 			TCID = optarg;
    196 			break;
    197 		case 'h':
    198 			help();
    199 			ret = 1;
    200 			break;
    201 		case 'D':	/* pipe name */
    202 			strcpy(pname, optarg);
    203 			break;
    204 		case 'b':	/* blocked */
    205 			ndelay = 0;
    206 			blk_type = BLOCKING_IO;
    207 			break;
    208 		case 'c':	/* number childern */
    209 			if (sscanf(optarg, "%d", &num_writers) != 1) {
    210 				fprintf(stderr,
    211 					"%s: --c option invalid arg '%s'.\n",
    212 					TCID, optarg);
    213 				ret = 1;
    214 			} else if (num_writers <= 0) {
    215 				fprintf(stderr, "%s: --c option must be "
    216 					"greater than zero.\n", TCID);
    217 				ret = 1;
    218 			}
    219 			break;
    220 		case 'e':	/* exit on error # */
    221 			if (sscanf(optarg, "%d", &exit_error) != 1) {
    222 				fprintf(stderr,
    223 					"%s: --e option invalid arg '%s'.\n",
    224 					TCID, optarg);
    225 				ret = 1;
    226 			} else if (exit_error < 0) {
    227 				fprintf(stderr, "%s: --e option must be "
    228 					"greater than zero.\n", TCID);
    229 				ret = 1;
    230 			}
    231 			break;
    232 		case 'E':
    233 			prt_examples();
    234 			ret = 1;
    235 			break;
    236 		case 'f':	/* format of buffer on error */
    237 			switch (optarg[0]) {
    238 			case 'x':
    239 			case 'X':
    240 				format = HEX;
    241 				break;
    242 			case 'o':
    243 			case 'O':
    244 				format = OCTAL;
    245 				break;
    246 			case 'd':
    247 			case 'D':
    248 				format = DECIMAL;
    249 				break;
    250 			case 'a':
    251 			case 'A':
    252 				format = ASCII;
    253 				break;
    254 			case 'n':	/* not output */
    255 			case 'N':
    256 				format = NO_OUT;
    257 				break;
    258 
    259 			default:
    260 				fprintf(stderr,
    261 					"%s: --f option invalid arg '%s'.\n",
    262 					TCID, optarg);
    263 				fprintf(stderr, "\tIt must be x(hex), o(octal),"
    264 					"d(decimal), a(ascii) or n(none) with "
    265 					"opt sz\n");
    266 				ret = 1;
    267 				break;
    268 			}
    269 			cp = optarg;
    270 			cp++;
    271 			if (*cp) {
    272 				if (sscanf(cp, "%i", &format_size) != 1) {
    273 					fprintf(stderr, "%s: --f option invalid"
    274 						"arg '%s'.\n", TCID, optarg);
    275 					fprintf(stderr, "\tIt must be x(hex),"
    276 						"o(octal), d(decimal), a(ascii)"
    277 						" or n(none) with opt sz\n");
    278 					ret = 1;
    279 					break;
    280 				}
    281 			}
    282 			break;
    283 
    284 		case 'I':
    285 			iotype = lio_parse_io_arg1(optarg);
    286 			if (iotype == -1) {
    287 				fprintf(stderr, "%s: --I arg is invalid, "
    288 					"must be s, p, f, a, l, L or r.\n",
    289 					TCID);
    290 				ret = 1;
    291 			}
    292 			break;
    293 
    294 		case 'l':	/* loop forever */
    295 			++loop;
    296 			break;
    297 
    298 		case 'i':
    299 		case 'n':	/* number writes per child */
    300 			if (sscanf(optarg, "%d", &num_writes) != 1) {
    301 				fprintf(stderr, "%s: --i/n option invalid "
    302 					"arg '%s'.\n", TCID, optarg);
    303 				ret = 1;
    304 			} else if (num_writes < 0) {
    305 				fprintf(stderr, "%s: --i/n option must be "
    306 					"greater than equal to zero.\n",
    307 					TCID);
    308 				ret = 1;
    309 			}
    310 
    311 			if (num_writes == 0)	/* loop forever */
    312 				++loop;
    313 			break;
    314 		case 'p':	/* ping */
    315 			if (sscanf(optarg, "%d", &num_rpt) != 1) {
    316 				fprintf(stderr,
    317 					"%s: --p option invalid arg '%s'.\n",
    318 					TCID, optarg);
    319 				ret = 1;
    320 			} else if (num_rpt < 0) {
    321 				fprintf(stderr, "%s: --p option must be greater"
    322 					" than equal to zero.\n", TCID);
    323 				ret = 1;
    324 			}
    325 			break;
    326 		case 'q':	/* Quiet - NOPASS */
    327 			quiet = 1;
    328 			break;
    329 		case 's':	/* size */
    330 			if (sscanf(optarg, "%d", &size) != 1) {
    331 				fprintf(stderr,
    332 					"%s: --s option invalid arg '%s'.\n",
    333 					TCID, optarg);
    334 				ret = 1;
    335 			} else if (size <= 0) {
    336 				fprintf(stderr, "%s: --s option must be greater"
    337 					" than zero.\n", TCID);
    338 				ret = 1;
    339 			}
    340 			break;
    341 		case 'u':
    342 			unpipe = 1;	/* un-named pipe */
    343 			break;
    344 		case 'v':	/* verbose */
    345 			verbose = 1;
    346 			break;
    347 		case 'W':	/* max wait time between reads */
    348 			d = strtod(optarg, &cp);
    349 			if (*cp != '\0') {
    350 				fprintf(stderr,
    351 					"%s: --w option invalid arg '%s'.\n",
    352 					TCID, optarg);
    353 				ret = 1;
    354 			} else if (d < 0) {
    355 				fprintf(stderr, "%s: --w option must be greater"
    356 					" than zero.\n", TCID);
    357 				ret = 1;
    358 			}
    359 			parent_wait = (int)(d * 1000000.0);
    360 			break;
    361 		case 'w':	/* max wait time between writes */
    362 			d = strtod(optarg, &cp);
    363 			if (*cp != '\0') {
    364 				fprintf(stderr,
    365 					"%s: --w option invalid arg '%s'.\n",
    366 					TCID, optarg);
    367 				ret = 1;
    368 			} else if (d < 0) {
    369 				fprintf(stderr, "%s: --w option must be greater"
    370 					" than zero.\n", TCID);
    371 				ret = 1;
    372 			}
    373 			chld_wait = (int)(d * 1000000.0);
    374 			break;
    375 		case '?':
    376 			ret = 1;
    377 			break;
    378 		}
    379 
    380 		if (ret == 1) {
    381 			usage();
    382 			return ret;
    383 		}
    384 	}
    385 
    386 	return ret;
    387 }
    388 
    389 static void setup(int argc, char *argv[])
    390 {
    391 	int ret;
    392 	char *toutput;
    393 	int fds[2];
    394 
    395 	tst_sig(FORK, DEF_HANDLER, cleanup);
    396 
    397 	TEST_PAUSE;
    398 
    399 	tst_tmpdir();
    400 
    401 	if (signal(SIGCHLD, sig_child) == SIG_ERR) {
    402 		tst_brkm(TBROK | TERRNO, cleanup,
    403 			 "set signal handler for SIGCHLD failed");
    404 	}
    405 
    406 	toutput = getenv("TOUTPUT");
    407 	if (toutput != NULL && strcmp(toutput, "NOPASS") == 0)
    408 		quiet = 1;
    409 
    410 	sprintf(pname, "%s", "tpipe");
    411 
    412 	ret = parse_options(argc, argv);
    413 	if (ret == 1)
    414 		tst_brkm(TBROK, cleanup, "options parse error");
    415 
    416 	if (format_size == -1)
    417 		format_size = size;
    418 
    419 	/*
    420 	 * If there is more than one writer, all writes and reads
    421 	 * must be the same size.  Only writes of a size <= PIPE_BUF
    422 	 * are atomic.  T
    423 	 * Therefore, if size is greater than PIPE_BUF, we will break
    424 	 * the writes into PIPE_BUF chunks.  We will also increase the
    425 	 * number of writes to ensure the same (or more) amount of
    426 	 * data is written.  This is the same as erroring and telling
    427 	 * the user the new cmd line to do the same thing.
    428 	 * Example:
    429 	 *      pipeio -s 5000 -n 10 -c 5
    430 	 *      (each child will write at least 50000 bytes, since all
    431 	 *      writes have to be in 4096 chuncks or 13*4096 (53248)
    432 	 *      bytes will be written.)  This is the same as:
    433 	 *      pipeio -s 4096 -n 13 -c 5
    434 	 */
    435 	if (size > PIPE_BUF && num_writers > 1) {
    436 		if (!loop) {
    437 			/*
    438 			 * we must set num_writes*num_writers
    439 			 * doesn't overflow later
    440 			 */
    441 			num_writes = MIN(((long long)num_writes * size +
    442 					 PIPE_BUF - 1) / PIPE_BUF,
    443 					 INT_MAX / num_writers);
    444 			tst_resm(TINFO, "adjusting i/o size to %d, and # of "
    445 				 "writes to %d", PIPE_BUF, num_writes);
    446 		} else {
    447 			tst_resm(TINFO, "adjusting i/o size to %d", PIPE_BUF);
    448 		}
    449 		size = PIPE_BUF;
    450 	}
    451 
    452 	writebuf = SAFE_MALLOC(cleanup, size);
    453 	readbuf = SAFE_MALLOC(cleanup, size);
    454 
    455 	memset(writebuf, 'Z', size);
    456 	writebuf[size - 1] = 'A';
    457 
    458 	sem_id = semget(IPC_PRIVATE, 2, IPC_CREAT | S_IRWXU);
    459 	if (sem_id == -1) {
    460 		tst_brkm(TBROK | TERRNO, cleanup,
    461 			 "Couldn't allocate semaphore");
    462 	}
    463 
    464 	if (semctl(sem_id, 0, SETVAL, u) == -1) {
    465 		tst_brkm(TBROK | TERRNO, cleanup,
    466 			 "Couldn't initialize semaphore 0 value");
    467 	}
    468 
    469 	if (semctl(sem_id, 1, SETVAL, u) == -1) {
    470 		tst_brkm(TBROK | TERRNO, cleanup,
    471 			 "Couldn't initialize semaphore 1 value");
    472 	}
    473 
    474 	if (unpipe) {
    475 		SAFE_PIPE(cleanup, fds);
    476 		read_fd = fds[0];
    477 		write_fd = fds[1];
    478 		pipe_type = PIPE_UNNAMED;
    479 		blk_type = UNNAMED_IO;
    480 	} else {
    481 		SAFE_MKFIFO(cleanup, pname, 0777);
    482 		pipe_type = PIPE_NAMED;
    483 	}
    484 }
    485 
    486 static void cleanup(void)
    487 {
    488 	SAFE_FREE(writebuf);
    489 	SAFE_FREE(readbuf);
    490 
    491 	semctl(sem_id, 0, IPC_RMID);
    492 
    493 	if (!unpipe)
    494 		unlink(pname);
    495 
    496 	tst_rmdir();
    497 }
    498 
    499 static void do_child(void)
    500 {
    501 	int *count_word;        /* holds address where to write writers count */
    502 	int *pid_word;          /* holds address where to write writers pid */
    503 	int nb, j;
    504 	long clock;
    505 	char *cp;
    506 	long int n;
    507 	struct sembuf sem_op;
    508 	pid_t self_pid =  getpid();
    509 
    510 	if (!unpipe) {
    511 		write_fd = open(pname, O_WRONLY);
    512 		if (write_fd == -1) {
    513 			fprintf(stderr, "child pipe open(%s, %#o) failed",
    514 				pname, O_WRONLY | ndelay);
    515 			exit(1);
    516 		}
    517 		if (ndelay && fcntl(write_fd, F_SETFL, O_NONBLOCK) == -1) {
    518 			fprintf(stderr, "Failed setting the pipe to "
    519 				"nonblocking mode");
    520 			exit(1);
    521 		}
    522 	} else {
    523 		close(read_fd);
    524 	}
    525 
    526 	sem_op = (struct sembuf) {
    527 		 .sem_num = 0, .sem_op = 1, .sem_flg = 0};
    528 
    529 	if (semop(sem_id, &sem_op, 1) == -1) {
    530 		fprintf(stderr, "child: %d couldn't raise the semaphore 0",
    531 			self_pid);
    532 		exit(1);
    533 	}
    534 
    535 	pid_word = (int *)&writebuf[0];
    536 	count_word = (int *)&writebuf[NBPW];
    537 
    538 	for (j = 0; j < num_writes || loop; ++j) {
    539 		/*
    540 		 * writes are only in one unit when the size of the write
    541 		 * is <= PIPE_BUF.
    542 		 * Therefore, if size is greater than PIPE_BUF, we will break
    543 		 * the writes into PIPE_BUF chunks.
    544 		 * All writes and read need to be same size.
    545 		 */
    546 
    547 		/*
    548 		 * write pid and count in first two
    549 		 * words of buffer
    550 		 */
    551 		*count_word = j;
    552 		*pid_word = self_pid;
    553 
    554 		nb = lio_write_buffer(write_fd, iotype, writebuf, size,
    555 				      SIGUSR1, &cp, 0);
    556 		if (nb < 0) {
    557 			/*
    558 			 * If lio_write_buffer returns a negative number,
    559 			 * the return will be -errno.
    560 			 */
    561 			fprintf(stderr, "pass %d: lio_write_buffer(%s) failed;"
    562 				" it returned %d: %s",
    563 				j, cp, nb, strerror(-nb));
    564 				exit(1);
    565 		} else if (nb != size) {
    566 			fprintf(stderr, "pass %d: lio_write_buffer(%s) failed,"
    567 				" write count %d, but expected to write %d",
    568 				j, cp, nb, size);
    569 		}
    570 		if (verbose) {
    571 			fprintf(stderr, "pass %d: pid %d: wrote %d bytes,"
    572 				"expected %d bytes",
    573 				j, self_pid, nb, size);
    574 		}
    575 
    576 		if (chld_wait) {
    577 			clock = time(0);
    578 			srand48(clock);
    579 			n = lrand48() % chld_wait;
    580 			usleep(n);
    581 		}
    582 		fflush(stderr);
    583 	}
    584 
    585 	/* child waits until parent completes open() */
    586 	sem_op = (struct sembuf) {
    587 		  .sem_num = 1, .sem_op = -1, .sem_flg = 0};
    588 	if (semop(sem_id, &sem_op, 1) == -1)
    589 		fprintf(stderr, "Couldn't lower the semaphore 1");
    590 
    591 	exit(0);
    592 }
    593 
    594 static int check_rw_buf(void)
    595 {
    596 	int i;
    597 
    598 	for (i = 2 * NBPW; i < size; ++i) {
    599 		if (writebuf[i] != readbuf[i]) {
    600 			++error;
    601 			tst_resm(TFAIL,
    602 				 "FAIL data error on byte %d; rd# %d, sz= %d, "
    603 				 "%s %s empty_reads= %d, err= %d",
    604 				 i, count, size, pipe_type, blk_type,
    605 				 empty_read, error);
    606 			prt_buf(&readbuf, readbuf, format_size, format);
    607 			fflush(stdout);
    608 			return 1;
    609 		}
    610 	}
    611 
    612 	return 0;
    613 }
    614 
    615 static void do_parent(void)
    616 {
    617 	int i, nb;
    618 	long clock;
    619 	time_t start_time, current_time, diff_time;
    620 	char *cp;
    621 	long int n;
    622 	struct sembuf sem_op;
    623 
    624 	start_time = time(0);
    625 	if (!unpipe) {
    626 		read_fd = SAFE_OPEN(cleanup, pname, O_RDONLY);
    627 		if (ndelay && fcntl(read_fd, F_SETFL, O_NONBLOCK) == -1) {
    628 			tst_brkm(TBROK | TERRNO, cleanup,
    629 				 "Failed setting the pipe to nonblocking mode");
    630 		}
    631 	} else {
    632 		SAFE_CLOSE(cleanup, write_fd);
    633 	}
    634 
    635 	/* raise semaphore so children can exit */
    636 	sem_op = (struct sembuf) {
    637 		  .sem_num = 1, .sem_op = num_writers, .sem_flg = 0};
    638 	if (semop(sem_id, &sem_op, 1) == -1) {
    639 		tst_brkm(TBROK | TERRNO, cleanup,
    640 			 "Couldn't raise the semaphore 1");
    641 	}
    642 
    643 	sem_op = (struct sembuf) {
    644 		  .sem_num = 0, .sem_op = -num_writers, .sem_flg = 0};
    645 
    646 	while (nchildcompleted < num_writers
    647 	       && semop(sem_id, &sem_op, 1) == -1) {
    648 		if (errno == EINTR)
    649 			continue;
    650 		tst_brkm(TBROK | TERRNO, cleanup,
    651 			 "Couldn't wait on semaphore 0");
    652 	}
    653 
    654 	/* parent start to read pipe */
    655 	for (i = num_writers * num_writes; i > 0 || loop; --i) {
    656 		if (error >= MAX_ERRS || empty_read >= MAX_EMPTY)
    657 			break;
    658 		if (parent_wait) {
    659 			clock = time(0);
    660 			srand48(clock);
    661 			n = lrand48() % parent_wait;
    662 			usleep(n);
    663 		}
    664 		++count;
    665 		nb = lio_read_buffer(read_fd, iotype, readbuf, size,
    666 				     SIGUSR1, &cp, 0);
    667 		if (nb < 0) {
    668 			/*
    669 			 * If lio_read_buffer returns a negative number,
    670 			 * the return will be -errno.
    671 			 */
    672 			tst_resm(TFAIL, "pass %d: lio_read_buffer(%s) failed; "
    673 				 "returned %d: %s", i, cp, nb, strerror(-nb));
    674 			++i;
    675 			count--;
    676 			error++;
    677 			continue;
    678 		} else {
    679 			if (nb == 0) {
    680 				if (nchildcompleted >= num_writers && !loop) {
    681 					tst_resm(TWARN, "The children have "
    682 						 "died prematurely");
    683 					break;	/* All children have died */
    684 				}
    685 				empty_read++;
    686 				++i;
    687 				count--;
    688 				continue;
    689 			} else if (nb < size && size <= PIPE_BUF) {
    690 				tst_resm(TFAIL, "pass %d: partial read from the"
    691 					" pipe: read %d bytes, expected %d, "
    692 					"read count %d", i, nb, size, count);
    693 				++error;
    694 			} else if (nb == size) {
    695 				check_rw_buf();
    696 				if (exit_error && exit_error == error)
    697 					return;
    698 			}
    699 
    700 			if (verbose || (num_rpt && !(count % num_rpt))) {
    701 				current_time = time(0);
    702 				diff_time = current_time - start_time;
    703 				tst_resm(TFAIL,
    704 					 "(%d) rd# %d, sz= %d, %s %s "
    705 					 "empty_reads= %d, err= %d\n",
    706 					 (int)diff_time, count, size,
    707 					 pipe_type, blk_type,
    708 					 empty_read, error);
    709 				fflush(stdout);
    710 			}
    711 		}
    712 	}
    713 
    714 	SAFE_CLOSE(cleanup, read_fd);
    715 }
    716 
    717 static void usage(void)
    718 {
    719 	fprintf(stderr, "Usage: %s [-bEv][-c #writers][-D pname][-h]"
    720 		"[-e exit_num][-f fmt][-l][-i #writes][-n #writes][-p num_rpt]"
    721 		"\n\t[-s size][-W max_wait][-w max_wait][-u]\n", TCID);
    722 	fflush(stderr);
    723 }
    724 
    725 static void help(void)
    726 {
    727 	usage();
    728 
    729 	printf(" -b    - blocking reads and writes. default non-block\n\
    730   -c #writers  - number of writers (childern)\n\
    731   -D pname     - name of fifo (def tpipe<pid>)\n\
    732   -h           - print this help message\n\
    733   -e exit_num  - exit on error exit_num, 0 is ignore errors, 1 is default.\n\
    734   -E           - print cmd line examples and exit\n\
    735   -f format    - define format of bad buffer: h(hex), o(octal)\n\
    736                  d(decimal), a(ascii), n (none). hex is default\n\
    737 	         option size can be added to control output\n\
    738   -i #writes   - number write per child, zero means forever.\n\
    739   -I io_type   - Specifies io type: s - sync, p - polled async, a - async (def s)\n\
    740                  l - listio sync, L - listio async, r - random\n\
    741   -l           - loop forever (implied by -n 0).\n\
    742   -n #writes   - same as -i (for compatability).\n\
    743   -p num_rpt   - number of reads before a report\n\
    744   -q           - quiet mode, no PASS results are printed\n\
    745   -s size      - size of read and write (def 327)\n\
    746                  if size >= 4096, i/o will be in 4096 chuncks\n\
    747   -w max_wait  - max time (seconds) for sleep between writes.\n\
    748                  max_wait is interpreted as a double with ms accuracy.\n\
    749   -W max_wait  - max time (seconds) for sleep between reads\n\
    750                  max_wait is interpreted as a double with ms accuracy.\n\
    751   -u           - un-named pipe instead of named pipe\n\
    752   -v           - verbose mode, all writes/reads resutlts printed\n");
    753 
    754 	fflush(stdout);
    755 }
    756 
    757 static void prt_buf(char **addr, char *buf, int length, int format)
    758 {
    759 	int i;
    760 	int num_words = length / NBPW;	/* given length in bytes, get length in words */
    761 	int width;		/* number of columns */
    762 	int extra_words = 0;	/* odd or even number of words */
    763 	char *a = buf;
    764 	char b[NBPW];
    765 	char c[NBPW * 2];
    766 	char *p;
    767 	long *word;
    768 
    769 	if (format == NO_OUT)	/* if no output wanted, return */
    770 		return;
    771 
    772 	if (length % NBPW)
    773 		++num_words;	/* is length in full words? */
    774 	if (format == ASCII) {
    775 		width = 3;
    776 	} else {
    777 		width = 2;
    778 		/* do we have an odd number of words? */
    779 		extra_words = num_words % width;
    780 	}
    781 	for (i = 0; i < num_words; ++i, a += NBPW, addr++) {
    782 		word = (long *)a;
    783 		if (!(i % width)) {
    784 			if (i > 0 && format != ASCII) {
    785 				/*
    786 				 * print the ascii equivalent of the data
    787 				 * before beginning the next line of output.
    788 				 */
    789 				memset(c, 0x00, width * NBPW);
    790 				/*
    791 				 * get the last 2 words printed
    792 				 */
    793 				memcpy(c, a - (width * NBPW), width * NBPW);
    794 				for (p = c; (p - c) < (int)(width*NBPW); ++p) {
    795 					if (*p < '!' || *p > '~')
    796 						*p = '.';
    797 				}
    798 				printf("\t%16.16s", c);
    799 			}
    800 			printf("\n%p: ", addr);
    801 			/***printf("\n%7o (%d): ",addr,i);***/
    802 		}
    803 
    804 		switch (format) {
    805 		case HEX:
    806 			printf("%16.16lx ", *word);
    807 			break;
    808 		case DECIMAL:
    809 			printf("%10.10ld ", *word);
    810 			break;
    811 		case ASCII:
    812 			memcpy(b, a, NBPW);
    813 			for (p = b; (p - b) < (int)NBPW; ++p) {
    814 				if (*p < '!' || *p > '~')
    815 					*p = '.';
    816 			}
    817 			printf("%8.8s ", b);
    818 			break;
    819 		default:
    820 			printf("%22.22lo ", *word);
    821 			break;
    822 		}
    823 	}
    824 	if (format != ASCII) {
    825 		/*
    826 		 * print the ascii equivalent of the last words in the buffer
    827 		 * before returning.
    828 		 */
    829 		memset(c, 0x00, width * NBPW);
    830 		if (extra_words)
    831 			width = extra_words;	/* odd number of words */
    832 		memcpy(c, a - (width * NBPW), width * NBPW);
    833 		for (p = c; (p - c) < (int)(width * NBPW); ++p) {
    834 			if (*p < '!' || *p > '~')
    835 				*p = '.';
    836 		}
    837 		if (width == 2)
    838 			printf("\t%16.16s", c);
    839 		else
    840 			printf("\t\t%16.8s", c);
    841 	}
    842 	printf("\n");
    843 	fflush(stdout);
    844 }
    845 
    846 static void prt_examples(void)
    847 {
    848 	printf("%s -c 5 -i 0 -s 4090 -b\n", TCID);
    849 	printf("%s -c 5 -i 0 -s 4090 -b -u \n", TCID);
    850 	printf("%s -c 5 -i 0 -s 4090 -b -W 3 -w 3 \n", TCID);
    851 }
    852 
    853 static void sig_child(int sig)
    854 {
    855 	int status;
    856 
    857 	nchildcompleted++;
    858 #if DEBUG
    859 	#define STR	"parent: received SIGCHLD\n"
    860 	write(STDOUT_FILENO, str, strlen(STR));
    861 #endif
    862 	waitpid(-1, &status, WNOHANG);
    863 }
    864