11558Srgrimes/*- 21558Srgrimes * Copyright (c) 1980, 1991, 1993, 1994 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer. 101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * notice, this list of conditions and the following disclaimer in the 121558Srgrimes * documentation and/or other materials provided with the distribution. 131558Srgrimes * 4. Neither the name of the University nor the names of its contributors 141558Srgrimes * may be used to endorse or promote products derived from this software 151558Srgrimes * without specific prior written permission. 161558Srgrimes * 171558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271558Srgrimes * SUCH DAMAGE. 281558Srgrimes */ 291558Srgrimes 301558Srgrimes#ifndef lint 3136997Scharnierstatic const char copyright[] = 321558Srgrimes"@(#) Copyright (c) 1980, 1991, 1993, 1994\n\ 331558Srgrimes The Regents of the University of California. All rights reserved.\n"; 341558Srgrimes#endif /* not lint */ 351558Srgrimes 361558Srgrimes#ifndef lint 3736997Scharnier#if 0 3823672Speterstatic char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/1/95"; 3936997Scharnier#endif 4036997Scharnierstatic const char rcsid[] = 4150476Speter "$FreeBSD$"; 421558Srgrimes#endif /* not lint */ 431558Srgrimes 441558Srgrimes#include <sys/param.h> 4558928Sjoerg#include <sys/stat.h> 46107559Smckusick#include <sys/mount.h> 4796478Sphk#include <sys/disklabel.h> 481558Srgrimes 4923672Speter#include <ufs/ufs/dinode.h> 50107559Smckusick#include <ufs/ufs/ufsmount.h> 511558Srgrimes#include <ufs/ffs/fs.h> 521558Srgrimes 531558Srgrimes#include <protocols/dumprestore.h> 541558Srgrimes 551558Srgrimes#include <ctype.h> 5623672Speter#include <err.h> 57107559Smckusick#include <errno.h> 581558Srgrimes#include <fcntl.h> 591558Srgrimes#include <fstab.h> 60103949Smike#include <limits.h> 611558Srgrimes#include <signal.h> 62122669Sjohan#include <stdint.h> 631558Srgrimes#include <stdio.h> 641558Srgrimes#include <stdlib.h> 651558Srgrimes#include <string.h> 66217769Smckusick#include <time.h> 6799562Siedowse#include <timeconv.h> 681558Srgrimes#include <unistd.h> 691558Srgrimes 701558Srgrimes#include "dump.h" 711558Srgrimes#include "pathnames.h" 721558Srgrimes 731558Srgrimesint notify = 0; /* notify operator flag */ 74107559Smckusickint snapdump = 0; /* dumping live filesystem, so use snapshot */ 751558Srgrimesint blockswritten = 0; /* number of blocks written on current tape */ 761558Srgrimesint tapeno = 0; /* current tape number */ 7712377Sjoergint density = 0; /* density in bytes/0.1" " <- this is for hilit19 */ 781558Srgrimesint ntrec = NTREC; /* # tape blocks in each tape record */ 791558Srgrimesint cartridge = 0; /* Assume non-cartridge tape */ 80109187Sdillonint cachesize = 0; /* block cache size (in bytes), defaults to 0 */ 811558Srgrimeslong dev_bsize = 1; /* recalculated below */ 821558Srgrimeslong blocksperfile; /* output blocks per file */ 831558Srgrimeschar *host = NULL; /* remote host (if any) */ 841558Srgrimes 8598542Smckusick/* 8698542Smckusick * Possible superblock locations ordered from most to least likely. 8798542Smckusick */ 8898542Smckusickstatic int sblock_try[] = SBLOCKSEARCH; 8998542Smckusick 90107559Smckusickstatic char *getmntpt(char *, int *); 9192837Simpstatic long numarg(const char *, long, long); 9292837Simpstatic void obsolete(int *, char **[]); 9392837Simpstatic void usage(void) __dead2; 941558Srgrimes 951558Srgrimesint 9692837Simpmain(int argc, char *argv[]) 971558Srgrimes{ 9886470Siedowse struct stat sb; 9986473Siedowse ino_t ino; 10086473Siedowse int dirty; 10198542Smckusick union dinode *dp; 102107559Smckusick struct fstab *dt; 103107559Smckusick char *map, *mntpt; 104107559Smckusick int ch, mode, mntflags; 1051558Srgrimes int i, anydirskipped, bflag = 0, Tflag = 0, honorlevel = 1; 10691540Siedowse int just_estimate = 0; 1071558Srgrimes ino_t maxino; 10885635Sdillon char *tmsg; 1091558Srgrimes 11098542Smckusick spcl.c_date = _time_to_time64(time(NULL)); 1111558Srgrimes 1121558Srgrimes tsize = 0; /* Default later, based on 'c' option for cart tapes */ 1131558Srgrimes dumpdates = _PATH_DUMPDATES; 114128175Sgreen popenout = NULL; 115128175Sgreen tape = NULL; 1161558Srgrimes temp = _PATH_DTMP; 1171558Srgrimes if (TP_BSIZE / DEV_BSIZE == 0 || TP_BSIZE % DEV_BSIZE != 0) 1181558Srgrimes quit("TP_BSIZE must be a multiple of DEV_BSIZE\n"); 119179275Smckusick level = 0; 120179267Smckusick rsync_friendly = 0; 1211558Srgrimes 12223672Speter if (argc < 2) 12323672Speter usage(); 1241558Srgrimes 12523672Speter obsolete(&argc, &argv); 126114463Sru while ((ch = getopt(argc, argv, 127179267Smckusick "0123456789aB:b:C:cD:d:f:h:LnP:RrSs:T:uWw")) != -1) 12823672Speter switch (ch) { 12923672Speter /* dump level */ 13023672Speter case '0': case '1': case '2': case '3': case '4': 13123672Speter case '5': case '6': case '7': case '8': case '9': 132179275Smckusick level = 10 * level + ch - '0'; 1331558Srgrimes break; 1341558Srgrimes 13523672Speter case 'a': /* `auto-size', Write to EOM. */ 13623672Speter unlimited = 1; 1371558Srgrimes break; 1381558Srgrimes 13923672Speter case 'B': /* blocks per output file */ 14023672Speter blocksperfile = numarg("number of blocks per file", 14123672Speter 1L, 0L); 1421558Srgrimes break; 1431558Srgrimes 1441558Srgrimes case 'b': /* blocks per tape write */ 14523672Speter ntrec = numarg("number of blocks per write", 14623672Speter 1L, 1000L); 1471558Srgrimes break; 1481558Srgrimes 149111287Sru case 'C': 150111287Sru cachesize = numarg("cachesize", 0, 0) * 1024 * 1024; 151111287Sru break; 152111287Sru 1531558Srgrimes case 'c': /* Tape is cart. not 9-track */ 1541558Srgrimes cartridge = 1; 1551558Srgrimes break; 1561558Srgrimes 157111287Sru case 'D': 158111287Sru dumpdates = optarg; 159111287Sru break; 160111287Sru 16123672Speter case 'd': /* density, in bits per inch */ 16223672Speter density = numarg("density", 10L, 327670L) / 10; 16323672Speter if (density >= 625 && !bflag) 16423672Speter ntrec = HIGHDENSITYTREC; 16522192Sjoerg break; 16622192Sjoerg 16723672Speter case 'f': /* output file */ 168128175Sgreen if (popenout != NULL) 169128175Sgreen errx(X_STARTUP, "You cannot use the P and f " 170128175Sgreen "flags together.\n"); 17123672Speter tape = optarg; 1721558Srgrimes break; 1731558Srgrimes 17423672Speter case 'h': 17523672Speter honorlevel = numarg("honor level", 0L, 10L); 1761558Srgrimes break; 1771558Srgrimes 178107559Smckusick case 'L': 179107559Smckusick snapdump = 1; 180107559Smckusick break; 181107559Smckusick 1821558Srgrimes case 'n': /* notify operators */ 1831558Srgrimes notify = 1; 1841558Srgrimes break; 1851558Srgrimes 186128175Sgreen case 'P': 187128175Sgreen if (tape != NULL) 188128175Sgreen errx(X_STARTUP, "You cannot use the P and f " 189128175Sgreen "flags together.\n"); 190128175Sgreen popenout = optarg; 191128175Sgreen break; 192128175Sgreen 193179267Smckusick case 'r': /* store slightly less data to be friendly to rsync */ 194179267Smckusick if (rsync_friendly < 1) 195179267Smckusick rsync_friendly = 1; 196179267Smckusick break; 197179267Smckusick 198179267Smckusick case 'R': /* store even less data to be friendlier to rsync */ 199179267Smckusick if (rsync_friendly < 2) 200179267Smckusick rsync_friendly = 2; 201179267Smckusick break; 202179267Smckusick 203111287Sru case 'S': /* exit after estimating # of tapes */ 204111287Sru just_estimate = 1; 205111287Sru break; 206111287Sru 20723672Speter case 's': /* tape size, feet */ 20823672Speter tsize = numarg("tape size", 1L, 0L) * 12 * 10; 2091558Srgrimes break; 2101558Srgrimes 21123672Speter case 'T': /* time of last dump */ 21223672Speter spcl.c_ddate = unctime(optarg); 21323672Speter if (spcl.c_ddate < 0) { 21423672Speter (void)fprintf(stderr, "bad time \"%s\"\n", 21523672Speter optarg); 21637635Sjkoshy exit(X_STARTUP); 21723672Speter } 21823672Speter Tflag = 1; 219179275Smckusick lastlevel = -1; 22023672Speter break; 22123672Speter 22223672Speter case 'u': /* update /etc/dumpdates */ 22323672Speter uflag = 1; 22423672Speter break; 22523672Speter 22623672Speter case 'W': /* what to do */ 22723672Speter case 'w': 22823672Speter lastdump(ch); 22937635Sjkoshy exit(X_FINOK); /* do nothing else */ 23023672Speter 2311558Srgrimes default: 23223672Speter usage(); 2331558Srgrimes } 23423672Speter argc -= optind; 23523672Speter argv += optind; 23623672Speter 2371558Srgrimes if (argc < 1) { 238102231Strhodes (void)fprintf(stderr, "Must specify disk or file system\n"); 23937635Sjkoshy exit(X_STARTUP); 2401558Srgrimes } 2411558Srgrimes disk = *argv++; 2421558Srgrimes argc--; 2431558Srgrimes if (argc >= 1) { 2441558Srgrimes (void)fprintf(stderr, "Unknown arguments to dump:"); 2451558Srgrimes while (argc--) 2461558Srgrimes (void)fprintf(stderr, " %s", *argv++); 2471558Srgrimes (void)fprintf(stderr, "\n"); 24837635Sjkoshy exit(X_STARTUP); 2491558Srgrimes } 250179275Smckusick if (rsync_friendly && (level > 0)) { 251179267Smckusick (void)fprintf(stderr, "%s %s\n", "rsync friendly options", 252179267Smckusick "can be used only with level 0 dumps."); 253179267Smckusick exit(X_STARTUP); 254179267Smckusick } 2551558Srgrimes if (Tflag && uflag) { 2561558Srgrimes (void)fprintf(stderr, 2571558Srgrimes "You cannot use the T and u flags together.\n"); 25837635Sjkoshy exit(X_STARTUP); 2591558Srgrimes } 260128175Sgreen if (popenout) { 261128175Sgreen tape = "child pipeline process"; 262128175Sgreen } else if (tape == NULL && (tape = getenv("TAPE")) == NULL) 263128175Sgreen tape = _PATH_DEFTAPE; 2641558Srgrimes if (strcmp(tape, "-") == 0) { 2651558Srgrimes pipeout++; 2661558Srgrimes tape = "standard output"; 2671558Srgrimes } 2681558Srgrimes 2691558Srgrimes if (blocksperfile) 2701558Srgrimes blocksperfile = blocksperfile / ntrec * ntrec; /* round down */ 27122192Sjoerg else if (!unlimited) { 2721558Srgrimes /* 2731558Srgrimes * Determine how to default tape size and density 2741558Srgrimes * 2751558Srgrimes * density tape size 2761558Srgrimes * 9-track 1600 bpi (160 bytes/.1") 2300 ft. 2771558Srgrimes * 9-track 6250 bpi (625 bytes/.1") 2300 ft. 2781558Srgrimes * cartridge 8000 bpi (100 bytes/.1") 1700 ft. 2791558Srgrimes * (450*4 - slop) 28012377Sjoerg * hilit19 hits again: " 2811558Srgrimes */ 2821558Srgrimes if (density == 0) 2831558Srgrimes density = cartridge ? 100 : 160; 2841558Srgrimes if (tsize == 0) 2851558Srgrimes tsize = cartridge ? 1700L*120L : 2300L*120L; 2861558Srgrimes } 2871558Srgrimes 28823672Speter if (strchr(tape, ':')) { 2891558Srgrimes host = tape; 29023672Speter tape = strchr(host, ':'); 2911558Srgrimes *tape++ = '\0'; 2921558Srgrimes#ifdef RDUMP 293229403Sed if (strchr(tape, '\n')) { 29421409Simp (void)fprintf(stderr, "invalid characters in tape\n"); 29537635Sjkoshy exit(X_STARTUP); 29621409Simp } 2971558Srgrimes if (rmthost(host) == 0) 29837635Sjkoshy exit(X_STARTUP); 2991558Srgrimes#else 3001558Srgrimes (void)fprintf(stderr, "remote dump not enabled\n"); 30137635Sjkoshy exit(X_STARTUP); 3021558Srgrimes#endif 3031558Srgrimes } 3041558Srgrimes (void)setuid(getuid()); /* rmthost() is the only reason to be setuid */ 3051558Srgrimes 3061558Srgrimes if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 3071558Srgrimes signal(SIGHUP, sig); 3081558Srgrimes if (signal(SIGTRAP, SIG_IGN) != SIG_IGN) 3091558Srgrimes signal(SIGTRAP, sig); 3101558Srgrimes if (signal(SIGFPE, SIG_IGN) != SIG_IGN) 3111558Srgrimes signal(SIGFPE, sig); 3121558Srgrimes if (signal(SIGBUS, SIG_IGN) != SIG_IGN) 3131558Srgrimes signal(SIGBUS, sig); 3141558Srgrimes if (signal(SIGSEGV, SIG_IGN) != SIG_IGN) 3151558Srgrimes signal(SIGSEGV, sig); 3161558Srgrimes if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 3171558Srgrimes signal(SIGTERM, sig); 3181558Srgrimes if (signal(SIGINT, interrupt) == SIG_IGN) 3191558Srgrimes signal(SIGINT, SIG_IGN); 3201558Srgrimes 321113214Smdodd dump_getfstab(); /* /etc/fstab snarfed */ 3221558Srgrimes /* 3231558Srgrimes * disk can be either the full special file name, 3241558Srgrimes * the suffix of the special file name, 3251558Srgrimes * the special name missing the leading '/', 326102231Strhodes * the file system name with or without the leading '/'. 3271558Srgrimes */ 3281558Srgrimes dt = fstabsearch(disk); 3291558Srgrimes if (dt != NULL) { 3301558Srgrimes disk = rawname(dt->fs_spec); 331161333Smjacob if (disk == NULL) 332161333Smjacob errx(X_STARTUP, "%s: unknown file system", dt->fs_spec); 3331558Srgrimes (void)strncpy(spcl.c_dev, dt->fs_spec, NAMELEN); 3341558Srgrimes (void)strncpy(spcl.c_filesys, dt->fs_file, NAMELEN); 3351558Srgrimes } else { 3361558Srgrimes (void)strncpy(spcl.c_dev, disk, NAMELEN); 337102231Strhodes (void)strncpy(spcl.c_filesys, "an unlisted file system", 3381558Srgrimes NAMELEN); 3391558Srgrimes } 34021409Simp spcl.c_dev[NAMELEN-1]='\0'; 34121409Simp spcl.c_filesys[NAMELEN-1]='\0'; 342107559Smckusick 343107559Smckusick if ((mntpt = getmntpt(disk, &mntflags)) != 0) { 344128166Sgreen if (mntflags & MNT_RDONLY) { 345128166Sgreen if (snapdump != 0) { 346128166Sgreen msg("WARNING: %s\n", 347128166Sgreen "-L ignored for read-only filesystem."); 348128166Sgreen snapdump = 0; 349128166Sgreen } 350128166Sgreen } else if (snapdump == 0) { 351128175Sgreen msg("WARNING: %s\n", 352128175Sgreen "should use -L when dumping live read-write " 353128166Sgreen "filesystems!"); 354107559Smckusick } else { 355122787Smckusick char snapname[BUFSIZ], snapcmd[BUFSIZ]; 356107559Smckusick 357140602Swes snprintf(snapname, sizeof snapname, "%s/.snap", mntpt); 358140602Swes if ((stat(snapname, &sb) < 0) || !S_ISDIR(sb.st_mode)) { 359140602Swes msg("WARNING: %s %s\n", 360140602Swes "-L requested but snapshot location", 361140602Swes snapname); 362140602Swes msg(" %s: %s\n", 363140602Swes "is not a directory", 364140602Swes "dump downgraded, -L ignored"); 365140602Swes snapdump = 0; 366140602Swes } else { 367140602Swes snprintf(snapname, sizeof snapname, 368140602Swes "%s/.snap/dump_snapshot", mntpt); 369140602Swes snprintf(snapcmd, sizeof snapcmd, "%s %s %s", 370140602Swes _PATH_MKSNAP_FFS, mntpt, snapname); 371107559Smckusick unlink(snapname); 372140602Swes if (system(snapcmd) != 0) 373140602Swes errx(X_STARTUP, "Cannot create %s: %s\n", 374140602Swes snapname, strerror(errno)); 375140602Swes if ((diskfd = open(snapname, O_RDONLY)) < 0) { 376140602Swes unlink(snapname); 377140602Swes errx(X_STARTUP, "Cannot open %s: %s\n", 378140602Swes snapname, strerror(errno)); 379140602Swes } 380140602Swes unlink(snapname); 381140602Swes if (fstat(diskfd, &sb) != 0) 382140602Swes err(X_STARTUP, "%s: stat", snapname); 383140602Swes spcl.c_date = _time_to_time64(sb.st_mtime); 384107559Smckusick } 385107559Smckusick } 386107559Smckusick } else if (snapdump != 0) { 387107559Smckusick msg("WARNING: Cannot use -L on an unmounted filesystem.\n"); 388107559Smckusick snapdump = 0; 389107559Smckusick } 390107559Smckusick if (snapdump == 0) { 391107559Smckusick if ((diskfd = open(disk, O_RDONLY)) < 0) 392107559Smckusick err(X_STARTUP, "Cannot open %s", disk); 393107559Smckusick if (fstat(diskfd, &sb) != 0) 394107559Smckusick err(X_STARTUP, "%s: stat", disk); 395107559Smckusick if (S_ISDIR(sb.st_mode)) 396107559Smckusick errx(X_STARTUP, "%s: unknown file system", disk); 397107559Smckusick } 398107559Smckusick 3991558Srgrimes (void)strcpy(spcl.c_label, "none"); 4001558Srgrimes (void)gethostname(spcl.c_host, NAMELEN); 401179275Smckusick spcl.c_level = level; 4021558Srgrimes spcl.c_type = TS_TAPE; 403179267Smckusick if (rsync_friendly) { 404179267Smckusick /* don't store real dump times */ 405179267Smckusick spcl.c_date = 0; 406179267Smckusick spcl.c_ddate = 0; 407179267Smckusick } 40885635Sdillon if (spcl.c_date == 0) { 40985635Sdillon tmsg = "the epoch\n"; 41085635Sdillon } else { 41198542Smckusick time_t t = _time64_to_time(spcl.c_date); 41285635Sdillon tmsg = ctime(&t); 41385635Sdillon } 414179275Smckusick msg("Date of this level %d dump: %s", level, tmsg); 415107559Smckusick 416179267Smckusick if (!Tflag && (!rsync_friendly)) 417107559Smckusick getdumptime(); /* /etc/dumpdates snarfed */ 41885635Sdillon if (spcl.c_ddate == 0) { 41985635Sdillon tmsg = "the epoch\n"; 42085635Sdillon } else { 42198542Smckusick time_t t = _time64_to_time(spcl.c_ddate); 42285635Sdillon tmsg = ctime(&t); 42385635Sdillon } 424179275Smckusick if (lastlevel < 0) 425179275Smckusick msg("Date of last (level unknown) dump: %s", tmsg); 426179275Smckusick else 427179275Smckusick msg("Date of last level %d dump: %s", lastlevel, tmsg); 428107559Smckusick 429107559Smckusick msg("Dumping %s%s ", snapdump ? "snapshot of ": "", disk); 4301558Srgrimes if (dt != NULL) 4311558Srgrimes msgtail("(%s) ", dt->fs_file); 4321558Srgrimes if (host) 4331558Srgrimes msgtail("to %s on host %s\n", tape, host); 4341558Srgrimes else 4351558Srgrimes msgtail("to %s\n", tape); 4361558Srgrimes 4371558Srgrimes sync(); 4381558Srgrimes sblock = (struct fs *)sblock_buf; 43998542Smckusick for (i = 0; sblock_try[i] != -1; i++) { 440114810Smckusick sblock->fs_fsize = SBLOCKSIZE; /* needed in bread */ 44198542Smckusick bread(sblock_try[i] >> dev_bshift, (char *) sblock, SBLOCKSIZE); 44298542Smckusick if ((sblock->fs_magic == FS_UFS1_MAGIC || 44398542Smckusick (sblock->fs_magic == FS_UFS2_MAGIC && 444107294Smckusick sblock->fs_sblockloc == sblock_try[i])) && 44598542Smckusick sblock->fs_bsize <= MAXBSIZE && 44698542Smckusick sblock->fs_bsize >= sizeof(struct fs)) 44798542Smckusick break; 44898542Smckusick } 44998542Smckusick if (sblock_try[i] == -1) 450102231Strhodes quit("Cannot find file system superblock\n"); 4511558Srgrimes dev_bsize = sblock->fs_fsize / fsbtodb(sblock, 1); 4521558Srgrimes dev_bshift = ffs(dev_bsize) - 1; 4531558Srgrimes if (dev_bsize != (1 << dev_bshift)) 45499562Siedowse quit("dev_bsize (%ld) is not a power of 2", dev_bsize); 4551558Srgrimes tp_bshift = ffs(TP_BSIZE) - 1; 4561558Srgrimes if (TP_BSIZE != (1 << tp_bshift)) 4571558Srgrimes quit("TP_BSIZE (%d) is not a power of 2", TP_BSIZE); 4581558Srgrimes maxino = sblock->fs_ipg * sblock->fs_ncg; 459103949Smike mapsize = roundup(howmany(maxino, CHAR_BIT), TP_BSIZE); 4601558Srgrimes usedinomap = (char *)calloc((unsigned) mapsize, sizeof(char)); 4611558Srgrimes dumpdirmap = (char *)calloc((unsigned) mapsize, sizeof(char)); 4621558Srgrimes dumpinomap = (char *)calloc((unsigned) mapsize, sizeof(char)); 4631558Srgrimes tapesize = 3 * (howmany(mapsize * sizeof(char), TP_BSIZE) + 1); 4641558Srgrimes 4651558Srgrimes nonodump = spcl.c_level < honorlevel; 4661558Srgrimes 46790743Siedowse passno = 1; 46890743Siedowse setproctitle("%s: pass 1: regular files", disk); 4691558Srgrimes msg("mapping (Pass I) [regular files]\n"); 4701558Srgrimes anydirskipped = mapfiles(maxino, &tapesize); 4711558Srgrimes 47290743Siedowse passno = 2; 47390743Siedowse setproctitle("%s: pass 2: directories", disk); 4741558Srgrimes msg("mapping (Pass II) [directories]\n"); 4751558Srgrimes while (anydirskipped) { 4761558Srgrimes anydirskipped = mapdirs(maxino, &tapesize); 4771558Srgrimes } 4781558Srgrimes 47922192Sjoerg if (pipeout || unlimited) { 4801558Srgrimes tapesize += 10; /* 10 trailer blocks */ 4811558Srgrimes msg("estimated %ld tape blocks.\n", tapesize); 4821558Srgrimes } else { 4831558Srgrimes double fetapes; 4841558Srgrimes 4851558Srgrimes if (blocksperfile) 4861558Srgrimes fetapes = (double) tapesize / blocksperfile; 4871558Srgrimes else if (cartridge) { 4881558Srgrimes /* Estimate number of tapes, assuming streaming stops at 4891558Srgrimes the end of each block written, and not in mid-block. 4901558Srgrimes Assume no erroneous blocks; this can be compensated 4911558Srgrimes for with an artificially low tape size. */ 4928871Srgrimes fetapes = 49321407Spst ( (double) tapesize /* blocks */ 4941558Srgrimes * TP_BSIZE /* bytes/block */ 49512377Sjoerg * (1.0/density) /* 0.1" / byte " */ 4961558Srgrimes + 49721407Spst (double) tapesize /* blocks */ 4981558Srgrimes * (1.0/ntrec) /* streaming-stops per block */ 49912377Sjoerg * 15.48 /* 0.1" / streaming-stop " */ 50012377Sjoerg ) * (1.0 / tsize ); /* tape / 0.1" " */ 5011558Srgrimes } else { 5021558Srgrimes /* Estimate number of tapes, for old fashioned 9-track 5031558Srgrimes tape */ 5041558Srgrimes int tenthsperirg = (density == 625) ? 3 : 7; 5051558Srgrimes fetapes = 50621407Spst ( (double) tapesize /* blocks */ 5071558Srgrimes * TP_BSIZE /* bytes / block */ 50812377Sjoerg * (1.0/density) /* 0.1" / byte " */ 5091558Srgrimes + 51021407Spst (double) tapesize /* blocks */ 5111558Srgrimes * (1.0/ntrec) /* IRG's / block */ 51212377Sjoerg * tenthsperirg /* 0.1" / IRG " */ 51312377Sjoerg ) * (1.0 / tsize ); /* tape / 0.1" " */ 5141558Srgrimes } 5151558Srgrimes etapes = fetapes; /* truncating assignment */ 5161558Srgrimes etapes++; 5171558Srgrimes /* count the dumped inodes map on each additional tape */ 5181558Srgrimes tapesize += (etapes - 1) * 5191558Srgrimes (howmany(mapsize * sizeof(char), TP_BSIZE) + 1); 5201558Srgrimes tapesize += etapes + 10; /* headers + 10 trailer blks */ 5211558Srgrimes msg("estimated %ld tape blocks on %3.2f tape(s).\n", 5221558Srgrimes tapesize, fetapes); 5231558Srgrimes } 5241558Srgrimes 52591540Siedowse /* 52691540Siedowse * If the user only wants an estimate of the number of 52791540Siedowse * tapes, exit now. 52891540Siedowse */ 52991540Siedowse if (just_estimate) 53091540Siedowse exit(0); 53191540Siedowse 5321558Srgrimes /* 5331558Srgrimes * Allocate tape buffer. 5341558Srgrimes */ 5351558Srgrimes if (!alloctape()) 53636997Scharnier quit( 53736997Scharnier "can't allocate tape buffers - try a smaller blocking factor.\n"); 5381558Srgrimes 5391558Srgrimes startnewtape(1); 5401558Srgrimes (void)time((time_t *)&(tstart_writing)); 5411558Srgrimes dumpmap(usedinomap, TS_CLRI, maxino - 1); 5421558Srgrimes 54390743Siedowse passno = 3; 54490743Siedowse setproctitle("%s: pass 3: directories", disk); 5451558Srgrimes msg("dumping (Pass III) [directories]\n"); 5461558Srgrimes dirty = 0; /* XXX just to get gcc to shut up */ 5471558Srgrimes for (map = dumpdirmap, ino = 1; ino < maxino; ino++) { 548103949Smike if (((ino - 1) % CHAR_BIT) == 0) /* map is offset by 1 */ 5491558Srgrimes dirty = *map++; 5501558Srgrimes else 5511558Srgrimes dirty >>= 1; 5521558Srgrimes if ((dirty & 1) == 0) 5531558Srgrimes continue; 5541558Srgrimes /* 5551558Srgrimes * Skip directory inodes deleted and maybe reallocated 5561558Srgrimes */ 55798542Smckusick dp = getino(ino, &mode); 55898542Smckusick if (mode != IFDIR) 5591558Srgrimes continue; 5601558Srgrimes (void)dumpino(dp, ino); 5611558Srgrimes } 5621558Srgrimes 56390743Siedowse passno = 4; 56490743Siedowse setproctitle("%s: pass 4: regular files", disk); 5651558Srgrimes msg("dumping (Pass IV) [regular files]\n"); 5661558Srgrimes for (map = dumpinomap, ino = 1; ino < maxino; ino++) { 567103949Smike if (((ino - 1) % CHAR_BIT) == 0) /* map is offset by 1 */ 5681558Srgrimes dirty = *map++; 5691558Srgrimes else 5701558Srgrimes dirty >>= 1; 5711558Srgrimes if ((dirty & 1) == 0) 5721558Srgrimes continue; 5731558Srgrimes /* 5741558Srgrimes * Skip inodes deleted and reallocated as directories. 5751558Srgrimes */ 57698542Smckusick dp = getino(ino, &mode); 5771558Srgrimes if (mode == IFDIR) 5781558Srgrimes continue; 5791558Srgrimes (void)dumpino(dp, ino); 5801558Srgrimes } 5811558Srgrimes 58212377Sjoerg (void)time((time_t *)&(tend_writing)); 5831558Srgrimes spcl.c_type = TS_END; 5841558Srgrimes for (i = 0; i < ntrec; i++) 5851558Srgrimes writeheader(maxino - 1); 5861558Srgrimes if (pipeout) 58799562Siedowse msg("DUMP: %jd tape blocks\n", (intmax_t)spcl.c_tapea); 5881558Srgrimes else 58999562Siedowse msg("DUMP: %jd tape blocks on %d volume%s\n", 59099562Siedowse (intmax_t)spcl.c_tapea, spcl.c_volume, 59147446Sjmz (spcl.c_volume == 1) ? "" : "s"); 59212377Sjoerg 59312377Sjoerg /* report dump performance, avoid division through zero */ 59412377Sjoerg if (tend_writing - tstart_writing == 0) 59512377Sjoerg msg("finished in less than a second\n"); 59612377Sjoerg else 597122669Sjohan msg("finished in %jd seconds, throughput %jd KBytes/sec\n", 598122669Sjohan (intmax_t)tend_writing - tstart_writing, 599122669Sjohan (intmax_t)(spcl.c_tapea / 60099562Siedowse (tend_writing - tstart_writing))); 60112377Sjoerg 6021558Srgrimes putdumptime(); 6031558Srgrimes trewind(); 60471750Sphk broadcast("DUMP IS DONE!\a\a\n"); 6051558Srgrimes msg("DUMP IS DONE\n"); 6061558Srgrimes Exit(X_FINOK); 6071558Srgrimes /* NOTREACHED */ 6081558Srgrimes} 6091558Srgrimes 61023672Speterstatic void 61192837Simpusage(void) 61223672Speter{ 61326543Scharnier fprintf(stderr, 614114463Sru "usage: dump [-0123456789acLnSu] [-B records] [-b blocksize] [-C cachesize]\n" 615141611Sru " [-D dumpdates] [-d density] [-f file | -P pipecommand] [-h level]\n" 616141611Sru " [-s feet] [-T date] filesystem\n" 617104290Sbde " dump -W | -w\n"); 61837635Sjkoshy exit(X_STARTUP); 61923672Speter} 62023672Speter 6211558Srgrimes/* 622107559Smckusick * Check to see if a disk is currently mounted. 623107559Smckusick */ 624107559Smckusickstatic char * 625107559Smckusickgetmntpt(char *name, int *mntflagsp) 626107559Smckusick{ 627107559Smckusick long mntsize, i; 628107559Smckusick struct statfs *mntbuf; 629107559Smckusick 630107559Smckusick mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 631107559Smckusick for (i = 0; i < mntsize; i++) { 632107559Smckusick if (!strcmp(mntbuf[i].f_mntfromname, name)) { 633107559Smckusick *mntflagsp = mntbuf[i].f_flags; 634107559Smckusick return (mntbuf[i].f_mntonname); 635107559Smckusick } 636107559Smckusick } 637107559Smckusick return (0); 638107559Smckusick} 639107559Smckusick 640107559Smckusick/* 6411558Srgrimes * Pick up a numeric argument. It must be nonnegative and in the given 6421558Srgrimes * range (except that a vmax of 0 means unlimited). 6431558Srgrimes */ 6441558Srgrimesstatic long 64592837Simpnumarg(const char *meaning, long vmin, long vmax) 6461558Srgrimes{ 64723672Speter char *p; 6481558Srgrimes long val; 6491558Srgrimes 65023672Speter val = strtol(optarg, &p, 10); 65123672Speter if (*p) 65223672Speter errx(1, "illegal %s -- %s", meaning, optarg); 6531558Srgrimes if (val < vmin || (vmax && val > vmax)) 65423672Speter errx(1, "%s must be between %ld and %ld", meaning, vmin, vmax); 6551558Srgrimes return (val); 6561558Srgrimes} 6571558Srgrimes 6581558Srgrimesvoid 65992837Simpsig(int signo) 6601558Srgrimes{ 6611558Srgrimes switch(signo) { 6621558Srgrimes case SIGALRM: 6631558Srgrimes case SIGBUS: 6641558Srgrimes case SIGFPE: 6651558Srgrimes case SIGHUP: 6661558Srgrimes case SIGTERM: 6671558Srgrimes case SIGTRAP: 6681558Srgrimes if (pipeout) 6691558Srgrimes quit("Signal on pipe: cannot recover\n"); 6701558Srgrimes msg("Rewriting attempted as response to unknown signal.\n"); 6711558Srgrimes (void)fflush(stderr); 6721558Srgrimes (void)fflush(stdout); 6731558Srgrimes close_rewind(); 6741558Srgrimes exit(X_REWRITE); 6751558Srgrimes /* NOTREACHED */ 6761558Srgrimes case SIGSEGV: 6771558Srgrimes msg("SIGSEGV: ABORTING!\n"); 6781558Srgrimes (void)signal(SIGSEGV, SIG_DFL); 6791558Srgrimes (void)kill(0, SIGSEGV); 6801558Srgrimes /* NOTREACHED */ 6811558Srgrimes } 6821558Srgrimes} 6831558Srgrimes 6841558Srgrimeschar * 68592837Simprawname(char *cp) 6861558Srgrimes{ 68758928Sjoerg struct stat sb; 6881558Srgrimes 689145238Simp /* 690145238Simp * Ensure that the device passed in is a raw device. 691145238Simp */ 692145238Simp if (stat(cp, &sb) == 0 && (sb.st_mode & S_IFMT) == S_IFCHR) 693145238Simp return (cp); 69458928Sjoerg 695145238Simp /* 696145238Simp * Since there's only one device type now, we can't construct any 697145238Simp * better name, so we have to return NULL. 698145238Simp */ 699145238Simp return (NULL); 7001558Srgrimes} 7011558Srgrimes 70223672Speter/* 70323672Speter * obsolete -- 70423672Speter * Change set of key letters and ordered arguments into something 70523672Speter * getopt(3) will like. 70623672Speter */ 70723672Speterstatic void 70892837Simpobsolete(int *argcp, char **argvp[]) 7091558Srgrimes{ 71023672Speter int argc, flags; 71123672Speter char *ap, **argv, *flagsp, **nargv, *p; 7121558Srgrimes 71323672Speter /* Setup. */ 71423672Speter argv = *argvp; 71523672Speter argc = *argcp; 71623672Speter 717163280Sru /* 718163280Sru * Return if no arguments or first argument has leading 719163280Sru * dash or slash. 720163280Sru */ 72123672Speter ap = argv[1]; 722163280Sru if (argc == 1 || *ap == '-' || *ap == '/') 72323672Speter return; 72423672Speter 72523672Speter /* Allocate space for new arguments. */ 72623672Speter if ((*argvp = nargv = malloc((argc + 1) * sizeof(char *))) == NULL || 72723672Speter (p = flagsp = malloc(strlen(ap) + 2)) == NULL) 72823672Speter err(1, NULL); 72923672Speter 73023672Speter *nargv++ = *argv; 73123672Speter argv += 2; 73223672Speter 73323672Speter for (flags = 0; *ap; ++ap) { 73423672Speter switch (*ap) { 73523672Speter case 'B': 73623672Speter case 'b': 73723672Speter case 'd': 73823672Speter case 'f': 73979428Sdillon case 'D': 740109188Sdillon case 'C': 74123672Speter case 'h': 74223672Speter case 's': 74323672Speter case 'T': 74423672Speter if (*argv == NULL) { 74523672Speter warnx("option requires an argument -- %c", *ap); 74623672Speter usage(); 74723672Speter } 74823672Speter if ((nargv[0] = malloc(strlen(*argv) + 2 + 1)) == NULL) 74923672Speter err(1, NULL); 75023672Speter nargv[0][0] = '-'; 75123672Speter nargv[0][1] = *ap; 75223672Speter (void)strcpy(&nargv[0][2], *argv); 75323672Speter ++argv; 75423672Speter ++nargv; 75523672Speter break; 75623672Speter default: 75723672Speter if (!flags) { 75823672Speter *p++ = '-'; 75923672Speter flags = 1; 76023672Speter } 76123672Speter *p++ = *ap; 76223672Speter break; 76323672Speter } 76423672Speter } 76523672Speter 76623672Speter /* Terminate flags. */ 76723672Speter if (flags) { 76823672Speter *p = '\0'; 76923672Speter *nargv++ = flagsp; 770203459Sdelphij } else 771203459Sdelphij free(flagsp); 77223672Speter 77323672Speter /* Copy remaining arguments. */ 77436997Scharnier while ((*nargv++ = *argv++)); 77523672Speter 77623672Speter /* Update argument count. */ 77723672Speter *argcp = nargv - *argvp - 1; 7781558Srgrimes} 779