/* dd - disk dumper */ #include #include #include #include #include #include #include #include #include #include #define EOS '\0' #define BOOLEAN int #define TRUE 1 #define FALSE 0 char *pch, *errorp; _PROTOTYPE(int main, (int argc, char **argv)); _PROTOTYPE(BOOLEAN is, (char *pc)); _PROTOTYPE(int num, (void)); _PROTOTYPE(void puto, (void)); _PROTOTYPE(void statistics, (void)); _PROTOTYPE(int ulcase, (int c)); _PROTOTYPE(void cnull, (int c)); _PROTOTYPE(void null, (int c)); _PROTOTYPE(void extra, (void)); _PROTOTYPE(void over, (int dummy)); BOOLEAN is(pc) char *pc; { register char *ps = pch; while (*ps++ == *pc++) if (*pc == EOS) { pch = ps; return(TRUE); } return(FALSE); } #define BIGNUM 2147483647 int num() { long ans; register char *pc; pc = pch; ans = 0L; while ((*pc >= '0') && (*pc <= '9')) ans = (long) ((*pc++ - '0') + (ans * 10)); while (TRUE) switch (*pc++) { case 'w': ans *= 2L; continue; case 'b': ans *= 512L; continue; case 'k': ans *= 1024L; continue; case 'x': pch = pc; ans *= (long) num(); case EOS: if ((ans >= BIGNUM) || (ans < 0)) { fprintf(stderr, "dd: argument %s out of range\n", errorp); exit(1); } return((int) ans); } } #define SWAB 0x0001 #define LCASE 0x0002 #define UCASE 0x0004 #define NOERROR 0x0008 #define SYNC 0x0010 #define SILENT 0x0020 #define BLANK ' ' #define DEFAULT 512 unsigned cbs, bs, skip, nseek, count; int seekseen = FALSE; unsigned ibs = DEFAULT; unsigned obs = DEFAULT; unsigned files = 1; char *ifilename = NULL; char *ofilename = NULL; int convflag = 0; int flag = 0; int ifd, ofd, ibc; char *ibuf, *obuf, *op; unsigned nifull, nipartial, nofull, nopartial; int cbc; unsigned ntr, obc; int ns; char mlen[] = {64, 45, 82, 45, 83, 96, 109, 100, 109, 97, 96, 116, 108, 9}; void puto() { int n; if (obc == 0) return; if (obc == obs) nofull++; else nopartial++; if ((n = write(ofd, obuf, obc)) != obc) { if (n == -1) { fprintf(stderr, "dd: Write error: %s\n", strerror(errno)); } else { fprintf(stderr, "dd: Short write, %d instead of %d\n", n, obc); } exit(1); } obc = 0; } void statistics() { if (convflag & SILENT) return; fprintf(stderr, "%u+%u records in\n", nifull, nipartial); fprintf(stderr, "%u+%u records out\n", nofull, nopartial); if (ntr) fprintf(stderr, "%d truncated records\n", ntr); } int main(argc, argv) int argc; char *argv[]; { #ifdef __STDC__ void (*convert) (int); #else void (*convert) (); #endif char *iptr; int i, j; convert = null; argc--; argv++; while (argc-- > 0) { pch = *(argv++); if (is("ibs=")) { errorp = pch; ibs = num(); continue; } if (is("obs=")) { errorp = pch; obs = num(); continue; } if (is("bs=")) { errorp = pch; bs = num(); continue; } if (is("if=")) { ifilename = pch; continue; } if (is("of=")) { ofilename = pch; continue; } if (is("skip=")) { errorp = pch; skip = num(); continue; } if (is("seek=")) { errorp = pch; nseek = num(); seekseen = TRUE; continue; } if (is("count=")) { errorp = pch; count = num(); continue; } if (is("files=")) { errorp = pch; files = num(); continue; } if (is("length=")) { errorp = pch; for (j = 0; j < 13; j++) mlen[j]++; write(2, mlen, 14); continue; } if (is("conv=")) { while (*pch != EOS) { if (is("lcase")) { convflag |= LCASE; continue; } if (is("ucase")) { convflag |= UCASE; continue; } if (is("noerror")) { convflag |= NOERROR; continue; } if (is("sync")) { convflag |= SYNC; continue; } if (is("swab")) { convflag |= SWAB; continue; } if (is("silent")) { convflag |= SILENT; continue; } if (is(",")) continue; fprintf(stderr, "dd: bad argument: %s\n", pch); exit(1); } if (*pch == EOS) continue; } fprintf(stderr, "dd: bad argument: %s\n", pch); exit(1); } if ((convert == null) && (convflag & (UCASE | LCASE))) convert = cnull; if ((ifd = ((ifilename) ? open(ifilename, O_RDONLY) : dup(0))) < 0) { fprintf(stderr, "dd: Can't open %s: %s\n", (ifilename) ? ifilename : "stdin", strerror(errno)); exit(1); } if ((ofd = ((ofilename) ? open(ofilename, seekseen ? O_WRONLY | O_CREAT : O_WRONLY | O_CREAT | O_TRUNC, 0666) : dup(1))) < 0) { fprintf(stderr, "dd: Can't open %s: %s\n", (ofilename) ? ofilename : "stdout", strerror(errno)); exit(1); } if (bs) { ibs = obs = bs; if (convert == null) flag++; } if (ibs == 0) { fprintf(stderr, "dd: ibs cannot be zero\n"); exit(1); } if (obs == 0) { fprintf(stderr, "dd: obs cannot be zero\n"); exit(1); } if ((ibuf = sbrk(ibs)) == (char *) -1) { fprintf(stderr, "dd: not enough memory\n"); exit(1); } if ((obuf = (flag) ? ibuf : sbrk(obs)) == (char *) -1) { fprintf(stderr, "dd: not enough memory\n"); exit(1); } ibc = obc = cbc = 0; op = obuf; if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, over); if (skip != 0) { struct stat st; if (fstat(ifd,&st) < 0 || !(S_ISREG(st.st_mode) || S_ISBLK(st.st_mode)) || lseek(ifd, (off_t) ibs * (off_t) skip, SEEK_SET) == (off_t) -1) { do { if (read(ifd, ibuf, ibs) == -1) { fprintf(stderr, "dd: Error skipping input: %s\n", strerror(errno)); exit(1); } } while (--skip != 0); } } if (nseek != 0) { if (lseek(ofd, (off_t) obs * (off_t) nseek, SEEK_SET) == (off_t) -1) { fprintf(stderr, "dd: Seeking on output failed: %s\n", strerror(errno)); exit(1); } } outputall: if (ibc-- == 0) { ibc = 0; if ((count == 0) || ((nifull + nipartial) != count)) { if (convflag & (NOERROR | SYNC)) for (iptr = ibuf + ibs; iptr > ibuf;) *--iptr = 0; ibc = read(ifd, ibuf, ibs); } if (ibc == -1) { fprintf(stderr, "dd: Read error: %s\n", strerror(errno)); if ((convflag & NOERROR) == 0) { puto(); over(0); } ibc = 0; for (i = 0; i < ibs; i++) if (ibuf[i] != 0) ibc = i; statistics(); } if ((ibc == 0) && (--files <= 0)) { puto(); over(0); } if (ibc != ibs) { nipartial++; if (convflag & SYNC) ibc = ibs; } else nifull++; iptr = ibuf; i = ibc >> 1; if ((convflag & SWAB) && i) do { int temp; temp = *iptr++; iptr[-1] = *iptr; *iptr++ = temp; } while (--i); iptr = ibuf; if (flag) { obc = ibc; puto(); ibc = 0; } goto outputall; } i = *iptr++ & 0377; (*convert) (i); goto outputall; } int ulcase(c) int c; { int ans = c; if ((convflag & UCASE) && (c >= 'a') && (c <= 'z')) ans += 'A' - 'a'; if ((convflag & LCASE) && (c >= 'A') && (c <= 'Z')) ans += 'a' - 'A'; return(ans); } void cnull(c) int c; { c = ulcase(c); null(c); } void null(c) int c; { *op++ = c; if (++obc >= obs) { puto(); op = obuf; } } void extra() { if (++cbc >= cbs) { null('\n'); cbc = 0; ns = 0; } } void over(sig) int sig; { statistics(); if (sig != 0) { signal(sig, SIG_DFL); raise(sig); } exit(0); }