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 		if (mkfifo(pname, 0777) == -1) {
    482 			tst_brkm(TBROK | TERRNO, cleanup,
    483 				"mkfifo(%s, 0777) failed", pname);
    484 		}
    485 		pipe_type = PIPE_NAMED;
    486 	}
    487 }
    488 
    489 static void cleanup(void)
    490 {
    491 	SAFE_FREE(writebuf);
    492 	SAFE_FREE(readbuf);
    493 
    494 	semctl(sem_id, 0, IPC_RMID);
    495 
    496 	if (!unpipe)
    497 		SAFE_UNLINK(NULL, pname);
    498 
    499 	tst_rmdir();
    500 }
    501 
    502 static void do_child(void)
    503 {
    504 	int *count_word;        /* holds address where to write writers count */
    505 	int *pid_word;          /* holds address where to write writers pid */
    506 	int nb, j;
    507 	long clock;
    508 	char *cp;
    509 	long int n;
    510 	struct sembuf sem_op;
    511 	pid_t self_pid =  getpid();
    512 
    513 	if (!unpipe) {
    514 		write_fd = open(pname, O_WRONLY);
    515 		if (write_fd == -1) {
    516 			fprintf(stderr, "child pipe open(%s, %#o) failed",
    517 				pname, O_WRONLY | ndelay);
    518 			exit(1);
    519 		}
    520 		if (ndelay && fcntl(write_fd, F_SETFL, O_NONBLOCK) == -1) {
    521 			fprintf(stderr, "Failed setting the pipe to "
    522 				"nonblocking mode");
    523 			exit(1);
    524 		}
    525 	} else {
    526 		close(read_fd);
    527 	}
    528 
    529 	sem_op = (struct sembuf) {
    530 		 .sem_num = 0, .sem_op = 1, .sem_flg = 0};
    531 
    532 	if (semop(sem_id, &sem_op, 1) == -1) {
    533 		fprintf(stderr, "child: %d couldn't raise the semaphore 0",
    534 			self_pid);
    535 		exit(1);
    536 	}
    537 
    538 	pid_word = (int *)&writebuf[0];
    539 	count_word = (int *)&writebuf[NBPW];
    540 
    541 	for (j = 0; j < num_writes || loop; ++j) {
    542 		/*
    543 		 * writes are only in one unit when the size of the write
    544 		 * is <= PIPE_BUF.
    545 		 * Therefore, if size is greater than PIPE_BUF, we will break
    546 		 * the writes into PIPE_BUF chunks.
    547 		 * All writes and read need to be same size.
    548 		 */
    549 
    550 		/*
    551 		 * write pid and count in first two
    552 		 * words of buffer
    553 		 */
    554 		*count_word = j;
    555 		*pid_word = self_pid;
    556 
    557 		nb = lio_write_buffer(write_fd, iotype, writebuf, size,
    558 				      SIGUSR1, &cp, 0);
    559 		if (nb < 0) {
    560 			/*
    561 			 * If lio_write_buffer returns a negative number,
    562 			 * the return will be -errno.
    563 			 */
    564 			fprintf(stderr, "pass %d: lio_write_buffer(%s) failed;"
    565 				" it returned %d: %s",
    566 				j, cp, nb, strerror(-nb));
    567 				exit(1);
    568 		} else if (nb != size) {
    569 			fprintf(stderr, "pass %d: lio_write_buffer(%s) failed,"
    570 				" write count %d, but expected to write %d",
    571 				j, cp, nb, size);
    572 		}
    573 		if (verbose) {
    574 			fprintf(stderr, "pass %d: pid %d: wrote %d bytes,"
    575 				"expected %d bytes",
    576 				j, self_pid, nb, size);
    577 		}
    578 
    579 		if (chld_wait) {
    580 			clock = time(0);
    581 			srand48(clock);
    582 			n = lrand48() % chld_wait;
    583 			usleep(n);
    584 		}
    585 		fflush(stderr);
    586 	}
    587 
    588 	/* child waits until parent completes open() */
    589 	sem_op = (struct sembuf) {
    590 		  .sem_num = 1, .sem_op = -1, .sem_flg = 0};
    591 	if (semop(sem_id, &sem_op, 1) == -1)
    592 		fprintf(stderr, "Couldn't lower the semaphore 1");
    593 
    594 	exit(0);
    595 }
    596 
    597 static int check_rw_buf(void)
    598 {
    599 	int i;
    600 
    601 	for (i = 2 * NBPW; i < size; ++i) {
    602 		if (writebuf[i] != readbuf[i]) {
    603 			++error;
    604 			tst_resm(TFAIL,
    605 				 "FAIL data error on byte %d; rd# %d, sz= %d, "
    606 				 "%s %s empty_reads= %d, err= %d",
    607 				 i, count, size, pipe_type, blk_type,
    608 				 empty_read, error);
    609 			prt_buf(&readbuf, readbuf, format_size, format);
    610 			fflush(stdout);
    611 			return 1;
    612 		}
    613 	}
    614 
    615 	return 0;
    616 }
    617 
    618 static void do_parent(void)
    619 {
    620 	int i, nb;
    621 	long clock;
    622 	time_t start_time, current_time, diff_time;
    623 	char *cp;
    624 	long int n;
    625 	struct sembuf sem_op;
    626 
    627 	start_time = time(0);
    628 	if (!unpipe) {
    629 		read_fd = SAFE_OPEN(cleanup, pname, O_RDONLY);
    630 		if (ndelay && fcntl(read_fd, F_SETFL, O_NONBLOCK) == -1) {
    631 			tst_brkm(TBROK | TERRNO, cleanup,
    632 				 "Failed setting the pipe to nonblocking mode");
    633 		}
    634 	} else {
    635 		SAFE_CLOSE(cleanup, write_fd);
    636 	}
    637 
    638 	/* raise semaphore so children can exit */
    639 	sem_op = (struct sembuf) {
    640 		  .sem_num = 1, .sem_op = num_writers, .sem_flg = 0};
    641 	if (semop(sem_id, &sem_op, 1) == -1) {
    642 		tst_brkm(TBROK | TERRNO, cleanup,
    643 			 "Couldn't raise the semaphore 1");
    644 	}
    645 
    646 	sem_op = (struct sembuf) {
    647 		  .sem_num = 0, .sem_op = -num_writers, .sem_flg = 0};
    648 
    649 	while (nchildcompleted < num_writers
    650 	       && semop(sem_id, &sem_op, 1) == -1) {
    651 		if (errno == EINTR)
    652 			continue;
    653 		tst_brkm(TBROK | TERRNO, cleanup,
    654 			 "Couldn't wait on semaphore 0");
    655 	}
    656 
    657 	/* parent start to read pipe */
    658 	for (i = num_writers * num_writes; i > 0 || loop; --i) {
    659 		if (error >= MAX_ERRS || empty_read >= MAX_EMPTY)
    660 			break;
    661 		if (parent_wait) {
    662 			clock = time(0);
    663 			srand48(clock);
    664 			n = lrand48() % parent_wait;
    665 			usleep(n);
    666 		}
    667 		++count;
    668 		nb = lio_read_buffer(read_fd, iotype, readbuf, size,
    669 				     SIGUSR1, &cp, 0);
    670 		if (nb < 0) {
    671 			/*
    672 			 * If lio_read_buffer returns a negative number,
    673 			 * the return will be -errno.
    674 			 */
    675 			tst_resm(TFAIL, "pass %d: lio_read_buffer(%s) failed; "
    676 				 "returned %d: %s", i, cp, nb, strerror(-nb));
    677 			++i;
    678 			count--;
    679 			error++;
    680 			continue;
    681 		} else {
    682 			if (nb == 0) {
    683 				if (nchildcompleted >= num_writers && !loop) {
    684 					tst_resm(TWARN, "The children have "
    685 						 "died prematurely");
    686 					break;	/* All children have died */
    687 				}
    688 				empty_read++;
    689 				++i;
    690 				count--;
    691 				continue;
    692 			} else if (nb < size && size <= PIPE_BUF) {
    693 				tst_resm(TFAIL, "pass %d: partial read from the"
    694 					" pipe: read %d bytes, expected %d, "
    695 					"read count %d", i, nb, size, count);
    696 				++error;
    697 			} else if (nb == size) {
    698 				check_rw_buf();
    699 				if (exit_error && exit_error == error)
    700 					return;
    701 			}
    702 
    703 			if (verbose || (num_rpt && !(count % num_rpt))) {
    704 				current_time = time(0);
    705 				diff_time = current_time - start_time;
    706 				tst_resm(TFAIL,
    707 					 "(%d) rd# %d, sz= %d, %s %s "
    708 					 "empty_reads= %d, err= %d\n",
    709 					 (int)diff_time, count, size,
    710 					 pipe_type, blk_type,
    711 					 empty_read, error);
    712 				fflush(stdout);
    713 			}
    714 		}
    715 	}
    716 
    717 	SAFE_CLOSE(cleanup, read_fd);
    718 }
    719 
    720 static void usage(void)
    721 {
    722 	fprintf(stderr, "Usage: %s [-bEv][-c #writers][-D pname][-h]"
    723 		"[-e exit_num][-f fmt][-l][-i #writes][-n #writes][-p num_rpt]"
    724 		"\n\t[-s size][-W max_wait][-w max_wait][-u]\n", TCID);
    725 	fflush(stderr);
    726 }
    727 
    728 static void help(void)
    729 {
    730 	usage();
    731 
    732 	printf(" -b    - blocking reads and writes. default non-block\n\
    733   -c #writers  - number of writers (childern)\n\
    734   -D pname     - name of fifo (def tpipe<pid>)\n\
    735   -h           - print this help message\n\
    736   -e exit_num  - exit on error exit_num, 0 is ignore errors, 1 is default.\n\
    737   -E           - print cmd line examples and exit\n\
    738   -f format    - define format of bad buffer: h(hex), o(octal)\n\
    739                  d(decimal), a(ascii), n (none). hex is default\n\
    740 	         option size can be added to control output\n\
    741   -i #writes   - number write per child, zero means forever.\n\
    742   -I io_type   - Specifies io type: s - sync, p - polled async, a - async (def s)\n\
    743                  l - listio sync, L - listio async, r - random\n\
    744   -l           - loop forever (implied by -n 0).\n\
    745   -n #writes   - same as -i (for compatability).\n\
    746   -p num_rpt   - number of reads before a report\n\
    747   -q           - quiet mode, no PASS results are printed\n\
    748   -s size      - size of read and write (def 327)\n\
    749                  if size >= 4096, i/o will be in 4096 chuncks\n\
    750   -w max_wait  - max time (seconds) for sleep between writes.\n\
    751                  max_wait is interpreted as a double with ms accuracy.\n\
    752   -W max_wait  - max time (seconds) for sleep between reads\n\
    753                  max_wait is interpreted as a double with ms accuracy.\n\
    754   -u           - un-named pipe instead of named pipe\n\
    755   -v           - verbose mode, all writes/reads resutlts printed\n");
    756 
    757 	fflush(stdout);
    758 }
    759 
    760 static void prt_buf(char **addr, char *buf, int length, int format)
    761 {
    762 	int i;
    763 	int num_words = length / NBPW;	/* given length in bytes, get length in words */
    764 	int width;		/* number of columns */
    765 	int extra_words = 0;	/* odd or even number of words */
    766 	char *a = buf;
    767 	char b[NBPW];
    768 	char c[NBPW * 2];
    769 	char *p;
    770 	long *word;
    771 
    772 	if (format == NO_OUT)	/* if no output wanted, return */
    773 		return;
    774 
    775 	if (length % NBPW)
    776 		++num_words;	/* is length in full words? */
    777 	if (format == ASCII) {
    778 		width = 3;
    779 	} else {
    780 		width = 2;
    781 		/* do we have an odd number of words? */
    782 		extra_words = num_words % width;
    783 	}
    784 	for (i = 0; i < num_words; ++i, a += NBPW, addr++) {
    785 		word = (long *)a;
    786 		if (!(i % width)) {
    787 			if (i > 0 && format != ASCII) {
    788 				/*
    789 				 * print the ascii equivalent of the data
    790 				 * before beginning the next line of output.
    791 				 */
    792 				memset(c, 0x00, width * NBPW);
    793 				/*
    794 				 * get the last 2 words printed
    795 				 */
    796 				memcpy(c, a - (width * NBPW), width * NBPW);
    797 				for (p = c; (p - c) < (int)(width*NBPW); ++p) {
    798 					if (*p < '!' || *p > '~')
    799 						*p = '.';
    800 				}
    801 				printf("\t%16.16s", c);
    802 			}
    803 			printf("\n%p: ", addr);
    804 			/***printf("\n%7o (%d): ",addr,i);***/
    805 		}
    806 
    807 		switch (format) {
    808 		case HEX:
    809 			printf("%16.16lx ", *word);
    810 			break;
    811 		case DECIMAL:
    812 			printf("%10.10ld ", *word);
    813 			break;
    814 		case ASCII:
    815 			memcpy(b, a, NBPW);
    816 			for (p = b; (p - b) < (int)NBPW; ++p) {
    817 				if (*p < '!' || *p > '~')
    818 					*p = '.';
    819 			}
    820 			printf("%8.8s ", b);
    821 			break;
    822 		default:
    823 			printf("%22.22lo ", *word);
    824 			break;
    825 		}
    826 	}
    827 	if (format != ASCII) {
    828 		/*
    829 		 * print the ascii equivalent of the last words in the buffer
    830 		 * before returning.
    831 		 */
    832 		memset(c, 0x00, width * NBPW);
    833 		if (extra_words)
    834 			width = extra_words;	/* odd number of words */
    835 		memcpy(c, a - (width * NBPW), width * NBPW);
    836 		for (p = c; (p - c) < (int)(width * NBPW); ++p) {
    837 			if (*p < '!' || *p > '~')
    838 				*p = '.';
    839 		}
    840 		if (width == 2)
    841 			printf("\t%16.16s", c);
    842 		else
    843 			printf("\t\t%16.8s", c);
    844 	}
    845 	printf("\n");
    846 	fflush(stdout);
    847 }
    848 
    849 static void prt_examples(void)
    850 {
    851 	printf("%s -c 5 -i 0 -s 4090 -b\n", TCID);
    852 	printf("%s -c 5 -i 0 -s 4090 -b -u \n", TCID);
    853 	printf("%s -c 5 -i 0 -s 4090 -b -W 3 -w 3 \n", TCID);
    854 }
    855 
    856 static void sig_child(int sig)
    857 {
    858 	int status;
    859 
    860 	nchildcompleted++;
    861 #if DEBUG
    862 	#define STR	"parent: received SIGCHLD\n"
    863 	write(STDOUT_FILENO, str, strlen(STR));
    864 #endif
    865 	waitpid(-1, &status, WNOHANG);
    866 }
    867