# 2.11BSD#431 - /usr/src/local/ddd/ddd.c

##### Functions

    catchsignals      X
    doerror           X
    dofork            X
    evalopt           X
    getcounters       X
    gettoken          X
    initbuffer        X
    inittokens        X
    main              X
    parsearguments    X
    passcounters      X
    passtoken         X
    readbuffer        X
    setdefaults       X
    terminate         X
    writebuffer       X

##### Macros

    DEFBS             X
    FALSE             X
    FULLIN            X
    FULLOUT           X
    P_REND            X
    P_WEND            X
    RTOK_P            X
    SHORTIN           X
    SHORTOUT          X
    STDIN             X
    STDOUT            X
    TOK_CONT          X
    TOK_DONE          X
    TOK_ERROR         X
    TRUE              X
    WTOK_P            X
    max               X
    min               X

       1: /*
       2:  * ddd.c - double dd (version 2)
       3:  *
       4:  * Copyright 1988 Helsinki University of Technology.
       5:  * All rights reserved.
       6:  *
       7:  * Permission granted to distribute, use and modify
       8:  * this code for uncommercial purposes, provided
       9:  * that this copyright notice is not changed.
      10:  *
      11:  * Author: Tapani Lindgren (nispa@cs.hut.fi)
      12:  *
      13:  * Ddd is a dd clone that operates as two processes;
      14:  * one process reads while the other one writes and vice versa.
      15:  * This way the throughput may be up to twice as good as that of dd,
      16:  * especially with slow devices such as tape drives.
      17:  *
      18:  * ***** WARNING ***** (For U.S. residents & citizens only)
      19:  *
      20:  * Do not use this program!  Get rid of it as soon as you can!
      21:  * It will probably corrupt all your data, break down your computer
      22:  * and cause severe injury to the operators.
      23:  * Even reading the source code may give you a headache.
      24:  * I warned you!  I will take no responsibility whatsoever!
      25:  */
      26:
      27: /* declarations common to all unix versions */
      28: #include <stdio.h>     /* for fprintf() and stderr() */
      29: #include <signal.h>    /* for SIGTERM */
      30: extern char *malloc();
      31:
      32: /* version dependent declarations */
      33:
      34: #ifdef BSD
      35: #include <sys/wait.h>  /* for union wait */
      36: #include <sys/file.h>  /* for O_RDONLY and O_WRONLY */
      37: extern char *sprintf();
      38: #endif
      39:
      40: #ifdef SYSV
      41: #include <fcntl.h>     /* for O_RDONLY and O_WRONLY */
      42: void exit();
      43: void perror();
      44: #endif
      45:
      46:
      47:
      48: /* macros to find min or max of two values */
      49: #define min(a,b) ((a)<(b)? (a): (b))
      50: #define max(a,b) ((a)>(b)? (a): (b))
      51:
      52: /* inherited file descriptors */
      53: #define STDIN 0
      54: #define STDOUT 1
      55:
      56: /* boolean values */
      57: #define FALSE 0
      58: #define TRUE 1
      59:
      60: /* pipes have a read end and a write end */
      61: #define P_REND 0
      62: #define P_WEND 1
      63:
      64: /* there are two pipes; one for read tokens and one for write tokens */
      65: #define RTOK_P 0
      66: #define WTOK_P 1
      67:
      68: /* token bytes passed along pipes */
      69: #define TOK_CONT 0     /* go ahead */
      70: #define TOK_DONE 1     /* end of data */
      71: #define TOK_ERROR 2    /* something's wrong, you've better stop now */
      72:
      73: /* input/output full/short record counters are in a table;
      74:  indexes defined below */
      75: #define FULLIN 0
      76: #define SHORTIN 1
      77: #define FULLOUT 2
      78: #define SHORTOUT 3
      79:
      80: /* defaults */
      81: #define DEFBS 512      /* default block size */
      82:
      83: /* forward declarations */
      84: int doerror();
      85:
      86: /* global variables */
      87: static int
      88:   ifd, ofd,    /* input/output file descriptors */
      89:   ibs, obs,    /* input/output block sizes */
      90:   cbs, /* "conversion" buffer size */
      91:   pid, /* pid of child (in parent) or 0 (in child) */
      92:   eof = FALSE, /* have we encountered end-of-file */
      93:   pipefd[2][2],        /* read/write fd's for 2 pipes */
      94:   counters[4] = {0, 0, 0, 0},  /* input/output full/short record counters */
      95:   buflen;      /* count of characters read into buffer */
      96: static char
      97:   *buffer;     /* address of buffer */
      98:
      99:
     100: main(argc, argv)
     101: int argc;
     102: char *argv[];
     103: {
     104:   (void) catchsignals();       /* prepare for interrupts etc */
     105:   (void) setdefaults();        /* set default values for parameters */
     106:   (void) parsearguments(argc, argv);   /* parse arguments */
     107:   (void) initbuffer(); /* initialize buffer */
     108:   (void) inittokens(); /* create one READ and one WRITE token */
     109:   (void) dofork();     /* 1 will be 2 */
     110:   while (!eof) {       /* enter main loop */
     111:     (void) gettoken(RTOK_P);   /* compete for first/next read turn */
     112:     (void) readbuffer();       /* fill buffer with input */
     113:     (void) gettoken(WTOK_P);   /* make sure we also get the next write turn */
     114:     /* now others may read if they wish (and if there's any data left */
     115:     (void) passtoken(RTOK_P, eof? TOK_DONE: TOK_CONT);
     116:     (void) writebuffer();      /* ... while we write to output */
     117:     /* this cycle is done now */
     118:     if (!eof) (void) passtoken(WTOK_P, TOK_CONT);
     119:   }    /* end of main loop */
     120:   (void) passcounters(RTOK_P); /* send record counters to our partner */
     121:   (void) terminate(0); /* and exit (no errors) */
     122:   /* NOTREACHED */
     123: }      /* end of main() */
     124:
     125:
     126: catchsignals()
     127: /* arrange for some signals to be catched, so that statistics can be printed */
     128: {
     129:   static int siglist[] = {
     130:     SIGINT, SIGQUIT, SIGILL, SIGFPE,
     131:     SIGBUS, SIGSEGV, SIGSYS, SIGPIPE,
     132:     SIGALRM, SIGTERM, 0
     133:     };
     134:   int *sigp;
     135:
     136:   for (sigp = siglist; *sigp != 0; sigp++)
     137:     (void) signal(*sigp, doerror);
     138: }      /* end of catchsignals() */
     139:
     140: doerror()
     141: /* what we do if we get an error or catch a signal */
     142: {
     143:   /* send error token to both pipes */
     144:   (void) passtoken(RTOK_P, TOK_ERROR);
     145:   (void) passtoken(WTOK_P, TOK_ERROR);
     146:   /* also send i/o record counters */
     147:   (void) passcounters(RTOK_P);
     148:   (void) passcounters(RTOK_P);
     149:   /* terminate with error status */
     150:   (void) terminate(1);
     151: }
     152:
     153: terminate(stat)
     154: int stat;
     155: {
     156:   /* parent will try to wait for child */
     157: #ifdef BSD
     158:   if (pid) (void) wait((union wait *) 0);
     159: #endif
     160: #ifdef SYSV
     161:   if (pid) (void) wait((int *) 0);
     162: #endif
     163:
     164:   exit(stat);
     165: }
     166:
     167: setdefaults()
     168: /* set default values */
     169: {
     170:   ifd = STDIN;
     171:   ofd = STDOUT;
     172:   ibs = obs = DEFBS;   /* block sizes */
     173:   cbs = 0;     /* initially; will be set to max(ibs, obs, cbs) */
     174: }
     175:
     176: parsearguments(argc, argv)
     177: int argc;
     178: char *argv[];
     179:   /* parse arguments */
     180: {
     181:   /* constant strings "array" for recognizing options */
     182:   static struct {
     183:     char *IF, *OF, *CBS, *IBS, *OBS, *BS, *NOTHING;
     184:   } consts = {
     185:     "if=", "of=", "cbs=", "ibs=", "obs=", "bs=", ""
     186:     };
     187:   char **constp;       /* const structure pointer */
     188:
     189:   for (argc--, argv++; argc > 0; argc--, argv++) {
     190:     constp = (char **) &consts;
     191:     while (**constp && strncmp(*argv, *constp, strlen(*constp)))
     192:       constp++;
     193:     /* constp now points to one of the pointers in consts structure */
     194:     *argv += strlen(*constp);  /* skip the constant part of the argument */
     195:     if (constp == &consts.IF) {        /* open another file for input */
     196:       ifd = open(*argv, O_RDONLY);
     197:       if (ifd < 0) perror (*argv);
     198:     } else if (constp == &consts.OF) {
     199:       ofd = open(*argv, O_WRONLY | O_CREAT);   /* open file for output */
     200:       if (ofd < 0) perror (*argv);
     201:     } else if (constp == &consts.CBS) {        /* set buffer size */
     202:       cbs = evalopt(*argv);
     203:     } else if (constp == &consts.IBS) {        /* set input block size */
     204:       ibs = evalopt(*argv);
     205:     } else if (constp == &consts.OBS) {        /* set output block size */
     206:       obs = evalopt(*argv);
     207:     } else if (constp == &consts.BS) { /* set input and output block sizes */
     208:       ibs = obs = evalopt(*argv);
     209:     } else {
     210:       (void) fprintf(stderr,
     211:                     "usage: ddd [if=name] [of=name] [bs=n] [ibs=n obs=n]\n");
     212:       exit(1);
     213:     }
     214:   } /* end of for loop */
     215: } /* end of parsearguments() */
     216:
     217: evalopt(p) /* return numerical value of string */
     218: char *p;
     219: {
     220:   int temp = 0;
     221:
     222:   for ( ; *p >= '0' && *p <= '9'; p++)
     223:     temp = temp * 10 + *p - '0';
     224:   if (temp < 1) {
     225:     (void) fprintf(stderr, "ddd: illegal size option\n");
     226:     exit(1);
     227:   }
     228:   switch (*p) {
     229:   case '\0':
     230:     return(temp);
     231:   case 'w':
     232:   case 'W':
     233:     return(temp << 2); /* 4-byte words */
     234:   case 'b':
     235:   case 'B':
     236:     return(temp << 9); /* 512-byte blocks */
     237:   case 'k':
     238:   case 'K':
     239:     return(temp << 10);        /* kilobytes */
     240:   default:
     241:     (void) fprintf(stderr, "ddd: bad size option\n");
     242:     exit(1);
     243:   }
     244:   /* NOTREACHED */
     245: }      /* end of evalopt() */
     246:
     247: initbuffer()
     248: /* initialize buffer */
     249: {
     250:   cbs = max(cbs, max(ibs, obs));       /* determine buffer size */
     251:   if (cbs % ibs || cbs % obs) {
     252:     (void) fprintf(stderr, "ddd: warning: incompatible block/buffer sizes\n");
     253:   }
     254:   buffer = malloc((unsigned) cbs);
     255:   if (buffer == NULL) {
     256:     (void) perror("ddd: cannot allocate buffer");
     257:     exit(1);
     258:   }
     259: }      /* end of initbuffer() */
     260:
     261: inittokens()
     262: /* initialize token passing system with 2 pipes */
     263: {
     264:   if(pipe(pipefd[RTOK_P]) < 0 || pipe(pipefd[WTOK_P]) < 0) {
     265:     (void) perror("ddd: cannot create token pipes");
     266:     exit(1);
     267:   }
     268:   /* create initial tokens */
     269:   (void) passtoken(RTOK_P, TOK_CONT);
     270:   (void) passtoken(WTOK_P, TOK_CONT);
     271: }      /* end of inittokens() */
     272:
     273: passtoken(pipenum, token)
     274: int pipenum;
     275: char token;
     276: /* pass a token to a pipe */
     277: {
     278:   if (write(pipefd[pipenum][P_WEND], &token, 1) < 1) {
     279:     (void) perror("ddd: cannot write token to pipe");
     280:     exit(1);
     281:   }
     282: }      /* end of passtoken() */
     283:
     284: gettoken(pipenum)
     285: int pipenum;
     286: /* wait to read a token from the pipe; also see if we should stop */
     287: {
     288:   char tokenbuf;
     289:
     290:   if (read(pipefd[pipenum][P_REND], &tokenbuf, 1) < 1) {
     291:     (void) perror("ddd: cannot read token from pipe");
     292:     exit(1);
     293:   }
     294:   if (tokenbuf != TOK_CONT) {  /* we did not get what we wanted */
     295:     (void) getcounters(pipenum);       /* report record counters */
     296:     terminate(tokenbuf == TOK_DONE);   /* TOK_DONE means no error */
     297:   }
     298: }      /* end of gettoken() */
     299:
     300: passcounters(pipenum)
     301: int pipenum;
     302: /* pass read/write counters to the other process */
     303: {
     304:   if (write(pipefd[pipenum][P_WEND], (char *) counters,
     305:            sizeof(counters)) < sizeof(counters)) {
     306:     (void) perror("ddd: cannot write counters to pipe");
     307:     exit(1);
     308:   }
     309: }
     310:
     311: getcounters(pipenum)
     312: int pipenum;
     313: /* report input/output record counts */
     314: {
     315:   int hiscounters[4];
     316:
     317:   if (read(pipefd[pipenum][P_REND], (char *) hiscounters,
     318:           sizeof(hiscounters)) < sizeof(hiscounters)) {
     319:     (void) perror("ddd: cannot read counters from pipe");
     320:     exit(1);
     321:   }
     322:   (void) fprintf(stderr,
     323:                 "%d+%d records in\n%d+%d records out\n",
     324:                 counters[FULLIN] + hiscounters[FULLIN],
     325:                 counters[SHORTIN] + hiscounters[SHORTIN],
     326:                 counters[FULLOUT] + hiscounters[FULLOUT],
     327:                 counters[SHORTOUT] + hiscounters[SHORTOUT]
     328:                 );
     329: }      /* end of printcounters() */
     330:
     331: dofork()
     332: /* fork into 2 processes */
     333: {
     334:   if ((pid = fork()) < 0) {
     335:     (void) perror("ddd: warning: cannot fork");
     336:     /* But continue and do our job anyway, as regular dd */
     337:   }
     338: }
     339:
     340: readbuffer()
     341: /* read buffer from input */
     342: {
     343:   int iolen, ioresult;
     344:
     345:   buflen = 0;
     346:   while (buflen < cbs && !eof) {
     347:     iolen = min(ibs, cbs - buflen);
     348: #ifdef BSD
     349:     ioresult = read(ifd, &buffer[buflen], iolen);
     350: #endif
     351: #ifdef SYSV
     352:     ioresult = read(ifd, &buffer[buflen], (unsigned) iolen);
     353: #endif
     354:     if (ioresult == 0) {       /* end of file */
     355:       eof = TRUE;
     356:     } else if (ioresult < 0) {
     357:       (void) perror("ddd: read error");
     358:       (void) doerror();
     359:     }
     360:     buflen += ioresult;        /* update current count of chars in buffer */
     361:     /* if we got any data, update appropriate input record count */
     362:     if (ioresult > 0) counters[(ioresult == ibs)? FULLIN: SHORTIN]++;
     363:   }
     364: }      /* end of readbuffer() */
     365:
     366: writebuffer()
     367: /* writing phase */
     368: {
     369:   int ocount, iolen, ioresult;
     370:
     371:   ocount = 0;  /* count of chars written */
     372:   while (ocount < buflen) {
     373:     iolen = min(obs, buflen - ocount);
     374: #ifdef BSD
     375:     ioresult = write(ofd, &buffer[ocount], iolen);
     376: #endif
     377: #ifdef SYSV
     378:     ioresult = write(ofd, &buffer[ocount], (unsigned) iolen);
     379: #endif
     380:     if (ioresult < iolen) {
     381:       perror("ddd: write error");
     382:       (void) doerror();
     383:     }
     384:     ocount += ioresult;
     385:     /* count output records */
     386:     counters[(ioresult == obs)? FULLOUT: SHORTOUT]++;
     387:   }
     388: }      /* end of writebuffer() */

#### Defined functions

catchsignals defined in line 126; used 1 times

- in line 104

doerror defined in line 140; used 4 times

- in line 84, 137, 358, 382

dofork defined in line 331; used 1 times

- in line 109

evalopt defined in line 217; used 4 times

- in line 202-208(4)

getcounters defined in line 311; used 1 times

- in line 295

gettoken defined in line 284; used 2 times

- in line 111-113(2)

initbuffer defined in line 247; used 1 times

- in line 107

inittokens defined in line 261; used 1 times

- in line 108

main defined in line 100; never used
parsearguments defined in line 176; used 1 times

- in line 106

passcounters defined in line 300; used 3 times

- in line 120, 147-148(2)

passtoken defined in line 273; used 6 times

- in line 115-118(2), 144-145(2), 269-270(2)

readbuffer defined in line 340; used 1 times

- in line 112

setdefaults defined in line 167; used 1 times

- in line 105

terminate defined in line 153; used 3 times

- in line 121, 150, 296

writebuffer defined in line 366; used 1 times

- in line 116

#### Defined variables

buffer defined in line 97; used 6 times

- in line 254-255(2), 349-352(2), 375-378(2)

cbs defined in line 90; used 9 times

- in line 173, 202, 250-254(5), 346-347(2)

eof defined in line 92; used 5 times

- in line 110-118(3), 346, 355

ibs defined in line 89; used 7 times

- in line 172, 204-208(2), 250-251(2), 347, 362

ifd defined in line 88; used 5 times

- in line 170, 196-197(2), 349-352(2)

obs defined in line 89; used 7 times

- in line 172, 206-208(2), 250-251(2), 373, 386

ofd defined in line 88; used 5 times

- in line 171, 199-200(2), 375-378(2)

pid defined in line 91; used 3 times

- in line 158-161(2), 334

#### Defined macros

DEFBS defined in line 81; used 1 times

- in line 172

FALSE defined in line 57; used 1 times

- in line 92

FULLIN defined in line 75; used 3 times

- in line 324(2), 362

FULLOUT defined in line 77; used 3 times

- in line 326(2), 386

P_REND defined in line 61; used 2 times

- in line 290, 317

P_WEND defined in line 62; used 2 times

- in line 278, 304

RTOK_P defined in line 65; used 8 times

- in line 111-120(3), 144-148(3), 264-269(2)

SHORTIN defined in line 76; used 3 times

- in line 325(2), 362

SHORTOUT defined in line 78; used 3 times

- in line 327(2), 386

STDIN defined in line 53; used 1 times

- in line 170

STDOUT defined in line 54; used 1 times

- in line 171

TOK_CONT defined in line 69; used 5 times

- in line 115-118(2), 269-270(2), 294

TOK_DONE defined in line 70; used 2 times

- in line 115, 296

TOK_ERROR defined in line 71; used 2 times

- in line 144-145(2)

TRUE defined in line 58; used 1 times

- in line 355

WTOK_P defined in line 66; used 5 times

- in line 113-118(2), 145, 264, 270

max defined in line 50; used 2 times

- in line 250(2)

min defined in line 49; used 2 times

- in line 347, 373

Last modified: 1990-09-27 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1796 |