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