xref: /csrg-svn/sbin/restore/main.c (revision 5327)
14610Smckusick /* Copyright (c) 1981 Regents of the University of California */
24610Smckusick 
3*5327Smckusic char version[] = "@(#)main.c 1.8 01/05/82";
44610Smckusick 
54610Smckusick /*	Modified to include h option (recursively extract all files within
64610Smckusick  *	a subtree) and m option (recreate the heirarchical structure of
74610Smckusick  *	that subtree and move extracted files to their proper homes).
84610Smckusick  *	8/29/80		by Mike Litzkow
94610Smckusick  *
104610Smckusick  *	Includes the s (skip files) option for use with multiple dumps on
114610Smckusick  *	a single tape.
124610Smckusick  */
134610Smckusick 
144611Smckusic /* static char *sccsid = "@(#)restor.c	4.3 (Berkeley) 6/3/81"; */
154610Smckusick 
164610Smckusick #define MAXINO	3000
174610Smckusick #define BITS	8
184610Smckusick #define NCACHE	3
194610Smckusick #define SIZEINC 10
204610Smckusick 
214610Smckusick #ifndef STANDALONE
224610Smckusick #include <stdio.h>
234610Smckusick #include <signal.h>
244610Smckusick #endif
254700Smckusic #include "../h/param.h"
264700Smckusic #include "../h/inode.h"
274700Smckusic #include "../h/fs.h"
284700Smckusic #include "../h/buf.h"
294700Smckusic #include "../h/dir.h"
304700Smckusic #include "../h/user.h"
314700Smckusic #include "../h/dumprestor.h"
325038Smckusic #include <sys/mtio.h>
334610Smckusick 
345038Smckusic struct odirect {
355038Smckusic 	u_short	d_ino;
365038Smckusic 	char	d_name[DIRSIZ];
375038Smckusic };
385038Smckusic 
39*5327Smckusic #define	MWORD(m,i) (m[(unsigned)(i-1)/NBBY])
40*5327Smckusic #define	MBIT(i)	(1<<((unsigned)(i-1)%NBBY))
414610Smckusick #define	BIS(i,w)	(MWORD(w,i) |=  MBIT(i))
424610Smckusick #define	BIC(i,w)	(MWORD(w,i) &= ~MBIT(i))
434610Smckusick #define	BIT(i,w)	(MWORD(w,i) & MBIT(i))
444610Smckusick 
454700Smckusic ino_t	ino, maxi;
465038Smckusic struct inode *cur_ip;
474610Smckusick 
485038Smckusic int	eflag = 0, hflag = 0, mflag = 0, cvtdir = 0;
494776Smckusic 
504700Smckusic char	mounted = 0;
514700Smckusic dev_t	dev = 0;
524610Smckusick char	tapename[] = "/dev/rmt8";
534610Smckusick char	*magtape = tapename;
545038Smckusic int	mt;
555038Smckusic int	dumpnum = 1;
565038Smckusic int	volno = 1;
575038Smckusic int	curblk = 0;
585038Smckusic int	bct = NTREC+1;
595038Smckusic char	tbf[NTREC*TP_BSIZE];
604610Smckusick 
614610Smckusick #ifdef STANDALONE
624610Smckusick char	mbuf[50];
634610Smckusick #endif
644610Smckusick 
654610Smckusick daddr_t	seekpt;
664837Smckusic FILE	*df;
674837Smckusic int	ofile;
684610Smckusick char	dirfile[] = "rstXXXXXX";
694610Smckusick 
704837Smckusic #define INOHASH(val) (val % MAXINO)
714837Smckusic struct inotab {
724837Smckusic 	struct inotab *t_next;
734610Smckusick 	ino_t	t_ino;
744610Smckusick 	daddr_t	t_seekpt;
754837Smckusic } *inotab[MAXINO];
764610Smckusick 
774837Smckusic #define XISDIR	1
784610Smckusick #define XTRACTD	2
794610Smckusick #define XINUSE	4
804837Smckusic #define XLINKED	8
814610Smckusick struct xtrlist {
824837Smckusic 	struct xtrlist	*x_next;
834837Smckusic 	struct xtrlist	*x_linkedto;
844843Smckusic 	time_t		x_timep[2];
854837Smckusic 	ino_t		x_ino;
864837Smckusic 	char		x_flags;
874843Smckusic 	char 		x_name[1];
884843Smckusic 	/* actually longer */
894837Smckusic } *xtrlist[MAXINO];
904776Smckusic int xtrcnt = 0;
914610Smckusick 
92*5327Smckusic #ifdef STANDALONE
93*5327Smckusic #define msiz 8192
94*5327Smckusic char	dumpmap[msiz];
95*5327Smckusic char	clrimap[msiz];
96*5327Smckusic #else
97*5327Smckusic int	msiz;
98*5327Smckusic char	*dumpmap;
99*5327Smckusic char	*clrimap;
100*5327Smckusic #endif
1014610Smckusick 
102*5327Smckusic char	clearedbuf[MAXBSIZE];
103*5327Smckusic 
1044837Smckusic extern char *ctime();
1054843Smckusic ino_t search();
1064700Smckusic char **envp;
1074610Smckusick 
1084700Smckusic main(argc, argv, arge)
1094700Smckusic 	int argc;
1104700Smckusic 	char *argv[];
1114700Smckusic 	char **arge;
1124610Smckusick {
1134610Smckusick 	register char *cp;
1144610Smckusick 	char command;
1154700Smckusic 	int (*signal())();
1164610Smckusick 	int done();
1174610Smckusick 
1184843Smckusic 	if (signal(SIGINT, done) == SIG_IGN)
1194843Smckusic 		signal(SIGINT, SIG_IGN);
1204843Smckusic 	if (signal(SIGTERM, done) == SIG_IGN)
1214843Smckusic 		signal(SIGTERM, SIG_IGN);
1224610Smckusick #ifndef STANDALONE
1234700Smckusic 	envp = arge;
1244700Smckusic 	mktmp(dirfile);
1254610Smckusick 	if (argc < 2) {
1264610Smckusick usage:
1274837Smckusic 		fprintf(stderr, "Usage: restor x[s|m|h|v] file file..., restor r|R filesys, or restor t\n");
1284700Smckusic 		done(1);
1294610Smckusick 	}
1304610Smckusick 	argv++;
1314610Smckusick 	argc -= 2;
1324610Smckusick 	for (cp = *argv++; *cp; cp++) {
1334610Smckusick 		switch (*cp) {
1344610Smckusick 		case '-':
1354610Smckusick 			break;
1364610Smckusick 		case 'f':
1374610Smckusick 			magtape = *argv++;
1384610Smckusick 			argc--;
1394610Smckusick 			break;
1404610Smckusick 		/* s dumpnum (skip to) for multifile dump tapes */
1414610Smckusick 		case 's':
1424610Smckusick 			dumpnum = atoi(*argv++);
1434610Smckusick 			if(dumpnum <= 0) {
1444700Smckusic 				fprintf(stderr, "Dump number must be a positive integer\n");
1454700Smckusic 				done(1);
1464610Smckusick 			}
1474610Smckusick 			argc--;
1484610Smckusick 			break;
1494610Smckusick 		case 'h':
1504610Smckusick 			hflag++;
1514610Smckusick 			break;
1524610Smckusick 		case 'm':
1534610Smckusick 			mflag++;
1544610Smckusick 			break;
1554610Smckusick 		case 'r':
1564610Smckusick 		case 'R':
1574610Smckusick 		case 't':
1584610Smckusick 		case 'x':
1594610Smckusick 			command = *cp;
1604610Smckusick 			break;
1614610Smckusick 		default:
1624700Smckusic 			fprintf(stderr, "Bad key character %c\n", *cp);
1634610Smckusick 			goto usage;
1644610Smckusick 		}
1654610Smckusick 	}
1664610Smckusick 	if (command == 'x') {
1674837Smckusic 		df = fopen(dirfile, "w");
1684837Smckusic 		if (df == 0) {
1694700Smckusic 			fprintf(stderr, "restor: %s - cannot create directory temporary\n", dirfile);
1704700Smckusic 			done(1);
1714610Smckusick 		}
1724700Smckusic 		xmount(envp);
1734700Smckusic 		mounted++;
1744610Smckusick 	}
1754610Smckusick 	doit(command, argc, argv);
1764700Smckusic 	done(0);
1774610Smckusick #else
1784610Smckusick 	magtape = "tape";
1794610Smckusick 	doit('r', 1, 0);
1804610Smckusick #endif
1814610Smckusick }
1824610Smckusick 
1834610Smckusick doit(command, argc, argv)
1844700Smckusic 	char	command;
1854700Smckusic 	int	argc;
1864700Smckusic 	char	*argv[];
1874610Smckusick {
1885038Smckusic 	struct mtop tcom;
1895038Smckusic 
1904610Smckusick #ifndef STANDALONE
1914610Smckusick 	if ((mt = open(magtape, 0)) < 0) {
1924700Smckusic 		fprintf(stderr, "%s: cannot open tape\n", magtape);
1934700Smckusic 		done(1);
1944610Smckusick 	}
1954843Smckusic 	if (dumpnum != 1) {
1964610Smckusick 		tcom.mt_op = MTFSF;
1974610Smckusick 		tcom.mt_count = dumpnum -1;
1984843Smckusic 		if (ioctl(mt,MTIOCTOP,&tcom) < 0)
1994610Smckusick 			perror("ioctl MTFSF");
2004610Smckusick 	}
2014610Smckusick #else
2024610Smckusick 	do {
2034700Smckusic 		fprintf(stderr, "Tape? ");
2044610Smckusick 		gets(mbuf);
2054610Smckusick 		mt = open(mbuf, 0);
2064610Smckusick 	} while (mt == -1);
2074610Smckusick 	magtape = mbuf;
2084610Smckusick #endif
209*5327Smckusic 	blkclr(clearedbuf, MAXBSIZE);
2104610Smckusick 	switch(command) {
2114610Smckusick #ifndef STANDALONE
2124610Smckusick 	case 't':
2134610Smckusick 		if (readhdr(&spcl) == 0) {
2144700Smckusic 			fprintf(stderr, "Tape is not a dump tape\n");
2154700Smckusic 			done(1);
2164610Smckusick 		}
2174843Smckusic 		fprintf(stdout, "Dump   date: %s", ctime(&spcl.c_date));
2184843Smckusic 		fprintf(stdout, "Dumped from: %s", ctime(&spcl.c_ddate));
2194610Smckusick 		return;
2204610Smckusick 	case 'x':
2214837Smckusic 		extractfiles(argc, argv);
2224837Smckusic 		return;
223*5327Smckusic #endif
2244837Smckusic 	case 'r':
2254837Smckusic 	case 'R':
2264837Smckusic 		restorfiles(command, argv);
2274837Smckusic 		return;
2284837Smckusic 	}
2294837Smckusic }
2304837Smckusic 
2314837Smckusic #ifndef STANDALONE
2324837Smckusic extractfiles(argc, argv)
2334837Smckusic 	int argc;
2344837Smckusic 	char **argv;
2354837Smckusic {
2364843Smckusic 	char	*ststore();
2374837Smckusic 	register struct xtrlist *xp;
2384837Smckusic 	struct xtrlist **xpp;
239*5327Smckusic 	struct fs *fs;
2404837Smckusic 	ino_t	d;
2415038Smckusic 	int	xtrfile(), xtrskip(), xtrcvtdir(), xtrcvtskip(), null();
2424843Smckusic 	int	mode;
2434843Smckusic 	char	name[BUFSIZ + 1];
2444837Smckusic 
2454837Smckusic 	if (readhdr(&spcl) == 0) {
2464837Smckusic 		fprintf(stderr, "Tape is not a dump tape\n");
2474837Smckusic 		done(1);
2484837Smckusic 	}
2494837Smckusic 	if (checkvol(&spcl, 1) == 0) {
2504837Smckusic 		fprintf(stderr, "Tape is not volume 1 of the dump\n");
2514837Smckusic 	}
252*5327Smckusic 	fs = getfs(dev);
253*5327Smckusic 	msiz = roundup(howmany(fs->fs_ipg * fs->fs_ncg, NBBY), TP_BSIZE);
254*5327Smckusic 	clrimap = (char *)calloc(msiz, sizeof(char));
255*5327Smckusic 	dumpmap = (char *)calloc(msiz, sizeof(char));
2565038Smckusic 	pass1(1);  /* This sets the various maps on the way by */
2574843Smckusic 	while (argc--) {
2584837Smckusic 		if ((d = psearch(*argv)) == 0 || BIT(d,dumpmap) == 0) {
2594843Smckusic 			fprintf(stdout, "%s: not on tape\n", *argv++);
2604837Smckusic 			continue;
2614610Smckusick 		}
2624843Smckusic 		if (mflag)
2634843Smckusic 			checkdir(*argv);
2644837Smckusic 		if(hflag)
2654837Smckusic 			getleaves(d, *argv++);
2664843Smckusic 		else
2674843Smckusic 			allocxtr(d, *argv++, XINUSE);
2684837Smckusic 	}
2694843Smckusic 	if (dumpnum > 1) {
2705038Smckusic 		/*
2715038Smckusic 		 * if this is a multi-dump tape we always start with
2725038Smckusic 		 * volume 1, so as to avoid accidentally restoring
2735038Smckusic 		 * from a different dump!
2745038Smckusic 		 */
2755038Smckusic 		resetmt();
2765038Smckusic 		dumpnum = 1;
2775038Smckusic 		volno = 1;
2785038Smckusic 		readhdr(&spcl);
2795038Smckusic 		goto rbits;
2804837Smckusic 	}
2815038Smckusic newvol:
2825038Smckusic 	resetmt();
2834610Smckusick getvol:
2845038Smckusic 	fprintf(stderr, "Mount desired tape volume; Specify volume #: ");
2854837Smckusic 	if (gets(tbf) == NULL)
2864837Smckusic 		return;
2874837Smckusic 	volno = atoi(tbf);
2884837Smckusic 	if (volno <= 0) {
2894837Smckusic 		fprintf(stderr, "Volume numbers are positive numerics\n");
2904837Smckusic 		goto getvol;
2914837Smckusic 	}
2924837Smckusic 	if (readhdr(&spcl) == 0) {
2934837Smckusic 		fprintf(stderr, "tape is not dump tape\n");
2944837Smckusic 		goto newvol;
2954837Smckusic 	}
2964837Smckusic 	if (checkvol(&spcl, volno) == 0) {
2974837Smckusic 		fprintf(stderr, "Wrong volume (%d)\n", spcl.c_volume);
2984837Smckusic 		goto newvol;
2994837Smckusic 	}
3004610Smckusick rbits:
3014837Smckusic 	while (gethead(&spcl) == 0)
3024837Smckusic 		;
3034837Smckusic 	if (checktype(&spcl, TS_INODE) == 1) {
3044837Smckusic 		fprintf(stderr, "Can't find inode mask!\n");
3054837Smckusic 		goto newvol;
3064837Smckusic 	}
3074837Smckusic 	if (checktype(&spcl, TS_BITS) == 0)
3084837Smckusic 		goto rbits;
3094837Smckusic 	readbits(dumpmap);
3104837Smckusic 	while (xtrcnt > 0) {
3114837Smckusic again:
3124837Smckusic 		if (ishead(&spcl) == 0)
3134837Smckusic 			while(gethead(&spcl) == 0)
3144837Smckusic 				;
3154837Smckusic 		if (checktype(&spcl, TS_END) == 1) {
3164837Smckusic 			fprintf(stderr, "end of tape\n");
3174837Smckusic 			break;
3184610Smckusick 		}
3194837Smckusic 		if (checktype(&spcl, TS_INODE) == 0) {
3204837Smckusic 			gethead(&spcl);
3214837Smckusic 			goto again;
3224610Smckusick 		}
3234837Smckusic 		d = spcl.c_inumber;
3244837Smckusic 		for (xp = xtrlist[INOHASH(d)]; xp; xp = xp->x_next) {
3254837Smckusic 			if (d != xp->x_ino)
3264837Smckusic 				continue;
3274837Smckusic 			if (xp->x_flags & XLINKED)
3284837Smckusic 				continue;
3294837Smckusic 			xp->x_timep[0] = spcl.c_dinode.di_atime;
3304837Smckusic 			xp->x_timep[1] = spcl.c_dinode.di_mtime;
3314837Smckusic 			mode = spcl.c_dinode.di_mode;
3324837Smckusic 			if (mflag)
3334843Smckusic 				strcpy(name, xp->x_name);
3344837Smckusic 			else
3354837Smckusic 				sprintf(name, "%u", xp->x_ino);
3364837Smckusic 			switch (mode & IFMT) {
3374837Smckusic 			default:
3384843Smckusic 				fprintf(stderr, "%s: unknown file type\n", name);
3394837Smckusic 				xp->x_flags |= XTRACTD;
3404837Smckusic 				xtrcnt--;
3414837Smckusic 				goto skipfile;
3424837Smckusic 			case IFCHR:
3434837Smckusic 			case IFBLK:
3444843Smckusic 				fprintf(stdout, "extract special file %s\n", name);
3454837Smckusic 				if (xmknod(name, mode, spcl.c_dinode.di_rdev)) {
3464837Smckusic 					fprintf(stderr, "%s: cannot create special file\n", name);
3474837Smckusic 					xp->x_flags |= XTRACTD;
3484837Smckusic 					xtrcnt--;
3494837Smckusic 					goto skipfile;
3504776Smckusic 				}
3514837Smckusic 				getfile(null, null, spcl.c_dinode.di_size);
3524837Smckusic 				break;
3534837Smckusic 			case IFDIR:
3544837Smckusic 				if (mflag) {
3554843Smckusic 					fprintf(stdout, "extract directory %s\n", name);
3564837Smckusic 					strncat(name, "/.", BUFSIZ);
3574843Smckusic 					checkdir(name);
3584843Smckusic 					xchown(xp->x_name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
3594837Smckusic 					getfile(null, null, spcl.c_dinode.di_size);
3604837Smckusic 					break;
3614610Smckusick 				}
3625038Smckusic 				fprintf(stdout, "extract file %s\n", name);
3635038Smckusic 				if ((ofile = xcreat(name, 0666)) < 0) {
3645038Smckusic 					fprintf(stderr, "%s: cannot create file\n", name);
3655038Smckusic 					xp->x_flags |= XTRACTD;
3665038Smckusic 					xtrcnt--;
3675038Smckusic 					goto skipfile;
3685038Smckusic 				}
3695038Smckusic 				xchown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
3705038Smckusic 				if (cvtdir)
3715038Smckusic 					getfile(xtrcvtdir, xtrcvtskip,
3725038Smckusic 					    spcl.c_dinode.di_size);
3735038Smckusic 				else
3745038Smckusic 					getfile(xtrfile, xtrskip,
3755038Smckusic 					    spcl.c_dinode.di_size);
3765038Smckusic 				xclose(ofile);
3775038Smckusic 				break;
3784837Smckusic 			case IFREG:
3794843Smckusic 				fprintf(stdout, "extract file %s\n", name);
3804837Smckusic 				if ((ofile = xcreat(name, 0666)) < 0) {
3814837Smckusic 					fprintf(stderr, "%s: cannot create file\n", name);
3824837Smckusic 					xp->x_flags |= XTRACTD;
3834837Smckusic 					xtrcnt--;
3844837Smckusic 					goto skipfile;
3854837Smckusic 				}
3864837Smckusic 				xchown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
3875038Smckusic 				getfile(xtrfile, xtrskip, spcl.c_dinode.di_size);
3884837Smckusic 				xclose(ofile);
3894837Smckusic 				break;
3904610Smckusick 			}
3914837Smckusic 			xchmod(name, mode);
3924837Smckusic 			xutime(name, xp->x_timep);
3934837Smckusic 			xp->x_flags |= XTRACTD;
3944837Smckusic 			xtrcnt--;
3954837Smckusic 			goto finished;
3964837Smckusic 		}
3974837Smckusic skipfile:
3984837Smckusic 		getfile(null, null, spcl.c_dinode.di_size);
3994700Smckusic finished:
4004837Smckusic 		;
4014837Smckusic 	}
4024837Smckusic 	if (xtrcnt == 0 && !mflag)
4034837Smckusic 		return;
4044837Smckusic 	for (xpp = xtrlist; xpp < &xtrlist[MAXINO]; xpp++) {
4054837Smckusic 		for (xp = *xpp; xp; xp = xp->x_next) {
4064837Smckusic 			if (mflag && (xp->x_flags & XISDIR))
4074837Smckusic 				xutime(xp->x_name, xp->x_timep);
4084837Smckusic 			if (xp->x_flags & XTRACTD)
4094837Smckusic 				continue;
4104837Smckusic 			if ((xp->x_flags & XLINKED) == 0) {
4114837Smckusic 				fprintf(stderr, "cannot find file %s\n",
4124837Smckusic 					xp->x_name);
4134837Smckusic 				continue;
4144837Smckusic 			}
4154843Smckusic 			if (!mflag)
4164843Smckusic 				continue;
4174843Smckusic 			fprintf(stdout, "link %s to %s\n",
4184843Smckusic 				xp->x_linkedto->x_name, xp->x_name);
4194843Smckusic 			if (xlink(xp->x_linkedto->x_name, xp->x_name) < 0)
4204843Smckusic 				fprintf(stderr, "link %s to %s failed\n",
4214837Smckusic 					xp->x_linkedto->x_name, xp->x_name);
4224610Smckusick 		}
4234837Smckusic 	}
4244837Smckusic }
4254610Smckusick #endif
4264837Smckusic 
4274837Smckusic restorfiles(command, argv)
4284837Smckusic 	char command;
4294837Smckusic 	char **argv;
4304837Smckusic {
4315038Smckusic 	int	rstrfile(), rstrskip(), rstrcvtdir(), rstrcvtskip();
4324837Smckusic 	register struct dinode *dp;
4334837Smckusic 	register struct inode *ip;
4344837Smckusic 	struct fs *fs;
4355038Smckusic 	int mode, type;
4364837Smckusic 	char mount[BUFSIZ + 1];
4374837Smckusic 	char *ptr[2];
4384837Smckusic 
4394837Smckusic 	mount[0] = '\0';
4404837Smckusic 	strcpy(mount, "MOUNT=");
441*5327Smckusic #ifndef STANDALONE
4424837Smckusic 	strncat(mount, *argv, BUFSIZ);
443*5327Smckusic #else
444*5327Smckusic 	fprintf(stderr, "Disk? ");
445*5327Smckusic 	gets(&mount[6]);
446*5327Smckusic #endif
4474837Smckusic 	ptr[0] = mount;
4484837Smckusic 	ptr[1] = 0;
4494837Smckusic 	xmount(ptr);
450*5327Smckusic 	mounted++;
4514837Smckusic 	iput(u.u_cdir); /* release root inode */
4524837Smckusic 	iput(u.u_rdir); /* release root inode */
453*5327Smckusic 	fs = getfs(dev);
454*5327Smckusic 	maxi = fs->fs_ipg * fs->fs_ncg;
4554610Smckusick #ifndef STANDALONE
456*5327Smckusic 	msiz = roundup(howmany(maxi, NBBY), TP_BSIZE);
457*5327Smckusic 	clrimap = (char *)calloc(msiz, sizeof(char));
458*5327Smckusic 	dumpmap = (char *)calloc(msiz, sizeof(char));
4594837Smckusic 	if (command == 'R') {
4604837Smckusic 		fprintf(stderr, "Enter starting volume number: ");
4614837Smckusic 		if (gets(tbf) == EOF) {
4624837Smckusic 			volno = 1;
4634837Smckusic 			fprintf(stderr, "\n");
4644610Smckusick 		}
4654610Smckusick 		else
4664837Smckusic 			volno = atoi(tbf);
4674837Smckusic 	}
4684837Smckusic 	else
4694610Smckusick #endif
4704837Smckusic 		volno = 1;
4714837Smckusic 	fprintf(stderr, "Last chance before scribbling on %s. ",
4724610Smckusick #ifdef STANDALONE
4734837Smckusic 							"disk");
4744610Smckusick #else
4754837Smckusic 							*argv);
4764610Smckusick #endif
4774837Smckusic 	while (getchar() != '\n');
4784837Smckusic 	if (readhdr(&spcl) == 0) {
4794837Smckusic 		fprintf(stderr, "Missing volume record\n");
4804837Smckusic 		done(1);
4814837Smckusic 	}
4824837Smckusic 	if (checkvol(&spcl, volno) == 0) {
4834837Smckusic 		fprintf(stderr, "Tape is not volume %d\n", volno);
4844837Smckusic 		done(1);
4854837Smckusic 	}
4865038Smckusic 	pass1(0);
4875038Smckusic 	gethead(&spcl); /* volume header already checked above */
4884837Smckusic 	gethead(&spcl);
4894837Smckusic 	for (;;) {
4904837Smckusic ragain:
4914837Smckusic 		if (ishead(&spcl) == 0) {
4924837Smckusic 			fprintf(stderr, "Missing header block\n");
4934837Smckusic 			while (gethead(&spcl) == 0)
4944837Smckusic 				;
4954837Smckusic 			eflag++;
4964610Smckusick 		}
4974837Smckusic 		if (checktype(&spcl, TS_END) == 1) {
4984837Smckusic 			fprintf(stderr, "End of tape\n");
4994837Smckusic 			close(mt);
5004837Smckusic 			return;
5014610Smckusick 		}
5024837Smckusic 		if (checktype(&spcl, TS_CLRI) == 1) {
5034837Smckusic 			readbits(clrimap);
5044837Smckusic 			for (ino = 1; ino <= maxi; ino++)
5054837Smckusic 				if (BIT(ino, clrimap) == 0) {
5064837Smckusic 					if (!iexist(dev, ino))
5074837Smckusic 						continue;
5084837Smckusic 					ip = iget(dev, ino);
5094837Smckusic 					if (ip == NULL) {
5104837Smckusic 						fprintf(stderr, "can't find inode %u\n", ino);
5114837Smckusic 						done(1);
5124610Smckusick 					}
5134837Smckusic 					ip->i_nlink = 0;
5144837Smckusic 					ip->i_flag |= ICHG;
5154837Smckusic 					iput(ip);
5164700Smckusic 				}
5174837Smckusic 			goto ragain;
5184837Smckusic 		}
5194837Smckusic 		if (checktype(&spcl, TS_BITS) == 1) {
5204837Smckusic 			readbits(dumpmap);
5214837Smckusic 			goto ragain;
5224837Smckusic 		}
5234837Smckusic 		if (checktype(&spcl, TS_INODE) == 0) {
5244837Smckusic 			fprintf(stderr, "Unknown header type\n");
5254837Smckusic 			eflag++;
5264837Smckusic 			gethead(&spcl);
5274837Smckusic 			goto ragain;
5284837Smckusic 		}
5294837Smckusic 		ino = spcl.c_inumber;
5304837Smckusic 		if (eflag)
5314837Smckusic 			fprintf(stderr, "Resynced at inode %u\n", ino);
5324837Smckusic 		eflag = 0;
5334837Smckusic 		if (ino > maxi) {
5344837Smckusic 			fprintf(stderr, "%u: ilist too small\n", ino);
5354837Smckusic 			gethead(&spcl);
5364837Smckusic 			goto ragain;
5374837Smckusic 		}
5384837Smckusic 		if (iexist(dev, ino)) {
5394837Smckusic 			ip = iget(dev, ino);
5404837Smckusic 			if (ip == NULL) {
5414837Smckusic 				fprintf(stderr, "can't find inode %u\n",
5424837Smckusic 					ino);
5434700Smckusic 				done(1);
5444700Smckusic 			}
5454837Smckusic 			ip->i_nlink = 0;
5464700Smckusic 			ip->i_flag |= ICHG;
5474700Smckusic 			iput(ip);
5484610Smckusick 		}
5494837Smckusic 		dp = &spcl.c_dinode;
5504837Smckusic 		ip = ialloc(dev, ino, dp->di_mode);
5514837Smckusic 		if (ip == NULL || ip->i_number != ino) {
5524837Smckusic 			fprintf(stderr, "can't create inode %u\n", ino);
5534837Smckusic 			done(1);
5544837Smckusic 		}
5554837Smckusic 		ip->i_mode = mode = dp->di_mode;
5564837Smckusic 		ip->i_nlink = dp->di_nlink;
5574837Smckusic 		ip->i_uid = dp->di_uid;
5584837Smckusic 		ip->i_gid = dp->di_gid;
5594837Smckusic 		ip->i_atime = dp->di_atime;
5604837Smckusic 		ip->i_mtime = dp->di_mtime;
5614837Smckusic 		ip->i_ctime = dp->di_ctime;
5625038Smckusic 		type = ip->i_mode & IFMT;
5635038Smckusic 		if (type == IFCHR || type == IFBLK)
5644837Smckusic 			ip->i_rdev = dp->di_rdev;
5654837Smckusic 		ip->i_size = 0;
5664837Smckusic 		cur_ip = ip;
5674837Smckusic 		u.u_offset = 0;
5684837Smckusic 		u.u_segflg = 1;
5695038Smckusic 		if (cvtdir && type == IFDIR)
5705038Smckusic 			getfile(rstrcvtdir, rstrcvtskip, dp->di_size);
5715038Smckusic 		else
5725038Smckusic 			getfile(rstrfile, rstrskip, dp->di_size);
5734837Smckusic 		ip->i_mode = mode;
5744837Smckusic 		ip->i_flag &= ~(IUPD|IACC);
5754837Smckusic 		ip->i_flag |= ICHG;
5764837Smckusic 		iput(ip);
5774610Smckusick 	}
5784610Smckusick }
5794610Smckusick 
5804610Smckusick /*
5814610Smckusick  * Read the tape, bulding up a directory structure for extraction
5824610Smckusick  * by name
5834610Smckusick  */
5844610Smckusick #ifndef STANDALONE
5855038Smckusic pass1(savedir)
5865038Smckusic 	int savedir;
5874610Smckusick {
5884776Smckusic 	register int i;
5894837Smckusic 	register struct dinode *ip;
5904837Smckusic 	struct direct nulldir;
5915038Smckusic 	char buf[TP_BSIZE];
5925038Smckusic 	int putdir(), null();
5934610Smckusick 
5944837Smckusic 	nulldir.d_ino = 0;
5954837Smckusic 	strncpy(nulldir.d_name, "/", DIRSIZ);
5964610Smckusick 	while (gethead(&spcl) == 0) {
5974700Smckusic 		fprintf(stderr, "Can't find directory header!\n");
5984610Smckusick 	}
5994610Smckusick 	for (;;) {
6004610Smckusick 		if (checktype(&spcl, TS_BITS) == 1) {
6014610Smckusick 			readbits(dumpmap);
6024610Smckusick 			continue;
6034610Smckusick 		}
6044610Smckusick 		if (checktype(&spcl, TS_CLRI) == 1) {
6054610Smckusick 			readbits(clrimap);
6064610Smckusick 			continue;
6074610Smckusick 		}
6084610Smckusick 		if (checktype(&spcl, TS_INODE) == 0) {
6094610Smckusick finish:
6105038Smckusic 			if (savedir)
6115038Smckusic 				freopen(dirfile, "r", df);
6125038Smckusic 			resetmt();
6134610Smckusick 			return;
6144610Smckusick 		}
6154610Smckusick 		ip = &spcl.c_dinode;
6164610Smckusick 		i = ip->di_mode & IFMT;
6174610Smckusick 		if (i != IFDIR) {
6184610Smckusick 			goto finish;
6194610Smckusick 		}
6205038Smckusic 		if (spcl.c_inumber == ROOTINO) {
6215038Smckusic 			readtape(buf);
6225038Smckusic 			bct--; /* push back this block */
6235038Smckusic 			if (((struct direct *)buf)->d_ino != ROOTINO) {
6245038Smckusic 				if (((struct odirect *)buf)->d_ino != ROOTINO) {
6255038Smckusic 					fprintf(stderr, "bad root directory\n");
6265038Smckusic 					done(1);
6275038Smckusic 				}
6285038Smckusic 				fprintf(stderr, "converting to new directory format\n");
6295038Smckusic 				cvtdir = 1;
6305038Smckusic 			}
6315038Smckusic 			if (!savedir && !cvtdir) {
6325038Smckusic 				/* if no conversion, just return */
6335038Smckusic 				goto finish;
6345038Smckusic 			}
6355038Smckusic 		}
6364843Smckusic 		allocinotab(spcl.c_inumber, seekpt);
6375038Smckusic 		if (savedir) {
6385038Smckusic 			getfile(putdir, null, spcl.c_dinode.di_size);
6395038Smckusic 			putent(&nulldir);
6405038Smckusic 		} else {
6415038Smckusic 			getfile(null, null, spcl.c_dinode.di_size);
6425038Smckusic 		}
6434610Smckusick 	}
6444610Smckusick }
6454610Smckusick #endif
6464610Smckusick 
6474610Smckusick /*
6484843Smckusic  * Put the directory entries in the directory file
6494843Smckusic  */
6504843Smckusic #ifndef STANDALONE
6514843Smckusic putdir(buf, size)
6524843Smckusic 	char *buf;
6534843Smckusic 	int size;
6544843Smckusic {
6555038Smckusic 	struct direct cvtbuf;
6565038Smckusic 	register struct odirect *odp;
6575038Smckusic 	struct odirect *eodp;
6584843Smckusic 	register struct direct *dp;
6595038Smckusic 	struct direct *edp;
6604843Smckusic 
6615038Smckusic 	if (cvtdir) {
6625038Smckusic 		eodp = (struct odirect *)&buf[size];
6635038Smckusic 		for (odp = (struct odirect *)buf; odp < eodp; odp++)
6645038Smckusic 			if (odp->d_ino != 0) {
6655038Smckusic 				dcvt(odp, &cvtbuf);
6665038Smckusic 				putent(&cvtbuf);
6675038Smckusic 			}
6685038Smckusic 	} else {
6695038Smckusic 		edp = (struct direct *)&buf[size];
6705038Smckusic 		for (dp = (struct direct *)buf; dp < edp; dp++)
6715038Smckusic 			if (dp->d_ino != 0)
6725038Smckusic 				putent(dp);
6735038Smckusic 	}
6744843Smckusic }
6754843Smckusic 
6764843Smckusic putent(dp)
6774843Smckusic 	struct direct *dp;
6784843Smckusic {
6794843Smckusic 	fwrite(dp, 1, sizeof(struct direct), df);
6804843Smckusic 	seekpt = ftell(df);
6814843Smckusic }
6824843Smckusic 
6835038Smckusic dcvt(odp, ndp)
6845038Smckusic 	register struct odirect *odp;
6855038Smckusic 	register struct direct *ndp;
6865038Smckusic {
6875038Smckusic 	register struct inotab *itp;
6885038Smckusic 
6895038Smckusic 	blkclr(ndp, sizeof *ndp);
6905038Smckusic 	ndp->d_ino =  odp->d_ino;
6915038Smckusic 	strncpy(ndp->d_name, odp->d_name, DIRSIZ);
6925038Smckusic 	for (itp = inotab[INOHASH(odp->d_ino)]; itp; itp = itp->t_next) {
6935038Smckusic 		if (itp->t_ino != odp->d_ino)
6945038Smckusic 			continue;
6955038Smckusic 		ndp->d_mode = IFDIR;
6965038Smckusic 		break;
6975038Smckusic 	}
6985038Smckusic }
6995038Smckusic 
7004843Smckusic /*
7014843Smckusic  *	Recursively find names and inumbers of all files in subtree
7024843Smckusic  *	pname and put them in xtrlist[]
7034843Smckusic  */
7044843Smckusic getleaves(ino, pname)
7054843Smckusic 	ino_t ino;
7064843Smckusic 	char *pname;
7074843Smckusic {
7084843Smckusic 	register struct inotab *itp;
7094843Smckusic 	int namelen;
7104843Smckusic 	daddr_t	bpt;
7114843Smckusic 	struct direct dir;
7124843Smckusic 	char 	locname[BUFSIZ + 1];
7134843Smckusic 
7144843Smckusic 	if (BIT(ino, dumpmap) == 0) {
7154843Smckusic 		fprintf(stdout, "%s: not on the tape\n", pname);
7164843Smckusic 		return;
7174843Smckusic 	}
7184843Smckusic 	for (itp = inotab[INOHASH(ino)]; itp; itp = itp->t_next) {
7194843Smckusic 		if (itp->t_ino != ino)
7204843Smckusic 			continue;
7214843Smckusic 		/*
7224843Smckusic 		 * pname is a directory name
7234843Smckusic 		 */
7244843Smckusic 		allocxtr(ino, pname, XISDIR);
7254843Smckusic 		/*
7264843Smckusic 		 * begin search through the directory
7274843Smckusic 		 * skipping over "." and ".."
7284843Smckusic 		 */
7294843Smckusic 		strncpy(locname, pname, BUFSIZ);
7304843Smckusic 		strncat(locname, "/", BUFSIZ);
7314843Smckusic 		namelen = strlen(locname);
7324843Smckusic 		fseek(df, itp->t_seekpt, 0);
7334843Smckusic 		fread(&dir, 1, sizeof(struct direct), df);
7344843Smckusic 		fread(&dir, 1, sizeof(struct direct), df);
7354843Smckusic 		fread(&dir, 1, sizeof(struct direct), df);
7364843Smckusic 		bpt = ftell(df);
7374843Smckusic 		/*
7384843Smckusic 		 * "/" signals end of directory
7394843Smckusic 		 */
7404843Smckusic 		while (strncmp(dir.d_name, "/", DIRSIZ)) {
7414843Smckusic 			locname[namelen] = '\0';
7424843Smckusic 			strncat(locname, dir.d_name, DIRSIZ);
7434843Smckusic 			if (strlen(locname) >= BUFSIZ) {
7444843Smckusic 				fprintf(stderr, "%s: name exceedes %d char\n",
7454843Smckusic 					locname, BUFSIZ);
7464843Smckusic 				continue;
7474843Smckusic 			}
7484843Smckusic 			getleaves(dir.d_ino, locname);
7494843Smckusic 			fseek(df, bpt, 0);
7504843Smckusic 			fread(&dir, 1, sizeof(struct direct), df);
7514843Smckusic 			bpt = ftell(df);
7524843Smckusic 		}
7534843Smckusic 		return;
7544843Smckusic 	}
7554843Smckusic 	/*
7564843Smckusic 	 * locname is name of a simple file
7574843Smckusic 	 */
7584843Smckusic 	allocxtr(ino, pname, XINUSE);
7594843Smckusic }
7604843Smckusic 
7614843Smckusic /*
7624843Smckusic  * Search the directory tree rooted at inode ROOTINO
7634843Smckusic  * for the path pointed at by n
7644843Smckusic  */
7654843Smckusic psearch(n)
7664843Smckusic 	char	*n;
7674843Smckusic {
7684843Smckusic 	register char *cp, *cp1;
7694843Smckusic 	char c;
7704843Smckusic 
7714843Smckusic 	ino = ROOTINO;
7724843Smckusic 	if (*(cp = n) == '/')
7734843Smckusic 		cp++;
7744843Smckusic next:
7754843Smckusic 	cp1 = cp + 1;
7764843Smckusic 	while (*cp1 != '/' && *cp1)
7774843Smckusic 		cp1++;
7784843Smckusic 	c = *cp1;
7794843Smckusic 	*cp1 = 0;
7804843Smckusic 	ino = search(ino, cp);
7814843Smckusic 	if (ino == 0) {
7824843Smckusic 		*cp1 = c;
7834843Smckusic 		return(0);
7844843Smckusic 	}
7854843Smckusic 	*cp1 = c;
7864843Smckusic 	if (c == '/') {
7874843Smckusic 		cp = cp1+1;
7884843Smckusic 		goto next;
7894843Smckusic 	}
7904843Smckusic 	return(ino);
7914843Smckusic }
7924843Smckusic 
7934843Smckusic /*
7944843Smckusic  * search the directory inode ino
7954843Smckusic  * looking for entry cp
7964843Smckusic  */
7974843Smckusic ino_t
7984843Smckusic search(inum, cp)
7994843Smckusic 	ino_t	inum;
8004843Smckusic 	char	*cp;
8014843Smckusic {
8024843Smckusic 	struct direct dir;
8034843Smckusic 	register struct inotab *itp;
8044843Smckusic 
8054843Smckusic 	for (itp = inotab[INOHASH(inum)]; itp; itp = itp->t_next)
8064843Smckusic 		if (itp->t_ino == inum)
8074843Smckusic 			goto found;
8084843Smckusic 	return(0);
8094843Smckusic found:
8104843Smckusic 	fseek(df, itp->t_seekpt, 0);
8114843Smckusic 	do {
8124843Smckusic 		fread(&dir, 1, sizeof(struct direct), df);
8134843Smckusic 		if (!strncmp(dir.d_name, "/", DIRSIZ))
8144843Smckusic 			return(0);
8154843Smckusic 	} while (strncmp(dir.d_name, cp, DIRSIZ));
8164843Smckusic 	return(dir.d_ino);
8174843Smckusic }
8184843Smckusic #endif
8194843Smckusic 
8204843Smckusic /*
8214610Smckusick  * Do the file extraction, calling the supplied functions
8224610Smckusick  * with the blocks
8234610Smckusick  */
8244700Smckusic getfile(f1, f2, size)
8254700Smckusic 	int	(*f2)(), (*f1)();
8264700Smckusic 	long	size;
8274610Smckusick {
8284776Smckusic 	register int i;
829*5327Smckusic 	char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
8304837Smckusic 	union u_spcl addrblk;
831*5327Smckusic 	register struct fs *fs;
8324837Smckusic #	define addrblock addrblk.s_spcl
8334610Smckusick 
8344837Smckusic 	addrblock = spcl;
835*5327Smckusic 	fs = getfs(dev);
8364610Smckusick 	for (;;) {
8374837Smckusic 		for (i = 0; i < addrblock.c_count; i++) {
8384837Smckusic 			if (addrblock.c_addr[i]) {
8394776Smckusic 				readtape(&buf[curblk++][0]);
840*5327Smckusic 				if (curblk == BLKING(fs) * fs->fs_frag) {
8414776Smckusic 					(*f1)(buf, size > TP_BSIZE ?
842*5327Smckusic 					     (long) (BLKING(fs) * fs->fs_frag * TP_BSIZE) :
8434776Smckusic 					     (curblk - 1) * TP_BSIZE + size);
8444776Smckusic 					curblk = 0;
8454776Smckusic 				}
846*5327Smckusic 			} else {
8474776Smckusic 				if (curblk > 0) {
8484776Smckusic 					(*f1)(buf, size > TP_BSIZE ?
8494776Smckusic 					     (long) (curblk * TP_BSIZE) :
8504776Smckusic 					     (curblk - 1) * TP_BSIZE + size);
8514776Smckusic 					curblk = 0;
8524776Smckusic 				}
853*5327Smckusic 				(*f2)(clearedbuf, size > TP_BSIZE ?
854*5327Smckusic 					(long) TP_BSIZE : size);
8554610Smckusick 			}
8564776Smckusic 			if ((size -= TP_BSIZE) <= 0) {
8574610Smckusick eloop:
8584610Smckusick 				while (gethead(&spcl) == 0)
8594610Smckusick 					;
8604610Smckusick 				if (checktype(&spcl, TS_ADDR) == 1)
8614610Smckusick 					goto eloop;
8624776Smckusic 				goto out;
8634610Smckusick 			}
8644610Smckusick 		}
8654837Smckusic 		if (gethead(&addrblock) == 0) {
8664776Smckusic 			fprintf(stderr, "Missing address (header) block, ino%u\n", ino);
8674700Smckusic 			goto eloop;
8684700Smckusic 		}
8694837Smckusic 		if (checktype(&addrblock, TS_ADDR) == 0) {
8704837Smckusic 			spcl = addrblock;
8714776Smckusic 			goto out;
8724700Smckusic 		}
8734610Smckusick 	}
8744776Smckusic out:
8754776Smckusic 	if (curblk > 0) {
8764776Smckusic 		(*f1)(buf, (curblk * TP_BSIZE) + size);
8774776Smckusic 		curblk = 0;
8784776Smckusic 	}
8794610Smckusick }
8804610Smckusick 
8814610Smckusick /*
8824843Smckusic  * The next routines are called during file extraction to
8834843Smckusic  * put the data into the right form and place.
8844843Smckusic  */
8854843Smckusic #ifndef STANDALONE
8864843Smckusic xtrfile(buf, size)
8874843Smckusic 	char	*buf;
8884843Smckusic 	long	size;
8894843Smckusic {
8904843Smckusic 	if (xwrite(ofile, buf, (int) size) == -1) {
8915038Smckusic 		perror("extract write");
8924843Smckusic 		done(1);
8934843Smckusic 	}
8944843Smckusic }
8954843Smckusic 
8965038Smckusic xtrskip(buf, size)
8974843Smckusic 	char *buf;
8984843Smckusic 	long size;
8994843Smckusic {
9004843Smckusic 	if (xseek(ofile, size, 1) == -1) {
9015038Smckusic 		perror("extract seek");
9024843Smckusic 		done(1);
9034843Smckusic 	}
9044843Smckusic }
9055038Smckusic 
9065038Smckusic xtrcvtdir(buf, size)
9075038Smckusic 	struct odirect *buf;
9085038Smckusic 	long size;
9095038Smckusic {
910*5327Smckusic 	struct direct
911*5327Smckusic 		cvtbuf[MAXBSIZE / sizeof(struct odirect)];
9125038Smckusic 	struct odirect *odp, *edp;
9135038Smckusic 	struct direct *dp;
9145038Smckusic 
9155038Smckusic 	edp = &buf[size / sizeof(struct odirect)];
9165038Smckusic 	for (odp = buf, dp = cvtbuf; odp < edp; odp++, dp++)
9175038Smckusic 		dcvt(odp, dp);
9185038Smckusic 	size = size * sizeof(struct direct) / sizeof(struct odirect);
9195038Smckusic 	if (xwrite(ofile, cvtbuf, (int) size) == -1) {
9205038Smckusic 		perror("extract write");
9215038Smckusic 		done(1);
9225038Smckusic 	}
9235038Smckusic }
9245038Smckusic 
9255038Smckusic xtrcvtskip(buf, size)
9265038Smckusic 	char *buf;
9275038Smckusic 	long size;
9285038Smckusic {
9295038Smckusic 	fprintf(stderr, "unallocated block in directory\n");
9305038Smckusic 	if (xseek(ofile, size, 1) == -1) {
9315038Smckusic 		perror("extract seek");
9325038Smckusic 		done(1);
9335038Smckusic 	}
9345038Smckusic }
9354843Smckusic #endif
9364843Smckusic 
9374843Smckusic rstrfile(buf, size)
9384843Smckusic 	char *buf;
9394843Smckusic 	long size;
9404843Smckusic {
9414843Smckusic 	u.u_base = buf;
9424843Smckusic 	u.u_count = size;
9434843Smckusic 	writei(cur_ip);
9444843Smckusic 	if (u.u_error) {
9455038Smckusic 		perror("restor write");
9464843Smckusic 		done(1);
9474843Smckusic 	}
9484843Smckusic }
9494843Smckusic 
9504843Smckusic rstrskip(buf, size)
9514843Smckusic 	char *buf;
9524843Smckusic 	long size;
9534843Smckusic {
9544843Smckusic 	u.u_offset += size;
9554843Smckusic }
9564843Smckusic 
9575038Smckusic rstrcvtdir(buf, size)
9585038Smckusic 	struct odirect *buf;
9595038Smckusic 	long size;
9605038Smckusic {
961*5327Smckusic 	struct direct
962*5327Smckusic 		cvtbuf[MAXBSIZE / sizeof(struct odirect)];
9635038Smckusic 	struct odirect *odp, *edp;
9645038Smckusic 	struct direct *dp;
9655038Smckusic 
9665038Smckusic 	edp = &buf[size / sizeof(struct odirect)];
9675038Smckusic 	for (odp = buf, dp = cvtbuf; odp < edp; odp++, dp++)
9685038Smckusic 		dcvt(odp, dp);
9695038Smckusic 	u.u_base = (char *)cvtbuf;
9705038Smckusic 	u.u_count = size * sizeof(struct direct) / sizeof(struct odirect);
9715038Smckusic 	writei(cur_ip);
9725038Smckusic 	if (u.u_error) {
9735038Smckusic 		perror("restor write");
9745038Smckusic 		done(1);
9755038Smckusic 	}
9765038Smckusic }
9775038Smckusic 
9785038Smckusic rstrcvtskip(buf, size)
9795038Smckusic 	char *buf;
9805038Smckusic 	long size;
9815038Smckusic {
9825038Smckusic 	fprintf(stderr, "unallocated block in directory\n");
9835038Smckusic 	u.u_offset += size;
9845038Smckusic }
9855038Smckusic 
9864843Smckusic null() {;}
9874843Smckusic 
9884843Smckusic /*
9894776Smckusic  * Do the tape i/o, dealing with volume changes
9904610Smckusick  * etc..
9914610Smckusick  */
9924610Smckusick readtape(b)
9934700Smckusic 	char *b;
9944610Smckusick {
9954776Smckusic 	register int i;
9964837Smckusic 	struct s_spcl tmpbuf;
9974610Smckusick 
9984610Smckusick 	if (bct >= NTREC) {
9994610Smckusick 		for (i = 0; i < NTREC; i++)
10004776Smckusic 			((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0;
10014610Smckusick 		bct = 0;
10024776Smckusic 		if ((i = read(mt, tbf, NTREC*TP_BSIZE)) < 0) {
10034700Smckusic 			perror("Tape read error");
10044610Smckusick 			eflag++;
10054700Smckusic 			done(1);
10064610Smckusick 		}
10074610Smckusick 		if (i == 0) {
10084610Smckusick 			bct = NTREC + 1;
10094610Smckusick 			volno++;
10104610Smckusick loop:
10114610Smckusick 			flsht();
10124610Smckusick 			close(mt);
10134700Smckusic 			fprintf(stderr, "Mount volume %d\n", volno);
10144610Smckusick 			while (getchar() != '\n')
10154610Smckusick 				;
10164610Smckusick 			if ((mt = open(magtape, 0)) == -1) {
10174700Smckusic 				fprintf(stderr, "Cannot open tape!\n");
10184610Smckusick 				goto loop;
10194610Smckusick 			}
10204610Smckusick 			if (readhdr(&tmpbuf) == 0) {
10214700Smckusic 				fprintf(stderr, "Not a dump tape.Try again\n");
10224610Smckusick 				goto loop;
10234610Smckusick 			}
10244610Smckusick 			if (checkvol(&tmpbuf, volno) == 0) {
10254700Smckusic 				fprintf(stderr, "Wrong tape. Try again\n");
10264610Smckusick 				goto loop;
10274610Smckusick 			}
10284610Smckusick 			readtape(b);
10294610Smckusick 			return;
10304610Smckusick 		}
10314610Smckusick 	}
10324776Smckusic 	copy(&tbf[(bct++*TP_BSIZE)], b, TP_BSIZE);
10334610Smckusick }
10344610Smckusick 
10354610Smckusick flsht()
10364610Smckusick {
10374610Smckusick 	bct = NTREC+1;
10384610Smckusick }
10394610Smckusick 
10404610Smckusick copy(f, t, s)
10414700Smckusic 	register char *f, *t;
10424610Smckusick {
10434776Smckusic 	register int i;
10444610Smckusick 
10454610Smckusick 	i = s;
10464610Smckusick 	do
10474610Smckusick 		*t++ = *f++;
10484610Smckusick 	while (--i);
10494610Smckusick }
10504610Smckusick 
10515038Smckusic blkclr(buf, size)
10525038Smckusic 	char *buf;
10535038Smckusic 	int size;
10545038Smckusic {
10555038Smckusic 	asm("movc5	$0,(r0),$0,8(ap),*4(ap)");
10565038Smckusic }
10575038Smckusic 
10585038Smckusic resetmt()
10595038Smckusic {
10605038Smckusic 	struct mtop tcom;
10615038Smckusic 
10625038Smckusic 	if(dumpnum > 1)
10635038Smckusic 		tcom.mt_op = MTBSF;
10645038Smckusic 	else
10655038Smckusic 		tcom.mt_op = MTREW;
10665038Smckusic 	tcom.mt_count = 1;
10675038Smckusic 	flsht();
10685038Smckusic 	if (ioctl(mt,MTIOCTOP,&tcom) == -1) {
10695038Smckusic 		/* kludge for disk dumps */
10705038Smckusic 		lseek(mt, (long)0, 0);
10715038Smckusic 	}
10725038Smckusic 	if (dumpnum > 1) {
10735038Smckusic 		tcom.mt_op = MTFSF;
10745038Smckusic 		tcom.mt_count = 1;
10755038Smckusic 		ioctl(mt,MTIOCTOP,&tcom);
10765038Smckusic 	}
10775038Smckusic }
10785038Smckusic 
10794843Smckusic checkvol(b, t)
10804843Smckusic 	struct s_spcl *b;
10814843Smckusic 	int t;
10824610Smckusick {
10834843Smckusic 	if (b->c_volume == t)
10844843Smckusic 		return(1);
10854610Smckusick 	return(0);
10864610Smckusick }
10874610Smckusick 
10884843Smckusic readhdr(b)
10894843Smckusic 	struct s_spcl *b;
10904610Smckusick {
10914843Smckusic 	if (gethead(b) == 0)
10924610Smckusick 		return(0);
10934843Smckusic 	if (checktype(b, TS_TAPE) == 0)
10944843Smckusic 		return(0);
10954843Smckusic 	return(1);
10964610Smckusick }
10974610Smckusick 
10984610Smckusick /*
10994610Smckusick  * read the tape into buf, then return whether or
11004610Smckusick  * or not it is a header block.
11014610Smckusick  */
11024610Smckusick gethead(buf)
11034837Smckusic 	struct s_spcl *buf;
11044610Smckusick {
11054610Smckusick 	readtape((char *)buf);
11064837Smckusic 	if (buf->c_magic != MAGIC || checksum((int *)buf) == 0)
11074610Smckusick 		return(0);
11084610Smckusick 	return(1);
11094610Smckusick }
11104610Smckusick 
11114610Smckusick /*
11124610Smckusick  * return whether or not the buffer contains a header block
11134610Smckusick  */
11144610Smckusick ishead(buf)
11154837Smckusic 	struct s_spcl *buf;
11164610Smckusick {
11174837Smckusic 	if (buf->c_magic != MAGIC || checksum((int *)buf) == 0)
11184610Smckusick 		return(0);
11194610Smckusick 	return(1);
11204610Smckusick }
11214610Smckusick 
11224610Smckusick checktype(b, t)
11234837Smckusic 	struct s_spcl *b;
11244700Smckusic 	int	t;
11254610Smckusick {
11264837Smckusic 	return(b->c_type == t);
11274610Smckusick }
11284610Smckusick 
11295038Smckusic /*
11305038Smckusic  * read a bit mask from the tape into m.
11315038Smckusic  */
11325038Smckusic readbits(m)
1133*5327Smckusic 	char	*m;
11345038Smckusic {
11355038Smckusic 	register int i;
11364610Smckusick 
11375038Smckusic 	i = spcl.c_count;
11385038Smckusic 
11395038Smckusic 	while (i--) {
11405038Smckusic 		readtape((char *) m);
1141*5327Smckusic 		m += (TP_BSIZE/(NBBY/BITS));
11425038Smckusic 	}
11435038Smckusic 	while (gethead(&spcl) == 0)
11445038Smckusic 		;
11455038Smckusic }
11465038Smckusic 
11474610Smckusick checksum(b)
11484700Smckusic 	int *b;
11494610Smckusick {
11504776Smckusic 	register int i, j;
11514610Smckusick 
11524776Smckusic 	j = sizeof(union u_spcl) / sizeof(int);
11534610Smckusick 	i = 0;
11544610Smckusick 	do
11554610Smckusick 		i += *b++;
11564610Smckusick 	while (--j);
11574610Smckusick 	if (i != CHECKSUM) {
11584776Smckusic 		fprintf(stderr, "Checksum error %o, ino %u\n", i, ino);
11594610Smckusick 		return(0);
11604610Smckusick 	}
11614610Smckusick 	return(1);
11624610Smckusick }
11634610Smckusick 
11644610Smckusick /*
11655038Smckusic  *	Check for access into each directory in the pathname of an extracted
11665038Smckusic  *	file and create such a directory if needed in preparation for moving
11675038Smckusic  *	the file to its proper home.
11685038Smckusic  */
11695038Smckusic checkdir(name)
11705038Smckusic 	register char *name;
11715038Smckusic {
11725038Smckusic 	register char *cp;
11735038Smckusic 	int i;
11745038Smckusic 
11755038Smckusic 	for (cp = name; *cp; cp++) {
11765038Smckusic 		if (*cp == '/') {
11775038Smckusic 			*cp = '\0';
11785038Smckusic 			if (xaccess(name, 01) < 0) {
11795038Smckusic 				register int pid, rp;
11805038Smckusic 
11815038Smckusic 				xumount();
11825038Smckusic 				if ((pid = fork()) == 0) {
11835038Smckusic 					execl("/bin/xmkdir", "xmkdir", name, 0);
11845038Smckusic 					execl("/usr/bin/xmkdir", "xmkdir", name, 0);
11855038Smckusic 					execl("./xmkdir", "xmkdir", name, 0);
11865038Smckusic 					fprintf(stderr, "xrestor: cannot find xmkdir!\n");
11875038Smckusic 					done(0);
11885038Smckusic 				}
11895038Smckusic 				while ((rp = wait(&i)) >= 0 && rp != pid)
11905038Smckusic 					;
11915038Smckusic 				xmount(envp);
11925038Smckusic 			}
11935038Smckusic 			*cp = '/';
11945038Smckusic 		}
11955038Smckusic 	}
11965038Smckusic }
11975038Smckusic 
11985038Smckusic /*
11994700Smckusic  * tell whether an inode is allocated
12004700Smckusic  * this is drawn from ialloccg in sys/alloc.c
12014700Smckusic  */
12024700Smckusic iexist(dev, ino)
12034700Smckusic 	dev_t dev;
12044700Smckusic 	ino_t ino;
12054610Smckusick {
12064700Smckusic 	register struct fs *fs;
12074700Smckusic 	register struct cg *cgp;
12084700Smckusic 	register struct buf *bp;
12094700Smckusic 	int cg;
12104700Smckusic 
12114700Smckusic 	fs = getfs(dev);
12124700Smckusic 	if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg)
12134700Smckusic 		return (0);
12144700Smckusic 	cg = itog(ino, fs);
1215*5327Smckusic 	bp = bread(dev, fsbtodb(fs, cgtod(cg, fs)), fs->fs_bsize);
12164700Smckusic 	if (bp->b_flags & B_ERROR)
12174700Smckusic 		return(0);
12184700Smckusic 	cgp = bp->b_un.b_cg;
12194700Smckusic 	ino %= fs->fs_ipg;
12204700Smckusic 	if (isclr(cgp->cg_iused, ino)) {
12214700Smckusic 		brelse(bp);
12224700Smckusic 		return(0);
12234700Smckusic 	}
12244700Smckusic 	brelse(bp);
12254700Smckusic 	return (1);
12264610Smckusick }
12274610Smckusick 
12284843Smckusic allocinotab(ino, seekpt)
12294837Smckusic 	ino_t ino;
12304843Smckusic 	daddr_t seekpt;
12314610Smckusick {
12324837Smckusic 	register struct inotab	*itp;
12334776Smckusic 
12344837Smckusic 	itp = (struct inotab *)calloc(1, sizeof(struct inotab));
12354837Smckusic 	itp->t_next = inotab[INOHASH(ino)];
12364837Smckusic 	inotab[INOHASH(ino)] = itp;
12374837Smckusic 	itp->t_ino = ino;
12384843Smckusic 	itp->t_seekpt = seekpt;
12394610Smckusick }
12404610Smckusick 
12414843Smckusic allocxtr(ino, name, flags)
12424837Smckusic 	ino_t ino;
12434843Smckusic 	char *name;
12444843Smckusic 	char flags;
12454610Smckusick {
12464843Smckusic 	register struct xtrlist	*xp, *pxp;
12474776Smckusic 
12484843Smckusic 	xp = (struct xtrlist *)calloc(1, sizeof(struct xtrlist) + strlen(name));
12494837Smckusic 	xp->x_next = xtrlist[INOHASH(ino)];
12504837Smckusic 	xtrlist[INOHASH(ino)] = xp;
12514837Smckusic 	xp->x_ino = ino;
12524843Smckusic 	strcpy(xp->x_name, name);
12534837Smckusic 	xtrcnt++;
12544843Smckusic 	xp->x_flags = flags;
12554843Smckusic 	for (pxp = xp->x_next; pxp; pxp = pxp->x_next)
12564843Smckusic 		if (pxp->x_ino == ino && (pxp->x_flags & XLINKED) == 0) {
12574843Smckusic 			xp->x_flags |= XLINKED;
12584843Smckusic 			xp->x_linkedto = pxp;
12594843Smckusic 			xtrcnt--;
12604843Smckusic 			break;
12614843Smckusic 		}
12624843Smckusic 	if (xp->x_flags & XLINKED)
12634843Smckusic 		fprintf(stdout, "%s: linked to %s\n", xp->x_name, pxp->x_name);
12644843Smckusic 	else if (xp->x_flags & XISDIR)
12654843Smckusic 		fprintf(stdout, "%s: directory inode %u\n", xp->x_name, ino);
12664843Smckusic 	else
12674843Smckusic 		fprintf(stdout, "%s: inode %u\n", xp->x_name, ino);
12684610Smckusick }
12694610Smckusick 
12705038Smckusic done(exitcode)
12715038Smckusic 	int exitcode;
12724610Smckusick {
12735038Smckusic #ifndef STANDALONE
12745038Smckusic 	unlink(dirfile);
12755038Smckusic #endif
12765038Smckusic 	if (mounted)
12775038Smckusic 		xumount();
12785038Smckusic 	exit(exitcode);
12794610Smckusick }
1280