Ultrix-3.1/src/cmd/dump.c

Compare this file to the similar file:
Show the results in this format:


/**********************************************************************
 *   Copyright (c) Digital Equipment Corporation 1984, 1985, 1986.    *
 *   All Rights Reserved. 					      *
 *   Reference "/usr/src/COPYRIGHT" for applicable restrictions.      *
 **********************************************************************/

static char Sccsid[] = "@(#)dump.c 3.1 7/10/87";
/*
 * ULTRIX-11 file system dump program (dump)
 *
 * Modified for use with the Micro/pdp-11 and to prevent
 * accidentally overwriting the file system being dumped, due to
 * typing errors when typing the dump command.
 *
 * Also modified to allow for restarting multi-volume dumps
 * in the event of dump device errors.
 *
 * The m option is used to dump to RX50 floppy diskettes
 * on the Micro/pdp-11. The e option is used for RX33 diskettes.
 *
 * The y option causes the `continue' question not to be asked.
 * This is required when dump is used in a makefile, for
 * making distributions.
 *
 * Usage:	dump 0mf /dev/rrx0 /dev/rrd2
 *
 * Fred Canter 4/7/83
 */

#define	NI	8     	/* changed to 8 from 16 with the increase in BSIZE */
			/* (to prevent size overflow for overlay version) */
#define	DIRPB	(BSIZE/sizeof(struct direct))

/*
 * Not using stdio here, kernel printf() has been included locally.
 * WARNING: the printf version here only recognizes a subset of
 * format specifications, see printf() routine at the end of this
 * file for details.
 */
/*
#include <stdio.h>
*/
#include <sys/param.h>
#include <sys/inode.h>
#include <sys/ino.h>
#include <sys/fblk.h>
#include <sys/filsys.h>
#include <sys/dir.h>
#include <dumprestor.h>
#include <signal.h>
#include <errno.h>

#define	MWORD(m,i) (m[(unsigned)(i-1)/MLEN])
#define	MBIT(i)	(1<<((unsigned)(i-1)%MLEN))
#define	BIS(i,w)	(MWORD(w,i) |=  MBIT(i))
#define	BIC(i,w)	(MWORD(w,i) &= ~MBIT(i))
#define	BIT(i,w)	(MWORD(w,i) & MBIT(i))

struct	filsys	sblock;
struct	dinode	itab[INOPB*NI];
short	clrmap[MSIZ];
short	dirmap[MSIZ];
short	nodmap[MSIZ];

char	*disk;
char	*tape;
char	*increm;
char	incno;
int	uflag;
int	mflag;
int	kflag;
int	yflag;
int	tflag;	/* flag used to prevent rewrite on error question */
		/* see flusht(). Causes dump to exit with status 1, */
		/* allows for more control in scripts using dump */
int	fi;
int	to;
ino_t	ino;
int	nsubdir;
int	ntape;
int	nadded;
int	dadded;
int	density = 160;
int	mpid;
int	ppid;

char	*ctime();
char	*prdate();
long	atol();
int	fi;
long	tsize;
long	esize;
long	asize;
int	mark();
int	add();
int	dump();
int	tapsrec();
int	dmpspc();
int	dsrch();
int	nullf();

#define	HOUR	(60L*60L)
#define	DAY	(24L*HOUR)
#define	YEAR	(365L*DAY)

int	intr();

main(argc, argv)
char *argv[];
{
	char *arg;
	register i;

	time(&spcl.c_date);

	tsize = 2300L*12L*10L;
	tape = "/dev/rht0";
	disk = "/dev/null";
	increm = "/etc/ddate";
	incno = '9';
	uflag = 0;
	mflag = 0;
	kflag = 0;
	yflag = 0;
	arg = "u";
	if(argc > 1) {
		argv++;
		argc--;
		arg = *argv;
	}
	while(*arg)
	switch (*arg++) {

	case 'f':
		if(argc > 1) {
			argv++;
			argc--;
			tape = *argv;
		}
		break;

	case 'd':
		if (argc > 1) {
			argv++;
			argc--;
			if(strlen(*argv) > 4) {
			denerr:
				printf("bad density\n");
				exit(1);
			}
			density = atoi(*argv)/10;
			if(density == 0)
				goto denerr;
		}
		break;

	case 's':
		if(argc > 1) {
			argv++;
			argc--;
			tsize = atol(*argv);
			tsize *= 12L*10L;
		}
		break;

	case '0':
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
		incno = arg[-1];
		break;

	case 'u':
		uflag++;
		break;
	case 'm':		/* dump to RX50 diskettes */
		mflag++;
#ifdef UCB_NKB
		tsize = 400L;
#else
		tsize = 800L;
#endif
		break;
	case 'e':		/* dump to RX33 diskettes */
		mflag++;
#ifdef UCB_NKB
		tsize = 1200L;
#else
		tsize = 2400L;
#endif
		break;
	case 'k':
		kflag++;
		tsize = 8000L;
		tape = "/dev/rtk0";
		break;
	case 'y':
		yflag++;
		break;
	case 't':
		tflag++;
		break;

	default:
		printf("bad key '%c%'\n", arg[-1]);
		exit(1);
	}
	if(argc > 1) {
		argv++;
		argc--;
		disk = *argv;
	}

	mpid = getpid();
	signal(SIGTERM, SIG_IGN);
	getitime();
	printf("     date = %s\n", prdate(spcl.c_date));
	printf("dump date = %s\n", prdate(spcl.c_ddate));
	printf("dumping %s to %s\n", disk, tape);
	if(yflag == 0) {
		printf("\n\7\7\7Last chance before writing on %s\n", tape);
		printf("\nContinue <y or n> ? ");
		if(getchar() != 'y') {
			printf("\nDump aborted\n");
			exit(1);
		}
		while(getchar() != '\n') ;	/* flush input */
	}
	fi = open(disk, 0);
	if(fi < 0) {
		printf("dump: cannot open %s\n", disk);
		exit(1);
	}
	otape();
	printf("I\n");
	esize = 0;
	CLR(clrmap);
	CLR(dirmap);
	CLR(nodmap);

	pass(mark, (short *)NULL);
	do {
		printf("II\n");
		nadded = 0;
		pass(add, dirmap);
	} while(nadded);

	bmapest(clrmap);
	bmapest(nodmap);
	if(mflag) {
		printf("estimated %D blocks on %D diskette(s)\n",
			esize, (esize/tsize)+1);
	} else {
		printf("estimated %D tape blocks on %d tape(s)\n",
			esize, 0);
	}

	printf("III\n");
	bitmap(clrmap, TS_CLRI);
	pass(dump, dirmap);
	printf("IV\n");
	pass(dump, nodmap);
	putitime();
	printf("DONE\n");
	spcl.c_type = TS_END;
	for(i=0; i<NTREC; i++)
		spclrec();
	if(mflag) {
		printf("%D blocks on %d diskette(s)\n",
			spcl.c_tapea, spcl.c_volume);
	} else {
		printf("%D tape blocks on %d tape(s)\n",
			spcl.c_tapea, spcl.c_volume);
	}
	close(to);
	kill(ppid, SIGTERM);
	kill(mpid, SIGINT);	/* kill master copy of dump */
}

pass(fn, map)
int (*fn)();
short *map;
{
	register i, j;
	int bits;
	ino_t mino;
	daddr_t d;

	sync();
	bread((daddr_t)1, (char *)&sblock, sizeof(sblock));
	mino = (sblock.s_isize-2) * INOPB;
	ino = 0;
	for(i=2;; i+=NI) {
		if(ino >= mino)
			break;
		d = (unsigned)i;
		for(j=0; j<INOPB*NI; j++) {
			if(ino >= mino)
				break;
			if((ino % MLEN) == 0) {
				bits = ~0;
				if(map != NULL)
					bits = *map++;
			}
			ino++;
			if(bits & 1) {
				if(d != 0) {
					bread(d, (char *)itab, sizeof(itab));
					d = 0;
				}
				(*fn)(&itab[j]);
			}
			bits >>= 1;
		}
	}
}

icat(ip, fn1, fn2)
struct	dinode	*ip;
int (*fn1)(), (*fn2)();
{
	register i;
	daddr_t d[NADDR];

	l3tol(&d[0], &ip->di_addr[0], NADDR);
	(*fn2)(d, NADDR-3);
	for(i=0; i<NADDR; i++) {
		if(d[i] != 0) {
			if(i < NADDR-3)
				(*fn1)(d[i]); else
				indir(d[i], fn1, fn2, i-(NADDR-3));
		}
	}
}

indir(d, fn1, fn2, n)
daddr_t d;
int (*fn1)(), (*fn2)();
{
	register i;
	daddr_t	idblk[NINDIR];

	bread(d, (char *)idblk, sizeof(idblk));
	if(n <= 0) {
		spcl.c_type = TS_ADDR;
		(*fn2)(idblk, NINDIR);
		for(i=0; i<NINDIR; i++) {
			d = idblk[i];
			if(d != 0)
				(*fn1)(d);
		}
	} else {
		n--;
		for(i=0; i<NINDIR; i++) {
			d = idblk[i];
			if(d != 0)
				indir(d, fn1, fn2, n);
		}
	}
}

mark(ip)
struct dinode *ip;
{
	register f;

	f = ip->di_mode & IFMT;
	if(f == 0)
		return;
	BIS(ino, clrmap);
	if(f == IFDIR)
		BIS(ino, dirmap);
	if(ip->di_mtime >= spcl.c_ddate ||
	   ip->di_ctime >= spcl.c_ddate) {
		BIS(ino, nodmap);
#ifdef	UCB_SYMLINKS
		if (f != IFREG && f != IFLNK)
#else
		if (f != IFREG)
#endif
			return;
		est(ip);
	}
}

add(ip)
struct dinode *ip;
{

	if(BIT(ino, nodmap))
		return;
	nsubdir = 0;
	dadded = 0;
	icat(ip, dsrch, nullf);
	if(dadded) {
		BIS(ino, nodmap);
		est(ip);
		nadded++;
	}
	if(nsubdir == 0)
		if(!BIT(ino, nodmap))
			BIC(ino, dirmap);
}

dump(ip)
struct dinode *ip;
{
	register i;

	if(ntape) {
		ntape = 0;
		bitmap(nodmap, TS_BITS);
	}
	BIC(ino, nodmap);
	spcl.c_dinode = *ip;
	spcl.c_type = TS_INODE;
	spcl.c_count = 0;
	i = ip->di_mode & IFMT;
#ifdef	UCB_SYMLINKS
	if(i != IFDIR && i != IFREG && i != IFLNK)
#else
	if(i != IFDIR && i != IFREG)
#endif
	{
		spclrec();
		return;
	}
	icat(ip, tapsrec, dmpspc);
}

dmpspc(dp, n)
daddr_t *dp;
{
	register i, t;

	spcl.c_count = n;
	for(i=0; i<n; i++) {
		t = 0;
		if(dp[i] != 0)
			t++;
		spcl.c_addr[i] = t;
	}
	spclrec();
}

bitmap(map, typ)
short *map;
{
	register i, n;
	char *cp;

	n = -1;
	for(i=0; i<MSIZ; i++)
		if(map[i])
			n = i;
	if(n < 0)
		return;
	spcl.c_type = typ;
	spcl.c_count = (n*sizeof(map[0]) + BSIZE)/BSIZE;
	spclrec();
	cp = (char *)map;
	for(i=0; i<spcl.c_count; i++) {
		taprec(cp);
		cp += BSIZE;
	}
}

spclrec()
{
	register i, *ip, s;

	spcl.c_inumber = ino;
	spcl.c_magic = MAGIC;
	spcl.c_checksum = 0;
	ip = (int *)&spcl;
	s = 0;
	for(i=0; i<BSIZE/sizeof(*ip); i++)
		s += *ip++;
	spcl.c_checksum = CHECKSUM - s;
	taprec((char *)&spcl);
}

dsrch(d)
daddr_t d;
{
	register char *cp;
	register i;
	register ino_t in;
	struct direct dblk[DIRPB];

	if(dadded)
		return;
	bread(d, (char *)dblk, sizeof(dblk));
	for(i=0; i<DIRPB; i++) {
		in = dblk[i].d_ino;
		if(in == 0)
			continue;
		cp = dblk[i].d_name;
		if(cp[0] == '.') {
			if(cp[1] == '\0')
				continue;
			if(cp[1] == '.' && cp[2] == '\0')
				continue;
		}
		if(BIT(in, nodmap)) {
			dadded++;
			return;
		}
		if(BIT(in, dirmap))
			nsubdir++;
	}
}

nullf()
{
}

bread(da, ba, c)
daddr_t da;
char *ba;
{
	register n;

#ifndef	UCB_NKB
	lseek(fi, da*512, 0);
#else
	lseek(fi, da*BSIZE, 0);
#endif	UCB_NKB
	n = read(fi, ba, c);
	if(n != c) {
		printf("\n\7\7\7Read error on %s, bn = %D\n", disk, da);
		printf("asked for %d; got %d bytes\n", c, n);
	}
}

CLR(map)
register short *map;
{
	register n;

	n = MSIZ;
	do
		*map++ = 0;
	while(--n);
}


char	tblock[NTREC][BSIZE];
daddr_t	tdaddr[NTREC];
int	trecno;

taprec(dp)
char *dp;
{
	register i;

	for(i=0; i<BSIZE; i++)
		tblock[trecno][i] = *dp++;
	tdaddr[trecno] = 0;
	trecno++;
	spcl.c_tapea++;
	if(trecno >= NTREC)
		flusht();
}

tapsrec(d)
daddr_t d;
{

	if(d == 0)
		return;
	tdaddr[trecno] = d;
	trecno++;
	spcl.c_tapea++;
	if(trecno >= NTREC)
		flusht();
}

flusht()
{
	char place[100];
	register i, si;
	daddr_t d;

	while(trecno < NTREC)
		tdaddr[trecno++] = 1;

loop:
	d = 0;
	for(i=0; i<NTREC; i++)
		if(tdaddr[i] != 0)
		if(d == 0 || tdaddr[i] < d) {
			si = i;
			d = tdaddr[i];
		}
	if(d != 0) {
		bread(d, tblock[si], BSIZE);
		tdaddr[si] = 0;
		goto loop;
	}
	trecno = 0;
	if(write(to, tblock[0], sizeof(tblock)) != sizeof(tblock)) {
		close(to);
		printf("dump: write error on %s \ndump: ", tape);
		switch(errno) {
		    case ENOSPC: printf("No space left on device");
				break;
		    case ETPL: printf("Fatal error - tape position lost");
				break;
		    default:
				break;
		}
		printf(" (errno = %d)\n",errno);

	/*  below is used to cause parent to exit with status 1
	     and let a controlling script/process decide what to
	     do (helps out dumps with TK25 where tape repositioning
	     must be done) */

		if(!tflag) {
			printf("\nRewrite this volume <y or n> ? ");
			read(0, place, sizeof(place));
			if((place[0] == 'y') || (place[0] == '\n'))
				exit(0);	/* tells parent to restart */
			else {
				kill(mpid, SIGINT); /* causes parent to exit */
				exit(1);	   /* with 0 status */
			}
		} else
			exit(1); /* tells parent to exit with status 1 */
	}
	if(mflag)
		asize += sizeof(tblock)/BSIZE;
	else if(kflag)
		asize++;
	else {
		asize += sizeof(tblock)/density;
		asize += 7;
	}
	if(asize >= tsize) {
		close(to);
		printf("\nMount next ");
		if(mflag)
			printf("diskette");
		else
			printf("tape");
		printf(" <type return when ready>");
		read(0, place, sizeof(place));
		kill(ppid, SIGTERM);
		otape();
	}
}

otape()
{
	int	cpid;
	int	status;
	char	c;

redump:
	ppid = getpid();
	if(ppid != mpid)
		signal(SIGTERM, SIG_DFL);
	cpid = fork();
	if(cpid < 0) {
		printf("Can't fork (pid = %d)\n", ppid);
		exit(1);
	}
	if(cpid != 0) {	/* parent */
		if(getpid() == mpid)
			signal(SIGINT, intr);
		wait(&status);
		if(status == 0)
			goto redump;
	/* tflag added to allow dump to exit with status 1 */
		if((getpid() == mpid) && (!tflag))
			for( ;;) ;
		exit(1);
	} else {	/* child */
	reopen:
		to = creat(tape, 0666);
		if(to < 0) {
			printf("dump: cannot create %s \ndump: ", tape);
			switch (errno) {
			    case ENODEV:
			    case ENXIO: printf("No such device or address");
					break;
			    case EACCES: printf("Permission denied");
					break;
			    case EROFS: printf("Read-only device");
					break;
			    case ETOL:	printf("Tape unit offline");
					break;
			    case ETWL:	printf("Tape unit write locked");
					break;
			    case ETO:	printf("Tape unit already open");
					break;
			    default:
					break;
			}
			printf(" (errno = %d)\n",errno);
		ask_rt:
			printf("\nretry <y or n> ? ");
			c = getchar();
			if(c == '\n')
				goto ask_rt;
			while(getchar() != '\n') ;
			if(c == 'y')
				goto reopen;
			if(c != 'n')
				goto ask_rt;
			kill(mpid, SIGINT);
			exit(1);
		}
		asize = 0;
		ntape++;
		spcl.c_volume++;
		spcl.c_type = TS_TAPE;
		spclrec();
	}
}

char *
prdate(d)
time_t d;
{
	char *p;

	if(d == 0)
		return("the epoch");
	p = ctime(&d);
	p[24] = 0;
	return(p);
}

getitime()
{
	register i, df;
	struct idates idbuf;
	char *fname;

	fname = disk;
l1:
	for(i=0; fname[i]; i++)
		if(fname[i] == '/') {
			fname += i+1;
			goto l1;
		}

	spcl.c_ddate = 0;
	df = open(increm, 0);
	if(df < 0) {
		printf("cannot open %s\n", increm);
		exit(1);
	}

l2:
	i = read(df, (char *)&idbuf, sizeof(idbuf));
	if(i != sizeof(idbuf)) {
		close(df);
		return;
	}
	for(i=0;; i++) {
		if(fname[i] != idbuf.id_name[i])
			goto l2;
		if(fname[i] == '\0')
			break;
	}
	if(idbuf.id_incno >= incno)
		goto l2;
	if(idbuf.id_ddate <= spcl.c_ddate)
		goto l2;
	spcl.c_ddate = idbuf.id_ddate;
	goto l2;
}

putitime()
{
	register i, n, df;
	struct idates idbuf;
	char *fname;

	if(uflag == 0)
		return;
	fname = disk;
l1:
	for(i=0; fname[i]; i++)
		if(fname[i] == '/') {
			fname += i+1;
			goto l1;
		}

	spcl.c_ddate = 0;
	df = open(increm, 2);
	if(df < 0) {
		printf("cannot open %s\n", increm);
		exit(1);
	}
	n = 0;
l2:
	i = read(df, (char *)&idbuf, sizeof(idbuf));
	if(i != sizeof(idbuf)) {
		lseek(df, (long)n*sizeof(idbuf), 0);
		goto l3;
	}
	n++;
	for(i=0;; i++) {
		if(fname[i] != idbuf.id_name[i])
			goto l2;
		if(fname[i] == '\0')
			break;
	}
	if(idbuf.id_incno != incno)
		goto l2;
	lseek(df, (long)(n-1)*sizeof(idbuf), 0);
l3:
	for(i=0;; i++) {
		idbuf.id_name[i] = fname[i];
		if(fname[i] == '\0') {   /* fill the rest of name with blanks: 
					  * George Mathew 6/20/85) */
			for (i++; i < (sizeof(idbuf.id_name) -1); i++)
				idbuf.id_name[i] = ' ';
			idbuf.id_name[i] = '\0';
			break;
		}
	}
	idbuf.id_incno = incno;
	idbuf.id_ddate = spcl.c_date;
	if (write(df, (char *)&idbuf, sizeof(idbuf)) != sizeof(idbuf)) {
		close(df);
		printf("dump: /etc/ddate write error\n");
		exit(-1);
	}
	close(df);
	printf("level %c dump on %s\n", incno, prdate(spcl.c_date));
}

est(ip)
struct dinode *ip;
{
	long s;

	esize++;
	s = (ip->di_size + BSIZE-1) / BSIZE;
	esize += s;
	if(s > NADDR-3) {
		s -= NADDR-3;
		s = (s + (BSIZE/sizeof(daddr_t))-1) / (BSIZE/sizeof(daddr_t));
		esize += s;
	}
}

bmapest(map)
short *map;
{
	register i, n;

	n = -1;
	for(i=0; i<MSIZ; i++)
		if(map[i])
			n = i;
	if(n < 0)
		return;
	esize++;
	esize += (n + (BSIZE/sizeof(short))-1) / (BSIZE/sizeof(short));
}

intr()
{
	exit(0);	/* to keep make happy */
}

getchar()
{
	char c;
	if (read(0, &c, 1) < 0)
		return(-1);
	else
		return(c);
}
putchar(c)
char c;
{
	write(1, &c, 1);
}

/*
 * Scaled down version of C Library printf.
 * Only %s %u %d (==%u) %o %x %D are recognized.
 */
/* VARARGS 1 */
printf(fmt, x1)
register char *fmt;
unsigned x1;
{
	register c;
	register unsigned int *adx;
	char *s;

	adx = &x1;
loop:
	while((c = *fmt++) != '%') {
		if(c == '\0')
			return;
		putchar(c);
	}
	c = *fmt++;
	if(c == 'd' || c == 'u' || c == 'o' || c == 'x')
		printn((long)*adx, c=='o'? 8: (c=='x'? 16:10));
	else if(c == 's') {
		s = (char *)*adx;
		while(c = *s++)
			putchar(c);
	} else if (c == 'c') {
		putchar(*(char *)adx);
	} else if (c == 'D') {
		printn(*(long *)adx, 10);
		adx += (sizeof(long) / sizeof(int)) - 1;
	}
	adx++;
	goto loop;
}

/*
 * Print an unsigned integer in base b.
 */
printn(n, b)
long n;
{
	register long a;

	if (n<0) {	/* shouldn't happen */
		putchar('-');
		n = -n;
	}
	if(a = n/b)
		printn(a, b);
	putchar("0123456789ABCDEF"[(int)(n%b)]);
}