xref: /csrg-svn/sbin/restore/main.c (revision 10202)
16847Smckusick /* Copyright (c) 1982 Regents of the University of California */
24610Smckusick 
36846Smckusick #ifndef lint
4*10202Smckusick char version[] = "@(#)main.c 2.17 01/08/83";
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 #include <sys/param.h>
286847Smckusick #include <sys/inode.h>
296847Smckusick #include <sys/fs.h>
306847Smckusick #include <dir.h>
316847Smckusick #include <stat.h>
326847Smckusick #include <dumprestor.h>
338296Smckusick #include <sys/ioctl.h>
345038Smckusic #include <sys/mtio.h>
354610Smckusick 
365943Smckusic #define ODIRSIZ 14
375038Smckusic struct odirect {
385038Smckusic 	u_short	d_ino;
395943Smckusic 	char	d_name[ODIRSIZ];
405038Smckusic };
415038Smckusic 
425327Smckusic #define	MWORD(m,i) (m[(unsigned)(i-1)/NBBY])
435327Smckusic #define	MBIT(i)	(1<<((unsigned)(i-1)%NBBY))
444610Smckusick #define	BIS(i,w)	(MWORD(w,i) |=  MBIT(i))
454610Smckusick #define	BIC(i,w)	(MWORD(w,i) &= ~MBIT(i))
464610Smckusick #define	BIT(i,w)	(MWORD(w,i) & MBIT(i))
474610Smckusick 
486846Smckusick ino_t	ino;
494610Smckusick 
50*10202Smckusick int	eflag = 0, hflag = 1, mflag = 1, tflag = 0, vflag = 0, yflag = 0;
51*10202Smckusick int	cvtflag = 0;
52*10202Smckusick #define vprintf		if (vflag) fprintf
534776Smckusic 
546844Smckusick long	fssize;
554610Smckusick char	tapename[] = "/dev/rmt8";
564610Smckusick char	*magtape = tapename;
575038Smckusic int	mt;
585038Smckusic int	dumpnum = 1;
595038Smckusic int	volno = 1;
605038Smckusic int	curblk = 0;
615038Smckusic int	bct = NTREC+1;
625038Smckusic char	tbf[NTREC*TP_BSIZE];
634610Smckusick 
644610Smckusick daddr_t	seekpt;
654837Smckusic FILE	*df;
665943Smckusic DIR	*dirp;
674837Smckusic int	ofile;
688485Smckusick char	dirfile[] = "/tmp/rstaXXXXXX";
696289Smckusick char	lnkbuf[MAXPATHLEN + 1];
706289Smckusick int	pathlen;
714610Smckusick 
724837Smckusic #define INOHASH(val) (val % MAXINO)
734837Smckusic struct inotab {
744837Smckusic 	struct inotab *t_next;
754610Smckusick 	ino_t	t_ino;
764610Smckusick 	daddr_t	t_seekpt;
77*10202Smckusick 	time_t t_timep[2];
784837Smckusic } *inotab[MAXINO];
798485Smckusick int maxino = 0;
804610Smckusick 
814837Smckusic #define XISDIR	1
824610Smckusick #define XTRACTD	2
834610Smckusick #define XINUSE	4
844837Smckusic #define XLINKED	8
854610Smckusick struct xtrlist {
864837Smckusic 	struct xtrlist	*x_next;
874837Smckusic 	struct xtrlist	*x_linkedto;
884837Smckusic 	ino_t		x_ino;
894837Smckusic 	char		x_flags;
904843Smckusic 	char 		x_name[1];
914843Smckusic 	/* actually longer */
924837Smckusic } *xtrlist[MAXINO];
934776Smckusic int xtrcnt = 0;
948505Smckusick struct xtrlist *entry;
958505Smckusick struct xtrlist *unknown;
968505Smckusick struct xtrlist *allocxtr();
974610Smckusick 
985327Smckusic char	*dumpmap;
995327Smckusic char	*clrimap;
1004610Smckusick 
1015327Smckusic char	clearedbuf[MAXBSIZE];
1025327Smckusic 
1034837Smckusic extern char *ctime();
1046846Smckusick extern int seek();
1054843Smckusic ino_t search();
1065943Smckusic int dirwrite();
1076849Smckusick #ifdef RRESTOR
1086849Smckusick char *host;
1096849Smckusick #endif
1104610Smckusick 
1116846Smckusick main(argc, argv)
1124700Smckusic 	int argc;
1134700Smckusic 	char *argv[];
1144610Smckusick {
1154610Smckusick 	register char *cp;
1164610Smckusick 	char command;
1174700Smckusic 	int (*signal())();
1184610Smckusick 	int done();
1194610Smckusick 
1204843Smckusic 	if (signal(SIGINT, done) == SIG_IGN)
1214843Smckusic 		signal(SIGINT, SIG_IGN);
1224843Smckusic 	if (signal(SIGTERM, done) == SIG_IGN)
1234843Smckusic 		signal(SIGTERM, SIG_IGN);
1246844Smckusick 	mktemp(dirfile);
1254610Smckusick 	if (argc < 2) {
1264610Smckusick usage:
127*10202Smckusick 		fprintf(stderr, "Usage: restor xfhmsvy file file... or restor tf\n");
1284700Smckusic 		done(1);
1294610Smckusick 	}
1304610Smckusick 	argv++;
1314610Smckusick 	argc -= 2;
132*10202Smckusick 	command = '\0';
1334610Smckusick 	for (cp = *argv++; *cp; cp++) {
1344610Smckusick 		switch (*cp) {
1354610Smckusick 		case '-':
1364610Smckusick 			break;
1378302Smckusick 		case 'c':
1388302Smckusick 			cvtflag++;
1398302Smckusick 			break;
1404610Smckusick 		case 'f':
1414610Smckusick 			magtape = *argv++;
1426849Smckusick #ifdef RRESTOR
1436849Smckusick 		{ char *index();
1446849Smckusick 		  host = magtape;
1456849Smckusick 		  magtape = index(host, ':');
1466849Smckusick 		  if (magtape == 0) {
1476849Smckusick nohost:
1486849Smckusick 			msg("need keyletter ``f'' and device ``host:tape''");
1496849Smckusick 			done(1);
1506849Smckusick 		  }
1516849Smckusick 		  *magtape++ = 0;
1526849Smckusick 		  if (rmthost(host) == 0)
1536849Smckusick 			done(1);
1546849Smckusick 		}
1556849Smckusick #endif
1564610Smckusick 			argc--;
1574610Smckusick 			break;
1584610Smckusick 		/* s dumpnum (skip to) for multifile dump tapes */
1594610Smckusick 		case 's':
1604610Smckusick 			dumpnum = atoi(*argv++);
1616847Smckusick 			if (dumpnum <= 0) {
1624700Smckusic 				fprintf(stderr, "Dump number must be a positive integer\n");
1634700Smckusic 				done(1);
1644610Smckusick 			}
1654610Smckusick 			argc--;
1664610Smckusick 			break;
1674610Smckusick 		case 'h':
168*10202Smckusick 			hflag = 0;
1694610Smckusick 			break;
1704610Smckusick 		case 'm':
171*10202Smckusick 			mflag = 0;
1724610Smckusick 			break;
1738374Smckusick 		case 'x':
174*10202Smckusick 			if (command != '\0') {
175*10202Smckusick 				fprintf(stderr, "x and t are exclusive\n");
176*10202Smckusick 				goto usage;
177*10202Smckusick 			}
178*10202Smckusick 			command = 'x';
179*10202Smckusick 			break;
1808374Smckusick 		case 'v':
1818374Smckusick 			vflag++;
1828374Smckusick 			break;
1838374Smckusick 		case 'y':
1848374Smckusick 			yflag++;
1858374Smckusick 			break;
1864610Smckusick 		case 't':
187*10202Smckusick 			if (command != '\0') {
188*10202Smckusick 				fprintf(stderr, "x and t are exclusive\n");
189*10202Smckusick 				goto usage;
190*10202Smckusick 			}
191*10202Smckusick 			command = 't';
192*10202Smckusick 			tflag++;
193*10202Smckusick 			vflag++;
1944610Smckusick 			break;
1954610Smckusick 		default:
1964700Smckusic 			fprintf(stderr, "Bad key character %c\n", *cp);
1974610Smckusick 			goto usage;
1984610Smckusick 		}
1994610Smckusick 	}
200*10202Smckusick 	if (command == '\0') {
201*10202Smckusick 		fprintf(stderr, "must specify x or t\n");
202*10202Smckusick 		goto usage;
203*10202Smckusick 	}
2046849Smckusick #ifdef RRESTOR
2056849Smckusick 	if (host == 0)
2066849Smckusick 		goto nohost;
2076849Smckusick #endif
2089405Smckusick 	setuid(getuid());	/* no longer need or want root privileges */
2094610Smckusick 	doit(command, argc, argv);
2104700Smckusic 	done(0);
2114610Smckusick }
2124610Smckusick 
2134610Smckusick doit(command, argc, argv)
2144700Smckusic 	char	command;
2154700Smckusic 	int	argc;
2164700Smckusic 	char	*argv[];
2174610Smckusick {
2185038Smckusic 	struct mtop tcom;
219*10202Smckusick 	char	*ststore();
220*10202Smckusick 	register struct inotab *itp;
221*10202Smckusick 	register struct xtrlist *xp;
222*10202Smckusick 	struct xtrlist **xpp;
223*10202Smckusick 	ino_t	d;
224*10202Smckusick 	int	xtrfile(), xtrskip(), xtrcvtdir(), xtrcvtskip(),
225*10202Smckusick 		xtrlnkfile(), xtrlnkskip(), null();
226*10202Smckusick 	int	mode, uid, gid, i;
227*10202Smckusick 	struct	stat stbuf;
228*10202Smckusick 	time_t	timep[2];
229*10202Smckusick 	char	name[BUFSIZ + 1];
2305038Smckusic 
231*10202Smckusick 	if (argc == 0) {
232*10202Smckusick 		argc++;
233*10202Smckusick 		*--argv = ".";
234*10202Smckusick 	}
2356849Smckusick #ifdef RRESTOR
2366849Smckusick 	if ((mt = rmtopen(magtape, 0)) < 0) {
2376849Smckusick #else
2384610Smckusick 	if ((mt = open(magtape, 0)) < 0) {
2396849Smckusick #endif
2404700Smckusic 		fprintf(stderr, "%s: cannot open tape\n", magtape);
2414700Smckusic 		done(1);
2424610Smckusick 	}
2434843Smckusic 	if (dumpnum != 1) {
2444610Smckusick 		tcom.mt_op = MTFSF;
2454610Smckusick 		tcom.mt_count = dumpnum -1;
2466849Smckusick #ifdef RRESTOR
2476849Smckusick 		rmtioctl(MTFSF,dumpnum - 1);
2486849Smckusick #else
2494843Smckusic 		if (ioctl(mt,MTIOCTOP,&tcom) < 0)
2504610Smckusick 			perror("ioctl MTFSF");
2516849Smckusick #endif
2524610Smckusick 	}
253*10202Smckusick 	bzero(clearedbuf, (long)MAXBSIZE);
2548369Smckusick 	if (readhdr(&spcl) == 0) {
2558369Smckusick 		bct--; /* push back this block */
2568369Smckusick 		cvtflag++;
2574610Smckusick 		if (readhdr(&spcl) == 0) {
2584700Smckusic 			fprintf(stderr, "Tape is not a dump tape\n");
2594700Smckusic 			done(1);
2604610Smckusick 		}
2618369Smckusick 		fprintf(stderr, "Converting to new file system format.\n");
2628369Smckusick 	}
263*10202Smckusick 	if (vflag) {
2644843Smckusic 		fprintf(stdout, "Dump   date: %s", ctime(&spcl.c_date));
2654843Smckusic 		fprintf(stdout, "Dumped from: %s", ctime(&spcl.c_ddate));
2664837Smckusic 	}
267*10202Smckusick 	df = fopen(dirfile, "w");
268*10202Smckusick 	if (df == 0) {
269*10202Smckusick 		fprintf(stderr,
270*10202Smckusick 		    "restor: %s - cannot create directory temporary\n",
271*10202Smckusick 		    dirfile);
272*10202Smckusick 		done(1);
273*10202Smckusick 	}
2746844Smckusick 	if (stat(".", &stbuf) < 0) {
2756844Smckusick 		fprintf(stderr, "cannot stat .\n");
2766844Smckusick 		done(1);
2776844Smckusick 	}
2786844Smckusick 	fssize = stbuf.st_blksize;
2798485Smckusick 	if (fssize <= 0 || ((fssize - 1) & fssize) != 0) {
2808485Smckusick 		fprintf(stderr, "bad block size %d\n", fssize);
2818485Smckusick 		done(1);
2828485Smckusick 	}
2834837Smckusic 	if (checkvol(&spcl, 1) == 0) {
2844837Smckusic 		fprintf(stderr, "Tape is not volume 1 of the dump\n");
2854837Smckusic 	}
2866844Smckusick 	clrimap = 0;
2876844Smckusick 	dumpmap = 0;
2888505Smckusick 	unknown = allocxtr(0, "name unknown - not extracted", 0);
289*10202Smckusick 	pass1();  /* This sets the various maps on the way by */
2904843Smckusic 	while (argc--) {
2914837Smckusic 		if ((d = psearch(*argv)) == 0 || BIT(d,dumpmap) == 0) {
2928374Smckusick 			fprintf(stderr, "%s: not on tape\n", *argv++);
2934837Smckusic 			continue;
2944610Smckusick 		}
295*10202Smckusick 		if (mflag && !tflag)
2964843Smckusic 			checkdir(*argv);
2976847Smckusick 		if (hflag)
2984837Smckusic 			getleaves(d, *argv++);
2994843Smckusic 		else
3008505Smckusick 			(void)allocxtr(d, *argv++, XINUSE);
3014837Smckusic 	}
3024843Smckusic 	if (dumpnum > 1) {
3035038Smckusic 		/*
3045038Smckusic 		 * if this is a multi-dump tape we always start with
3055038Smckusic 		 * volume 1, so as to avoid accidentally restoring
3065038Smckusic 		 * from a different dump!
3075038Smckusic 		 */
3085038Smckusic 		resetmt();
3095038Smckusic 		dumpnum = 1;
3105038Smckusic 		volno = 1;
3115038Smckusic 		readhdr(&spcl);
3125038Smckusic 		goto rbits;
3134837Smckusic 	}
3145038Smckusic newvol:
3156849Smckusick #ifdef RRESTOR
3166849Smckusick 	rmtclose();
3176849Smckusick #else
3186847Smckusick 	close(mt);
3196849Smckusick #endif
320*10202Smckusick 	if (tflag)
321*10202Smckusick 		return;
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++;
3658485Smckusick 			fprintf(stderr, "resync restor, skipped %d 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;
3778505Smckusick 		entry = unknown;
3788505Smckusick 		entry->x_ino = d;
3798505Smckusick 		for (xp = xtrlist[INOHASH(d)]; xp; xp = xp->x_next) {
3808505Smckusick 			if (d != xp->x_ino || (xp->x_flags & XLINKED))
3818505Smckusick 				continue;
3828505Smckusick 			entry = xp;
383*10202Smckusick 			timep[0] = spcl.c_dinode.di_atime;
384*10202Smckusick 			timep[1] = spcl.c_dinode.di_mtime;
3854837Smckusic 			mode = spcl.c_dinode.di_mode;
3864837Smckusic 			if (mflag)
3874843Smckusic 				strcpy(name, xp->x_name);
3884837Smckusic 			else
3894837Smckusic 				sprintf(name, "%u", xp->x_ino);
3904837Smckusic 			switch (mode & IFMT) {
3914837Smckusic 			default:
3926847Smckusick 				fprintf(stderr, "%s: unknown file mode 0%o\n",
3936847Smckusick 				    name, mode);
3948505Smckusick 				xp->x_flags |= XTRACTD;
3954837Smckusic 				xtrcnt--;
3964837Smckusic 				goto skipfile;
3974837Smckusic 			case IFCHR:
3984837Smckusic 			case IFBLK:
399*10202Smckusick 				vprintf(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);
4028505Smckusick 					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*10202Smckusick 					for (itp = inotab[INOHASH(d)];
411*10202Smckusick 					     itp; itp = itp->t_next) {
412*10202Smckusick 						if (itp->t_ino != d)
413*10202Smckusick 							continue;
414*10202Smckusick 						itp->t_timep[0] = timep[0];
415*10202Smckusick 						itp->t_timep[1] = timep[1];
416*10202Smckusick 						break;
417*10202Smckusick 					}
418*10202Smckusick 					if (itp == 0)
419*10202Smckusick 						fprintf(stderr, "missing directory entry\n");
420*10202Smckusick 					vprintf(stdout, "extract directory %s\n", name);
4214837Smckusic 					strncat(name, "/.", BUFSIZ);
4224843Smckusic 					checkdir(name);
4236844Smckusick 					chown(xp->x_name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
4244837Smckusic 					getfile(null, null, spcl.c_dinode.di_size);
4254837Smckusic 					break;
4264610Smckusick 				}
427*10202Smckusick 				vprintf(stdout, "extract file %s\n", name);
4286844Smckusick 				if ((ofile = creat(name, 0666)) < 0) {
4295038Smckusic 					fprintf(stderr, "%s: cannot create file\n", name);
4308505Smckusick 					xp->x_flags |= XTRACTD;
4315038Smckusic 					xtrcnt--;
4325038Smckusic 					goto skipfile;
4335038Smckusic 				}
4346844Smckusick 				chown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
435*10202Smckusick 				if (cvtflag) {
4365038Smckusic 					getfile(xtrcvtdir, xtrcvtskip,
4375038Smckusic 					    spcl.c_dinode.di_size);
4385943Smckusic 					flushent(xtrfile);
4395943Smckusic 				} else
4405038Smckusic 					getfile(xtrfile, xtrskip,
4415038Smckusic 					    spcl.c_dinode.di_size);
4426844Smckusick 				close(ofile);
4435038Smckusic 				break;
4446289Smckusick 			case IFLNK:
4459402Ssam 				/*
4469402Ssam 				 * Some early dump tapes have symbolic links
4479402Ssam 				 * present without the associated data blocks.
4489402Ssam 				 * This hack avoids trashing a file system with
4499402Ssam 				 * inodes with missing data blocks.
4509402Ssam 				 */
4519402Ssam 				if (spcl.c_count == 0) {
452*10202Smckusick 					vprintf(stdout, "%s: 0 length symbolic link (ignored)\n", name);
4539402Ssam 					xp->x_flags |= XTRACTD;
4549402Ssam 					xtrcnt--;
4559402Ssam 					goto skipfile;
4569402Ssam 				}
457*10202Smckusick 				vprintf(stdout, "extract symbolic link %s\n", name);
4586289Smckusick 				uid = spcl.c_dinode.di_uid;
4596289Smckusick 				gid = spcl.c_dinode.di_gid;
4606289Smckusick 				lnkbuf[0] = '\0';
4616289Smckusick 				pathlen = 0;
4626289Smckusick 				getfile(xtrlnkfile, xtrlnkskip, spcl.c_dinode.di_size);
4636844Smckusick 				if (symlink(lnkbuf, name) < 0) {
4646289Smckusick 					fprintf(stderr, "%s: cannot create symbolic link\n", name);
4658505Smckusick 					xp->x_flags |= XTRACTD;
4666289Smckusick 					xtrcnt--;
4676289Smckusick 					goto finished;
4686289Smckusick 				}
4696844Smckusick 				chown(name, uid, gid);
4706289Smckusick 				break;
4714837Smckusic 			case IFREG:
472*10202Smckusick 				vprintf(stdout, "extract file %s\n", name);
4736844Smckusick 				if ((ofile = creat(name, 0666)) < 0) {
4744837Smckusic 					fprintf(stderr, "%s: cannot create file\n", name);
4758505Smckusick 					xp->x_flags |= XTRACTD;
4764837Smckusic 					xtrcnt--;
4774837Smckusic 					goto skipfile;
4784837Smckusic 				}
4796844Smckusick 				chown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
4805038Smckusic 				getfile(xtrfile, xtrskip, spcl.c_dinode.di_size);
4816844Smckusick 				close(ofile);
4824837Smckusic 				break;
4834610Smckusick 			}
4846844Smckusick 			chmod(name, mode);
485*10202Smckusick 			utime(name, timep);
4868505Smckusick 			xp->x_flags |= XTRACTD;
4874837Smckusic 			xtrcnt--;
4884837Smckusic 			goto finished;
4894837Smckusic 		}
4904837Smckusic skipfile:
4914837Smckusic 		getfile(null, null, spcl.c_dinode.di_size);
4924700Smckusic finished:
4934837Smckusic 		;
4944837Smckusic 	}
4954837Smckusic 	if (xtrcnt == 0 && !mflag)
4964837Smckusic 		return;
4974837Smckusic 	for (xpp = xtrlist; xpp < &xtrlist[MAXINO]; xpp++) {
4984837Smckusic 		for (xp = *xpp; xp; xp = xp->x_next) {
499*10202Smckusick 			if (mflag && (xp->x_flags & XISDIR)) {
500*10202Smckusick 				for (itp = inotab[INOHASH(xp->x_ino)];
501*10202Smckusick 				     itp; itp = itp->t_next) {
502*10202Smckusick 					if (itp->t_ino != xp->x_ino)
503*10202Smckusick 						continue;
504*10202Smckusick 					utime(xp->x_name, itp->t_timep);
505*10202Smckusick 					break;
506*10202Smckusick 				}
507*10202Smckusick 				if (itp == 0)
508*10202Smckusick 					fprintf(stderr, "missing dir entry\n");
509*10202Smckusick 			}
5104837Smckusic 			if (xp->x_flags & XTRACTD)
5114837Smckusic 				continue;
5124837Smckusic 			if ((xp->x_flags & XLINKED) == 0) {
5134837Smckusic 				fprintf(stderr, "cannot find file %s\n",
5144837Smckusic 					xp->x_name);
5154837Smckusic 				continue;
5164837Smckusic 			}
5174843Smckusic 			if (!mflag)
5184843Smckusic 				continue;
519*10202Smckusick 			vprintf(stdout, "link %s to %s\n",
5208374Smckusick 					xp->x_linkedto->x_name, xp->x_name);
5216844Smckusick 			if (link(xp->x_linkedto->x_name, xp->x_name) < 0)
5224843Smckusic 				fprintf(stderr, "link %s to %s failed\n",
5234837Smckusic 					xp->x_linkedto->x_name, xp->x_name);
5244610Smckusick 		}
5254837Smckusic 	}
5264837Smckusic }
5274837Smckusic 
5284610Smckusick /*
5294610Smckusick  * Read the tape, bulding up a directory structure for extraction
5304610Smckusick  * by name
5314610Smckusick  */
532*10202Smckusick pass1()
5334610Smckusick {
5344776Smckusic 	register int i;
5354837Smckusic 	register struct dinode *ip;
5364837Smckusic 	struct direct nulldir;
5375038Smckusic 	char buf[TP_BSIZE];
5385943Smckusic 	int putdir(), null(), dirwrite();
5394610Smckusick 
5405943Smckusic 	nulldir.d_ino = 1;
5415943Smckusic 	nulldir.d_namlen = 1;
5425943Smckusic 	strncpy(nulldir.d_name, "/", nulldir.d_namlen);
5435943Smckusic 	nulldir.d_reclen = DIRSIZ(&nulldir);
5444610Smckusick 	while (gethead(&spcl) == 0) {
5454700Smckusic 		fprintf(stderr, "Can't find directory header!\n");
5464610Smckusick 	}
5474610Smckusick 	for (;;) {
5484610Smckusick 		if (checktype(&spcl, TS_BITS) == 1) {
5496844Smckusick 			readbits(&dumpmap);
5504610Smckusick 			continue;
5514610Smckusick 		}
5524610Smckusick 		if (checktype(&spcl, TS_CLRI) == 1) {
5536844Smckusick 			readbits(&clrimap);
5544610Smckusick 			continue;
5554610Smckusick 		}
5564610Smckusick 		if (checktype(&spcl, TS_INODE) == 0) {
5574610Smckusick finish:
558*10202Smckusick 			fclose(df);
559*10202Smckusick 			dirp = opendir(dirfile);
560*10202Smckusick 			if (dirp == NULL)
561*10202Smckusick 				perror("opendir");
5625038Smckusic 			resetmt();
5634610Smckusick 			return;
5644610Smckusick 		}
5654610Smckusick 		ip = &spcl.c_dinode;
5664610Smckusick 		i = ip->di_mode & IFMT;
5674610Smckusick 		if (i != IFDIR) {
5684610Smckusick 			goto finish;
5694610Smckusick 		}
5704843Smckusic 		allocinotab(spcl.c_inumber, seekpt);
571*10202Smckusick 		getfile(putdir, null, spcl.c_dinode.di_size);
572*10202Smckusick 		putent(&nulldir, dirwrite);
573*10202Smckusick 		flushent(dirwrite);
5744610Smckusick 	}
5754610Smckusick }
5764610Smckusick 
5774610Smckusick /*
5784843Smckusic  * Put the directory entries in the directory file
5794843Smckusic  */
5804843Smckusic putdir(buf, size)
5814843Smckusic 	char *buf;
5824843Smckusic 	int size;
5834843Smckusic {
5845038Smckusic 	struct direct cvtbuf;
5855038Smckusic 	register struct odirect *odp;
5865038Smckusic 	struct odirect *eodp;
5874843Smckusic 	register struct direct *dp;
5886289Smckusick 	long loc, i;
5894843Smckusic 
590*10202Smckusick 	if (cvtflag) {
5915038Smckusic 		eodp = (struct odirect *)&buf[size];
5925038Smckusic 		for (odp = (struct odirect *)buf; odp < eodp; odp++)
5935038Smckusic 			if (odp->d_ino != 0) {
5945038Smckusic 				dcvt(odp, &cvtbuf);
5955943Smckusic 				putent(&cvtbuf, dirwrite);
5965038Smckusic 			}
5975038Smckusic 	} else {
5985943Smckusic 		for (loc = 0; loc < size; ) {
5995943Smckusic 			dp = (struct direct *)(buf + loc);
6006289Smckusick 			i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1));
6016289Smckusick 			if (dp->d_reclen <= 0 || dp->d_reclen > i) {
6026289Smckusick 				loc += i;
6036289Smckusick 				continue;
6046289Smckusick 			}
6056289Smckusick 			loc += dp->d_reclen;
6066847Smckusick 			if (dp->d_ino != 0) {
6075943Smckusic 				putent(dp, dirwrite);
6086847Smckusick 			}
6095943Smckusic 		}
6105038Smckusic 	}
6114843Smckusic }
6124843Smckusic 
6134843Smckusic /*
6144843Smckusic  *	Recursively find names and inumbers of all files in subtree
6154843Smckusic  *	pname and put them in xtrlist[]
6164843Smckusic  */
6174843Smckusic getleaves(ino, pname)
6184843Smckusic 	ino_t ino;
6194843Smckusic 	char *pname;
6204843Smckusic {
6214843Smckusic 	register struct inotab *itp;
6224843Smckusic 	int namelen;
6236846Smckusick 	daddr_t bpt;
6245943Smckusic 	register struct direct *dp;
6255943Smckusic 	char locname[BUFSIZ + 1];
6264843Smckusic 
6274843Smckusic 	if (BIT(ino, dumpmap) == 0) {
628*10202Smckusick 		vprintf(stdout, "%s: not on the tape\n", pname);
6294843Smckusic 		return;
6304843Smckusic 	}
6314843Smckusic 	for (itp = inotab[INOHASH(ino)]; itp; itp = itp->t_next) {
6324843Smckusic 		if (itp->t_ino != ino)
6334843Smckusic 			continue;
6344843Smckusic 		/*
6354843Smckusic 		 * pname is a directory name
6364843Smckusic 		 */
6378505Smckusick 		(void)allocxtr(ino, pname, XISDIR);
6384843Smckusic 		/*
6394843Smckusic 		 * begin search through the directory
6404843Smckusic 		 * skipping over "." and ".."
6414843Smckusic 		 */
6424843Smckusic 		strncpy(locname, pname, BUFSIZ);
6434843Smckusic 		strncat(locname, "/", BUFSIZ);
6444843Smckusic 		namelen = strlen(locname);
6455943Smckusic 		seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
6465943Smckusic 		dp = readdir(dirp);
6475943Smckusic 		dp = readdir(dirp);
6485943Smckusic 		dp = readdir(dirp);
6495943Smckusic 		bpt = telldir(dirp);
6504843Smckusic 		/*
6514843Smckusic 		 * "/" signals end of directory
6524843Smckusic 		 */
653*10202Smckusick 		while (dp != NULL &&
654*10202Smckusick 		    !(dp->d_namlen == 1 && dp->d_name[0] == '/')) {
6554843Smckusic 			locname[namelen] = '\0';
6565943Smckusic 			if (namelen + dp->d_namlen >= BUFSIZ) {
657*10202Smckusick 				fprintf(stderr, "%s%s: name exceeds %d char\n",
6585943Smckusic 					locname, dp->d_name, BUFSIZ);
659*10202Smckusick 			} else {
660*10202Smckusick 				strncat(locname, dp->d_name, dp->d_namlen);
661*10202Smckusick 				getleaves(dp->d_ino, locname);
662*10202Smckusick 				seekdir(dirp, bpt, itp->t_seekpt);
6634843Smckusic 			}
6645943Smckusic 			dp = readdir(dirp);
6655943Smckusic 			bpt = telldir(dirp);
6664843Smckusic 		}
6674843Smckusic 		return;
6684843Smckusic 	}
6694843Smckusic 	/*
6704843Smckusic 	 * locname is name of a simple file
6714843Smckusic 	 */
6728505Smckusick 	(void)allocxtr(ino, pname, XINUSE);
6734843Smckusic }
6744843Smckusic 
6754843Smckusic /*
6764843Smckusic  * Search the directory tree rooted at inode ROOTINO
6774843Smckusic  * for the path pointed at by n
6784843Smckusic  */
6794843Smckusic psearch(n)
6804843Smckusic 	char	*n;
6814843Smckusic {
6824843Smckusic 	register char *cp, *cp1;
6834843Smckusic 	char c;
6844843Smckusic 
6854843Smckusic 	ino = ROOTINO;
6864843Smckusic 	if (*(cp = n) == '/')
6874843Smckusic 		cp++;
6884843Smckusic next:
6894843Smckusic 	cp1 = cp + 1;
6904843Smckusic 	while (*cp1 != '/' && *cp1)
6914843Smckusic 		cp1++;
6924843Smckusic 	c = *cp1;
6934843Smckusic 	*cp1 = 0;
6944843Smckusic 	ino = search(ino, cp);
6954843Smckusic 	if (ino == 0) {
6964843Smckusic 		*cp1 = c;
6974843Smckusic 		return(0);
6984843Smckusic 	}
6994843Smckusic 	*cp1 = c;
7004843Smckusic 	if (c == '/') {
7014843Smckusic 		cp = cp1+1;
7024843Smckusic 		goto next;
7034843Smckusic 	}
7044843Smckusic 	return(ino);
7054843Smckusic }
7064843Smckusic 
7074843Smckusic /*
7084843Smckusic  * search the directory inode ino
7094843Smckusic  * looking for entry cp
7104843Smckusic  */
7114843Smckusic ino_t
7124843Smckusic search(inum, cp)
7134843Smckusic 	ino_t	inum;
7144843Smckusic 	char	*cp;
7154843Smckusic {
7165943Smckusic 	register struct direct *dp;
7174843Smckusic 	register struct inotab *itp;
7185943Smckusic 	int len;
7194843Smckusic 
7204843Smckusic 	for (itp = inotab[INOHASH(inum)]; itp; itp = itp->t_next)
7214843Smckusic 		if (itp->t_ino == inum)
7224843Smckusic 			goto found;
7234843Smckusic 	return(0);
7244843Smckusic found:
7255943Smckusic 	seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
7265943Smckusic 	len = strlen(cp);
7274843Smckusic 	do {
7285943Smckusic 		dp = readdir(dirp);
7295943Smckusic 		if (dp->d_namlen == 1 && dp->d_name[0] == '/')
7304843Smckusic 			return(0);
7315943Smckusic 	} while (dp->d_namlen != len || strncmp(dp->d_name, cp, len));
7325943Smckusic 	return(dp->d_ino);
7334843Smckusic }
7344843Smckusic 
7354843Smckusic /*
7364610Smckusick  * Do the file extraction, calling the supplied functions
7374610Smckusick  * with the blocks
7384610Smckusick  */
7394700Smckusic getfile(f1, f2, size)
7404700Smckusic 	int	(*f2)(), (*f1)();
7416846Smckusick 	off_t	size;
7424610Smckusick {
7434776Smckusic 	register int i;
7445327Smckusic 	char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
7454837Smckusic 	union u_spcl addrblk;
7464837Smckusic #	define addrblock addrblk.s_spcl
7474610Smckusick 
7484837Smckusic 	addrblock = spcl;
7494610Smckusick 	for (;;) {
7504837Smckusic 		for (i = 0; i < addrblock.c_count; i++) {
7514837Smckusic 			if (addrblock.c_addr[i]) {
7524776Smckusic 				readtape(&buf[curblk++][0]);
7536844Smckusick 				if (curblk == fssize / TP_BSIZE) {
7544776Smckusic 					(*f1)(buf, size > TP_BSIZE ?
7556844Smckusick 					     (long) (fssize) :
7564776Smckusic 					     (curblk - 1) * TP_BSIZE + size);
7574776Smckusic 					curblk = 0;
7584776Smckusic 				}
7595327Smckusic 			} else {
7604776Smckusic 				if (curblk > 0) {
7614776Smckusic 					(*f1)(buf, size > TP_BSIZE ?
7624776Smckusic 					     (long) (curblk * TP_BSIZE) :
7634776Smckusic 					     (curblk - 1) * TP_BSIZE + size);
7644776Smckusic 					curblk = 0;
7654776Smckusic 				}
7665327Smckusic 				(*f2)(clearedbuf, size > TP_BSIZE ?
7675327Smckusic 					(long) TP_BSIZE : size);
7684610Smckusick 			}
7694776Smckusic 			if ((size -= TP_BSIZE) <= 0) {
7708485Smckusick 				gethead(&spcl);
7714776Smckusic 				goto out;
7724610Smckusick 			}
7734610Smckusick 		}
7744837Smckusic 		if (gethead(&addrblock) == 0) {
7758485Smckusick 			fprintf(stderr, "Missing address (header) block for %s\n",
7768505Smckusick 				entry->x_name);
7778485Smckusick 			spcl.c_magic = 0;
7788485Smckusick 			goto out;
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 
8408485Smckusick 	fprintf(stderr, "unallocated block in directory %s\n",
8418505Smckusick 		entry->x_name);
8425943Smckusic 	xtrskip(buf, size);
8435038Smckusic }
8446289Smckusick 
8456289Smckusick xtrlnkfile(buf, size)
8466289Smckusick 	char	*buf;
8476289Smckusick 	long	size;
8486289Smckusick {
8496847Smckusick 
8506289Smckusick 	pathlen += size;
8516289Smckusick 	if (pathlen > MAXPATHLEN) {
8526289Smckusick 		fprintf(stderr, "symbolic link name: %s; too long %d\n",
8536289Smckusick 		    buf, size);
8546289Smckusick 		done(1);
8556289Smckusick 	}
8566289Smckusick 	strcat(lnkbuf, buf);
8576289Smckusick }
8586289Smckusick 
8596289Smckusick xtrlnkskip(buf, size)
8606289Smckusick 	char *buf;
8616289Smckusick 	long size;
8626289Smckusick {
8636847Smckusick 
8646846Smckusick #ifdef lint
8656846Smckusick 	buf = buf, size = size;
8666846Smckusick #endif
8678485Smckusick 	fprintf(stderr, "unallocated block in symbolic link %s\n",
8688505Smckusick 		entry->x_name);
8696289Smckusick 	done(1);
8706289Smckusick }
8714843Smckusic 
8724843Smckusic null() {;}
8734843Smckusic 
8744843Smckusic /*
8754776Smckusic  * Do the tape i/o, dealing with volume changes
8764610Smckusick  * etc..
8774610Smckusick  */
8784610Smckusick readtape(b)
8794700Smckusic 	char *b;
8804610Smckusick {
8816846Smckusick 	register long i;
8826847Smckusick 	struct u_spcl tmpbuf;
8836845Smckusick 	char c;
8844610Smckusick 
8854610Smckusick 	if (bct >= NTREC) {
8864610Smckusick 		for (i = 0; i < NTREC; i++)
8874776Smckusic 			((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0;
8884610Smckusick 		bct = 0;
8896849Smckusick #ifdef RRESTOR
8906849Smckusick 		if ((i = rmtread(tbf, NTREC*TP_BSIZE)) < 0) {
8916849Smckusick #else
8924776Smckusic 		if ((i = read(mt, tbf, NTREC*TP_BSIZE)) < 0) {
8936849Smckusick #endif
8948485Smckusick 			fprintf(stderr, "Tape read error while restoring %s\n",
8958505Smckusick 				entry->x_name);
8968374Smckusick 			if (!yflag) {
8978485Smckusick 				fprintf(stderr, "continue? ");
8988374Smckusick 				do	{
8998485Smckusick 					fprintf(stderr, "[yn] ");
9008374Smckusick 					c = getchar();
9018374Smckusick 					while (getchar() != '\n')
9028374Smckusick 						/* void */;
9038374Smckusick 				} while (c != 'y' && c != 'n');
9048374Smckusick 				if (c == 'n')
9058374Smckusick 					done(1);
9068374Smckusick 			}
9074610Smckusick 			eflag++;
9086845Smckusick 			i = NTREC*TP_BSIZE;
909*10202Smckusick 			bzero(tbf, i);
9106849Smckusick #ifdef RRESTOR
9116849Smckusick 			if (rmtseek(i, 1) < 0) {
9126849Smckusick #else
9136846Smckusick 			if (lseek(mt, i, 1) < 0) {
9146849Smckusick #endif
9156846Smckusick 				fprintf(stderr, "continuation failed\n");
9166846Smckusick 				done(1);
9176846Smckusick 			}
9184610Smckusick 		}
9194610Smckusick 		if (i == 0) {
9204610Smckusick 			bct = NTREC + 1;
9214610Smckusick 			volno++;
9224610Smckusick loop:
9234610Smckusick 			flsht();
9246849Smckusick #ifdef RRESTOR
9256849Smckusick 			rmtclose();
9266849Smckusick #else
9274610Smckusick 			close(mt);
9286849Smckusick #endif
9294700Smckusic 			fprintf(stderr, "Mount volume %d\n", volno);
9304610Smckusick 			while (getchar() != '\n')
9314610Smckusick 				;
9326849Smckusick #ifdef RRESTOR
9336849Smckusick 			if ((mt = rmtopen(magtape, 0)) == -1) {
9346849Smckusick #else
9354610Smckusick 			if ((mt = open(magtape, 0)) == -1) {
9366849Smckusick #endif
9374700Smckusic 				fprintf(stderr, "Cannot open tape!\n");
9384610Smckusick 				goto loop;
9394610Smckusick 			}
9404610Smckusick 			if (readhdr(&tmpbuf) == 0) {
9414700Smckusic 				fprintf(stderr, "Not a dump tape.Try again\n");
9424610Smckusick 				goto loop;
9434610Smckusick 			}
9444610Smckusick 			if (checkvol(&tmpbuf, volno) == 0) {
9454700Smckusic 				fprintf(stderr, "Wrong tape. Try again\n");
9464610Smckusick 				goto loop;
9474610Smckusick 			}
9484610Smckusick 			readtape(b);
9494610Smckusick 			return;
9504610Smckusick 		}
9514610Smckusick 	}
952*10202Smckusick 	bcopy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
9534610Smckusick }
9544610Smckusick 
9554610Smckusick flsht()
9564610Smckusick {
9576847Smckusick 
9584610Smckusick 	bct = NTREC+1;
9594610Smckusick }
9604610Smckusick 
9615038Smckusic resetmt()
9625038Smckusic {
9635038Smckusic 	struct mtop tcom;
9645038Smckusic 
9656847Smckusick 	if (dumpnum > 1)
9665038Smckusic 		tcom.mt_op = MTBSF;
9675038Smckusic 	else
9685038Smckusic 		tcom.mt_op = MTREW;
9695038Smckusic 	tcom.mt_count = 1;
9705038Smckusic 	flsht();
9716849Smckusick #ifdef RRESTOR
9726849Smckusick 	if (rmtioctl(tcom.mt_op, 1) == -1) {
9736849Smckusick 		/* kludge for disk dumps */
9746849Smckusick 		rmtseek((long)0, 0);
9756849Smckusick 	}
9766849Smckusick #else
9775038Smckusic 	if (ioctl(mt,MTIOCTOP,&tcom) == -1) {
9785038Smckusic 		/* kludge for disk dumps */
9795038Smckusic 		lseek(mt, (long)0, 0);
9805038Smckusic 	}
9816849Smckusick #endif
9825038Smckusic 	if (dumpnum > 1) {
9836849Smckusick #ifdef RRESTOR
9846849Smckusick 		rmtioctl(MTFSF, 1);
9856849Smckusick #else
9865038Smckusic 		tcom.mt_op = MTFSF;
9875038Smckusic 		tcom.mt_count = 1;
9885038Smckusic 		ioctl(mt,MTIOCTOP,&tcom);
9896849Smckusick #endif
9905038Smckusic 	}
9915038Smckusic }
9925038Smckusic 
9934843Smckusic checkvol(b, t)
9944843Smckusic 	struct s_spcl *b;
9954843Smckusic 	int t;
9964610Smckusick {
9976847Smckusick 
9984843Smckusic 	if (b->c_volume == t)
9994843Smckusic 		return(1);
10004610Smckusick 	return(0);
10014610Smckusick }
10024610Smckusick 
10034843Smckusic readhdr(b)
10044843Smckusic 	struct s_spcl *b;
10054610Smckusick {
10066847Smckusick 
10074843Smckusic 	if (gethead(b) == 0)
10084610Smckusick 		return(0);
10094843Smckusic 	if (checktype(b, TS_TAPE) == 0)
10104843Smckusic 		return(0);
10114843Smckusic 	return(1);
10124610Smckusick }
10134610Smckusick 
10144610Smckusick /*
10154610Smckusick  * read the tape into buf, then return whether or
10164610Smckusick  * or not it is a header block.
10174610Smckusick  */
10184610Smckusick gethead(buf)
10194837Smckusic 	struct s_spcl *buf;
10204610Smckusick {
10218302Smckusick 	union u_ospcl {
10228302Smckusick 		char dummy[TP_BSIZE];
10238302Smckusick 		struct	s_ospcl {
10248302Smckusick 			int	c_type;
10258302Smckusick 			time_t	c_date;
10268302Smckusick 			time_t	c_ddate;
10278302Smckusick 			int	c_volume;
10288302Smckusick 			daddr_t	c_tapea;
10298302Smckusick 			ino_t	c_inumber;
10308302Smckusick 			int	c_magic;
10318302Smckusick 			int	c_checksum;
10328302Smckusick 			struct odinode {
10338302Smckusick 				unsigned short odi_mode;
10348302Smckusick 				short	odi_nlink;
10358302Smckusick 				short	odi_uid;
10368302Smckusick 				short	odi_gid;
10378302Smckusick 				off_t	odi_size;
10388302Smckusick 				daddr_t	odi_rdev;
10398302Smckusick 				char	odi_addr[36];
10408302Smckusick 				time_t	odi_atime;
10418302Smckusick 				time_t	odi_mtime;
10428302Smckusick 				time_t	odi_ctime;
10438302Smckusick 			} c_dinode;
10448302Smckusick 			int	c_count;
10458302Smckusick 			char	c_addr[TP_NINDIR];
10468302Smckusick 		} s_ospcl;
10478302Smckusick 	} u_ospcl;
10486847Smckusick 
10498302Smckusick 	if (!cvtflag) {
10508302Smckusick 		readtape((char *)buf);
10518369Smckusick 		if (buf->c_magic != NFS_MAGIC || checksum((int *)buf) == 0)
10528302Smckusick 			return(0);
10538302Smckusick 		return(1);
10548302Smckusick 	}
10558302Smckusick 	readtape((char *)(&u_ospcl.s_ospcl));
1056*10202Smckusick 	bzero((char *)buf, TP_BSIZE);
10578302Smckusick 	buf->c_type = u_ospcl.s_ospcl.c_type;
10588302Smckusick 	buf->c_date = u_ospcl.s_ospcl.c_date;
10598302Smckusick 	buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
10608302Smckusick 	buf->c_volume = u_ospcl.s_ospcl.c_volume;
10618302Smckusick 	buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
10628302Smckusick 	buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
10638302Smckusick 	buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
10648485Smckusick 	buf->c_magic = u_ospcl.s_ospcl.c_magic;
10658302Smckusick 	buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
10668302Smckusick 	buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
10678302Smckusick 	buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
10688302Smckusick 	buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
10698302Smckusick 	buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
10708302Smckusick 	buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
10718302Smckusick 	buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
10728302Smckusick 	buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
10738302Smckusick 	buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
10748302Smckusick 	buf->c_count = u_ospcl.s_ospcl.c_count;
1075*10202Smckusick 	bcopy(u_ospcl.s_ospcl.c_addr, buf->c_addr, TP_NINDIR);
10768485Smckusick 	if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
10778485Smckusick 	    checksum((int *)(&u_ospcl.s_ospcl)) == 0)
10788485Smckusick 		return(0);
10798485Smckusick 	buf->c_magic = NFS_MAGIC;
10804610Smckusick 	return(1);
10814610Smckusick }
10824610Smckusick 
10834610Smckusick /*
10844610Smckusick  * return whether or not the buffer contains a header block
10854610Smckusick  */
10864610Smckusick ishead(buf)
10874837Smckusic 	struct s_spcl *buf;
10884610Smckusick {
10896847Smckusick 
10908369Smckusick 	if (buf->c_magic != NFS_MAGIC)
10914610Smckusick 		return(0);
10924610Smckusick 	return(1);
10934610Smckusick }
10944610Smckusick 
10954610Smckusick checktype(b, t)
10964837Smckusic 	struct s_spcl *b;
10974700Smckusic 	int	t;
10984610Smckusick {
10996847Smckusick 
11004837Smckusic 	return(b->c_type == t);
11014610Smckusick }
11024610Smckusick 
11035038Smckusic /*
11045038Smckusic  * read a bit mask from the tape into m.
11055038Smckusic  */
11066844Smckusick readbits(mapp)
11076844Smckusick 	char **mapp;
11085038Smckusic {
11095038Smckusic 	register int i;
11106844Smckusick 	char	*m;
11114610Smckusick 
11125038Smckusic 	i = spcl.c_count;
11135038Smckusic 
11146844Smckusick 	if (*mapp == 0)
11156846Smckusick 		*mapp = (char *)calloc(i, (TP_BSIZE/(NBBY/BITS)));
11166844Smckusick 	m = *mapp;
11175038Smckusic 	while (i--) {
11185038Smckusic 		readtape((char *) m);
11195327Smckusic 		m += (TP_BSIZE/(NBBY/BITS));
11205038Smckusic 	}
11215038Smckusic 	while (gethead(&spcl) == 0)
11225038Smckusic 		;
11235038Smckusic }
11245038Smckusic 
11254610Smckusick checksum(b)
11268302Smckusick 	register int *b;
11274610Smckusick {
11284776Smckusic 	register int i, j;
11294610Smckusick 
11304776Smckusic 	j = sizeof(union u_spcl) / sizeof(int);
11314610Smckusick 	i = 0;
11324610Smckusick 	do
11334610Smckusick 		i += *b++;
11344610Smckusick 	while (--j);
11354610Smckusick 	if (i != CHECKSUM) {
11368485Smckusick 		fprintf(stderr, "Checksum error %o, file %s\n", i,
11378505Smckusick 			entry->x_name);
11384610Smckusick 		return(0);
11394610Smckusick 	}
11404610Smckusick 	return(1);
11414610Smckusick }
11424610Smckusick 
11434610Smckusick /*
11445038Smckusic  *	Check for access into each directory in the pathname of an extracted
11455038Smckusic  *	file and create such a directory if needed in preparation for moving
11465038Smckusic  *	the file to its proper home.
11475038Smckusic  */
11485038Smckusic checkdir(name)
11495038Smckusic 	register char *name;
11505038Smckusic {
11515038Smckusic 	register char *cp;
11525038Smckusic 	int i;
11535038Smckusic 
11545038Smckusic 	for (cp = name; *cp; cp++) {
11559871Ssam 		if (*cp != '/')
11569871Ssam 			continue;
11579871Ssam 		*cp = '\0';
11589871Ssam 		if (access(name, 01) < 0 && mkdir(name, 0777) < 0)
11599871Ssam 			fprintf(stderr, "restor: "), perror(name);
11609871Ssam 		*cp = '/';
11615038Smckusic 	}
11625038Smckusic }
11635038Smckusic 
11646844Smckusick setdir(dev)
11656844Smckusick 	char *dev;
11666844Smckusick {
11676844Smckusick 	struct fstab *fsp;
11686844Smckusick 
11696844Smckusick 	if (setfsent() == 0) {
11706844Smckusick 		fprintf(stderr, "Can't open checklist file: %s\n", FSTAB);
11716844Smckusick 		done(1);
11726844Smckusick 	}
11736844Smckusick 	while ((fsp = getfsent()) != 0) {
11746844Smckusick 		if (strcmp(fsp->fs_spec, dev) == 0) {
11758374Smckusick 			fprintf(stderr, "%s mounted on %s\n", dev, fsp->fs_file);
11766844Smckusick 			if (chdir(fsp->fs_file) >= 0)
11776844Smckusick 				return;
11786844Smckusick 			fprintf(stderr, "%s cannot chdir to %s\n",
11796844Smckusick 			    fsp->fs_file);
11806844Smckusick 			done(1);
11816844Smckusick 		}
11826844Smckusick 	}
11836844Smckusick 	fprintf(stderr, "%s not mounted\n", dev);
11846844Smckusick 	done(1);
11856844Smckusick }
11866844Smckusick 
11875038Smckusic /*
11885943Smckusic  * These variables are "local" to the following two functions.
11895943Smckusic  */
11905943Smckusic char dirbuf[DIRBLKSIZ];
11915943Smckusic long dirloc = 0;
11925943Smckusic long prev = 0;
11935943Smckusic 
11945943Smckusic /*
11955943Smckusic  * add a new directory entry to a file.
11965943Smckusic  */
11975943Smckusic putent(dp, wrtfunc)
11985943Smckusic 	struct direct *dp;
11995943Smckusic 	int (*wrtfunc)();
12005943Smckusic {
12016847Smckusick 
12025943Smckusic 	if (dp->d_ino == 0)
12035943Smckusic 		return;
12046847Smckusick 	if (dirloc + dp->d_reclen > DIRBLKSIZ) {
12056847Smckusick 		((struct direct *)(dirbuf + prev))->d_reclen =
12066847Smckusick 		    DIRBLKSIZ - prev;
12075943Smckusic 		(*wrtfunc)(dirbuf, DIRBLKSIZ);
12085943Smckusic 		dirloc = 0;
12095943Smckusic 	}
1210*10202Smckusick 	bcopy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen);
12116847Smckusick 	prev = dirloc;
12126847Smckusick 	dirloc += dp->d_reclen;
12135943Smckusic }
12145943Smckusic 
12155943Smckusic /*
12165943Smckusic  * flush out a directory that is finished.
12175943Smckusic  */
12185943Smckusic flushent(wrtfunc)
12195943Smckusic 	int (*wrtfunc)();
12205943Smckusic {
12216847Smckusick 
12225943Smckusic 	((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
12235943Smckusic 	(*wrtfunc)(dirbuf, dirloc);
12245943Smckusic 	dirloc = 0;
12255943Smckusic }
12265943Smckusic 
12275943Smckusic dirwrite(buf, size)
12285943Smckusic 	char *buf;
12295943Smckusic 	int size;
12305943Smckusic {
12316847Smckusick 
12325943Smckusic 	fwrite(buf, 1, size, df);
12335943Smckusic 	seekpt = ftell(df);
12345943Smckusic }
12355943Smckusic 
12365943Smckusic dcvt(odp, ndp)
12375943Smckusic 	register struct odirect *odp;
12385943Smckusic 	register struct direct *ndp;
12395943Smckusic {
12406847Smckusick 
1241*10202Smckusick 	bzero((char *)ndp, (long)(sizeof *ndp));
12425943Smckusic 	ndp->d_ino =  odp->d_ino;
12435943Smckusic 	strncpy(ndp->d_name, odp->d_name, ODIRSIZ);
12445943Smckusic 	ndp->d_namlen = strlen(ndp->d_name);
12455943Smckusic 	ndp->d_reclen = DIRSIZ(ndp);
12465943Smckusic 	/*
12475943Smckusic 	 * this quickly calculates if this inode is a directory.
12485943Smckusic 	 * Currently not maintained.
12495943Smckusic 	 *
12505943Smckusic 	for (itp = inotab[INOHASH(odp->d_ino)]; itp; itp = itp->t_next) {
12515943Smckusic 		if (itp->t_ino != odp->d_ino)
12525943Smckusic 			continue;
12535943Smckusic 		ndp->d_fmt = IFDIR;
12545943Smckusic 		break;
12555943Smckusic 	}
12565943Smckusic 	 */
12575943Smckusic }
12585943Smckusic 
12595943Smckusic /*
12606289Smckusick  * Open a directory.
12616289Smckusick  * Modified to allow any random file to be a legal directory.
12626289Smckusick  */
12636289Smckusick DIR *
12646289Smckusick opendir(name)
12656289Smckusick 	char *name;
12666289Smckusick {
12676289Smckusick 	register DIR *dirp;
12686289Smckusick 
12696289Smckusick 	dirp = (DIR *)malloc(sizeof(DIR));
12706289Smckusick 	dirp->dd_fd = open(name, 0);
12716289Smckusick 	if (dirp->dd_fd == -1) {
12726846Smckusick 		free((char *)dirp);
12736289Smckusick 		return NULL;
12746289Smckusick 	}
12756289Smckusick 	dirp->dd_loc = 0;
12766289Smckusick 	return dirp;
12776289Smckusick }
12786289Smckusick 
12796289Smckusick /*
12806289Smckusick  * Seek to an entry in a directory.
12815943Smckusic  * Only values returned by ``telldir'' should be passed to seekdir.
12825943Smckusic  * Modified to have many directories based in one file.
12835943Smckusic  */
12845943Smckusic void
12855943Smckusic seekdir(dirp, loc, base)
12865943Smckusic 	register DIR *dirp;
12876846Smckusick 	daddr_t loc, base;
12885943Smckusic {
12896847Smckusick 
12905943Smckusic 	if (loc == telldir(dirp))
12915943Smckusic 		return;
12925943Smckusic 	loc -= base;
12935943Smckusic 	if (loc < 0)
12945943Smckusic 		fprintf(stderr, "bad seek pointer to seekdir %d\n", loc);
12956846Smckusick 	(void)lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0);
12965943Smckusic 	dirp->dd_loc = loc & (DIRBLKSIZ - 1);
12975943Smckusic 	if (dirp->dd_loc != 0)
12985943Smckusic 		dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ);
12995943Smckusic }
13005943Smckusic 
13015943Smckusic /*
13026844Smckusick  * get next entry in a directory.
13034700Smckusic  */
13046844Smckusick struct direct *
13056844Smckusick readdir(dirp)
13066844Smckusick 	register DIR *dirp;
13074610Smckusick {
13086844Smckusick 	register struct direct *dp;
13094700Smckusic 
13106844Smckusick 	for (;;) {
13116844Smckusick 		if (dirp->dd_loc == 0) {
13126844Smckusick 			dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
13136844Smckusick 			    DIRBLKSIZ);
13146844Smckusick 			if (dirp->dd_size <= 0)
13156844Smckusick 				return NULL;
13166844Smckusick 		}
13176844Smckusick 		if (dirp->dd_loc >= dirp->dd_size) {
13186844Smckusick 			dirp->dd_loc = 0;
13196844Smckusick 			continue;
13206844Smckusick 		}
13216844Smckusick 		dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc);
13226844Smckusick 		if (dp->d_reclen <= 0 ||
13236844Smckusick 		    dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc)
13246844Smckusick 			return NULL;
13256844Smckusick 		dirp->dd_loc += dp->d_reclen;
13266844Smckusick 		if (dp->d_ino == 0)
13276844Smckusick 			continue;
13286844Smckusick 		return (dp);
13295948Smckusic 	}
13304610Smckusick }
13314610Smckusick 
13324843Smckusic allocinotab(ino, seekpt)
13334837Smckusic 	ino_t ino;
13344843Smckusic 	daddr_t seekpt;
13354610Smckusick {
13364837Smckusic 	register struct inotab	*itp;
13374776Smckusic 
13384837Smckusic 	itp = (struct inotab *)calloc(1, sizeof(struct inotab));
13394837Smckusic 	itp->t_next = inotab[INOHASH(ino)];
13404837Smckusic 	inotab[INOHASH(ino)] = itp;
13414837Smckusic 	itp->t_ino = ino;
13424843Smckusic 	itp->t_seekpt = seekpt;
13434610Smckusick }
13444610Smckusick 
13458505Smckusick struct xtrlist *
13464843Smckusic allocxtr(ino, name, flags)
13474837Smckusic 	ino_t ino;
13484843Smckusic 	char *name;
13494843Smckusic 	char flags;
13504610Smckusick {
13514843Smckusic 	register struct xtrlist	*xp, *pxp;
13528485Smckusick 	int size;
13534776Smckusic 
13548485Smckusick 	size = sizeof(struct xtrlist) + strlen(name);
13558485Smckusick 	xp = (struct xtrlist *)calloc(1, size);
13568505Smckusick 	xp->x_ino = ino;
13578505Smckusick 	xp->x_flags = flags;
13588505Smckusick 	strcpy(xp->x_name, name);
13598505Smckusick 	if (flags == 0)
13608505Smckusick 		return (xp);
13614837Smckusic 	xp->x_next = xtrlist[INOHASH(ino)];
13624837Smckusic 	xtrlist[INOHASH(ino)] = xp;
13634837Smckusic 	xtrcnt++;
13644843Smckusic 	for (pxp = xp->x_next; pxp; pxp = pxp->x_next)
13654843Smckusic 		if (pxp->x_ino == ino && (pxp->x_flags & XLINKED) == 0) {
13664843Smckusic 			xp->x_flags |= XLINKED;
13674843Smckusic 			xp->x_linkedto = pxp;
13684843Smckusic 			xtrcnt--;
13694843Smckusic 			break;
13704843Smckusic 		}
1371*10202Smckusick 	if (!vflag && !tflag)
13728505Smckusick 		return (xp);
13734843Smckusic 	if (xp->x_flags & XLINKED)
13744843Smckusic 		fprintf(stdout, "%s: linked to %s\n", xp->x_name, pxp->x_name);
13754843Smckusic 	else if (xp->x_flags & XISDIR)
13764843Smckusic 		fprintf(stdout, "%s: directory inode %u\n", xp->x_name, ino);
13774843Smckusic 	else
13784843Smckusic 		fprintf(stdout, "%s: inode %u\n", xp->x_name, ino);
13798505Smckusick 	return (xp);
13804610Smckusick }
13814610Smckusick 
13828505Smckusick #ifdef RRESTOR
13838505Smckusick msg(cp, a1, a2, a3)
13848505Smckusick 	char *cp;
13858505Smckusick {
13868505Smckusick 
13878505Smckusick 	fprintf(stderr, cp, a1, a2, a3);
13888505Smckusick }
13898505Smckusick #endif RRESTOR
13908505Smckusick 
13915038Smckusic done(exitcode)
13925038Smckusic 	int exitcode;
13934610Smckusick {
13946847Smckusick 
13955038Smckusic 	unlink(dirfile);
13965038Smckusic 	exit(exitcode);
13974610Smckusick }
1398