xref: /original-bsd/sbin/dump/main.c (revision ae291b9c)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)main.c	5.13 (Berkeley) 02/28/91";
9 #endif /* not lint */
10 
11 #include <sys/param.h>
12 #include <ufs/dir.h>
13 #include <ufs/dinode.h>
14 #include <ufs/fs.h>
15 #include <protocols/dumprestore.h>
16 #include <signal.h>
17 #ifdef __STDC__
18 #include <time.h>
19 #endif
20 #include <fcntl.h>
21 #include <fstab.h>
22 #include <stdio.h>
23 #ifdef __STDC__
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #endif
28 #include "dump.h"
29 #include "pathnames.h"
30 
31 int	notify = 0;	/* notify operator flag */
32 int	blockswritten = 0;	/* number of blocks written on current tape */
33 int	tapeno = 0;	/* current tape number */
34 int	density = 0;	/* density in bytes/0.1" */
35 int	ntrec = NTREC;	/* # tape blocks in each tape record */
36 int	cartridge = 0;	/* Assume non-cartridge tape */
37 long	dev_bsize = 1;	/* recalculated below */
38 long	blocksperfile;	/* output blocks per file */
39 #ifdef RDUMP
40 char	*host;
41 int	rmthost();
42 #endif
43 
44 main(argc, argv)
45 	int argc;
46 	char **argv;
47 {
48 	register ino_t ino;
49 	register long bits;
50 	register struct dinode *dp;
51 	register struct	fstab *dt;
52 	register char *map;
53 	register char *cp;
54 	int i, anydirskipped, bflag = 0;
55 	float fetapes;
56 	ino_t maxino;
57 
58 	time(&(spcl.c_date));
59 
60 	tsize = 0;	/* Default later, based on 'c' option for cart tapes */
61 	tape = _PATH_DEFTAPE;
62 	dumpdates = _PATH_DUMPDATES;
63 	temp = _PATH_DTMP;
64 	if (TP_BSIZE / DEV_BSIZE == 0 || TP_BSIZE % DEV_BSIZE != 0)
65 		quit("TP_BSIZE must be a multiple of DEV_BSIZE\n");
66 	level = '0';
67 	argv++;
68 	argc -= 2;
69 	for (cp = *argv++; *cp; cp++) {
70 		switch (*cp) {
71 		case '-':
72 			continue;
73 
74 		case 'w':
75 			lastdump('w');	/* tell us only what has to be done */
76 			exit(0);
77 
78 		case 'W':		/* what to do */
79 			lastdump('W');	/* tell us state of what is done */
80 			exit(0);	/* do nothing else */
81 
82 		case 'f':		/* output file */
83 			if (argc < 1)
84 				break;
85 			tape = *argv++;
86 			argc--;
87 			continue;
88 
89 		case 'd':		/* density, in bits per inch */
90 			if (argc < 1)
91 				break;
92 			density = atoi(*argv) / 10;
93 			if (density < 1) {
94 				fprintf(stderr, "bad density \"%s\"\n", *argv);
95 				Exit(X_ABORT);
96 			}
97 			argc--;
98 			argv++;
99 			if (density >= 625 && !bflag)
100 				ntrec = HIGHDENSITYTREC;
101 			continue;
102 
103 		case 's':		/* tape size, feet */
104 			if (argc < 1)
105 				break;
106 			tsize = atol(*argv);
107 			if (tsize < 1) {
108 				fprintf(stderr, "bad size \"%s\"\n", *argv);
109 				Exit(X_ABORT);
110 			}
111 			argc--;
112 			argv++;
113 			tsize *= 12 * 10;
114 			continue;
115 
116 		case 'b':		/* blocks per tape write */
117 			if (argc < 1)
118 				break;
119 			bflag++;
120 			ntrec = atol(*argv);
121 			if (ntrec < 1) {
122 				fprintf(stderr, "%s \"%s\"\n",
123 				    "bad number of blocks per write ", *argv);
124 				Exit(X_ABORT);
125 			}
126 			argc--;
127 			argv++;
128 			continue;
129 
130 		case 'B':		/* blocks per output file */
131 			if (argc < 1)
132 				break;
133 			blocksperfile = atol(*argv);
134 			if (blocksperfile < 1) {
135 				fprintf(stderr, "%s \"%s\"\n",
136 				    "bad number of blocks per file ", *argv);
137 				Exit(X_ABORT);
138 			}
139 			argc--;
140 			argv++;
141 			continue;
142 
143 		case 'c':		/* Tape is cart. not 9-track */
144 			cartridge++;
145 			continue;
146 
147 		case '0':		/* dump level */
148 		case '1':
149 		case '2':
150 		case '3':
151 		case '4':
152 		case '5':
153 		case '6':
154 		case '7':
155 		case '8':
156 		case '9':
157 			level = *cp;
158 			continue;
159 
160 		case 'u':		/* update /etc/dumpdates */
161 			uflag++;
162 			continue;
163 
164 		case 'n':		/* notify operators */
165 			notify++;
166 			continue;
167 
168 		default:
169 			fprintf(stderr, "bad key '%c'\n", *cp);
170 			Exit(X_ABORT);
171 		}
172 		fprintf(stderr, "missing argument to '%c'\n", *cp);
173 		Exit(X_ABORT);
174 	}
175 	if (argc < 1) {
176 		fprintf(stderr, "Must specify disk or filesystem\n");
177 		Exit(X_ABORT);
178 	} else {
179 		disk = *argv++;
180 		argc--;
181 	}
182 	if (argc >= 1) {
183 		fprintf(stderr, "Unknown arguments to dump:");
184 		while (argc--)
185 			fprintf(stderr, " %s", *argv++);
186 		fprintf(stderr, "\n");
187 		Exit(X_ABORT);
188 	}
189 	if (strcmp(tape, "-") == 0) {
190 		pipeout++;
191 		tape = "standard output";
192 	}
193 
194 	if (blocksperfile)
195 		blocksperfile = blocksperfile / ntrec * ntrec; /* round down */
196 	else {
197 		/*
198 		 * Determine how to default tape size and density
199 		 *
200 		 *         	density				tape size
201 		 * 9-track	1600 bpi (160 bytes/.1")	2300 ft.
202 		 * 9-track	6250 bpi (625 bytes/.1")	2300 ft.
203 		 * cartridge	8000 bpi (100 bytes/.1")	1700 ft.
204 		 *						(450*4 - slop)
205 		 */
206 		if (density == 0)
207 			density = cartridge ? 100 : 160;
208 		if (tsize == 0)
209 			tsize = cartridge ? 1700L*120L : 2300L*120L;
210 	}
211 
212 #ifdef RDUMP
213 	{ char *index();
214 	  host = tape;
215 	  tape = index(host, ':');
216 	  if (tape == 0) {
217 		msg("need keyletter ``f'' and device ``host:tape''\n");
218 		exit(1);
219 	  }
220 	  *tape++ = 0;
221 	  if (rmthost(host) == 0)
222 		exit(X_ABORT);
223 	}
224 	setuid(getuid());	/* rmthost() is the only reason to be setuid */
225 #endif
226 	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
227 		signal(SIGHUP, sighup);
228 	if (signal(SIGTRAP, SIG_IGN) != SIG_IGN)
229 		signal(SIGTRAP, sigtrap);
230 	if (signal(SIGFPE, SIG_IGN) != SIG_IGN)
231 		signal(SIGFPE, sigfpe);
232 	if (signal(SIGBUS, SIG_IGN) != SIG_IGN)
233 		signal(SIGBUS, sigbus);
234 	if (signal(SIGSEGV, SIG_IGN) != SIG_IGN)
235 		signal(SIGSEGV, sigsegv);
236 	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
237 		signal(SIGTERM, sigterm);
238 
239 
240 	if (signal(SIGINT, interrupt) == SIG_IGN)
241 		signal(SIGINT, SIG_IGN);
242 
243 	set_operators();	/* /etc/group snarfed */
244 	getfstab();		/* /etc/fstab snarfed */
245 	/*
246 	 *	disk can be either the full special file name,
247 	 *	the suffix of the special file name,
248 	 *	the special name missing the leading '/',
249 	 *	the file system name with or without the leading '/'.
250 	 */
251 	dt = fstabsearch(disk);
252 	if (dt != 0) {
253 		disk = rawname(dt->fs_spec);
254 		strncpy(spcl.c_dev, dt->fs_spec, NAMELEN);
255 		strncpy(spcl.c_filesys, dt->fs_file, NAMELEN);
256 	} else {
257 		strncpy(spcl.c_dev, disk, NAMELEN);
258 		strncpy(spcl.c_filesys, "an unlisted file system", NAMELEN);
259 	}
260 	strcpy(spcl.c_label, "none");
261 	gethostname(spcl.c_host, NAMELEN);
262 	spcl.c_level = level - '0';
263 	spcl.c_type = TS_TAPE;
264 	getdumptime();		/* /etc/dumpdates snarfed */
265 
266 	msg("Date of this level %c dump: %s", level,
267 		spcl.c_date == 0 ? "the epoch\n" : ctime(&spcl.c_date));
268  	msg("Date of last level %c dump: %s", lastlevel,
269 		spcl.c_ddate == 0 ? "the epoch\n" : ctime(&spcl.c_ddate));
270 	msg("Dumping %s ", disk);
271 	if (dt != 0)
272 		msgtail("(%s) ", dt->fs_file);
273 #ifdef RDUMP
274 	msgtail("to %s on host %s\n", tape, host);
275 #else
276 	msgtail("to %s\n", tape);
277 #endif
278 
279 	if ((diskfd = open(disk, O_RDONLY)) < 0) {
280 		msg("Cannot open %s\n", disk);
281 		Exit(X_ABORT);
282 	}
283 	sync();
284 	sblock = (struct fs *)buf;
285 	bread(SBOFF, sblock, SBSIZE);
286 	if (sblock->fs_magic != FS_MAGIC)
287 		quit("bad sblock magic number\n");
288 	dev_bsize = sblock->fs_fsize / fsbtodb(sblock, 1);
289 	dev_bshift = ffs(dev_bsize) - 1;
290 	if (dev_bsize != (1 << dev_bshift))
291 		quit("dev_bsize (%d) is not a power of 2", dev_bsize);
292 	tp_bshift = ffs(TP_BSIZE) - 1;
293 	if (TP_BSIZE != (1 << tp_bshift))
294 		quit("TP_BSIZE (%d) is not a power of 2", TP_BSIZE);
295 	maxino = sblock->fs_ipg * sblock->fs_ncg - 1;
296 	mapsize = roundup(howmany(sblock->fs_ipg * sblock->fs_ncg, NBBY),
297 		TP_BSIZE);
298 	usedinomap = (char *)calloc(mapsize, sizeof(char));
299 	dumpdirmap = (char *)calloc(mapsize, sizeof(char));
300 	dumpinomap = (char *)calloc(mapsize, sizeof(char));
301 	tapesize = 3 * (howmany(mapsize * sizeof(char), TP_BSIZE) + 1);
302 
303 	msg("mapping (Pass I) [regular files]\n");
304 	anydirskipped = mapfiles(maxino, &tapesize);
305 
306 	msg("mapping (Pass II) [directories]\n");
307 	while (anydirskipped) {
308 		anydirskipped = mapdirs(maxino, &tapesize);
309 	}
310 
311 	if (pipeout)
312 		tapesize += 10;	/* 10 trailer blocks */
313 	else {
314 		if (blocksperfile)
315 			fetapes = tapesize / blocksperfile;
316 		else if (cartridge) {
317 			/* Estimate number of tapes, assuming streaming stops at
318 			   the end of each block written, and not in mid-block.
319 			   Assume no erroneous blocks; this can be compensated
320 			   for with an artificially low tape size. */
321 			fetapes =
322 			(	  tapesize	/* blocks */
323 				* TP_BSIZE	/* bytes/block */
324 				* (1.0/density)	/* 0.1" / byte */
325 			  +
326 				  tapesize	/* blocks */
327 				* (1.0/ntrec)	/* streaming-stops per block */
328 				* 15.48		/* 0.1" / streaming-stop */
329 			) * (1.0 / tsize );	/* tape / 0.1" */
330 		} else {
331 			/* Estimate number of tapes, for old fashioned 9-track
332 			   tape */
333 			int tenthsperirg = (density == 625) ? 3 : 7;
334 			fetapes =
335 			(	  tapesize	/* blocks */
336 				* TP_BSIZE	/* bytes / block */
337 				* (1.0/density)	/* 0.1" / byte */
338 			  +
339 				  tapesize	/* blocks */
340 				* (1.0/ntrec)	/* IRG's / block */
341 				* tenthsperirg	/* 0.1" / IRG */
342 			) * (1.0 / tsize );	/* tape / 0.1" */
343 		}
344 		etapes = fetapes;		/* truncating assignment */
345 		etapes++;
346 		/* count the dumped inodes map on each additional tape */
347 		tapesize += (etapes - 1) *
348 			(howmany(mapsize * sizeof(char), TP_BSIZE) + 1);
349 		tapesize += etapes + 10;	/* headers + 10 trailer blks */
350 	}
351 	if (pipeout)
352 		msg("estimated %ld tape blocks.\n", tapesize);
353 	else
354 		msg("estimated %ld tape blocks on %3.2f tape(s).\n",
355 		    tapesize, fetapes);
356 
357 	alloctape();			/* Allocate tape buffer */
358 
359 	startnewtape();
360 	time(&(tstart_writing));
361 	dumpmap(usedinomap, TS_CLRI, maxino);
362 
363 	msg("dumping (Pass III) [directories]\n");
364 	for (map = dumpdirmap, ino = 0; ino < maxino; ) {
365 		if ((ino % NBBY) == 0)
366 			bits = *map++;
367 		else
368 			bits >>= 1;
369 		ino++;
370 		if ((bits & 1) == 0)
371 			continue;
372 		/*
373 		 * Skip directory inodes deleted and maybe reallocated
374 		 */
375 		dp = getino(ino);
376 		if ((dp->di_mode & IFMT) != IFDIR)
377 			continue;
378 		dumpino(dp, ino);
379 	}
380 
381 	msg("dumping (Pass IV) [regular files]\n");
382 	for (map = dumpinomap, ino = 0; ino < maxino; ) {
383 		if ((ino % NBBY) == 0)
384 			bits = *map++;
385 		else
386 			bits >>= 1;
387 		ino++;
388 		if ((bits & 1) == 0)
389 			continue;
390 		/*
391 		 * Skip inodes deleted and reallocated as directories.
392 		 */
393 		dp = getino(ino);
394 		if ((dp->di_mode & IFMT) == IFDIR)
395 			continue;
396 		dumpino(dp, ino);
397 	}
398 
399 	spcl.c_type = TS_END;
400 #ifndef RDUMP
401 	for (i = 0; i < ntrec; i++)
402 		writeheader(maxino);
403 #endif
404 	if (pipeout)
405 		msg("DUMP: %ld tape blocks\n",spcl.c_tapea);
406 	else
407 		msg("DUMP: %ld tape blocks on %d volumes(s)\n",
408 		    spcl.c_tapea, spcl.c_volume);
409 	msg("DUMP IS DONE\n");
410 
411 	putdumptime();
412 #ifndef RDUMP
413 	if (!pipeout) {
414 		close(tapefd);
415 		trewind();
416 	}
417 #else
418 	for (i = 0; i < ntrec; i++)
419 		writeheader(curino);
420 	trewind();
421 #endif
422 	broadcast("DUMP IS DONE!\7\7\n");
423 	Exit(X_FINOK);
424 	/* NOTREACHED */
425 }
426 
427 void
428 sigAbort()
429 {
430 	if (pipeout)
431 		quit("Unknown signal, cannot recover\n");
432 	msg("Rewriting attempted as response to unknown signal.\n");
433 	fflush(stderr);
434 	fflush(stdout);
435 	close_rewind();
436 	exit(X_REWRITE);
437 }
438 
439 void	sighup(){	msg("SIGHUP()  try rewriting\n"); sigAbort();}
440 void	sigtrap(){	msg("SIGTRAP()  try rewriting\n"); sigAbort();}
441 void	sigfpe(){	msg("SIGFPE()  try rewriting\n"); sigAbort();}
442 void	sigbus(){	msg("SIGBUS()  try rewriting\n"); sigAbort();}
443 void	sigsegv(){	msg("SIGSEGV()  ABORTING!\n"); abort();}
444 void	sigalrm(){	msg("SIGALRM()  try rewriting\n"); sigAbort();}
445 void	sigterm(){	msg("SIGTERM()  try rewriting\n"); sigAbort();}
446 
447 char *
448 rawname(cp)
449 	char *cp;
450 {
451 	static char rawbuf[32];
452 	char *rindex();
453 	char *dp = rindex(cp, '/');
454 
455 	if (dp == 0)
456 		return (0);
457 	*dp = 0;
458 	strcpy(rawbuf, cp);
459 	*dp = '/';
460 	strcat(rawbuf, "/r");
461 	strcat(rawbuf, dp+1);
462 	return (rawbuf);
463 }
464