xref: /csrg-svn/sbin/dump/main.c (revision 46794)
122037Sdist /*
222037Sdist  * Copyright (c) 1980 Regents of the University of California.
322037Sdist  * All rights reserved.  The Berkeley software License Agreement
422037Sdist  * specifies the terms and conditions for redistribution.
522037Sdist  */
622037Sdist 
722037Sdist #ifndef lint
8*46794Smckusick static char sccsid[] = "@(#)main.c	5.12 (Berkeley) 02/28/91";
946586Storek #endif /* not lint */
1022037Sdist 
111423Sroot #include "dump.h"
1246586Storek #include <fcntl.h>
1337266Sbostic #include "pathnames.h"
141423Sroot 
151423Sroot int	notify = 0;	/* notify operator flag */
161423Sroot int	blockswritten = 0;	/* number of blocks written on current tape */
171423Sroot int	tapeno = 0;	/* current tape number */
1810910Ssam int	density = 0;	/* density in bytes/0.1" */
1910910Ssam int	ntrec = NTREC;	/* # tape blocks in each tape record */
2010910Ssam int	cartridge = 0;	/* Assume non-cartridge tape */
2130560Smckusick long	dev_bsize = 1;	/* recalculated below */
2246614Smckusick long	blocksperfile;	/* output blocks per file */
236882Ssam #ifdef RDUMP
246882Ssam char	*host;
2546586Storek int	rmthost();
266882Ssam #endif
271423Sroot 
281423Sroot main(argc, argv)
29*46794Smckusick 	int argc;
30*46794Smckusick 	char *argv[];
311423Sroot {
32*46794Smckusick 	register ino_t ino;
33*46794Smckusick 	register long bits;
34*46794Smckusick 	register struct dinode *dp;
35*46794Smckusick 	register struct	fstab *dt;
36*46794Smckusick 	register char *map;
37*46794Smckusick 	register char *cp;
38*46794Smckusick 	int i, anydirskipped, bflag = 0;
39*46794Smckusick 	float fetapes;
40*46794Smckusick 	ino_t maxino;
411423Sroot 
421423Sroot 	time(&(spcl.c_date));
431423Sroot 
4410910Ssam 	tsize = 0;	/* Default later, based on 'c' option for cart tapes */
4537946Sbostic 	tape = _PATH_DEFTAPE;
46*46794Smckusick 	dumpdates = _PATH_DUMPDATES;
4737266Sbostic 	temp = _PATH_DTMP;
4846586Storek 	if (TP_BSIZE / DEV_BSIZE == 0 || TP_BSIZE % DEV_BSIZE != 0)
4946586Storek 		quit("TP_BSIZE must be a multiple of DEV_BSIZE\n");
50*46794Smckusick 	level = '0';
51*46794Smckusick 	argv++;
52*46794Smckusick 	argc -= 2;
53*46794Smckusick 	for (cp = *argv++; *cp; cp++) {
54*46794Smckusick 		switch (*cp) {
55*46794Smckusick 		case '-':
56*46794Smckusick 			continue;
571423Sroot 
58*46794Smckusick 		case 'w':
59*46794Smckusick 			lastdump('w');	/* tell us only what has to be done */
60*46794Smckusick 			exit(0);
61*46794Smckusick 
62*46794Smckusick 		case 'W':		/* what to do */
63*46794Smckusick 			lastdump('W');	/* tell us state of what is done */
64*46794Smckusick 			exit(0);	/* do nothing else */
65*46794Smckusick 
66*46794Smckusick 		case 'f':		/* output file */
67*46794Smckusick 			if (argc < 1)
68*46794Smckusick 				break;
69*46794Smckusick 			tape = *argv++;
701423Sroot 			argc--;
71*46794Smckusick 			continue;
721423Sroot 
73*46794Smckusick 		case 'd':		/* density, in bits per inch */
74*46794Smckusick 			if (argc < 1)
75*46794Smckusick 				break;
76*46794Smckusick 			density = atoi(*argv) / 10;
77*46794Smckusick 			if (density < 1) {
78*46794Smckusick 				fprintf(stderr, "bad density \"%s\"\n", *argv);
79*46794Smckusick 				Exit(X_ABORT);
80*46794Smckusick 			}
81*46794Smckusick 			argc--;
821423Sroot 			argv++;
8318494Smckusick 			if (density >= 625 && !bflag)
8418494Smckusick 				ntrec = HIGHDENSITYTREC;
85*46794Smckusick 			continue;
861423Sroot 
87*46794Smckusick 		case 's':		/* tape size, feet */
88*46794Smckusick 			if (argc < 1)
89*46794Smckusick 				break;
90*46794Smckusick 			tsize = atol(*argv);
91*46794Smckusick 			if (tsize < 1) {
92*46794Smckusick 				fprintf(stderr, "bad size \"%s\"\n", *argv);
93*46794Smckusick 				Exit(X_ABORT);
94*46794Smckusick 			}
95*46794Smckusick 			argc--;
961423Sroot 			argv++;
97*46794Smckusick 			tsize *= 12 * 10;
98*46794Smckusick 			continue;
991423Sroot 
100*46794Smckusick 		case 'b':		/* blocks per tape write */
101*46794Smckusick 			if (argc < 1)
102*46794Smckusick 				break;
10318494Smckusick 			bflag++;
10410910Ssam 			ntrec = atol(*argv);
105*46794Smckusick 			if (ntrec < 1) {
106*46794Smckusick 				fprintf(stderr, "%s \"%s\"\n",
107*46794Smckusick 				    "bad number of blocks per write ", *argv);
10846614Smckusick 				Exit(X_ABORT);
10946614Smckusick 			}
110*46794Smckusick 			argc--;
111*46794Smckusick 			argv++;
112*46794Smckusick 			continue;
11310910Ssam 
114*46794Smckusick 		case 'B':		/* blocks per output file */
115*46794Smckusick 			if (argc < 1)
116*46794Smckusick 				break;
117*46794Smckusick 			blocksperfile = atol(*argv);
118*46794Smckusick 			if (blocksperfile < 1) {
119*46794Smckusick 				fprintf(stderr, "%s \"%s\"\n",
120*46794Smckusick 				    "bad number of blocks per file ", *argv);
121*46794Smckusick 				Exit(X_ABORT);
122*46794Smckusick 			}
123*46794Smckusick 			argc--;
12446614Smckusick 			argv++;
125*46794Smckusick 			continue;
12646614Smckusick 
127*46794Smckusick 		case 'c':		/* Tape is cart. not 9-track */
128*46794Smckusick 			cartridge++;
129*46794Smckusick 			continue;
13010910Ssam 
131*46794Smckusick 		case '0':		/* dump level */
132*46794Smckusick 		case '1':
133*46794Smckusick 		case '2':
134*46794Smckusick 		case '3':
135*46794Smckusick 		case '4':
136*46794Smckusick 		case '5':
137*46794Smckusick 		case '6':
138*46794Smckusick 		case '7':
139*46794Smckusick 		case '8':
140*46794Smckusick 		case '9':
141*46794Smckusick 			level = *cp;
142*46794Smckusick 			continue;
1431423Sroot 
144*46794Smckusick 		case 'u':		/* update /etc/dumpdates */
145*46794Smckusick 			uflag++;
146*46794Smckusick 			continue;
1471423Sroot 
148*46794Smckusick 		case 'n':		/* notify operators */
149*46794Smckusick 			notify++;
150*46794Smckusick 			continue;
1511423Sroot 
152*46794Smckusick 		default:
153*46794Smckusick 			fprintf(stderr, "bad key '%c'\n", *cp);
154*46794Smckusick 			Exit(X_ABORT);
155*46794Smckusick 		}
156*46794Smckusick 		fprintf(stderr, "missing argument to '%c'\n", *cp);
1571423Sroot 		Exit(X_ABORT);
1581423Sroot 	}
159*46794Smckusick 	if (argc < 1) {
160*46794Smckusick 		fprintf(stderr, "Must specify disk or filesystem\n");
161*46794Smckusick 		Exit(X_ABORT);
162*46794Smckusick 	} else {
163*46794Smckusick 		disk = *argv++;
1641423Sroot 		argc--;
1651423Sroot 	}
166*46794Smckusick 	if (argc >= 1) {
167*46794Smckusick 		fprintf(stderr, "Unknown arguments to dump:");
168*46794Smckusick 		while (argc--)
169*46794Smckusick 			fprintf(stderr, " %s", *argv++);
170*46794Smckusick 		fprintf(stderr, "\n");
171*46794Smckusick 		Exit(X_ABORT);
172*46794Smckusick 	}
17312331Smckusick 	if (strcmp(tape, "-") == 0) {
17412331Smckusick 		pipeout++;
17512331Smckusick 		tape = "standard output";
17612331Smckusick 	}
17710910Ssam 
17846614Smckusick 	if (blocksperfile)
17946614Smckusick 		blocksperfile = blocksperfile / ntrec * ntrec; /* round down */
18046614Smckusick 	else {
18146614Smckusick 		/*
18246614Smckusick 		 * Determine how to default tape size and density
18346614Smckusick 		 *
18446614Smckusick 		 *         	density				tape size
18546614Smckusick 		 * 9-track	1600 bpi (160 bytes/.1")	2300 ft.
18646614Smckusick 		 * 9-track	6250 bpi (625 bytes/.1")	2300 ft.
18746614Smckusick 		 * cartridge	8000 bpi (100 bytes/.1")	1700 ft.
18846614Smckusick 		 *						(450*4 - slop)
18946614Smckusick 		 */
19046614Smckusick 		if (density == 0)
19146614Smckusick 			density = cartridge ? 100 : 160;
19246614Smckusick 		if (tsize == 0)
19346614Smckusick 			tsize = cartridge ? 1700L*120L : 2300L*120L;
19446614Smckusick 	}
19510910Ssam 
1966886Ssam #ifdef RDUMP
1976886Ssam 	{ char *index();
1986886Ssam 	  host = tape;
1996886Ssam 	  tape = index(host, ':');
2006886Ssam 	  if (tape == 0) {
20128642Smckusick 		msg("need keyletter ``f'' and device ``host:tape''\n");
2026886Ssam 		exit(1);
2036886Ssam 	  }
2046886Ssam 	  *tape++ = 0;
2056886Ssam 	  if (rmthost(host) == 0)
2066886Ssam 		exit(X_ABORT);
2076886Ssam 	}
20828860Smckusick 	setuid(getuid());	/* rmthost() is the only reason to be setuid */
2096886Ssam #endif
21046614Smckusick 	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
21146614Smckusick 		signal(SIGHUP, sighup);
21246614Smckusick 	if (signal(SIGTRAP, SIG_IGN) != SIG_IGN)
21346614Smckusick 		signal(SIGTRAP, sigtrap);
21446614Smckusick 	if (signal(SIGFPE, SIG_IGN) != SIG_IGN)
21546614Smckusick 		signal(SIGFPE, sigfpe);
21646614Smckusick 	if (signal(SIGBUS, SIG_IGN) != SIG_IGN)
21746614Smckusick 		signal(SIGBUS, sigbus);
21846614Smckusick 	if (signal(SIGSEGV, SIG_IGN) != SIG_IGN)
21946614Smckusick 		signal(SIGSEGV, sigsegv);
22046614Smckusick 	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
22146614Smckusick 		signal(SIGTERM, sigterm);
2221423Sroot 
2231423Sroot 
2241423Sroot 	if (signal(SIGINT, interrupt) == SIG_IGN)
2251423Sroot 		signal(SIGINT, SIG_IGN);
2261423Sroot 
2271423Sroot 	set_operators();	/* /etc/group snarfed */
2281423Sroot 	getfstab();		/* /etc/fstab snarfed */
2291423Sroot 	/*
2301423Sroot 	 *	disk can be either the full special file name,
2311423Sroot 	 *	the suffix of the special file name,
2321423Sroot 	 *	the special name missing the leading '/',
2331423Sroot 	 *	the file system name with or without the leading '/'.
2341423Sroot 	 */
2351423Sroot 	dt = fstabsearch(disk);
23629900Smckusick 	if (dt != 0) {
2371423Sroot 		disk = rawname(dt->fs_spec);
23829900Smckusick 		strncpy(spcl.c_dev, dt->fs_spec, NAMELEN);
23929900Smckusick 		strncpy(spcl.c_filesys, dt->fs_file, NAMELEN);
24029900Smckusick 	} else {
24129900Smckusick 		strncpy(spcl.c_dev, disk, NAMELEN);
24229900Smckusick 		strncpy(spcl.c_filesys, "an unlisted file system", NAMELEN);
24329900Smckusick 	}
24429900Smckusick 	strcpy(spcl.c_label, "none");
24529900Smckusick 	gethostname(spcl.c_host, NAMELEN);
246*46794Smckusick 	spcl.c_level = level - '0';
24729900Smckusick 	spcl.c_type = TS_TAPE;
248*46794Smckusick 	getdumptime();		/* /etc/dumpdates snarfed */
2491423Sroot 
250*46794Smckusick 	msg("Date of this level %c dump: %s", level,
251*46794Smckusick 		spcl.c_date == 0 ? "the epoch\n" : ctime(&spcl.c_date));
252*46794Smckusick  	msg("Date of last level %c dump: %s", lastlevel,
253*46794Smckusick 		spcl.c_ddate == 0 ? "the epoch\n" : ctime(&spcl.c_ddate));
2541423Sroot 	msg("Dumping %s ", disk);
2551423Sroot 	if (dt != 0)
2561423Sroot 		msgtail("(%s) ", dt->fs_file);
2578506Smckusick #ifdef RDUMP
2588506Smckusick 	msgtail("to %s on host %s\n", tape, host);
2598506Smckusick #else
2608371Smckusick 	msgtail("to %s\n", tape);
2616882Ssam #endif
2621423Sroot 
263*46794Smckusick 	if ((diskfd = open(disk, O_RDONLY)) < 0) {
2641423Sroot 		msg("Cannot open %s\n", disk);
2651423Sroot 		Exit(X_ABORT);
2661423Sroot 	}
267*46794Smckusick 	sync();
2685328Smckusic 	sblock = (struct fs *)buf;
26930560Smckusick 	bread(SBOFF, sblock, SBSIZE);
27046586Storek 	if (sblock->fs_magic != FS_MAGIC)
27146586Storek 		quit("bad sblock magic number\n");
27230560Smckusick 	dev_bsize = sblock->fs_fsize / fsbtodb(sblock, 1);
27346586Storek 	dev_bshift = ffs(dev_bsize) - 1;
27446586Storek 	if (dev_bsize != (1 << dev_bshift))
27546586Storek 		quit("dev_bsize (%d) is not a power of 2", dev_bsize);
27646586Storek 	tp_bshift = ffs(TP_BSIZE) - 1;
27746586Storek 	if (TP_BSIZE != (1 << tp_bshift))
27846586Storek 		quit("TP_BSIZE (%d) is not a power of 2", TP_BSIZE);
279*46794Smckusick 	maxino = sblock->fs_ipg * sblock->fs_ncg - 1;
280*46794Smckusick 	mapsize = roundup(howmany(sblock->fs_ipg * sblock->fs_ncg, NBBY),
2815328Smckusic 		TP_BSIZE);
282*46794Smckusick 	usedinomap = (char *)calloc(mapsize, sizeof(char));
283*46794Smckusick 	dumpdirmap = (char *)calloc(mapsize, sizeof(char));
284*46794Smckusick 	dumpinomap = (char *)calloc(mapsize, sizeof(char));
285*46794Smckusick 	tapesize = 3 * (howmany(mapsize * sizeof(char), TP_BSIZE) + 1);
2861423Sroot 
2871423Sroot 	msg("mapping (Pass I) [regular files]\n");
288*46794Smckusick 	anydirskipped = mapfiles(maxino, &tapesize);
2891423Sroot 
290*46794Smckusick 	msg("mapping (Pass II) [directories]\n");
291*46794Smckusick 	while (anydirskipped) {
292*46794Smckusick 		anydirskipped = mapdirs(maxino, &tapesize);
293*46794Smckusick 	}
2941423Sroot 
29546614Smckusick 	if (pipeout)
296*46794Smckusick 		tapesize += 10;	/* 10 trailer blocks */
29746614Smckusick 	else {
29846614Smckusick 		if (blocksperfile)
299*46794Smckusick 			fetapes = tapesize / blocksperfile;
30046614Smckusick 		else if (cartridge) {
30146614Smckusick 			/* Estimate number of tapes, assuming streaming stops at
30246614Smckusick 			   the end of each block written, and not in mid-block.
30346614Smckusick 			   Assume no erroneous blocks; this can be compensated
30446614Smckusick 			   for with an artificially low tape size. */
30546614Smckusick 			fetapes =
306*46794Smckusick 			(	  tapesize	/* blocks */
30746614Smckusick 				* TP_BSIZE	/* bytes/block */
30846614Smckusick 				* (1.0/density)	/* 0.1" / byte */
30946614Smckusick 			  +
310*46794Smckusick 				  tapesize	/* blocks */
31146614Smckusick 				* (1.0/ntrec)	/* streaming-stops per block */
31246614Smckusick 				* 15.48		/* 0.1" / streaming-stop */
31346614Smckusick 			) * (1.0 / tsize );	/* tape / 0.1" */
31446614Smckusick 		} else {
31546614Smckusick 			/* Estimate number of tapes, for old fashioned 9-track
31646614Smckusick 			   tape */
31746614Smckusick 			int tenthsperirg = (density == 625) ? 3 : 7;
31846614Smckusick 			fetapes =
319*46794Smckusick 			(	  tapesize	/* blocks */
32046614Smckusick 				* TP_BSIZE	/* bytes / block */
32146614Smckusick 				* (1.0/density)	/* 0.1" / byte */
32246614Smckusick 			  +
323*46794Smckusick 				  tapesize	/* blocks */
32446614Smckusick 				* (1.0/ntrec)	/* IRG's / block */
32546614Smckusick 				* tenthsperirg	/* 0.1" / IRG */
32646614Smckusick 			) * (1.0 / tsize );	/* tape / 0.1" */
32746614Smckusick 		}
32846614Smckusick 		etapes = fetapes;		/* truncating assignment */
32946614Smckusick 		etapes++;
330*46794Smckusick 		/* count the dumped inodes map on each additional tape */
331*46794Smckusick 		tapesize += (etapes - 1) *
332*46794Smckusick 			(howmany(mapsize * sizeof(char), TP_BSIZE) + 1);
333*46794Smckusick 		tapesize += etapes + 10;	/* headers + 10 trailer blks */
33410910Ssam 	}
33546614Smckusick 	if (pipeout)
336*46794Smckusick 		msg("estimated %ld tape blocks.\n", tapesize);
33746614Smckusick 	else
33846614Smckusick 		msg("estimated %ld tape blocks on %3.2f tape(s).\n",
339*46794Smckusick 		    tapesize, fetapes);
3401423Sroot 
34110910Ssam 	alloctape();			/* Allocate tape buffer */
34210910Ssam 
343*46794Smckusick 	startnewtape();
3441423Sroot 	time(&(tstart_writing));
345*46794Smckusick 	dumpmap(usedinomap, TS_CLRI, maxino);
3461423Sroot 
3471423Sroot 	msg("dumping (Pass III) [directories]\n");
348*46794Smckusick 	for (map = dumpdirmap, ino = 0; ino < maxino; ) {
349*46794Smckusick 		if ((ino % NBBY) == 0)
350*46794Smckusick 			bits = *map++;
351*46794Smckusick 		else
352*46794Smckusick 			bits >>= 1;
353*46794Smckusick 		ino++;
354*46794Smckusick 		if ((bits & 1) == 0)
355*46794Smckusick 			continue;
356*46794Smckusick 		/*
357*46794Smckusick 		 * Skip directory inodes deleted and maybe reallocated
358*46794Smckusick 		 */
359*46794Smckusick 		dp = getino(ino);
360*46794Smckusick 		if ((dp->di_mode & IFMT) != IFDIR)
361*46794Smckusick 			continue;
362*46794Smckusick 		dumpino(dp, ino);
363*46794Smckusick 	}
3641423Sroot 
3651423Sroot 	msg("dumping (Pass IV) [regular files]\n");
366*46794Smckusick 	for (map = dumpinomap, ino = 0; ino < maxino; ) {
367*46794Smckusick 		if ((ino % NBBY) == 0)
368*46794Smckusick 			bits = *map++;
369*46794Smckusick 		else
370*46794Smckusick 			bits >>= 1;
371*46794Smckusick 		ino++;
372*46794Smckusick 		if ((bits & 1) == 0)
373*46794Smckusick 			continue;
374*46794Smckusick 		/*
375*46794Smckusick 		 * Skip inodes deleted and reallocated as directories.
376*46794Smckusick 		 */
377*46794Smckusick 		dp = getino(ino);
378*46794Smckusick 		if ((dp->di_mode & IFMT) == IFDIR)
379*46794Smckusick 			continue;
380*46794Smckusick 		dumpino(dp, ino);
381*46794Smckusick 	}
3821423Sroot 
3831423Sroot 	spcl.c_type = TS_END;
3846882Ssam #ifndef RDUMP
385*46794Smckusick 	for (i = 0; i < ntrec; i++)
386*46794Smckusick 		writeheader(maxino);
3876882Ssam #endif
38846614Smckusick 	if (pipeout)
38946614Smckusick 		msg("DUMP: %ld tape blocks\n",spcl.c_tapea);
39046614Smckusick 	else
39146614Smckusick 		msg("DUMP: %ld tape blocks on %d volumes(s)\n",
39246614Smckusick 		    spcl.c_tapea, spcl.c_volume);
3931423Sroot 	msg("DUMP IS DONE\n");
3941423Sroot 
395*46794Smckusick 	putdumptime();
3966882Ssam #ifndef RDUMP
39712331Smckusick 	if (!pipeout) {
398*46794Smckusick 		close(tapefd);
39946239Storek 		trewind();
40012331Smckusick 	}
4016882Ssam #else
402*46794Smckusick 	for (i = 0; i < ntrec; i++)
403*46794Smckusick 		writeheader(curino);
40446239Storek 	trewind();
4056882Ssam #endif
4061423Sroot 	broadcast("DUMP IS DONE!\7\7\n");
4071423Sroot 	Exit(X_FINOK);
40846586Storek 	/* NOTREACHED */
4091423Sroot }
4101423Sroot 
41146586Storek void
4121423Sroot sigAbort()
4131423Sroot {
41446586Storek 	if (pipeout)
41546586Storek 		quit("Unknown signal, cannot recover\n");
4161423Sroot 	msg("Rewriting attempted as response to unknown signal.\n");
4171423Sroot 	fflush(stderr);
4181423Sroot 	fflush(stdout);
4191423Sroot 	close_rewind();
4201423Sroot 	exit(X_REWRITE);
4211423Sroot }
4221423Sroot 
42346586Storek void	sighup(){	msg("SIGHUP()  try rewriting\n"); sigAbort();}
42446586Storek void	sigtrap(){	msg("SIGTRAP()  try rewriting\n"); sigAbort();}
42546586Storek void	sigfpe(){	msg("SIGFPE()  try rewriting\n"); sigAbort();}
42646586Storek void	sigbus(){	msg("SIGBUS()  try rewriting\n"); sigAbort();}
42746586Storek void	sigsegv(){	msg("SIGSEGV()  ABORTING!\n"); abort();}
42846586Storek void	sigalrm(){	msg("SIGALRM()  try rewriting\n"); sigAbort();}
42946586Storek void	sigterm(){	msg("SIGTERM()  try rewriting\n"); sigAbort();}
43046586Storek 
43146586Storek char *
43246586Storek rawname(cp)
4331423Sroot 	char *cp;
4341423Sroot {
4351423Sroot 	static char rawbuf[32];
4364608Smckusic 	char *rindex();
4371423Sroot 	char *dp = rindex(cp, '/');
4381423Sroot 
4391423Sroot 	if (dp == 0)
4401423Sroot 		return (0);
4411423Sroot 	*dp = 0;
4421423Sroot 	strcpy(rawbuf, cp);
4431423Sroot 	*dp = '/';
4441423Sroot 	strcat(rawbuf, "/r");
4451423Sroot 	strcat(rawbuf, dp+1);
4461423Sroot 	return (rawbuf);
4471423Sroot }
448