Home | History | Annotate | Line # | Download | only in dump
main.c revision 1.2
      1 /*-
      2  * Copyright (c) 1980, 1991 The Regents of the University of California.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *	This product includes software developed by the University of
     16  *	California, Berkeley and its contributors.
     17  * 4. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  */
     33 
     34 #ifndef lint
     35 char copyright[] =
     36 "@(#) Copyright (c) 1980, 1991 The Regents of the University of California.\n\
     37  All rights reserved.\n";
     38 #endif /* not lint */
     39 
     40 #ifndef lint
     41 /* from: static char sccsid[] = "@(#)main.c	5.24 (Berkeley) 7/16/92"; */
     42 static char *rcsid = "$Id: main.c,v 1.2 1994/03/28 01:50:05 cgd Exp $";
     43 #endif /* not lint */
     44 
     45 #ifdef sunos
     46 #include <stdio.h>
     47 #include <errno.h>
     48 #include <ctype.h>
     49 #include <sys/param.h>
     50 #include <sys/stat.h>
     51 #include <ufs/fs.h>
     52 #else
     53 #include <sys/param.h>
     54 #include <sys/time.h>
     55 #include <ufs/fs.h>
     56 #endif
     57 #include <ufs/dinode.h>
     58 #include <protocols/dumprestore.h>
     59 #include <signal.h>
     60 #ifdef __STDC__
     61 #include <time.h>
     62 #endif
     63 #include <fcntl.h>
     64 #include <fstab.h>
     65 #include <stdio.h>
     66 #ifdef __STDC__
     67 #include <unistd.h>
     68 #include <stdlib.h>
     69 #include <string.h>
     70 #endif
     71 #include "dump.h"
     72 #include "pathnames.h"
     73 
     74 int	notify = 0;	/* notify operator flag */
     75 int	blockswritten = 0;	/* number of blocks written on current tape */
     76 int	tapeno = 0;	/* current tape number */
     77 int	density = 0;	/* density in bytes/0.1" */
     78 int	ntrec = NTREC;	/* # tape blocks in each tape record */
     79 int	cartridge = 0;	/* Assume non-cartridge tape */
     80 long	dev_bsize = 1;	/* recalculated below */
     81 long	blocksperfile;	/* output blocks per file */
     82 char	*host = NULL;	/* remote host (if any) */
     83 #ifdef RDUMP
     84 int	rmthost();
     85 #endif
     86 
     87 main(argc, argv)
     88 	int argc;
     89 	char **argv;
     90 {
     91 	register ino_t ino;
     92 	register int dirty;
     93 	register struct dinode *dp;
     94 	register struct	fstab *dt;
     95 	register char *map;
     96 	register char *cp;
     97 	int i, anydirskipped, bflag = 0, Tflag = 0;
     98 	float fetapes;
     99 	ino_t maxino;
    100 
    101 	spcl.c_date = 0;
    102 	(void) time((time_t *) &(spcl.c_date));
    103 
    104 	tsize = 0;	/* Default later, based on 'c' option for cart tapes */
    105 	tape = _PATH_DEFTAPE;
    106 	dumpdates = _PATH_DUMPDATES;
    107 	temp = _PATH_DTMP;
    108 	if (TP_BSIZE / DEV_BSIZE == 0 || TP_BSIZE % DEV_BSIZE != 0)
    109 		quit("TP_BSIZE must be a multiple of DEV_BSIZE\n");
    110 	level = '0';
    111 	if (argc == 1) {
    112 		(void) fprintf(stderr, "Must specify a key.\n");
    113 		Exit(X_ABORT);
    114 	}
    115 	argv++;
    116 	argc -= 2;
    117 	for (cp = *argv++; *cp; cp++) {
    118 		switch (*cp) {
    119 		case '-':
    120 			continue;
    121 
    122 		case 'w':
    123 			lastdump('w');	/* tell us only what has to be done */
    124 			(void) exit(0);
    125 
    126 		case 'W':		/* what to do */
    127 			lastdump('W');	/* tell us state of what is done */
    128 			(void) exit(0);	/* do nothing else */
    129 
    130 		case 'f':		/* output file */
    131 			if (argc < 1)
    132 				break;
    133 			tape = *argv++;
    134 			argc--;
    135 			continue;
    136 
    137 		case 'd':		/* density, in bits per inch */
    138 			if (argc < 1)
    139 				break;
    140 			density = atoi(*argv) / 10;
    141 			if (density < 1) {
    142 				(void) fprintf(stderr, "bad density \"%s\"\n",
    143 				    *argv);
    144 				Exit(X_ABORT);
    145 			}
    146 			argc--;
    147 			argv++;
    148 			if (density >= 625 && !bflag)
    149 				ntrec = HIGHDENSITYTREC;
    150 			continue;
    151 
    152 		case 's':		/* tape size, feet */
    153 			if (argc < 1)
    154 				break;
    155 			tsize = atol(*argv);
    156 			if (tsize < 1) {
    157 				(void) fprintf(stderr, "bad size \"%s\"\n",
    158 				    *argv);
    159 				Exit(X_ABORT);
    160 			}
    161 			argc--;
    162 			argv++;
    163 			tsize *= 12 * 10;
    164 			continue;
    165 
    166 		case 'T':		/* time of last dump */
    167 			if (argc < 1)
    168 				break;
    169 			spcl.c_ddate = unctime(*argv);
    170 			if (spcl.c_ddate < 0) {
    171 				(void) fprintf(stderr, "bad time \"%s\"\n",
    172 				    *argv);
    173 				Exit(X_ABORT);
    174 			}
    175 			Tflag++;
    176 			lastlevel = '?';
    177 			argc--;
    178 			argv++;
    179 			continue;
    180 
    181 		case 'b':		/* blocks per tape write */
    182 			if (argc < 1)
    183 				break;
    184 			bflag++;
    185 			ntrec = atoi(*argv);
    186 			if (ntrec < 1) {
    187 				(void) fprintf(stderr, "%s \"%s\"\n",
    188 				    "bad number of blocks per write ", *argv);
    189 				Exit(X_ABORT);
    190 			}
    191 			argc--;
    192 			argv++;
    193 			continue;
    194 
    195 		case 'B':		/* blocks per output file */
    196 			if (argc < 1)
    197 				break;
    198 			blocksperfile = atol(*argv);
    199 			if (blocksperfile < 1) {
    200 				(void) fprintf(stderr, "%s \"%s\"\n",
    201 				    "bad number of blocks per file ", *argv);
    202 				Exit(X_ABORT);
    203 			}
    204 			argc--;
    205 			argv++;
    206 			continue;
    207 
    208 		case 'c':		/* Tape is cart. not 9-track */
    209 			cartridge++;
    210 			continue;
    211 
    212 		case '0':		/* dump level */
    213 		case '1':
    214 		case '2':
    215 		case '3':
    216 		case '4':
    217 		case '5':
    218 		case '6':
    219 		case '7':
    220 		case '8':
    221 		case '9':
    222 			level = *cp;
    223 			continue;
    224 
    225 		case 'u':		/* update /etc/dumpdates */
    226 			uflag++;
    227 			continue;
    228 
    229 		case 'n':		/* notify operators */
    230 			notify++;
    231 			continue;
    232 
    233 		default:
    234 			(void) fprintf(stderr, "bad key '%c'\n", *cp);
    235 			Exit(X_ABORT);
    236 		}
    237 		(void) fprintf(stderr, "missing argument to '%c'\n", *cp);
    238 		Exit(X_ABORT);
    239 	}
    240 	if (argc < 1) {
    241 		(void) fprintf(stderr, "Must specify disk or filesystem\n");
    242 		Exit(X_ABORT);
    243 	} else {
    244 		disk = *argv++;
    245 		argc--;
    246 	}
    247 	if (argc >= 1) {
    248 		(void) fprintf(stderr, "Unknown arguments to dump:");
    249 		while (argc--)
    250 			(void) fprintf(stderr, " %s", *argv++);
    251 		(void) fprintf(stderr, "\n");
    252 		Exit(X_ABORT);
    253 	}
    254 	if (Tflag && uflag) {
    255 	        (void) fprintf(stderr,
    256 		    "You cannot use the T and u flags together.\n");
    257 		Exit(X_ABORT);
    258 	}
    259 	if (strcmp(tape, "-") == 0) {
    260 		pipeout++;
    261 		tape = "standard output";
    262 	}
    263 
    264 	if (blocksperfile)
    265 		blocksperfile = blocksperfile / ntrec * ntrec; /* round down */
    266 	else {
    267 		/*
    268 		 * Determine how to default tape size and density
    269 		 *
    270 		 *         	density				tape size
    271 		 * 9-track	1600 bpi (160 bytes/.1")	2300 ft.
    272 		 * 9-track	6250 bpi (625 bytes/.1")	2300 ft.
    273 		 * cartridge	8000 bpi (100 bytes/.1")	1700 ft.
    274 		 *						(450*4 - slop)
    275 		 */
    276 		if (density == 0)
    277 			density = cartridge ? 100 : 160;
    278 		if (tsize == 0)
    279 			tsize = cartridge ? 1700L*120L : 2300L*120L;
    280 	}
    281 
    282 	if (index(tape, ':')) {
    283 		host = tape;
    284 		tape = index(host, ':');
    285 		*tape++ = 0;
    286 #ifdef RDUMP
    287 		if (rmthost(host) == 0)
    288 			(void) exit(X_ABORT);
    289 #else
    290 		(void) fprintf(stderr, "remote dump not enabled\n");
    291 		(void) exit(X_ABORT);
    292 #endif
    293 	}
    294 	(void) setuid(getuid()); /* rmthost() is the only reason to be setuid */
    295 
    296 	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
    297 		signal(SIGHUP, sig);
    298 	if (signal(SIGTRAP, SIG_IGN) != SIG_IGN)
    299 		signal(SIGTRAP, sig);
    300 	if (signal(SIGFPE, SIG_IGN) != SIG_IGN)
    301 		signal(SIGFPE, sig);
    302 	if (signal(SIGBUS, SIG_IGN) != SIG_IGN)
    303 		signal(SIGBUS, sig);
    304 	if (signal(SIGSEGV, SIG_IGN) != SIG_IGN)
    305 		signal(SIGSEGV, sig);
    306 	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
    307 		signal(SIGTERM, sig);
    308 	if (signal(SIGINT, interrupt) == SIG_IGN)
    309 		signal(SIGINT, SIG_IGN);
    310 
    311 	set_operators();	/* /etc/group snarfed */
    312 	getfstab();		/* /etc/fstab snarfed */
    313 	/*
    314 	 *	disk can be either the full special file name,
    315 	 *	the suffix of the special file name,
    316 	 *	the special name missing the leading '/',
    317 	 *	the file system name with or without the leading '/'.
    318 	 */
    319 	dt = fstabsearch(disk);
    320 	if (dt != 0) {
    321 		disk = rawname(dt->fs_spec);
    322 		(void) strncpy(spcl.c_dev, dt->fs_spec, NAMELEN);
    323 		(void) strncpy(spcl.c_filesys, dt->fs_file, NAMELEN);
    324 	} else {
    325 		(void) strncpy(spcl.c_dev, disk, NAMELEN);
    326 		(void) strncpy(spcl.c_filesys, "an unlisted file system",
    327 		    NAMELEN);
    328 	}
    329 	(void) strcpy(spcl.c_label, "none");
    330 	(void) gethostname(spcl.c_host, NAMELEN);
    331 	spcl.c_level = level - '0';
    332 	spcl.c_type = TS_TAPE;
    333 	if (!Tflag)
    334 	        getdumptime();		/* /etc/dumpdates snarfed */
    335 
    336 	msg("Date of this level %c dump: %s", level,
    337 		spcl.c_date == 0 ? "the epoch\n" : ctime(&spcl.c_date));
    338  	msg("Date of last level %c dump: %s", lastlevel,
    339 		spcl.c_ddate == 0 ? "the epoch\n" : ctime(&spcl.c_ddate));
    340 	msg("Dumping %s ", disk);
    341 	if (dt != 0)
    342 		msgtail("(%s) ", dt->fs_file);
    343 	if (host)
    344 		msgtail("to %s on host %s\n", tape, host);
    345 	else
    346 		msgtail("to %s\n", tape);
    347 
    348 	if ((diskfd = open(disk, O_RDONLY)) < 0) {
    349 		msg("Cannot open %s\n", disk);
    350 		Exit(X_ABORT);
    351 	}
    352 	sync();
    353 	sblock = (struct fs *)sblock_buf;
    354 	bread(SBOFF, (char *) sblock, SBSIZE);
    355 	if (sblock->fs_magic != FS_MAGIC)
    356 		quit("bad sblock magic number\n");
    357 	dev_bsize = sblock->fs_fsize / fsbtodb(sblock, 1);
    358 	dev_bshift = ffs(dev_bsize) - 1;
    359 	if (dev_bsize != (1 << dev_bshift))
    360 		quit("dev_bsize (%d) is not a power of 2", dev_bsize);
    361 	tp_bshift = ffs(TP_BSIZE) - 1;
    362 	if (TP_BSIZE != (1 << tp_bshift))
    363 		quit("TP_BSIZE (%d) is not a power of 2", TP_BSIZE);
    364 #ifdef BSD44
    365 	if (sblock->fs_inodefmt >= FS_44INODEFMT)
    366 		spcl.c_flags |= DR_NEWINODEFMT;
    367 #endif
    368 	maxino = sblock->fs_ipg * sblock->fs_ncg - 1;
    369 	mapsize = roundup(howmany(sblock->fs_ipg * sblock->fs_ncg, NBBY),
    370 		TP_BSIZE);
    371 	usedinomap = (char *)calloc((unsigned) mapsize, sizeof(char));
    372 	dumpdirmap = (char *)calloc((unsigned) mapsize, sizeof(char));
    373 	dumpinomap = (char *)calloc((unsigned) mapsize, sizeof(char));
    374 	tapesize = 3 * (howmany(mapsize * sizeof(char), TP_BSIZE) + 1);
    375 
    376 	msg("mapping (Pass I) [regular files]\n");
    377 	anydirskipped = mapfiles(maxino, &tapesize);
    378 
    379 	msg("mapping (Pass II) [directories]\n");
    380 	while (anydirskipped) {
    381 		anydirskipped = mapdirs(maxino, &tapesize);
    382 	}
    383 
    384 	if (pipeout)
    385 		tapesize += 10;	/* 10 trailer blocks */
    386 	else {
    387 		if (blocksperfile)
    388 			fetapes = (float) tapesize / blocksperfile;
    389 		else if (cartridge) {
    390 			/* Estimate number of tapes, assuming streaming stops at
    391 			   the end of each block written, and not in mid-block.
    392 			   Assume no erroneous blocks; this can be compensated
    393 			   for with an artificially low tape size. */
    394 			fetapes =
    395 			(	  tapesize	/* blocks */
    396 				* TP_BSIZE	/* bytes/block */
    397 				* (1.0/density)	/* 0.1" / byte */
    398 			  +
    399 				  tapesize	/* blocks */
    400 				* (1.0/ntrec)	/* streaming-stops per block */
    401 				* 15.48		/* 0.1" / streaming-stop */
    402 			) * (1.0 / tsize );	/* tape / 0.1" */
    403 		} else {
    404 			/* Estimate number of tapes, for old fashioned 9-track
    405 			   tape */
    406 			int tenthsperirg = (density == 625) ? 3 : 7;
    407 			fetapes =
    408 			(	  tapesize	/* blocks */
    409 				* TP_BSIZE	/* bytes / block */
    410 				* (1.0/density)	/* 0.1" / byte */
    411 			  +
    412 				  tapesize	/* blocks */
    413 				* (1.0/ntrec)	/* IRG's / block */
    414 				* tenthsperirg	/* 0.1" / IRG */
    415 			) * (1.0 / tsize );	/* tape / 0.1" */
    416 		}
    417 		etapes = fetapes;		/* truncating assignment */
    418 		etapes++;
    419 		/* count the dumped inodes map on each additional tape */
    420 		tapesize += (etapes - 1) *
    421 			(howmany(mapsize * sizeof(char), TP_BSIZE) + 1);
    422 		tapesize += etapes + 10;	/* headers + 10 trailer blks */
    423 	}
    424 	if (pipeout)
    425 		msg("estimated %ld tape blocks.\n", tapesize);
    426 	else
    427 		msg("estimated %ld tape blocks on %3.2f tape(s).\n",
    428 		    tapesize, fetapes);
    429 
    430 	/*
    431 	 * Allocate tape buffer
    432 	 */
    433 	if (!alloctape())
    434 		quit("can't allocate tape buffers - try a smaller blocking factor.\n");
    435 
    436 	startnewtape(1);
    437 	(void) time((time_t *)&(tstart_writing));
    438 	dumpmap(usedinomap, TS_CLRI, maxino);
    439 
    440 	msg("dumping (Pass III) [directories]\n");
    441 	for (map = dumpdirmap, ino = 0; ino < maxino; ) {
    442 		if ((ino % NBBY) == 0)
    443 			dirty = *map++;
    444 		else
    445 			dirty >>= 1;
    446 		ino++;
    447 		if ((dirty & 1) == 0)
    448 			continue;
    449 		/*
    450 		 * Skip directory inodes deleted and maybe reallocated
    451 		 */
    452 		dp = getino(ino);
    453 		if ((dp->di_mode & IFMT) != IFDIR)
    454 			continue;
    455 		(void) dumpino(dp, ino);
    456 	}
    457 
    458 	msg("dumping (Pass IV) [regular files]\n");
    459 	for (map = dumpinomap, ino = 0; ino < maxino; ) {
    460 		if ((ino % NBBY) == 0)
    461 			dirty = *map++;
    462 		else
    463 			dirty >>= 1;
    464 		ino++;
    465 		if ((dirty & 1) == 0)
    466 			continue;
    467 		/*
    468 		 * Skip inodes deleted and reallocated as directories.
    469 		 */
    470 		dp = getino(ino);
    471 		if ((dp->di_mode & IFMT) == IFDIR)
    472 			continue;
    473 		(void) dumpino(dp, ino);
    474 	}
    475 
    476 	spcl.c_type = TS_END;
    477 	for (i = 0; i < ntrec; i++)
    478 		writeheader(maxino);
    479 	if (pipeout)
    480 		msg("DUMP: %ld tape blocks\n",spcl.c_tapea);
    481 	else
    482 		msg("DUMP: %ld tape blocks on %d volumes(s)\n",
    483 		    spcl.c_tapea, spcl.c_volume);
    484 	putdumptime();
    485 	trewind();
    486 	broadcast("DUMP IS DONE!\7\7\n");
    487 	msg("DUMP IS DONE\n");
    488 	Exit(X_FINOK);
    489 	/* NOTREACHED */
    490 }
    491 
    492 void
    493 sig(signo)
    494 	int signo;
    495 {
    496 	switch(signo) {
    497 	case SIGALRM:
    498 	case SIGBUS:
    499 	case SIGFPE:
    500 	case SIGHUP:
    501 	case SIGTERM:
    502 	case SIGTRAP:
    503 		if (pipeout)
    504 			quit("Signal on pipe: cannot recover\n");
    505 		msg("Rewriting attempted as response to unknown signal.\n");
    506 		(void) fflush(stderr);
    507 		(void) fflush(stdout);
    508 		close_rewind();
    509 		(void) exit(X_REWRITE);
    510 		/* NOTREACHED */
    511 	case SIGSEGV:
    512 		msg("SIGSEGV: ABORTING!\n");
    513 		(void) signal(SIGSEGV, SIG_DFL);
    514 		(void) kill(0, SIGSEGV);
    515 		/* NOTREACHED */
    516 	}
    517 }
    518 
    519 char *
    520 rawname(cp)
    521 	char *cp;
    522 {
    523 	static char rawbuf[MAXPATHLEN];
    524 	char *rindex();
    525 	char *dp = rindex(cp, '/');
    526 
    527 	if (dp == 0)
    528 		return (0);
    529 	*dp = 0;
    530 	(void) strcpy(rawbuf, cp);
    531 	*dp = '/';
    532 	(void) strcat(rawbuf, "/r");
    533 	(void) strcat(rawbuf, dp+1);
    534 	return (rawbuf);
    535 }
    536 
    537 #ifdef sunos
    538 char *
    539 strerror(errnum)
    540 	int errnum;
    541 {
    542 	extern int sys_nerr;
    543 	extern char *sys_errlist[];
    544 
    545 	if (errnum < sys_nerr) {
    546 		return(sys_errlist[errnum]);
    547 	} else {
    548 		return("bogus errno in strerror");
    549 	}
    550 }
    551 #endif
    552