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