xref: /csrg-svn/sbin/restore/main.c (revision 8374)
16847Smckusick /* Copyright (c) 1982 Regents of the University of California */
24610Smckusick 
36846Smckusick #ifndef lint
4*8374Smckusick char version[] = "@(#)main.c 2.10 10/07/82";
56846Smckusick #endif
64610Smckusick 
74610Smckusick /*	Modified to include h option (recursively extract all files within
84610Smckusick  *	a subtree) and m option (recreate the heirarchical structure of
94610Smckusick  *	that subtree and move extracted files to their proper homes).
104610Smckusick  *	8/29/80		by Mike Litzkow
114610Smckusick  *
126846Smckusick  *	Modified to work on the new file system
136846Smckusick  *	1/19/82		by Kirk McKusick
146846Smckusick  *
154610Smckusick  *	Includes the s (skip files) option for use with multiple dumps on
164610Smckusick  *	a single tape.
174610Smckusick  */
184610Smckusick 
194610Smckusick #define MAXINO	3000
204610Smckusick #define BITS	8
214610Smckusick #define NCACHE	3
224610Smckusick #define SIZEINC 10
234610Smckusick 
244610Smckusick #include <stdio.h>
254610Smckusick #include <signal.h>
266844Smckusick #include <fstab.h>
276847Smckusick #ifndef SIMFS
286847Smckusick #include <sys/param.h>
296847Smckusick #include <sys/inode.h>
306847Smckusick #include <sys/fs.h>
316847Smckusick #include <dir.h>
326847Smckusick #include <stat.h>
336847Smckusick #include <dumprestor.h>
346847Smckusick #else
356844Smckusick #include "../h/param.h"
366844Smckusick #include "../h/dir.h"
376844Smckusick #include "../h/stat.h"
386844Smckusick #include "../h/inode.h"
396844Smckusick #include "../h/fs.h"
406844Smckusick #include "../h/dumprestor.h"
416847Smckusick #endif
428296Smckusick #include <sys/ioctl.h>
435038Smckusic #include <sys/mtio.h>
444610Smckusick 
455943Smckusic #define ODIRSIZ 14
465038Smckusic struct odirect {
475038Smckusic 	u_short	d_ino;
485943Smckusic 	char	d_name[ODIRSIZ];
495038Smckusic };
505038Smckusic 
515327Smckusic #define	MWORD(m,i) (m[(unsigned)(i-1)/NBBY])
525327Smckusic #define	MBIT(i)	(1<<((unsigned)(i-1)%NBBY))
534610Smckusick #define	BIS(i,w)	(MWORD(w,i) |=  MBIT(i))
544610Smckusick #define	BIC(i,w)	(MWORD(w,i) &= ~MBIT(i))
554610Smckusick #define	BIT(i,w)	(MWORD(w,i) & MBIT(i))
564610Smckusick 
576846Smckusick ino_t	ino;
584610Smckusick 
59*8374Smckusick int	eflag = 0, hflag = 0, mflag = 0, vflag = 0, yflag = 0;
60*8374Smckusick int	cvtflag = 0, cvtdir = 0;
614776Smckusic 
626844Smckusick long	fssize;
634610Smckusick char	tapename[] = "/dev/rmt8";
644610Smckusick char	*magtape = tapename;
655038Smckusic int	mt;
665038Smckusic int	dumpnum = 1;
675038Smckusic int	volno = 1;
685038Smckusic int	curblk = 0;
695038Smckusic int	bct = NTREC+1;
705038Smckusic char	tbf[NTREC*TP_BSIZE];
714610Smckusick 
724610Smckusick daddr_t	seekpt;
734837Smckusic FILE	*df;
745943Smckusic DIR	*dirp;
754837Smckusic int	ofile;
766847Smckusick char	dirfile[] = "/tmp/rstXXXXXX";
776289Smckusick char	lnkbuf[MAXPATHLEN + 1];
786289Smckusick int	pathlen;
794610Smckusick 
804837Smckusic #define INOHASH(val) (val % MAXINO)
814837Smckusic struct inotab {
824837Smckusic 	struct inotab *t_next;
834610Smckusick 	ino_t	t_ino;
844610Smckusick 	daddr_t	t_seekpt;
854837Smckusic } *inotab[MAXINO];
864610Smckusick 
874837Smckusic #define XISDIR	1
884610Smckusick #define XTRACTD	2
894610Smckusick #define XINUSE	4
904837Smckusic #define XLINKED	8
914610Smckusick struct xtrlist {
924837Smckusic 	struct xtrlist	*x_next;
934837Smckusic 	struct xtrlist	*x_linkedto;
944843Smckusic 	time_t		x_timep[2];
954837Smckusic 	ino_t		x_ino;
964837Smckusic 	char		x_flags;
974843Smckusic 	char 		x_name[1];
984843Smckusic 	/* actually longer */
994837Smckusic } *xtrlist[MAXINO];
1004776Smckusic int xtrcnt = 0;
1014610Smckusick 
1025327Smckusic char	*dumpmap;
1035327Smckusic char	*clrimap;
1044610Smckusick 
1055327Smckusic char	clearedbuf[MAXBSIZE];
1065327Smckusic 
1074837Smckusic extern char *ctime();
1086846Smckusick extern int seek();
1094843Smckusic ino_t search();
1105943Smckusic int dirwrite();
1116849Smckusick #ifdef RRESTOR
1126849Smckusick char *host;
1136849Smckusick #endif
1144610Smckusick 
1156846Smckusick main(argc, argv)
1164700Smckusic 	int argc;
1174700Smckusic 	char *argv[];
1184610Smckusick {
1194610Smckusick 	register char *cp;
1204610Smckusick 	char command;
1214700Smckusic 	int (*signal())();
1224610Smckusick 	int done();
1234610Smckusick 
1244843Smckusic 	if (signal(SIGINT, done) == SIG_IGN)
1254843Smckusic 		signal(SIGINT, SIG_IGN);
1264843Smckusic 	if (signal(SIGTERM, done) == SIG_IGN)
1274843Smckusic 		signal(SIGTERM, SIG_IGN);
1286844Smckusick 	mktemp(dirfile);
1294610Smckusick 	if (argc < 2) {
1304610Smckusick usage:
1314837Smckusic 		fprintf(stderr, "Usage: restor x[s|m|h|v] file file..., restor r|R filesys, or restor t\n");
1324700Smckusic 		done(1);
1334610Smckusick 	}
1344610Smckusick 	argv++;
1354610Smckusick 	argc -= 2;
1364610Smckusick 	for (cp = *argv++; *cp; cp++) {
1374610Smckusick 		switch (*cp) {
1384610Smckusick 		case '-':
1394610Smckusick 			break;
1408302Smckusick 		case 'c':
1418302Smckusick 			cvtflag++;
1428302Smckusick 			break;
1434610Smckusick 		case 'f':
1444610Smckusick 			magtape = *argv++;
1456849Smckusick #ifdef RRESTOR
1466849Smckusick 		{ char *index();
1476849Smckusick 		  host = magtape;
1486849Smckusick 		  magtape = index(host, ':');
1496849Smckusick 		  if (magtape == 0) {
1506849Smckusick nohost:
1516849Smckusick 			msg("need keyletter ``f'' and device ``host:tape''");
1526849Smckusick 			done(1);
1536849Smckusick 		  }
1546849Smckusick 		  *magtape++ = 0;
1556849Smckusick 		  if (rmthost(host) == 0)
1566849Smckusick 			done(1);
1576849Smckusick 		}
1586849Smckusick #endif
1594610Smckusick 			argc--;
1604610Smckusick 			break;
1614610Smckusick 		/* s dumpnum (skip to) for multifile dump tapes */
1624610Smckusick 		case 's':
1634610Smckusick 			dumpnum = atoi(*argv++);
1646847Smckusick 			if (dumpnum <= 0) {
1654700Smckusic 				fprintf(stderr, "Dump number must be a positive integer\n");
1664700Smckusic 				done(1);
1674610Smckusick 			}
1684610Smckusick 			argc--;
1694610Smckusick 			break;
1704610Smckusick 		case 'h':
1714610Smckusick 			hflag++;
1724610Smckusick 			break;
1734610Smckusick 		case 'm':
1744610Smckusick 			mflag++;
1754610Smckusick 			break;
176*8374Smckusick 		case 'x':
177*8374Smckusick 			command = *cp;
178*8374Smckusick 			/* set verbose mode by default */
179*8374Smckusick 		case 'v':
180*8374Smckusick 			vflag++;
181*8374Smckusick 			break;
182*8374Smckusick 		case 'y':
183*8374Smckusick 			yflag++;
184*8374Smckusick 			break;
1854610Smckusick 		case 'r':
1864610Smckusick 		case 'R':
1876844Smckusick 			hflag++;
1886844Smckusick 			mflag++;
1894610Smckusick 		case 't':
1904610Smckusick 			command = *cp;
1914610Smckusick 			break;
1924610Smckusick 		default:
1934700Smckusic 			fprintf(stderr, "Bad key character %c\n", *cp);
1944610Smckusick 			goto usage;
1954610Smckusick 		}
1964610Smckusick 	}
1976849Smckusick #ifdef RRESTOR
1986849Smckusick 	if (host == 0)
1996849Smckusick 		goto nohost;
2006849Smckusick #endif
2014610Smckusick 	doit(command, argc, argv);
2024700Smckusic 	done(0);
2034610Smckusick }
2044610Smckusick 
2054610Smckusick doit(command, argc, argv)
2064700Smckusic 	char	command;
2074700Smckusic 	int	argc;
2084700Smckusic 	char	*argv[];
2094610Smckusick {
2105038Smckusic 	struct mtop tcom;
2115038Smckusic 
2126849Smckusick #ifdef RRESTOR
2136849Smckusick 	if ((mt = rmtopen(magtape, 0)) < 0) {
2146849Smckusick #else
2154610Smckusick 	if ((mt = open(magtape, 0)) < 0) {
2166849Smckusick #endif
2174700Smckusic 		fprintf(stderr, "%s: cannot open tape\n", magtape);
2184700Smckusic 		done(1);
2194610Smckusick 	}
2204843Smckusic 	if (dumpnum != 1) {
2214610Smckusick 		tcom.mt_op = MTFSF;
2224610Smckusick 		tcom.mt_count = dumpnum -1;
2236849Smckusick #ifdef RRESTOR
2246849Smckusick 		rmtioctl(MTFSF,dumpnum - 1);
2256849Smckusick #else
2264843Smckusic 		if (ioctl(mt,MTIOCTOP,&tcom) < 0)
2274610Smckusick 			perror("ioctl MTFSF");
2286849Smckusick #endif
2294610Smckusick 	}
2306846Smckusick 	blkclr(clearedbuf, (long)MAXBSIZE);
2318369Smckusick 	if (readhdr(&spcl) == 0) {
2328369Smckusick 		bct--; /* push back this block */
2338369Smckusick 		cvtflag++;
2344610Smckusick 		if (readhdr(&spcl) == 0) {
2354700Smckusic 			fprintf(stderr, "Tape is not a dump tape\n");
2364700Smckusic 			done(1);
2374610Smckusick 		}
2388369Smckusick 		fprintf(stderr, "Converting to new file system format.\n");
2398369Smckusick 	}
2408369Smckusick 	switch(command) {
2418369Smckusick 	case 't':
2424843Smckusic 		fprintf(stdout, "Dump   date: %s", ctime(&spcl.c_date));
2434843Smckusic 		fprintf(stdout, "Dumped from: %s", ctime(&spcl.c_ddate));
2444610Smckusick 		return;
2456844Smckusick 	case 'R':
2466844Smckusick 	case 'r':
2476844Smckusick 		setdir(*argv);
2486844Smckusick 		argc = 1;
2496844Smckusick 		*argv = ".";
2506844Smckusick 		/* and then extract it all */
2514610Smckusick 	case 'x':
2526844Smckusick 		df = fopen(dirfile, "w");
2536844Smckusick 		if (df == 0) {
2546844Smckusick 			fprintf(stderr, "restor: %s - cannot create directory temporary\n", dirfile);
2556844Smckusick 			done(1);
2566844Smckusick 		}
2574837Smckusic 		extractfiles(argc, argv);
2584837Smckusic 		return;
2594837Smckusic 	}
2604837Smckusic }
2614837Smckusic 
2624837Smckusic extractfiles(argc, argv)
2634837Smckusic 	int argc;
2644837Smckusic 	char **argv;
2654837Smckusic {
2664843Smckusic 	char	*ststore();
2674837Smckusic 	register struct xtrlist *xp;
2684837Smckusic 	struct xtrlist **xpp;
2694837Smckusic 	ino_t	d;
2706289Smckusick 	int	xtrfile(), xtrskip(), xtrcvtdir(), xtrcvtskip(),
2716289Smckusick 		xtrlnkfile(), xtrlnkskip(), null();
2726845Smckusick 	int	mode, uid, gid, i;
2734843Smckusic 	char	name[BUFSIZ + 1];
2746844Smckusick 	struct	stat stbuf;
2754837Smckusic 
2766844Smckusick 	if (stat(".", &stbuf) < 0) {
2776844Smckusick 		fprintf(stderr, "cannot stat .\n");
2786844Smckusick 		done(1);
2796844Smckusick 	}
2806844Smckusick 	/*
2816844Smckusick 	 * should be!!!
2826844Smckusick 	 *
2836844Smckusick 	fssize = stbuf.st_blksize;
2846844Smckusick 	 */
2856844Smckusick 	fssize = MAXBSIZE;
2864837Smckusic 	if (checkvol(&spcl, 1) == 0) {
2874837Smckusic 		fprintf(stderr, "Tape is not volume 1 of the dump\n");
2884837Smckusic 	}
2896844Smckusick 	clrimap = 0;
2906844Smckusick 	dumpmap = 0;
2915038Smckusic 	pass1(1);  /* This sets the various maps on the way by */
2924843Smckusic 	while (argc--) {
2934837Smckusic 		if ((d = psearch(*argv)) == 0 || BIT(d,dumpmap) == 0) {
294*8374Smckusick 			fprintf(stderr, "%s: not on tape\n", *argv++);
2954837Smckusic 			continue;
2964610Smckusick 		}
2974843Smckusic 		if (mflag)
2984843Smckusic 			checkdir(*argv);
2996847Smckusick 		if (hflag)
3004837Smckusic 			getleaves(d, *argv++);
3014843Smckusic 		else
3024843Smckusic 			allocxtr(d, *argv++, XINUSE);
3034837Smckusic 	}
3044843Smckusic 	if (dumpnum > 1) {
3055038Smckusic 		/*
3065038Smckusic 		 * if this is a multi-dump tape we always start with
3075038Smckusic 		 * volume 1, so as to avoid accidentally restoring
3085038Smckusic 		 * from a different dump!
3095038Smckusic 		 */
3105038Smckusic 		resetmt();
3115038Smckusic 		dumpnum = 1;
3125038Smckusic 		volno = 1;
3135038Smckusic 		readhdr(&spcl);
3145038Smckusic 		goto rbits;
3154837Smckusic 	}
3165038Smckusic newvol:
3176849Smckusick #ifdef RRESTOR
3186849Smckusick 	rmtclose();
3196849Smckusick #else
3206847Smckusick 	close(mt);
3216849Smckusick #endif
3224610Smckusick getvol:
3235038Smckusic 	fprintf(stderr, "Mount desired tape volume; Specify volume #: ");
3244837Smckusic 	if (gets(tbf) == NULL)
3254837Smckusic 		return;
3264837Smckusic 	volno = atoi(tbf);
3274837Smckusic 	if (volno <= 0) {
3284837Smckusic 		fprintf(stderr, "Volume numbers are positive numerics\n");
3294837Smckusic 		goto getvol;
3304837Smckusic 	}
3316849Smckusick #ifdef RRESTOR
3326849Smckusick 	if ((mt = rmtopen(magtape, 0)) == -1) {
3336849Smckusick #else
3346847Smckusick 	if ((mt = open(magtape, 0)) == -1) {
3356849Smckusick #endif
3366847Smckusick 		fprintf(stderr, "Cannot open tape!\n");
3376847Smckusick 		goto getvol;
3386847Smckusick 	}
3396847Smckusick 	if (dumpnum > 1)
3406847Smckusick 		resetmt();
3414837Smckusic 	if (readhdr(&spcl) == 0) {
3424837Smckusic 		fprintf(stderr, "tape is not dump tape\n");
3434837Smckusic 		goto newvol;
3444837Smckusic 	}
3454837Smckusic 	if (checkvol(&spcl, volno) == 0) {
3464837Smckusic 		fprintf(stderr, "Wrong volume (%d)\n", spcl.c_volume);
3474837Smckusic 		goto newvol;
3484837Smckusic 	}
3494610Smckusick rbits:
3504837Smckusic 	while (gethead(&spcl) == 0)
3514837Smckusic 		;
3524837Smckusic 	if (checktype(&spcl, TS_INODE) == 1) {
3534837Smckusic 		fprintf(stderr, "Can't find inode mask!\n");
3544837Smckusic 		goto newvol;
3554837Smckusic 	}
3564837Smckusic 	if (checktype(&spcl, TS_BITS) == 0)
3574837Smckusic 		goto rbits;
3586844Smckusick 	readbits(&dumpmap);
3594837Smckusic 	while (xtrcnt > 0) {
3604837Smckusic again:
3616845Smckusick 		if (ishead(&spcl) == 0) {
3626845Smckusick 			i = 0;
3636847Smckusick 			while (gethead(&spcl) == 0)
3646845Smckusick 				i++;
3656845Smckusick 			fprintf(stderr, "resync restor, skipped %i blocks\n",
3666845Smckusick 			    i);
3676845Smckusick 		}
3684837Smckusic 		if (checktype(&spcl, TS_END) == 1) {
3694837Smckusic 			fprintf(stderr, "end of tape\n");
3704837Smckusic 			break;
3714610Smckusick 		}
3724837Smckusic 		if (checktype(&spcl, TS_INODE) == 0) {
3734837Smckusic 			gethead(&spcl);
3744837Smckusic 			goto again;
3754610Smckusick 		}
3764837Smckusic 		d = spcl.c_inumber;
3774837Smckusic 		for (xp = xtrlist[INOHASH(d)]; xp; xp = xp->x_next) {
3784837Smckusic 			if (d != xp->x_ino)
3794837Smckusic 				continue;
3804837Smckusic 			if (xp->x_flags & XLINKED)
3814837Smckusic 				continue;
3824837Smckusic 			xp->x_timep[0] = spcl.c_dinode.di_atime;
3834837Smckusic 			xp->x_timep[1] = spcl.c_dinode.di_mtime;
3844837Smckusic 			mode = spcl.c_dinode.di_mode;
3854837Smckusic 			if (mflag)
3864843Smckusic 				strcpy(name, xp->x_name);
3874837Smckusic 			else
3884837Smckusic 				sprintf(name, "%u", xp->x_ino);
3894837Smckusic 			switch (mode & IFMT) {
3904837Smckusic 			default:
3916847Smckusick 				fprintf(stderr, "%s: unknown file mode 0%o\n",
3926847Smckusick 				    name, mode);
3934837Smckusic 				xp->x_flags |= XTRACTD;
3944837Smckusic 				xtrcnt--;
3954837Smckusic 				goto skipfile;
3964837Smckusic 			case IFCHR:
3974837Smckusic 			case IFBLK:
398*8374Smckusick 				if (vflag)
399*8374Smckusick 					fprintf(stdout, "extract special file %s\n", name);
4006844Smckusick 				if (mknod(name, mode, spcl.c_dinode.di_rdev)) {
4014837Smckusic 					fprintf(stderr, "%s: cannot create special file\n", name);
4024837Smckusic 					xp->x_flags |= XTRACTD;
4034837Smckusic 					xtrcnt--;
4044837Smckusic 					goto skipfile;
4054776Smckusic 				}
4064837Smckusic 				getfile(null, null, spcl.c_dinode.di_size);
4074837Smckusic 				break;
4084837Smckusic 			case IFDIR:
4094837Smckusic 				if (mflag) {
410*8374Smckusick 					if (vflag)
411*8374Smckusick 						fprintf(stdout, "extract directory %s\n", name);
4124837Smckusic 					strncat(name, "/.", BUFSIZ);
4134843Smckusic 					checkdir(name);
4146844Smckusick 					chown(xp->x_name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
4154837Smckusic 					getfile(null, null, spcl.c_dinode.di_size);
4164837Smckusic 					break;
4174610Smckusick 				}
418*8374Smckusick 				if (vflag)
419*8374Smckusick 					fprintf(stdout, "extract file %s\n", name);
4206844Smckusick 				if ((ofile = creat(name, 0666)) < 0) {
4215038Smckusic 					fprintf(stderr, "%s: cannot create file\n", name);
4225038Smckusic 					xp->x_flags |= XTRACTD;
4235038Smckusic 					xtrcnt--;
4245038Smckusic 					goto skipfile;
4255038Smckusic 				}
4266844Smckusick 				chown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
4275943Smckusic 				if (cvtdir) {
4285038Smckusic 					getfile(xtrcvtdir, xtrcvtskip,
4295038Smckusic 					    spcl.c_dinode.di_size);
4305943Smckusic 					flushent(xtrfile);
4315943Smckusic 				} else
4325038Smckusic 					getfile(xtrfile, xtrskip,
4335038Smckusic 					    spcl.c_dinode.di_size);
4346844Smckusick 				close(ofile);
4355038Smckusic 				break;
4366289Smckusick 			case IFLNK:
437*8374Smckusick 				if (vflag)
438*8374Smckusick 					fprintf(stdout, "extract symbolic link %s\n", name);
4396289Smckusick 				uid = spcl.c_dinode.di_uid;
4406289Smckusick 				gid = spcl.c_dinode.di_gid;
4416289Smckusick 				lnkbuf[0] = '\0';
4426289Smckusick 				pathlen = 0;
4436289Smckusick 				getfile(xtrlnkfile, xtrlnkskip, spcl.c_dinode.di_size);
4446844Smckusick 				if (symlink(lnkbuf, name) < 0) {
4456289Smckusick 					fprintf(stderr, "%s: cannot create symbolic link\n", name);
4466289Smckusick 					xp->x_flags |= XTRACTD;
4476289Smckusick 					xtrcnt--;
4486289Smckusick 					goto finished;
4496289Smckusick 				}
4506844Smckusick 				chown(name, uid, gid);
4516289Smckusick 				break;
4524837Smckusic 			case IFREG:
453*8374Smckusick 				if (vflag)
454*8374Smckusick 					fprintf(stdout, "extract file %s\n", name);
4556844Smckusick 				if ((ofile = creat(name, 0666)) < 0) {
4564837Smckusic 					fprintf(stderr, "%s: cannot create file\n", name);
4574837Smckusic 					xp->x_flags |= XTRACTD;
4584837Smckusic 					xtrcnt--;
4594837Smckusic 					goto skipfile;
4604837Smckusic 				}
4616844Smckusick 				chown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
4625038Smckusic 				getfile(xtrfile, xtrskip, spcl.c_dinode.di_size);
4636844Smckusick 				close(ofile);
4644837Smckusic 				break;
4654610Smckusick 			}
4666844Smckusick 			chmod(name, mode);
4676844Smckusick 			utime(name, xp->x_timep);
4684837Smckusic 			xp->x_flags |= XTRACTD;
4694837Smckusic 			xtrcnt--;
4704837Smckusic 			goto finished;
4714837Smckusic 		}
4724837Smckusic skipfile:
4734837Smckusic 		getfile(null, null, spcl.c_dinode.di_size);
4744700Smckusic finished:
4754837Smckusic 		;
4764837Smckusic 	}
4774837Smckusic 	if (xtrcnt == 0 && !mflag)
4784837Smckusic 		return;
4794837Smckusic 	for (xpp = xtrlist; xpp < &xtrlist[MAXINO]; xpp++) {
4804837Smckusic 		for (xp = *xpp; xp; xp = xp->x_next) {
4814837Smckusic 			if (mflag && (xp->x_flags & XISDIR))
4826844Smckusick 				utime(xp->x_name, xp->x_timep);
4834837Smckusic 			if (xp->x_flags & XTRACTD)
4844837Smckusic 				continue;
4854837Smckusic 			if ((xp->x_flags & XLINKED) == 0) {
4864837Smckusic 				fprintf(stderr, "cannot find file %s\n",
4874837Smckusic 					xp->x_name);
4884837Smckusic 				continue;
4894837Smckusic 			}
4904843Smckusic 			if (!mflag)
4914843Smckusic 				continue;
492*8374Smckusick 			if (vflag)
493*8374Smckusick 				fprintf(stdout, "link %s to %s\n",
494*8374Smckusick 					xp->x_linkedto->x_name, xp->x_name);
4956844Smckusick 			if (link(xp->x_linkedto->x_name, xp->x_name) < 0)
4964843Smckusic 				fprintf(stderr, "link %s to %s failed\n",
4974837Smckusic 					xp->x_linkedto->x_name, xp->x_name);
4984610Smckusick 		}
4994837Smckusic 	}
5004837Smckusic }
5014837Smckusic 
5024610Smckusick /*
5034610Smckusick  * Read the tape, bulding up a directory structure for extraction
5044610Smckusick  * by name
5054610Smckusick  */
5065038Smckusic pass1(savedir)
5075038Smckusic 	int savedir;
5084610Smckusick {
5094776Smckusic 	register int i;
5104837Smckusic 	register struct dinode *ip;
5114837Smckusic 	struct direct nulldir;
5125038Smckusic 	char buf[TP_BSIZE];
5135943Smckusic 	int putdir(), null(), dirwrite();
5144610Smckusick 
5155943Smckusic 	nulldir.d_ino = 1;
5165943Smckusic 	nulldir.d_namlen = 1;
5175943Smckusic 	strncpy(nulldir.d_name, "/", nulldir.d_namlen);
5185943Smckusic 	nulldir.d_reclen = DIRSIZ(&nulldir);
5194610Smckusick 	while (gethead(&spcl) == 0) {
5204700Smckusic 		fprintf(stderr, "Can't find directory header!\n");
5214610Smckusick 	}
5224610Smckusick 	for (;;) {
5234610Smckusick 		if (checktype(&spcl, TS_BITS) == 1) {
5246844Smckusick 			readbits(&dumpmap);
5254610Smckusick 			continue;
5264610Smckusick 		}
5274610Smckusick 		if (checktype(&spcl, TS_CLRI) == 1) {
5286844Smckusick 			readbits(&clrimap);
5294610Smckusick 			continue;
5304610Smckusick 		}
5314610Smckusick 		if (checktype(&spcl, TS_INODE) == 0) {
5324610Smckusick finish:
5335943Smckusic 			if (savedir) {
5345943Smckusic 				fclose(df);
5355943Smckusic 				dirp = opendir(dirfile);
5365943Smckusic 				if (dirp == NULL)
5375943Smckusic 					perror("opendir");
5385943Smckusic 			}
5395038Smckusic 			resetmt();
5404610Smckusick 			return;
5414610Smckusick 		}
5424610Smckusick 		ip = &spcl.c_dinode;
5434610Smckusick 		i = ip->di_mode & IFMT;
5444610Smckusick 		if (i != IFDIR) {
5454610Smckusick 			goto finish;
5464610Smckusick 		}
5475038Smckusic 		if (spcl.c_inumber == ROOTINO) {
5485038Smckusic 			readtape(buf);
5495038Smckusic 			bct--; /* push back this block */
5505038Smckusic 			if (((struct direct *)buf)->d_ino != ROOTINO) {
5515038Smckusic 				if (((struct odirect *)buf)->d_ino != ROOTINO) {
5525038Smckusic 					fprintf(stderr, "bad root directory\n");
5535038Smckusic 					done(1);
5545038Smckusic 				}
5555038Smckusic 				fprintf(stderr, "converting to new directory format\n");
5565038Smckusic 				cvtdir = 1;
5578302Smckusick 				cvtflag = 1;
5585038Smckusic 			}
5595038Smckusic 			if (!savedir && !cvtdir) {
5605038Smckusic 				/* if no conversion, just return */
5615038Smckusic 				goto finish;
5625038Smckusic 			}
5635038Smckusic 		}
5644843Smckusic 		allocinotab(spcl.c_inumber, seekpt);
5655038Smckusic 		if (savedir) {
5665038Smckusic 			getfile(putdir, null, spcl.c_dinode.di_size);
5675943Smckusic 			putent(&nulldir, dirwrite);
5685943Smckusic 			flushent(dirwrite);
5695038Smckusic 		} else {
5705038Smckusic 			getfile(null, null, spcl.c_dinode.di_size);
5715038Smckusic 		}
5724610Smckusick 	}
5734610Smckusick }
5744610Smckusick 
5754610Smckusick /*
5764843Smckusic  * Put the directory entries in the directory file
5774843Smckusic  */
5784843Smckusic putdir(buf, size)
5794843Smckusic 	char *buf;
5804843Smckusic 	int size;
5814843Smckusic {
5825038Smckusic 	struct direct cvtbuf;
5835038Smckusic 	register struct odirect *odp;
5845038Smckusic 	struct odirect *eodp;
5854843Smckusic 	register struct direct *dp;
5866289Smckusick 	long loc, i;
5874843Smckusic 
5885038Smckusic 	if (cvtdir) {
5895038Smckusic 		eodp = (struct odirect *)&buf[size];
5905038Smckusic 		for (odp = (struct odirect *)buf; odp < eodp; odp++)
5915038Smckusic 			if (odp->d_ino != 0) {
5925038Smckusic 				dcvt(odp, &cvtbuf);
5935943Smckusic 				putent(&cvtbuf, dirwrite);
5945038Smckusic 			}
5955038Smckusic 	} else {
5965943Smckusic 		for (loc = 0; loc < size; ) {
5975943Smckusic 			dp = (struct direct *)(buf + loc);
5986289Smckusick 			i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1));
5996289Smckusick 			if (dp->d_reclen <= 0 || dp->d_reclen > i) {
6006289Smckusick 				loc += i;
6016289Smckusick 				continue;
6026289Smckusick 			}
6036289Smckusick 			loc += dp->d_reclen;
6046847Smckusick 			if (dp->d_ino != 0) {
6055943Smckusic 				putent(dp, dirwrite);
6066847Smckusick 			}
6075943Smckusic 		}
6085038Smckusic 	}
6094843Smckusic }
6104843Smckusic 
6114843Smckusic /*
6124843Smckusic  *	Recursively find names and inumbers of all files in subtree
6134843Smckusic  *	pname and put them in xtrlist[]
6144843Smckusic  */
6154843Smckusic getleaves(ino, pname)
6164843Smckusic 	ino_t ino;
6174843Smckusic 	char *pname;
6184843Smckusic {
6194843Smckusic 	register struct inotab *itp;
6204843Smckusic 	int namelen;
6216846Smckusick 	daddr_t bpt;
6225943Smckusic 	register struct direct *dp;
6235943Smckusic 	char locname[BUFSIZ + 1];
6244843Smckusic 
6254843Smckusic 	if (BIT(ino, dumpmap) == 0) {
626*8374Smckusick 		if (vflag)
627*8374Smckusick 			fprintf(stdout, "%s: not on the tape\n", pname);
6284843Smckusic 		return;
6294843Smckusic 	}
6304843Smckusic 	for (itp = inotab[INOHASH(ino)]; itp; itp = itp->t_next) {
6314843Smckusic 		if (itp->t_ino != ino)
6324843Smckusic 			continue;
6334843Smckusic 		/*
6344843Smckusic 		 * pname is a directory name
6354843Smckusic 		 */
6364843Smckusic 		allocxtr(ino, pname, XISDIR);
6374843Smckusic 		/*
6384843Smckusic 		 * begin search through the directory
6394843Smckusic 		 * skipping over "." and ".."
6404843Smckusic 		 */
6414843Smckusic 		strncpy(locname, pname, BUFSIZ);
6424843Smckusic 		strncat(locname, "/", BUFSIZ);
6434843Smckusic 		namelen = strlen(locname);
6445943Smckusic 		seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
6455943Smckusic 		dp = readdir(dirp);
6465943Smckusic 		dp = readdir(dirp);
6475943Smckusic 		dp = readdir(dirp);
6485943Smckusic 		bpt = telldir(dirp);
6494843Smckusic 		/*
6504843Smckusic 		 * "/" signals end of directory
6514843Smckusic 		 */
6525943Smckusic 		while (dp->d_namlen != 1 || dp->d_name[0] != '/') {
6534843Smckusic 			locname[namelen] = '\0';
6545943Smckusic 			if (namelen + dp->d_namlen >= BUFSIZ) {
6555943Smckusic 				fprintf(stderr, "%s%s: name exceedes %d char\n",
6565943Smckusic 					locname, dp->d_name, BUFSIZ);
6574843Smckusic 				continue;
6584843Smckusic 			}
6595943Smckusic 			strncat(locname, dp->d_name, dp->d_namlen);
6605943Smckusic 			getleaves(dp->d_ino, locname);
6615943Smckusic 			seekdir(dirp, bpt, itp->t_seekpt);
6625943Smckusic 			dp = readdir(dirp);
6635943Smckusic 			bpt = telldir(dirp);
6644843Smckusic 		}
6654843Smckusic 		return;
6664843Smckusic 	}
6674843Smckusic 	/*
6684843Smckusic 	 * locname is name of a simple file
6694843Smckusic 	 */
6704843Smckusic 	allocxtr(ino, pname, XINUSE);
6714843Smckusic }
6724843Smckusic 
6734843Smckusic /*
6744843Smckusic  * Search the directory tree rooted at inode ROOTINO
6754843Smckusic  * for the path pointed at by n
6764843Smckusic  */
6774843Smckusic psearch(n)
6784843Smckusic 	char	*n;
6794843Smckusic {
6804843Smckusic 	register char *cp, *cp1;
6814843Smckusic 	char c;
6824843Smckusic 
6834843Smckusic 	ino = ROOTINO;
6844843Smckusic 	if (*(cp = n) == '/')
6854843Smckusic 		cp++;
6864843Smckusic next:
6874843Smckusic 	cp1 = cp + 1;
6884843Smckusic 	while (*cp1 != '/' && *cp1)
6894843Smckusic 		cp1++;
6904843Smckusic 	c = *cp1;
6914843Smckusic 	*cp1 = 0;
6924843Smckusic 	ino = search(ino, cp);
6934843Smckusic 	if (ino == 0) {
6944843Smckusic 		*cp1 = c;
6954843Smckusic 		return(0);
6964843Smckusic 	}
6974843Smckusic 	*cp1 = c;
6984843Smckusic 	if (c == '/') {
6994843Smckusic 		cp = cp1+1;
7004843Smckusic 		goto next;
7014843Smckusic 	}
7024843Smckusic 	return(ino);
7034843Smckusic }
7044843Smckusic 
7054843Smckusic /*
7064843Smckusic  * search the directory inode ino
7074843Smckusic  * looking for entry cp
7084843Smckusic  */
7094843Smckusic ino_t
7104843Smckusic search(inum, cp)
7114843Smckusic 	ino_t	inum;
7124843Smckusic 	char	*cp;
7134843Smckusic {
7145943Smckusic 	register struct direct *dp;
7154843Smckusic 	register struct inotab *itp;
7165943Smckusic 	int len;
7174843Smckusic 
7184843Smckusic 	for (itp = inotab[INOHASH(inum)]; itp; itp = itp->t_next)
7194843Smckusic 		if (itp->t_ino == inum)
7204843Smckusic 			goto found;
7214843Smckusic 	return(0);
7224843Smckusic found:
7235943Smckusic 	seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
7245943Smckusic 	len = strlen(cp);
7254843Smckusic 	do {
7265943Smckusic 		dp = readdir(dirp);
7275943Smckusic 		if (dp->d_namlen == 1 && dp->d_name[0] == '/')
7284843Smckusic 			return(0);
7295943Smckusic 	} while (dp->d_namlen != len || strncmp(dp->d_name, cp, len));
7305943Smckusic 	return(dp->d_ino);
7314843Smckusic }
7324843Smckusic 
7334843Smckusic /*
7344610Smckusick  * Do the file extraction, calling the supplied functions
7354610Smckusick  * with the blocks
7364610Smckusick  */
7374700Smckusic getfile(f1, f2, size)
7384700Smckusic 	int	(*f2)(), (*f1)();
7396846Smckusick 	off_t	size;
7404610Smckusick {
7414776Smckusic 	register int i;
7425327Smckusic 	char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
7434837Smckusic 	union u_spcl addrblk;
7444837Smckusic #	define addrblock addrblk.s_spcl
7454610Smckusick 
7464837Smckusic 	addrblock = spcl;
7474610Smckusick 	for (;;) {
7484837Smckusic 		for (i = 0; i < addrblock.c_count; i++) {
7494837Smckusic 			if (addrblock.c_addr[i]) {
7504776Smckusic 				readtape(&buf[curblk++][0]);
7516844Smckusick 				if (curblk == fssize / TP_BSIZE) {
7524776Smckusic 					(*f1)(buf, size > TP_BSIZE ?
7536844Smckusick 					     (long) (fssize) :
7544776Smckusic 					     (curblk - 1) * TP_BSIZE + size);
7554776Smckusic 					curblk = 0;
7564776Smckusic 				}
7575327Smckusic 			} else {
7584776Smckusic 				if (curblk > 0) {
7594776Smckusic 					(*f1)(buf, size > TP_BSIZE ?
7604776Smckusic 					     (long) (curblk * TP_BSIZE) :
7614776Smckusic 					     (curblk - 1) * TP_BSIZE + size);
7624776Smckusic 					curblk = 0;
7634776Smckusic 				}
7645327Smckusic 				(*f2)(clearedbuf, size > TP_BSIZE ?
7655327Smckusic 					(long) TP_BSIZE : size);
7664610Smckusick 			}
7674776Smckusic 			if ((size -= TP_BSIZE) <= 0) {
7684610Smckusick eloop:
7694610Smckusick 				while (gethead(&spcl) == 0)
7704610Smckusick 					;
7714610Smckusick 				if (checktype(&spcl, TS_ADDR) == 1)
7724610Smckusick 					goto eloop;
7734776Smckusic 				goto out;
7744610Smckusick 			}
7754610Smckusick 		}
7764837Smckusic 		if (gethead(&addrblock) == 0) {
7774776Smckusic 			fprintf(stderr, "Missing address (header) block, ino%u\n", ino);
7784700Smckusic 			goto eloop;
7794700Smckusic 		}
7804837Smckusic 		if (checktype(&addrblock, TS_ADDR) == 0) {
7814837Smckusic 			spcl = addrblock;
7824776Smckusic 			goto out;
7834700Smckusic 		}
7844610Smckusick 	}
7854776Smckusic out:
7864776Smckusic 	if (curblk > 0) {
7874776Smckusic 		(*f1)(buf, (curblk * TP_BSIZE) + size);
7884776Smckusic 		curblk = 0;
7894776Smckusic 	}
7904610Smckusick }
7914610Smckusick 
7924610Smckusick /*
7934843Smckusic  * The next routines are called during file extraction to
7944843Smckusic  * put the data into the right form and place.
7954843Smckusic  */
7964843Smckusic xtrfile(buf, size)
7974843Smckusic 	char	*buf;
7984843Smckusic 	long	size;
7994843Smckusic {
8006847Smckusick 
8016844Smckusick 	if (write(ofile, buf, (int) size) == -1) {
8025038Smckusic 		perror("extract write");
8034843Smckusic 		done(1);
8044843Smckusic 	}
8054843Smckusic }
8064843Smckusic 
8075038Smckusic xtrskip(buf, size)
8084843Smckusic 	char *buf;
8094843Smckusic 	long size;
8104843Smckusic {
8116847Smckusick 
8126846Smckusick #ifdef lint
8136846Smckusick 	buf = buf;
8146846Smckusick #endif
8156844Smckusick 	if (lseek(ofile, size, 1) == -1) {
8165038Smckusic 		perror("extract seek");
8174843Smckusic 		done(1);
8184843Smckusic 	}
8194843Smckusic }
8205038Smckusic 
8215038Smckusic xtrcvtdir(buf, size)
8225038Smckusic 	struct odirect *buf;
8235038Smckusic 	long size;
8245038Smckusic {
8255038Smckusic 	struct odirect *odp, *edp;
8266846Smckusick 	struct direct cvtbuf;
8275038Smckusic 
8285038Smckusic 	edp = &buf[size / sizeof(struct odirect)];
8295943Smckusic 	for (odp = buf; odp < edp; odp++) {
8305943Smckusic 		dcvt(odp, &cvtbuf);
8315943Smckusic 		putent(&cvtbuf, xtrfile);
8325038Smckusic 	}
8335038Smckusic }
8345038Smckusic 
8355038Smckusic xtrcvtskip(buf, size)
8365038Smckusic 	char *buf;
8375038Smckusic 	long size;
8385038Smckusic {
8396847Smckusick 
8405038Smckusic 	fprintf(stderr, "unallocated block in directory\n");
8415943Smckusic 	xtrskip(buf, size);
8425038Smckusic }
8436289Smckusick 
8446289Smckusick xtrlnkfile(buf, size)
8456289Smckusick 	char	*buf;
8466289Smckusick 	long	size;
8476289Smckusick {
8486847Smckusick 
8496289Smckusick 	pathlen += size;
8506289Smckusick 	if (pathlen > MAXPATHLEN) {
8516289Smckusick 		fprintf(stderr, "symbolic link name: %s; too long %d\n",
8526289Smckusick 		    buf, size);
8536289Smckusick 		done(1);
8546289Smckusick 	}
8556289Smckusick 	strcat(lnkbuf, buf);
8566289Smckusick }
8576289Smckusick 
8586289Smckusick xtrlnkskip(buf, size)
8596289Smckusick 	char *buf;
8606289Smckusick 	long size;
8616289Smckusick {
8626847Smckusick 
8636846Smckusick #ifdef lint
8646846Smckusick 	buf = buf, size = size;
8656846Smckusick #endif
8666289Smckusick 	fprintf(stderr, "unallocated block in symbolic link\n");
8676289Smckusick 	done(1);
8686289Smckusick }
8694843Smckusic 
8704843Smckusic null() {;}
8714843Smckusic 
8724843Smckusic /*
8734776Smckusic  * Do the tape i/o, dealing with volume changes
8744610Smckusick  * etc..
8754610Smckusick  */
8764610Smckusick readtape(b)
8774700Smckusic 	char *b;
8784610Smckusick {
8796846Smckusick 	register long i;
8806847Smckusick 	struct u_spcl tmpbuf;
8816845Smckusick 	char c;
8824610Smckusick 
8834610Smckusick 	if (bct >= NTREC) {
8844610Smckusick 		for (i = 0; i < NTREC; i++)
8854776Smckusic 			((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0;
8864610Smckusick 		bct = 0;
8876849Smckusick #ifdef RRESTOR
8886849Smckusick 		if ((i = rmtread(tbf, NTREC*TP_BSIZE)) < 0) {
8896849Smckusick #else
8904776Smckusic 		if ((i = read(mt, tbf, NTREC*TP_BSIZE)) < 0) {
8916849Smckusick #endif
892*8374Smckusick 			fprintf(stderr, "Tape read error");
893*8374Smckusick 			if (!yflag) {
894*8374Smckusick 				fprintf(stderr, "continue?");
895*8374Smckusick 				do	{
896*8374Smckusick 					fprintf(stderr, "[yn]\n");
897*8374Smckusick 					c = getchar();
898*8374Smckusick 					while (getchar() != '\n')
899*8374Smckusick 						/* void */;
900*8374Smckusick 				} while (c != 'y' && c != 'n');
901*8374Smckusick 				if (c == 'n')
902*8374Smckusick 					done(1);
903*8374Smckusick 			}
9044610Smckusick 			eflag++;
9056845Smckusick 			i = NTREC*TP_BSIZE;
9066845Smckusick 			blkclr(tbf, i);
9076849Smckusick #ifdef RRESTOR
9086849Smckusick 			if (rmtseek(i, 1) < 0) {
9096849Smckusick #else
9106846Smckusick 			if (lseek(mt, i, 1) < 0) {
9116849Smckusick #endif
9126846Smckusick 				fprintf(stderr, "continuation failed\n");
9136846Smckusick 				done(1);
9146846Smckusick 			}
9154610Smckusick 		}
9164610Smckusick 		if (i == 0) {
9174610Smckusick 			bct = NTREC + 1;
9184610Smckusick 			volno++;
9194610Smckusick loop:
9204610Smckusick 			flsht();
9216849Smckusick #ifdef RRESTOR
9226849Smckusick 			rmtclose();
9236849Smckusick #else
9244610Smckusick 			close(mt);
9256849Smckusick #endif
9264700Smckusic 			fprintf(stderr, "Mount volume %d\n", volno);
9274610Smckusick 			while (getchar() != '\n')
9284610Smckusick 				;
9296849Smckusick #ifdef RRESTOR
9306849Smckusick 			if ((mt = rmtopen(magtape, 0)) == -1) {
9316849Smckusick #else
9324610Smckusick 			if ((mt = open(magtape, 0)) == -1) {
9336849Smckusick #endif
9344700Smckusic 				fprintf(stderr, "Cannot open tape!\n");
9354610Smckusick 				goto loop;
9364610Smckusick 			}
9374610Smckusick 			if (readhdr(&tmpbuf) == 0) {
9384700Smckusic 				fprintf(stderr, "Not a dump tape.Try again\n");
9394610Smckusick 				goto loop;
9404610Smckusick 			}
9414610Smckusick 			if (checkvol(&tmpbuf, volno) == 0) {
9424700Smckusic 				fprintf(stderr, "Wrong tape. Try again\n");
9434610Smckusick 				goto loop;
9444610Smckusick 			}
9454610Smckusick 			readtape(b);
9464610Smckusick 			return;
9474610Smckusick 		}
9484610Smckusick 	}
9496846Smckusick 	blkcpy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
9504610Smckusick }
9514610Smckusick 
9524610Smckusick flsht()
9534610Smckusick {
9546847Smckusick 
9554610Smckusick 	bct = NTREC+1;
9564610Smckusick }
9574610Smckusick 
9585943Smckusic blkcpy(from, to, size)
9595943Smckusic 	char *from, *to;
9606846Smckusick 	long size;
9614610Smckusick {
9626847Smckusick 
9636846Smckusick #ifdef lint
9646846Smckusick 	from = from, to = to, size = size;
9656846Smckusick #endif
9665943Smckusic 	asm("	movc3	12(ap),*4(ap),*8(ap)");
9674610Smckusick }
9684610Smckusick 
9695038Smckusic blkclr(buf, size)
9705038Smckusic 	char *buf;
9716846Smckusick 	long size;
9725038Smckusic {
9736847Smckusick 
9746846Smckusick #ifdef lint
9756846Smckusick 	buf = buf, size = size;
9766846Smckusick #endif
9775038Smckusic 	asm("movc5	$0,(r0),$0,8(ap),*4(ap)");
9785038Smckusic }
9795038Smckusic 
9805038Smckusic resetmt()
9815038Smckusic {
9825038Smckusic 	struct mtop tcom;
9835038Smckusic 
9846847Smckusick 	if (dumpnum > 1)
9855038Smckusic 		tcom.mt_op = MTBSF;
9865038Smckusic 	else
9875038Smckusic 		tcom.mt_op = MTREW;
9885038Smckusic 	tcom.mt_count = 1;
9895038Smckusic 	flsht();
9906849Smckusick #ifdef RRESTOR
9916849Smckusick 	if (rmtioctl(tcom.mt_op, 1) == -1) {
9926849Smckusick 		/* kludge for disk dumps */
9936849Smckusick 		rmtseek((long)0, 0);
9946849Smckusick 	}
9956849Smckusick #else
9965038Smckusic 	if (ioctl(mt,MTIOCTOP,&tcom) == -1) {
9975038Smckusic 		/* kludge for disk dumps */
9985038Smckusic 		lseek(mt, (long)0, 0);
9995038Smckusic 	}
10006849Smckusick #endif
10015038Smckusic 	if (dumpnum > 1) {
10026849Smckusick #ifdef RRESTOR
10036849Smckusick 		rmtioctl(MTFSF, 1);
10046849Smckusick #else
10055038Smckusic 		tcom.mt_op = MTFSF;
10065038Smckusic 		tcom.mt_count = 1;
10075038Smckusic 		ioctl(mt,MTIOCTOP,&tcom);
10086849Smckusick #endif
10095038Smckusic 	}
10105038Smckusic }
10115038Smckusic 
10124843Smckusic checkvol(b, t)
10134843Smckusic 	struct s_spcl *b;
10144843Smckusic 	int t;
10154610Smckusick {
10166847Smckusick 
10174843Smckusic 	if (b->c_volume == t)
10184843Smckusic 		return(1);
10194610Smckusick 	return(0);
10204610Smckusick }
10214610Smckusick 
10224843Smckusic readhdr(b)
10234843Smckusic 	struct s_spcl *b;
10244610Smckusick {
10256847Smckusick 
10264843Smckusic 	if (gethead(b) == 0)
10274610Smckusick 		return(0);
10284843Smckusic 	if (checktype(b, TS_TAPE) == 0)
10294843Smckusic 		return(0);
10304843Smckusic 	return(1);
10314610Smckusick }
10324610Smckusick 
10334610Smckusick /*
10344610Smckusick  * read the tape into buf, then return whether or
10354610Smckusick  * or not it is a header block.
10364610Smckusick  */
10374610Smckusick gethead(buf)
10384837Smckusic 	struct s_spcl *buf;
10394610Smckusick {
10408302Smckusick 	union u_ospcl {
10418302Smckusick 		char dummy[TP_BSIZE];
10428302Smckusick 		struct	s_ospcl {
10438302Smckusick 			int	c_type;
10448302Smckusick 			time_t	c_date;
10458302Smckusick 			time_t	c_ddate;
10468302Smckusick 			int	c_volume;
10478302Smckusick 			daddr_t	c_tapea;
10488302Smckusick 			ino_t	c_inumber;
10498302Smckusick 			int	c_magic;
10508302Smckusick 			int	c_checksum;
10518302Smckusick 			struct odinode {
10528302Smckusick 				unsigned short odi_mode;
10538302Smckusick 				short	odi_nlink;
10548302Smckusick 				short	odi_uid;
10558302Smckusick 				short	odi_gid;
10568302Smckusick 				off_t	odi_size;
10578302Smckusick 				daddr_t	odi_rdev;
10588302Smckusick 				char	odi_addr[36];
10598302Smckusick 				time_t	odi_atime;
10608302Smckusick 				time_t	odi_mtime;
10618302Smckusick 				time_t	odi_ctime;
10628302Smckusick 			} c_dinode;
10638302Smckusick 			int	c_count;
10648302Smckusick 			char	c_addr[TP_NINDIR];
10658302Smckusick 		} s_ospcl;
10668302Smckusick 	} u_ospcl;
10676847Smckusick 
10688302Smckusick 	if (!cvtflag) {
10698302Smckusick 		readtape((char *)buf);
10708369Smckusick 		if (buf->c_magic != NFS_MAGIC || checksum((int *)buf) == 0)
10718302Smckusick 			return(0);
10728302Smckusick 		return(1);
10738302Smckusick 	}
10748302Smckusick 	readtape((char *)(&u_ospcl.s_ospcl));
10758369Smckusick 	if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
10768302Smckusick 	    checksum((int *)(&u_ospcl.s_ospcl)) == 0)
10774610Smckusick 		return(0);
10788302Smckusick 	blkclr((char *)buf, TP_BSIZE);
10798302Smckusick 	buf->c_type = u_ospcl.s_ospcl.c_type;
10808302Smckusick 	buf->c_date = u_ospcl.s_ospcl.c_date;
10818302Smckusick 	buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
10828302Smckusick 	buf->c_volume = u_ospcl.s_ospcl.c_volume;
10838302Smckusick 	buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
10848302Smckusick 	buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
10858369Smckusick 	buf->c_magic = NFS_MAGIC;
10868302Smckusick 	buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
10878302Smckusick 	buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
10888302Smckusick 	buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
10898302Smckusick 	buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
10908302Smckusick 	buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
10918302Smckusick 	buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
10928302Smckusick 	buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
10938302Smckusick 	buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
10948302Smckusick 	buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
10958302Smckusick 	buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
10968302Smckusick 	buf->c_count = u_ospcl.s_ospcl.c_count;
10978302Smckusick 	blkcpy(u_ospcl.s_ospcl.c_addr, buf->c_addr, TP_NINDIR);
10984610Smckusick 	return(1);
10994610Smckusick }
11004610Smckusick 
11014610Smckusick /*
11024610Smckusick  * return whether or not the buffer contains a header block
11034610Smckusick  */
11044610Smckusick ishead(buf)
11054837Smckusic 	struct s_spcl *buf;
11064610Smckusick {
11076847Smckusick 
11088369Smckusick 	if (buf->c_magic != NFS_MAGIC)
11094610Smckusick 		return(0);
11104610Smckusick 	return(1);
11114610Smckusick }
11124610Smckusick 
11134610Smckusick checktype(b, t)
11144837Smckusic 	struct s_spcl *b;
11154700Smckusic 	int	t;
11164610Smckusick {
11176847Smckusick 
11184837Smckusic 	return(b->c_type == t);
11194610Smckusick }
11204610Smckusick 
11215038Smckusic /*
11225038Smckusic  * read a bit mask from the tape into m.
11235038Smckusic  */
11246844Smckusick readbits(mapp)
11256844Smckusick 	char **mapp;
11265038Smckusic {
11275038Smckusic 	register int i;
11286844Smckusick 	char	*m;
11294610Smckusick 
11305038Smckusic 	i = spcl.c_count;
11315038Smckusic 
11326844Smckusick 	if (*mapp == 0)
11336846Smckusick 		*mapp = (char *)calloc(i, (TP_BSIZE/(NBBY/BITS)));
11346844Smckusick 	m = *mapp;
11355038Smckusic 	while (i--) {
11365038Smckusic 		readtape((char *) m);
11375327Smckusic 		m += (TP_BSIZE/(NBBY/BITS));
11385038Smckusic 	}
11395038Smckusic 	while (gethead(&spcl) == 0)
11405038Smckusic 		;
11415038Smckusic }
11425038Smckusic 
11434610Smckusick checksum(b)
11448302Smckusick 	register int *b;
11454610Smckusick {
11464776Smckusic 	register int i, j;
11474610Smckusick 
11484776Smckusic 	j = sizeof(union u_spcl) / sizeof(int);
11494610Smckusick 	i = 0;
11504610Smckusick 	do
11514610Smckusick 		i += *b++;
11524610Smckusick 	while (--j);
11534610Smckusick 	if (i != CHECKSUM) {
11544776Smckusic 		fprintf(stderr, "Checksum error %o, ino %u\n", i, ino);
11554610Smckusick 		return(0);
11564610Smckusick 	}
11574610Smckusick 	return(1);
11584610Smckusick }
11594610Smckusick 
11604610Smckusick /*
11615038Smckusic  *	Check for access into each directory in the pathname of an extracted
11625038Smckusic  *	file and create such a directory if needed in preparation for moving
11635038Smckusic  *	the file to its proper home.
11645038Smckusic  */
11655038Smckusic checkdir(name)
11665038Smckusic 	register char *name;
11675038Smckusic {
11685038Smckusic 	register char *cp;
11695038Smckusic 	int i;
11705038Smckusic 
11715038Smckusic 	for (cp = name; *cp; cp++) {
11725038Smckusic 		if (*cp == '/') {
11735038Smckusic 			*cp = '\0';
11746844Smckusick 			if (access(name, 01) < 0) {
11755038Smckusic 				register int pid, rp;
11765038Smckusic 
11775038Smckusic 				if ((pid = fork()) == 0) {
11786844Smckusick 					execl("/bin/mkdir", "mkdir", name, 0);
11796844Smckusick 					execl("/usr/bin/mkdir", "mkdir", name, 0);
11806844Smckusick 					fprintf(stderr, "restor: cannot find mkdir!\n");
11815038Smckusic 					done(0);
11825038Smckusic 				}
11835038Smckusic 				while ((rp = wait(&i)) >= 0 && rp != pid)
11845038Smckusic 					;
11855038Smckusic 			}
11865038Smckusic 			*cp = '/';
11875038Smckusic 		}
11885038Smckusic 	}
11895038Smckusic }
11905038Smckusic 
11916844Smckusick setdir(dev)
11926844Smckusick 	char *dev;
11936844Smckusick {
11946844Smckusick 	struct fstab *fsp;
11956844Smckusick 
11966844Smckusick 	if (setfsent() == 0) {
11976844Smckusick 		fprintf(stderr, "Can't open checklist file: %s\n", FSTAB);
11986844Smckusick 		done(1);
11996844Smckusick 	}
12006844Smckusick 	while ((fsp = getfsent()) != 0) {
12016844Smckusick 		if (strcmp(fsp->fs_spec, dev) == 0) {
1202*8374Smckusick 			fprintf(stderr, "%s mounted on %s\n", dev, fsp->fs_file);
12036844Smckusick 			if (chdir(fsp->fs_file) >= 0)
12046844Smckusick 				return;
12056844Smckusick 			fprintf(stderr, "%s cannot chdir to %s\n",
12066844Smckusick 			    fsp->fs_file);
12076844Smckusick 			done(1);
12086844Smckusick 		}
12096844Smckusick 	}
12106844Smckusick 	fprintf(stderr, "%s not mounted\n", dev);
12116844Smckusick 	done(1);
12126844Smckusick }
12136844Smckusick 
12145038Smckusic /*
12155943Smckusic  * These variables are "local" to the following two functions.
12165943Smckusic  */
12175943Smckusic char dirbuf[DIRBLKSIZ];
12185943Smckusic long dirloc = 0;
12195943Smckusic long prev = 0;
12205943Smckusic 
12215943Smckusic /*
12225943Smckusic  * add a new directory entry to a file.
12235943Smckusic  */
12245943Smckusic putent(dp, wrtfunc)
12255943Smckusic 	struct direct *dp;
12265943Smckusic 	int (*wrtfunc)();
12275943Smckusic {
12286847Smckusick 
12295943Smckusic 	if (dp->d_ino == 0)
12305943Smckusic 		return;
12316847Smckusick 	if (dirloc + dp->d_reclen > DIRBLKSIZ) {
12326847Smckusick 		((struct direct *)(dirbuf + prev))->d_reclen =
12336847Smckusick 		    DIRBLKSIZ - prev;
12345943Smckusic 		(*wrtfunc)(dirbuf, DIRBLKSIZ);
12355943Smckusic 		dirloc = 0;
12365943Smckusic 	}
12376847Smckusick 	blkcpy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen);
12386847Smckusick 	prev = dirloc;
12396847Smckusick 	dirloc += dp->d_reclen;
12405943Smckusic }
12415943Smckusic 
12425943Smckusic /*
12435943Smckusic  * flush out a directory that is finished.
12445943Smckusic  */
12455943Smckusic flushent(wrtfunc)
12465943Smckusic 	int (*wrtfunc)();
12475943Smckusic {
12486847Smckusick 
12495943Smckusic 	((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
12505943Smckusic 	(*wrtfunc)(dirbuf, dirloc);
12515943Smckusic 	dirloc = 0;
12525943Smckusic }
12535943Smckusic 
12545943Smckusic dirwrite(buf, size)
12555943Smckusic 	char *buf;
12565943Smckusic 	int size;
12575943Smckusic {
12586847Smckusick 
12595943Smckusic 	fwrite(buf, 1, size, df);
12605943Smckusic 	seekpt = ftell(df);
12615943Smckusic }
12625943Smckusic 
12635943Smckusic dcvt(odp, ndp)
12645943Smckusic 	register struct odirect *odp;
12655943Smckusic 	register struct direct *ndp;
12665943Smckusic {
12676847Smckusick 
12686846Smckusick 	blkclr((char *)ndp, (long)(sizeof *ndp));
12695943Smckusic 	ndp->d_ino =  odp->d_ino;
12705943Smckusic 	strncpy(ndp->d_name, odp->d_name, ODIRSIZ);
12715943Smckusic 	ndp->d_namlen = strlen(ndp->d_name);
12725943Smckusic 	ndp->d_reclen = DIRSIZ(ndp);
12735943Smckusic 	/*
12745943Smckusic 	 * this quickly calculates if this inode is a directory.
12755943Smckusic 	 * Currently not maintained.
12765943Smckusic 	 *
12775943Smckusic 	for (itp = inotab[INOHASH(odp->d_ino)]; itp; itp = itp->t_next) {
12785943Smckusic 		if (itp->t_ino != odp->d_ino)
12795943Smckusic 			continue;
12805943Smckusic 		ndp->d_fmt = IFDIR;
12815943Smckusic 		break;
12825943Smckusic 	}
12835943Smckusic 	 */
12845943Smckusic }
12855943Smckusic 
12865943Smckusic /*
12876289Smckusick  * Open a directory.
12886289Smckusick  * Modified to allow any random file to be a legal directory.
12896289Smckusick  */
12906289Smckusick DIR *
12916289Smckusick opendir(name)
12926289Smckusick 	char *name;
12936289Smckusick {
12946289Smckusick 	register DIR *dirp;
12956289Smckusick 
12966289Smckusick 	dirp = (DIR *)malloc(sizeof(DIR));
12976289Smckusick 	dirp->dd_fd = open(name, 0);
12986289Smckusick 	if (dirp->dd_fd == -1) {
12996846Smckusick 		free((char *)dirp);
13006289Smckusick 		return NULL;
13016289Smckusick 	}
13026289Smckusick 	dirp->dd_loc = 0;
13036289Smckusick 	return dirp;
13046289Smckusick }
13056289Smckusick 
13066289Smckusick /*
13076289Smckusick  * Seek to an entry in a directory.
13085943Smckusic  * Only values returned by ``telldir'' should be passed to seekdir.
13095943Smckusic  * Modified to have many directories based in one file.
13105943Smckusic  */
13115943Smckusic void
13125943Smckusic seekdir(dirp, loc, base)
13135943Smckusic 	register DIR *dirp;
13146846Smckusick 	daddr_t loc, base;
13155943Smckusic {
13166847Smckusick 
13175943Smckusic 	if (loc == telldir(dirp))
13185943Smckusic 		return;
13195943Smckusic 	loc -= base;
13205943Smckusic 	if (loc < 0)
13215943Smckusic 		fprintf(stderr, "bad seek pointer to seekdir %d\n", loc);
13226846Smckusick 	(void)lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0);
13235943Smckusic 	dirp->dd_loc = loc & (DIRBLKSIZ - 1);
13245943Smckusic 	if (dirp->dd_loc != 0)
13255943Smckusic 		dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ);
13265943Smckusic }
13275943Smckusic 
13285943Smckusic /*
13296844Smckusick  * get next entry in a directory.
13304700Smckusic  */
13316844Smckusick struct direct *
13326844Smckusick readdir(dirp)
13336844Smckusick 	register DIR *dirp;
13344610Smckusick {
13356844Smckusick 	register struct direct *dp;
13364700Smckusic 
13376844Smckusick 	for (;;) {
13386844Smckusick 		if (dirp->dd_loc == 0) {
13396844Smckusick 			dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
13406844Smckusick 			    DIRBLKSIZ);
13416844Smckusick 			if (dirp->dd_size <= 0)
13426844Smckusick 				return NULL;
13436844Smckusick 		}
13446844Smckusick 		if (dirp->dd_loc >= dirp->dd_size) {
13456844Smckusick 			dirp->dd_loc = 0;
13466844Smckusick 			continue;
13476844Smckusick 		}
13486844Smckusick 		dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc);
13496844Smckusick 		if (dp->d_reclen <= 0 ||
13506844Smckusick 		    dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc)
13516844Smckusick 			return NULL;
13526844Smckusick 		dirp->dd_loc += dp->d_reclen;
13536844Smckusick 		if (dp->d_ino == 0)
13546844Smckusick 			continue;
13556844Smckusick 		return (dp);
13565948Smckusic 	}
13574610Smckusick }
13584610Smckusick 
13594843Smckusic allocinotab(ino, seekpt)
13604837Smckusic 	ino_t ino;
13614843Smckusic 	daddr_t seekpt;
13624610Smckusick {
13634837Smckusic 	register struct inotab	*itp;
13644776Smckusic 
13654837Smckusic 	itp = (struct inotab *)calloc(1, sizeof(struct inotab));
13664837Smckusic 	itp->t_next = inotab[INOHASH(ino)];
13674837Smckusic 	inotab[INOHASH(ino)] = itp;
13684837Smckusic 	itp->t_ino = ino;
13694843Smckusic 	itp->t_seekpt = seekpt;
13704610Smckusick }
13714610Smckusick 
13724843Smckusic allocxtr(ino, name, flags)
13734837Smckusic 	ino_t ino;
13744843Smckusic 	char *name;
13754843Smckusic 	char flags;
13764610Smckusick {
13774843Smckusic 	register struct xtrlist	*xp, *pxp;
13784776Smckusic 
13794843Smckusic 	xp = (struct xtrlist *)calloc(1, sizeof(struct xtrlist) + strlen(name));
13804837Smckusic 	xp->x_next = xtrlist[INOHASH(ino)];
13814837Smckusic 	xtrlist[INOHASH(ino)] = xp;
13824837Smckusic 	xp->x_ino = ino;
13834843Smckusic 	strcpy(xp->x_name, name);
13844837Smckusic 	xtrcnt++;
13854843Smckusic 	xp->x_flags = flags;
13864843Smckusic 	for (pxp = xp->x_next; pxp; pxp = pxp->x_next)
13874843Smckusic 		if (pxp->x_ino == ino && (pxp->x_flags & XLINKED) == 0) {
13884843Smckusic 			xp->x_flags |= XLINKED;
13894843Smckusic 			xp->x_linkedto = pxp;
13904843Smckusic 			xtrcnt--;
13914843Smckusic 			break;
13924843Smckusic 		}
1393*8374Smckusick 	if (!vflag)
1394*8374Smckusick 		return;
13954843Smckusic 	if (xp->x_flags & XLINKED)
13964843Smckusic 		fprintf(stdout, "%s: linked to %s\n", xp->x_name, pxp->x_name);
13974843Smckusic 	else if (xp->x_flags & XISDIR)
13984843Smckusic 		fprintf(stdout, "%s: directory inode %u\n", xp->x_name, ino);
13994843Smckusic 	else
14004843Smckusic 		fprintf(stdout, "%s: inode %u\n", xp->x_name, ino);
14014610Smckusick }
14024610Smckusick 
14035038Smckusic done(exitcode)
14045038Smckusic 	int exitcode;
14054610Smckusick {
14066847Smckusick 
14075038Smckusic 	unlink(dirfile);
14085038Smckusic 	exit(exitcode);
14094610Smckusick }
1410