402 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			402 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* dd - disk dumper */
 | 
						|
 | 
						|
#include <sys/types.h>
 | 
						|
#include <sys/stat.h>
 | 
						|
#include <signal.h>
 | 
						|
#include <fcntl.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <string.h>
 | 
						|
#include <errno.h>
 | 
						|
 | 
						|
#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 NOTRUNC 0x0040
 | 
						|
#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, oflags;
 | 
						|
 | 
						|
  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("notrunc")) {
 | 
						|
				convflag |= NOTRUNC;
 | 
						|
				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);
 | 
						|
  }
 | 
						|
  oflags = O_WRONLY | O_CREAT;
 | 
						|
  if (!seekseen && (convflag & NOTRUNC) != NOTRUNC)
 | 
						|
  	oflags |= O_TRUNC;
 | 
						|
  if ((ofd = ((ofilename) ? open(ofilename, oflags, 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);
 | 
						|
}
 |