Imported Upstream version 20081219
[ltp-debian.git] / testcases / kernel / ipc / pipeio / pipeio.c
bloba04ffb02a3bc092daf044a4194e8983cada52467
1 /*
2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
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.
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.
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.
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., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
26 * http://www.sgi.com
28 * For further information regarding this notice, see:
30 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
33 /* $Header: /cvsroot/ltp/ltp/testcases/kernel/ipc/pipeio/pipeio.c,v 1.15 2008/12/11 13:17:49 subrata_modak Exp $ */
35 * This tool can be used to beat on system or named pipes.
36 * See the help() function below for user information.
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>
52 #include "tlibio.h"
54 #include "test.h"
56 char *TCID="pipeio"; /* Test program identifier. */
57 int TST_TOTAL=1; /* Total number of test cases. */
58 extern int Tst_count; /* Test Case counter for tst_* routines */
60 #define SAFE_FREE(p) { if(p) { free(p); (p)=NULL; } }
62 /* To avoid extensive modifications to the code, use this bodge */
63 #define exit(x) myexit(x)
64 void
65 myexit (int x)
67 if (x)
68 tst_resm (TFAIL, "Test failed");
69 else
70 tst_resm (TPASS, "Test passed");
71 tst_exit();
74 #if defined(__linux__)
75 # define NBPW sizeof(int)
76 #endif
79 #define PPATH "tpipe"
80 #define OCTAL 'o'
81 #define HEX 'x'
82 #define DECIMAL 'd'
83 #define ASCII 'a'
84 #define NO_OUT 'n'
86 #define PIPE_NAMED "named pipe,"
87 #define PIPE_UNNAMED "sys pipe,"
89 #define BLOCKING_IO "blking,"
90 #define NON_BLOCKING_IO "non-blking,"
91 #define UNNAMED_IO ""
93 #define MAX_ERRS 16
94 #define MAX_EMPTY 256
96 void sig_handler(), help(), usage(), prt_buf(), prt_examples();
97 void sig_child();
99 int count = 0;
100 int Nchildcomplete = 0;
103 * Ensure PATH_MAX is define
105 #ifndef PATH_MAX
106 #ifdef MAXPATHLEN
107 #define PATH_MAX MAXPATHLEN
108 #else
109 #define PATH_MAX 1024
110 #endif /* ! MAXPATHLEN */
111 #endif /* PATH_MAX */
114 main(ac,av)
115 int ac;
116 char *av[];
118 int i,j,c,error = 0;
119 int n;
120 int nb; /* number of bytes read */
121 int num_wrters=1; /* number of writers */
122 int num_writes=1; /* number of writes per child */
123 int loop=0; /* loop indefinitely */
124 int exit_error = 1; /* exit on error #, zero means no exit */
125 int size=327; /* default size */
126 int unpipe = 0; /* un-named pipe if non-zero */
127 int verbose=0; /* verbose mode if set */
128 int quiet=0; /* quiet mode if set */
129 int num_rpt=0; /* ping number, how often to print message */
130 int chld_wait = 0; /* max time to wait between writes, 1 == no wait */
131 int parent_wait = 0; /* max time to wait between reads, 1 == no wait*/
132 int ndelay = O_NDELAY; /* additional flag to open */
133 long clock;
134 char *writebuf = NULL;
135 char *readbuf = NULL;
136 double d;
137 char *cp;
138 extern char *optarg;
139 char pname[PATH_MAX]; /* contains the name of the unamed pipe */
140 char dir[PATH_MAX]; /* directory to create pipe in */
141 char *blk_type; /* blocking i/o or not */
142 char *pipe_type; /* type of pipe under test */
143 int fds[2]; /* un-named pipe fds */
144 int read_fd = 0;
145 int write_fd = 0;
146 int empty_read = 0; /* counter for the number of empty reads */
147 time_t start_time, current_time, diff_time; /* start time, current time, diff of times */
148 int *count_word; /* holds address where to write writers count */
149 int *pid_word; /* holds address where to write writers pid */
150 int format;
151 int format_size = -1;
152 int background = 0; /* if set, put process in background */
153 struct stat stbuf;
154 int iotype = 0; /* sync io */
155 char *toutput; /* for getenv() */
156 int sem_id;
157 struct sembuf sem_op;
159 format = HEX;
160 blk_type = NON_BLOCKING_IO;
161 dir[0] = '\0';
162 sprintf(pname,"%s.%d",PPATH,getpid());
164 if( (toutput=getenv("TOUTPUT")) != NULL ) {
165 if( strcmp( toutput, "NOPASS") == 0 ) {
166 quiet=1;
170 while ((c=getopt (ac, av, "T:BbCc:D:d:he:Ef:i:I:ln:p:qs:uvW:w:P:")) != EOF) {
171 switch (c) {
172 case 'T':
173 TCID = optarg;
174 break;
175 case 'h':
176 help();
177 exit(0);
178 break;
179 case 'd': /* dir name */
180 strcpy(dir, optarg);
181 break;
182 case 'D': /* pipe name */
183 strcpy(pname, optarg);
184 break;
185 case 'B': /* background */
186 background=1;
187 break;
188 case 'b': /* blocked */
189 ndelay=0;
190 blk_type = BLOCKING_IO;
191 break;
192 case 'C':
193 fprintf(stderr,
194 "%s: --C option not supported on this architecture\n",
195 TCID);
196 exit(1);
197 break;
198 case 'c': /* number childern */
199 if (sscanf(optarg, "%d", &num_wrters) != 1) {
200 fprintf(stderr,"%s: --c option invalid arg '%s'.\n",
201 TCID,optarg);
202 usage();
203 exit(1);
205 else if ( num_wrters <= 0 ) {
206 fprintf(stderr,
207 "%s: --c option must be greater than zero.\n",
208 TCID);
209 usage();
210 exit(1);
212 break;
213 case 'e': /* exit on error # */
214 if (sscanf(optarg, "%d", &exit_error) != 1) {
215 fprintf(stderr,"%s: --e option invalid arg '%s'.\n",
216 TCID,optarg);
217 usage();
218 exit(1);
220 else if ( exit_error < 0 ) {
221 fprintf(stderr,
222 "%s: --e option must be greater than zero.\n",
223 TCID);
224 usage();
225 exit(1);
227 break;
229 case 'E':
230 prt_examples();
231 exit(0);
232 break;
233 case 'f': /* format of buffer on error */
234 switch(optarg[0]) {
235 case 'x':
236 case 'X':
237 format = HEX;
238 break;
239 case 'o':
240 case 'O':
241 format = OCTAL;
242 break;
243 case 'd':
244 case 'D':
245 format = DECIMAL;
246 break;
247 case 'a':
248 case 'A':
249 format = ASCII;
250 break;
251 case 'n': /* not output */
252 case 'N':
253 format = NO_OUT;
254 break;
256 default :
257 fprintf(stderr,"%s: --f option invalid arg '%s'.\n",
258 TCID,optarg);
259 fprintf(stderr,
260 "\tIt must be x(hex), o(octal), d(decimal), a(ascii) or n(none) with opt sz\n");
261 exit(1);
262 break;
264 cp = optarg;
265 cp++;
266 if ( *cp ) {
267 if ( sscanf(cp, "%i", &format_size) != 1 ) {
268 fprintf(stderr,"%s: --f option invalid arg '%s'.\n",
269 TCID,optarg);
270 fprintf(stderr,
271 "\tIt must be x(hex), o(octal), d(decimal), a(ascii) or n(none) with opt sz\n");
272 exit(1);
273 break;
276 break;
278 case 'I':
279 if((iotype=lio_parse_io_arg1(optarg)) == -1 ) {
280 fprintf(stderr,
281 "%s: --I arg is invalid, must be s, p, f, a, l, L or r.\n",
282 TCID);
283 exit(1);
285 break;
287 case 'l': /* loop forever */
288 ++loop;
289 break;
291 case 'i':
292 case 'n': /* number writes per child */
293 if (sscanf(optarg, "%d", &num_writes) != 1) {
294 fprintf(stderr,"%s: --i/n option invalid arg '%s'.\n",
295 TCID,optarg);
296 usage();
297 exit(1);
299 else if ( num_writes < 0 ) {
300 fprintf(stderr,
301 "%s: --i/n option must be greater than equal to zero.\n",
302 TCID);
303 usage();
304 exit(1);
307 if (num_writes == 0) /* loop forever */
308 ++loop;
310 break;
311 case 'P': /* panic flag */
312 fprintf(stderr, "%s: --P not supported on this architecture\n",
313 TCID);
314 exit(1);
315 break;
316 case 'p': /* ping */
317 if (sscanf(optarg, "%d", &num_rpt) != 1) {
318 fprintf(stderr,"%s: --p option invalid arg '%s'.\n",
319 TCID,optarg);
320 usage();
321 exit(1);
323 else if ( num_rpt < 0 ) {
324 fprintf(stderr,
325 "%s: --p option must be greater than equal to zero.\n",
326 TCID);
327 usage();
328 exit(1);
330 break;
331 case 'q': /* Quiet - NOPASS */
332 quiet=1;
333 break;
334 case 's': /* size */
335 if (sscanf(optarg, "%d", &size) != 1) {
336 fprintf(stderr,"%s: --s option invalid arg '%s'.\n",
337 TCID,optarg);
338 usage();
339 exit(1);
341 else if ( size <= 0 ) {
342 fprintf(stderr,
343 "%s: --s option must be greater than zero.\n",
344 TCID);
345 usage();
346 exit(1);
348 break;
349 case 'u':
350 unpipe=1; /* un-named pipe */
351 break;
352 case 'v': /* verbose */
353 verbose=1;
354 break;
355 case 'W': /* max wait time between writes */
356 d = strtod(optarg, &cp);
357 if (*cp != '\0') {
358 fprintf(stderr,"%s: --w option invalid arg '%s'.\n",
359 TCID,optarg);
360 usage();
361 exit(1);
363 else if ( d < 0 ) {
364 fprintf(stderr,
365 "%s: --w option must be greater than zero.\n",
366 TCID);
367 usage();
368 exit(1);
370 parent_wait = (int)(d * 1000000.0);
371 break;
372 case 'w': /* max wait time between writes */
373 d = strtod(optarg, &cp);
374 if (*cp != '\0') {
375 fprintf(stderr,"%s: --w option invalid arg '%s'.\n",
376 TCID,optarg);
377 usage();
378 exit(1);
380 else if ( d < 0 ) {
381 fprintf(stderr,
382 "%s: --w option must be greater than zero.\n",
383 TCID);
384 usage();
385 exit(1);
387 chld_wait = (int)(d * 1000000.0);
388 break;
389 case '?':
390 usage();
391 exit (1);
392 break;
396 if ( format_size == -1 )
397 format_size = size;
401 * If there is more than one writer, all writes and reads
402 * must be the same size. Only writes of a size <= PIPE_BUF
403 * are atomic. T
404 * Therefore, if size is greater than PIPE_BUF, we will break
405 * the writes into PIPE_BUF chunks. We will also increase the
406 * number of writes to ensure the same (or more) amount of
407 * data is written. This is the same as erroring and telling
408 * the user the new cmd line to do the same thing.
409 * Example:
410 * pipeio -s 5000 -n 10 -c 5
411 * (each child will write at least 50000 bytes, since all
412 * writes have to be in 4096 chuncks or 13*4096 (53248)
413 * bytes will be written.) This is the same as:
414 * pipeio -s 4096 -n 13 -c 5
416 if ( size > PIPE_BUF && num_wrters > 1 ) {
417 if ( ! loop ) {
418 /* we must set num_writes s.t. num_writes*num_wrters doesn't overflow later */
419 num_writes=MIN(((long long)num_writes*size+PIPE_BUF-1)/PIPE_BUF, INT_MAX/num_wrters);
420 tst_resm (TINFO, "adjusting i/o size to %d, and # of writes to %d",
421 PIPE_BUF, num_writes);
423 else {
424 tst_resm (TINFO, "adjusting i/o size to %d", PIPE_BUF);
426 size=PIPE_BUF;
430 if ((writebuf = (char *) malloc(size)) == NULL ||
431 (readbuf = (char *) malloc(size)) == NULL) {
432 tst_resm (TFAIL, "malloc() failed: %s", strerror(errno));
433 SAFE_FREE(writebuf);
434 SAFE_FREE(readbuf);
435 exit(1);
438 memset(writebuf,'Z',size);
440 writebuf[size-1] = 'A'; /* to detect partial read/write problem */
442 if((sem_id = semget(IPC_PRIVATE, 1, IPC_CREAT|S_IRWXU)) == -1) {
443 tst_brkm(TBROK, tst_exit, "Couldn't allocate semaphore: %s", strerror(errno));
446 if(semctl(sem_id, 0, SETVAL, 0) == -1)
447 tst_brkm(TBROK, tst_exit, "Couldn't initialize semaphore value: %s", strerror(errno));
449 if ( background ) {
450 if ( (n=fork() ) == -1 ) {
451 tst_resm (TFAIL, "fork() failed: %s", strerror(errno));
452 exit(1);
454 else if ( n != 0 ) /* parent */
455 exit(0);
458 if ( unpipe ) {
459 if ( pipe(fds) == -1 ) {
460 tst_resm (TFAIL, "pipe() failed to create un-named pipe: %s", strerror(errno));
461 exit(1);
463 read_fd = fds[0];
464 write_fd = fds[1];
465 pipe_type = PIPE_UNNAMED;
466 blk_type = UNNAMED_IO;
467 } else {
468 if (strlen(dir) && chdir(dir) == -1) {
469 tst_resm (TFAIL, "chdir(%s) failed: %s", dir, strerror(errno));
470 exit(1);
473 if ( stat(pname, &stbuf) == -1 ) {
475 if ( mkfifo(pname,0777) == -1 ) {
476 tst_resm (TFAIL, "mkfifo(%s,0777) failed: %s", pname, strerror(errno));
477 exit(1);
480 pipe_type = PIPE_NAMED;
483 start_time=time(0);
485 #if DEBUG
486 printf("num_wrters = %d\n", num_wrters);
487 #endif
489 #ifdef linux
490 signal(SIGCHLD, sig_child);
491 signal(SIGHUP, sig_handler);
492 signal(SIGINT, sig_handler);
493 signal(SIGQUIT, sig_handler);
494 #ifdef SIGRECOVERY
495 signal(SIGRECOVERY, sig_handler);
496 #endif /* SIGRECOVERY */
497 #else
498 sigset(SIGCHLD, sig_child);
499 sigset(SIGHUP, sig_handler);
500 sigset(SIGINT, sig_handler);
501 sigset(SIGQUIT, sig_handler);
502 #ifdef SIGRECOVERY
503 sigset(SIGRECOVERY, sig_handler);
504 #endif /* SIGRECOVERY */
505 #endif /* linux */
507 for (i=num_wrters; i > 0; --i) {
508 if ((c=fork()) < 0) {
509 tst_resm (TFAIL, "fork() failed: %s", strerror(errno));
510 exit(1);
512 if (c == 0) break; /* stop child from forking */
514 if (c == 0) { /***** if child *****/
515 #if DEBUG
516 printf("child after fork pid = %d\n", getpid());
517 #endif
518 if ( ! unpipe ) {
519 if ((write_fd = open(pname,O_WRONLY)) == -1) {
520 tst_resm (TFAIL, "child pipe open(%s, %#o) failed: %s", pname, O_WRONLY|ndelay, strerror(errno));
521 exit(1);
523 if(ndelay && fcntl(write_fd, F_SETFL, O_NONBLOCK) == -1) {
524 tst_brkm(TBROK, tst_exit, "Failed setting the pipe to nonblocking mode: %s", strerror(errno));
527 else {
528 close(read_fd);
531 sem_op = (struct sembuf) {
532 .sem_num = 0,
533 .sem_op = 1,
534 .sem_flg = 0
537 if(semop(sem_id, &sem_op, 1) == -1)
538 tst_brkm(TBROK, tst_exit, "Couldn't raise the semaphore: %s", strerror(errno));
541 pid_word = (int *)&writebuf[0];
542 count_word = (int *)&writebuf[NBPW];
544 for (j=0; j < num_writes || loop; ++j) {
546 /* writes are only in one unit when the size of the write
547 * is <= PIPE_BUF.
548 * Therefore, if size is greater than PIPE_BUF, we will break
549 * the writes into PIPE_BUF chunks.
550 * All writes and read need to be same size.
554 * write pid and count in first two
555 * words of buffer
558 *count_word = j;
559 *pid_word = getpid();
561 if ((nb = lio_write_buffer(write_fd, iotype, writebuf, size,
562 SIGUSR1, &cp, 0)) < 0 ) {
564 * If lio_write_buffer returns a negative number,
565 * the return will be -errno.
567 tst_resm (TFAIL, "pass %d: lio_write_buffer(%s) failed; it returned %d: %s", j, cp, nb, strerror(-nb));
568 exit(1);
570 else if (nb != size ) {
571 tst_resm (TFAIL, "pass %d: lio_write_buffer(%s) failed, write count %d, but expected to write %d",
572 j, cp, nb, size);
574 if (verbose)
575 tst_resm (TINFO, "pass %d: pid %d: wrote %d bytes, expected %d bytes",
576 j, getpid(), nb, size);
578 if (chld_wait) {
579 clock=time(0);
580 srand48(clock);
581 n = lrand48() % chld_wait;
582 usleep(n);
584 fflush(stderr);
587 if (c > 0) { /***** if parent *****/
589 if ( ! unpipe ) {
590 if ((read_fd = open(pname,O_RDONLY)) == -1) {
591 tst_resm (TFAIL, "parent pipe open(%s, %#o) failed: %s", pname, O_RDONLY, strerror(errno));
592 exit(1);
594 if(ndelay && fcntl(read_fd, F_SETFL, O_NONBLOCK) == -1) {
595 tst_brkm(TBROK, tst_exit, "Failed setting the pipe to nonblocking mode: %s", strerror(errno));
598 else {
599 close(write_fd);
602 sem_op = (struct sembuf) {
603 .sem_num = 0,
604 .sem_op = -num_wrters,
605 .sem_flg = 0
608 while(Nchildcomplete < num_wrters && semop(sem_id, &sem_op, 1) == -1) {
609 if(errno == EINTR) {
610 continue;
612 tst_brkm(TBROK, tst_exit, "Couldn't wait on semaphore: %s", strerror(errno));
615 for (i=num_wrters*num_writes; i > 0 || loop; --i) {
616 if(error >= MAX_ERRS || empty_read >= MAX_EMPTY)
617 break;
618 if (parent_wait) {
619 clock=time(0);
620 srand48(clock);
621 n = lrand48() % parent_wait;
622 usleep(n);
624 ++count;
625 if ((nb = lio_read_buffer(read_fd, iotype, readbuf, size,
626 SIGUSR1, &cp, 0)) < 0 ) {
628 * If lio_read_buffer returns a negative number,
629 * the return will be -errno.
631 tst_resm (TFAIL, "pass %d: lio_read_buffer(%s) failed; it returned %d: %s", i, cp, nb, strerror(-nb));
632 ++i;
633 count--;
634 error++;
635 continue;
637 } else {
638 if (nb == 0) {
639 if ( Nchildcomplete >= num_wrters ) {
640 if(!loop)
641 tst_resm(TWARN, "The children have died prematurely");
642 break; /* All children have died */
644 empty_read++;
646 fprintf(stdout,
647 "%s: Nothing on the pipe (%d),read count %d (read not counted)\n",
648 TCID,empty_read,count);
649 fflush(stdout);
651 ++i;
652 count--;
653 continue;
654 } else if (nb < size && size <= PIPE_BUF) {
655 tst_resm (TFAIL, "pass %d: partial read from the pipe: read %d bytes, expected %d, read count %d",
656 i, nb, size, count);
657 ++error;
658 } else if (nb == size) {
659 for (j=2*NBPW;j < size; ++j) {
660 if (writebuf[j] != readbuf[j]) {
661 ++error;
662 tst_resm (TFAIL, "1 FAIL data error on byte %d; rd# %d, sz= %d, %s %s empty_reads= %d, err= %d",
663 j, count, size, pipe_type, blk_type, empty_read, error);
664 prt_buf(&readbuf,readbuf,format_size,format);
665 fflush(stdout);
666 if ( exit_error && exit_error == error )
667 goto output;
669 else
670 break;
674 if (verbose || (num_rpt && !(count % num_rpt))) {
675 current_time = time(0);
676 diff_time = current_time - start_time; /* elapsed time */
677 tst_resm (TFAIL, "(%d) rd# %d, sz= %d, %s %s empty_reads= %d, err= %d\n",
678 (int)diff_time,count,size,pipe_type,blk_type,empty_read,error);
679 fflush(stdout);
683 if(empty_read)
684 tst_resm(TWARN, "%d empty reads", empty_read);
685 output:
686 if (error)
687 tst_resm (TFAIL, "1 FAIL %d data errors on pipe, read size = %d, %s %s",
688 error,size,pipe_type,blk_type);
689 else
690 if( !quiet )
691 tst_resm (TPASS, "1 PASS %d pipe reads complete, read size = %d, %s %s",
692 count+1,size,pipe_type,blk_type);
694 semctl(sem_id, 0, IPC_RMID);
696 if (!unpipe)
697 unlink(pname);
700 SAFE_FREE(writebuf);
701 SAFE_FREE(readbuf);
702 return (error);
705 void
706 usage ()
708 fprintf(stderr, "Usage: %s [-BbCEv][-c #writers][-D pname][-d dir][-h][-e exit_num][-f fmt][-l][-i #writes][-n #writes][-p num_rpt]\n\t[-s size][-W max_wait][-w max_wait][-u]\n",TCID);
709 fflush(stderr);
713 void
714 help()
716 usage();
718 printf(" -B - execute actions in background\n\
719 -b - blocking reads and writes. default non-block\n\
720 -c #writers - number of writers (childern)\n\
721 -D pname - name of fifo (def tpipe<pid>)\n\
722 -d dir - cd to dir before creating named pipe\n\
723 - (silently ignored if used with -u)\n\
724 -h - print this help message\n\
725 -e exit_num - exit on error exit_num, 0 is ignore errors, 1 is default.\n\
726 -E - print cmd line examples and exit\n\
727 -f format - define format of bad buffer: h(hex), o(octal)\n\
728 d(decimal), a(ascii), n (none). hex is default\n\
729 option size can be added to control output\n\
730 -i #writes - number write per child, zero means forever.\n\
731 -I io_type - Specifies io type: s - sync, p - polled async, a - async (def s)\n\
732 l - listio sync, L - listio async, r - random\n\
733 -l - loop forever (implied by -n 0).\n\
734 -n #writes - same as -i (for compatability).\n\
735 -p num_rpt - number of reads before a report\n\
736 -q - quiet mode, no PASS results are printed\n\
737 -s size - size of read and write (def 327)\n\
738 if size >= 4096, i/o will be in 4096 chuncks\n\
739 -w max_wait - max time (seconds) for sleep between writes.\n\
740 max_wait is interpreted as a double with ms accuracy.\n\
741 -W max_wait - max time (seconds) for sleep between reads\n\
742 max_wait is interpreted as a double with ms accuracy.\n\
743 -u - un-named pipe instead of named pipe\n\
744 -v - verbose mode, all writes/reads resutlts printed\n");
746 fflush(stdout);
750 void
751 prt_buf(long addr, char * buf, int length, int format)
754 int i;
755 int num_words = length/NBPW; /* given length in bytes, get length in words */
756 int width; /* number of columns */
757 int extra_words = 0; /* odd or even number of words */
758 char *a = buf;
759 char b[NBPW];
760 char c[NBPW*2];
761 char *p;
762 long *word;
764 if ( format == NO_OUT ) /* if no output wanted, return */
765 return;
767 if (length % NBPW) ++num_words; /* is length in full words? */
768 if (format == ASCII) {
769 width = 3;
770 } else {
771 width = 2;
772 /* do we have an odd number of words? */
773 extra_words = num_words%width;
775 for(i=0; i < num_words; ++i, a += NBPW, addr++) {
776 word = (long *) a;
777 if (!(i%width)) {
778 if (i > 0 && format != ASCII) {
780 * print the ascii equivalent of the data
781 * before beginning the next line of output.
783 memset(c,0x00,width*NBPW);
785 * get the last 2 words printed
787 memcpy(c,a-(width*NBPW),width*NBPW);
788 for (p = c; (p-c) < width*NBPW; ++p) {
789 if (*p < '!' || *p > '~')
790 *p = '.';
792 printf("\t%16.16s",c);
794 printf("\n%7lo: ",addr);
795 /***printf("\n%7o (%d): ",addr,i);***/
798 switch (format) {
799 case HEX:
800 printf("%16.16lx ",*word);
801 break;
802 case DECIMAL:
803 printf("%10.10ld ",*word);
804 break;
805 case ASCII:
806 memcpy(b,a,NBPW);
807 for (p = b; (p-b) < NBPW; ++p) {
808 if (*p < '!' || *p > '~')
809 *p = '.';
811 printf("%8.8s ",b);
812 break;
813 default:
814 printf("%22.22lo ",*word);
815 break;
818 if (format != ASCII) {
820 * print the ascii equivalent of the last words in the buffer
821 * before returning.
823 memset(c,0x00,width*NBPW);
824 if (extra_words) width = extra_words; /* odd number of words */
825 memcpy(c,a-(width*NBPW),width*NBPW);
826 for (p = c; (p-c) < width*NBPW; ++p) {
827 if (*p < '!' || *p > '~')
828 *p = '.';
830 if (width == 2)
831 printf("\t%16.16s",c);
832 else
833 printf("\t\t%16.8s",c);
835 printf("\n");
836 fflush(stdout);
839 void
840 prt_examples()
842 printf("%s -c 5 -i 0 -s 4090 -b\n", TCID);
843 printf("%s -c 5 -i 0 -s 4090 -b -u \n", TCID);
844 printf("%s -c 5 -i 0 -s 4090 -b -W 3 -w 3 \n", TCID);
848 void
849 sig_child(int sig)
851 int status;
853 Nchildcomplete++;
854 #if DEBUG
855 printf("parent: received SIGCHLD\n");
856 #endif
857 waitpid(-1, &status, WNOHANG);
858 #if linux
859 signal(SIGCHLD, sig_child);
860 #else
861 sigset(SIGCHLD, sig_child);
862 #endif
865 void
866 sig_handler(int sig)
868 #ifdef SIGRECOVERY
869 if ( sig == SIGRECOVERY) {
870 printf("%s: received SIGRECOVERY, count = %d\n", TCID, count);
871 fflush(stdout);
872 #ifdef linux
873 signal(sig, sig_handler);
874 #else
875 sigset(sig, sig_handler);
876 #endif
877 return;
879 #endif
880 printf("%s: received unexpected signal: %d\n", TCID, sig);
881 fflush(stdout);
882 exit(3);