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 
main(int ac,char * av[])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 
parse_options(int argc,char * argv[])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 
setup(int argc,char * argv[])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 
cleanup(void)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 
do_child(void)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 
check_rw_buf(void)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 
do_parent(void)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 
usage(void)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 
help(void)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 
prt_buf(char ** addr,char * buf,int length,int format)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 
prt_examples(void)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 
sig_child(int sig)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