1 1.79 rillig /* $NetBSD: main.c,v 1.79 2024/10/04 11:38:44 rillig Exp $ */ 2 1.6 cgd 3 1.1 cgd /*- 4 1.3 mycroft * Copyright (c) 1980, 1991, 1993, 1994 5 1.3 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.56 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.15 lukem #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.64 lukem __COPYRIGHT("@(#) Copyright (c) 1980, 1991, 1993, 1994\ 35 1.64 lukem The Regents of the University of California. All rights reserved."); 36 1.1 cgd #endif /* not lint */ 37 1.1 cgd 38 1.1 cgd #ifndef lint 39 1.6 cgd #if 0 40 1.16 lukem static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/1/95"; 41 1.6 cgd #else 42 1.79 rillig __RCSID("$NetBSD: main.c,v 1.79 2024/10/04 11:38:44 rillig Exp $"); 43 1.6 cgd #endif 44 1.1 cgd #endif /* not lint */ 45 1.1 cgd 46 1.3 mycroft #include <sys/param.h> 47 1.3 mycroft #include <sys/time.h> 48 1.14 lukem #include <sys/stat.h> 49 1.14 lukem #include <sys/mount.h> 50 1.72 bouyer #include <sys/sysctl.h> 51 1.14 lukem 52 1.3 mycroft #include <ufs/ffs/fs.h> 53 1.18 bouyer #include <ufs/ffs/ffs_extern.h> 54 1.3 mycroft 55 1.3 mycroft #include <ctype.h> 56 1.5 mycroft #include <err.h> 57 1.3 mycroft #include <errno.h> 58 1.1 cgd #include <fcntl.h> 59 1.1 cgd #include <fstab.h> 60 1.3 mycroft #include <signal.h> 61 1.1 cgd #include <stdio.h> 62 1.1 cgd #include <stdlib.h> 63 1.1 cgd #include <string.h> 64 1.10 lukem #include <time.h> 65 1.3 mycroft #include <unistd.h> 66 1.68 christos #include <util.h> 67 1.3 mycroft 68 1.1 cgd #include "dump.h" 69 1.1 cgd #include "pathnames.h" 70 1.58 hannken #include "snapshot.h" 71 1.1 cgd 72 1.77 joerg union u_spcl u_spcl; 73 1.77 joerg struct ufsi *ufsib; 74 1.77 joerg int mapsize; 75 1.77 joerg char *usedinomap; 76 1.77 joerg char *dumpdirmap; 77 1.77 joerg char *dumpinomap; 78 1.77 joerg char *disk; 79 1.77 joerg char *disk_dev; 80 1.77 joerg const char *tape; 81 1.77 joerg const char *dumpdates; 82 1.77 joerg const char *temp; 83 1.77 joerg char lastlevel; 84 1.77 joerg char level; 85 1.77 joerg int uflag; 86 1.77 joerg const char *dumpdev; 87 1.77 joerg int eflag; 88 1.77 joerg int lflag; 89 1.77 joerg int diskfd; 90 1.77 joerg int tapefd; 91 1.77 joerg int pipeout; 92 1.77 joerg int trueinc; 93 1.77 joerg ino_t curino; 94 1.77 joerg int newtape; 95 1.77 joerg u_int64_t tapesize; 96 1.77 joerg long tsize; 97 1.77 joerg long asize; 98 1.77 joerg int etapes; 99 1.77 joerg int nonodump; 100 1.77 joerg int unlimited; 101 1.77 joerg time_t tstart_writing; 102 1.77 joerg time_t tstart_volume; 103 1.77 joerg int xferrate; 104 1.77 joerg char sblock_buf[MAXBSIZE]; 105 1.77 joerg int dev_bshift; 106 1.77 joerg int tp_bshift; 107 1.77 joerg int needswap; 108 1.77 joerg 109 1.44 lukem int timestamp; /* print message timestamps */ 110 1.27 scw int notify; /* notify operator flag */ 111 1.78 kre u_int64_t blockswritten; /* number of blocks written on current tape */ 112 1.27 scw int tapeno; /* current tape number */ 113 1.27 scw int density; /* density in bytes/0.1" */ 114 1.17 lukem int ntrec = NTREC; /* # tape blocks in each tape record */ 115 1.27 scw int cartridge; /* Assume non-cartridge tape */ 116 1.17 lukem long dev_bsize = 1; /* recalculated below */ 117 1.27 scw long blocksperfile; /* output blocks per file */ 118 1.59 christos const char *host; /* remote host (if any) */ 119 1.22 bouyer int readcache = -1; /* read cache size (in readblksize blks) */ 120 1.72 bouyer int readblksize = -1; /* read block size */ 121 1.39 blymn char default_time_string[] = "%T %Z"; /* default timestamp string */ 122 1.39 blymn char *time_string = default_time_string; /* timestamp string */ 123 1.1 cgd 124 1.59 christos static long numarg(const char *, long, long); 125 1.31 lukem static void obsolete(int *, char **[]); 126 1.31 lukem static void usage(void); 127 1.3 mycroft 128 1.3 mycroft int 129 1.31 lukem main(int argc, char *argv[]) 130 1.1 cgd { 131 1.11 lukem ino_t ino; 132 1.45 lukem int dirty; 133 1.55 fvdl union dinode *dp; 134 1.33 lukem struct fstab *dt; 135 1.57 christos struct statvfs *mntinfo, fsbuf; 136 1.59 christos char *map, *cp; 137 1.11 lukem int ch; 138 1.38 lukem int i, anydirskipped, bflag = 0, Tflag = 0, Fflag = 0, honorlevel = 1; 139 1.58 hannken int snap_internal = 0; 140 1.1 cgd ino_t maxino; 141 1.18 bouyer time_t tnow, date; 142 1.33 lukem int dirc; 143 1.33 lukem char *mountpoint; 144 1.17 lukem int just_estimate = 0; 145 1.21 lukem char labelstr[LBLSIZE]; 146 1.69 christos char buf[MAXPATHLEN], rbuf[MAXPATHLEN]; 147 1.39 blymn char *new_time_format; 148 1.58 hannken char *snap_backup = NULL; 149 1.45 lukem 150 1.1 cgd spcl.c_date = 0; 151 1.47 lukem (void)time(&tnow); 152 1.47 lukem spcl.c_date = tnow; 153 1.39 blymn tzset(); /* set up timezone for strftime */ 154 1.39 blymn if ((new_time_format = getenv("TIMEFORMAT")) != NULL) 155 1.39 blymn time_string = new_time_format; 156 1.45 lukem 157 1.1 cgd tsize = 0; /* Default later, based on 'c' option for cart tapes */ 158 1.7 mrg if ((tape = getenv("TAPE")) == NULL) 159 1.7 mrg tape = _PATH_DEFTAPE; 160 1.1 cgd dumpdates = _PATH_DUMPDATES; 161 1.1 cgd temp = _PATH_DTMP; 162 1.21 lukem strcpy(labelstr, "none"); /* XXX safe strcpy. */ 163 1.1 cgd if (TP_BSIZE / DEV_BSIZE == 0 || TP_BSIZE % DEV_BSIZE != 0) 164 1.74 christos quit("TP_BSIZE must be a multiple of DEV_BSIZE"); 165 1.1 cgd level = '0'; 166 1.39 blymn timestamp = 0; 167 1.45 lukem 168 1.5 mycroft if (argc < 2) 169 1.5 mycroft usage(); 170 1.5 mycroft 171 1.5 mycroft obsolete(&argc, &argv); 172 1.17 lukem while ((ch = getopt(argc, argv, 173 1.76 perseant "0123456789aB:b:cd:D:eFf:h:ik:l:L:nr:s:StT:uU:Wwx:X")) != -1) 174 1.5 mycroft switch (ch) { 175 1.5 mycroft /* dump level */ 176 1.5 mycroft case '0': case '1': case '2': case '3': case '4': 177 1.5 mycroft case '5': case '6': case '7': case '8': case '9': 178 1.5 mycroft level = ch; 179 1.3 mycroft break; 180 1.1 cgd 181 1.49 lukem case 'a': /* `auto-size', Write to EOM. */ 182 1.49 lukem unlimited = 1; 183 1.49 lukem break; 184 1.49 lukem 185 1.5 mycroft case 'B': /* blocks per output file */ 186 1.5 mycroft blocksperfile = numarg("blocks per file", 1L, 0L); 187 1.5 mycroft break; 188 1.1 cgd 189 1.5 mycroft case 'b': /* blocks per tape write */ 190 1.5 mycroft ntrec = numarg("blocks per write", 1L, 1000L); 191 1.9 mikel bflag = 1; 192 1.5 mycroft break; 193 1.1 cgd 194 1.5 mycroft case 'c': /* Tape is cart. not 9-track */ 195 1.5 mycroft cartridge = 1; 196 1.3 mycroft break; 197 1.1 cgd 198 1.1 cgd case 'd': /* density, in bits per inch */ 199 1.5 mycroft density = numarg("density", 10L, 327670L) / 10; 200 1.1 cgd if (density >= 625 && !bflag) 201 1.1 cgd ntrec = HIGHDENSITYTREC; 202 1.28 tron break; 203 1.28 tron 204 1.76 perseant case 'D': /* specify alt. dumpdates file */ 205 1.76 perseant dumpdates = optarg; 206 1.76 perseant break; 207 1.76 perseant 208 1.38 lukem case 'e': /* eject full tapes */ 209 1.28 tron eflag = 1; 210 1.3 mycroft break; 211 1.1 cgd 212 1.38 lukem case 'F': /* files-to-dump is an fs image */ 213 1.38 lukem Fflag = 1; 214 1.38 lukem break; 215 1.38 lukem 216 1.5 mycroft case 'f': /* output file */ 217 1.5 mycroft tape = optarg; 218 1.5 mycroft break; 219 1.5 mycroft 220 1.5 mycroft case 'h': 221 1.5 mycroft honorlevel = numarg("honor level", 0L, 10L); 222 1.5 mycroft break; 223 1.5 mycroft 224 1.66 christos case 'i': /* "true incremental" regardless level */ 225 1.66 christos level = 'i'; 226 1.65 christos trueinc = 1; 227 1.65 christos break; 228 1.65 christos 229 1.22 bouyer case 'k': 230 1.22 bouyer readblksize = numarg("read block size", 0, 64) * 1024; 231 1.22 bouyer break; 232 1.22 bouyer 233 1.41 bouyer case 'l': /* autoload after eject full tapes */ 234 1.41 bouyer eflag = 1; 235 1.50 bouyer lflag = numarg("timeout (in seconds)", 1, 0); 236 1.41 bouyer break; 237 1.41 bouyer 238 1.21 lukem case 'L': 239 1.21 lukem /* 240 1.21 lukem * Note that although there are LBLSIZE characters, 241 1.21 lukem * the last must be '\0', so the limit on strlen() 242 1.21 lukem * is really LBLSIZE-1. 243 1.21 lukem */ 244 1.51 itojun if (strlcpy(labelstr, optarg, sizeof(labelstr)) 245 1.51 itojun >= sizeof(labelstr)) { 246 1.21 lukem msg( 247 1.53 itojun "WARNING Label `%s' is larger than limit of %lu characters.\n", 248 1.53 itojun optarg, 249 1.53 itojun (unsigned long)sizeof(labelstr) - 1); 250 1.21 lukem msg("WARNING: Using truncated label `%s'.\n", 251 1.21 lukem labelstr); 252 1.21 lukem } 253 1.21 lukem break; 254 1.5 mycroft case 'n': /* notify operators */ 255 1.5 mycroft notify = 1; 256 1.5 mycroft break; 257 1.5 mycroft 258 1.22 bouyer case 'r': /* read cache size */ 259 1.22 bouyer readcache = numarg("read cache size", 0, 512); 260 1.22 bouyer break; 261 1.45 lukem 262 1.1 cgd case 's': /* tape size, feet */ 263 1.5 mycroft tsize = numarg("tape size", 1L, 0L) * 12 * 10; 264 1.3 mycroft break; 265 1.1 cgd 266 1.17 lukem case 'S': /* exit after estimating # of tapes */ 267 1.17 lukem just_estimate = 1; 268 1.17 lukem break; 269 1.17 lukem 270 1.39 blymn case 't': 271 1.39 blymn timestamp = 1; 272 1.39 blymn break; 273 1.39 blymn 274 1.1 cgd case 'T': /* time of last dump */ 275 1.5 mycroft spcl.c_ddate = unctime(optarg); 276 1.1 cgd if (spcl.c_ddate < 0) { 277 1.3 mycroft (void)fprintf(stderr, "bad time \"%s\"\n", 278 1.5 mycroft optarg); 279 1.48 lukem exit(X_STARTUP); 280 1.1 cgd } 281 1.3 mycroft Tflag = 1; 282 1.1 cgd lastlevel = '?'; 283 1.3 mycroft break; 284 1.1 cgd 285 1.1 cgd case 'u': /* update /etc/dumpdates */ 286 1.3 mycroft uflag = 1; 287 1.3 mycroft break; 288 1.1 cgd 289 1.75 manu case 'U': /* dump device in /etc/dumpdates */ 290 1.75 manu dumpdev = optarg; 291 1.75 manu break; 292 1.75 manu 293 1.5 mycroft case 'W': /* what to do */ 294 1.5 mycroft case 'w': 295 1.5 mycroft lastdump(ch); 296 1.48 lukem exit(X_FINOK); /* do nothing else */ 297 1.1 cgd 298 1.58 hannken case 'x': 299 1.58 hannken snap_backup = optarg; 300 1.58 hannken break; 301 1.58 hannken 302 1.58 hannken case 'X': 303 1.58 hannken snap_internal = 1; 304 1.58 hannken break; 305 1.58 hannken 306 1.1 cgd default: 307 1.5 mycroft usage(); 308 1.1 cgd } 309 1.5 mycroft argc -= optind; 310 1.5 mycroft argv += optind; 311 1.5 mycroft 312 1.1 cgd if (argc < 1) { 313 1.38 lukem (void)fprintf(stderr, 314 1.38 lukem "Must specify disk or image, or file list\n"); 315 1.48 lukem exit(X_STARTUP); 316 1.1 cgd } 317 1.14 lukem 318 1.33 lukem 319 1.14 lukem /* 320 1.14 lukem * determine if disk is a subdirectory, and setup appropriately 321 1.14 lukem */ 322 1.33 lukem getfstab(); /* /etc/fstab snarfed */ 323 1.33 lukem disk = NULL; 324 1.63 hannken disk_dev = NULL; 325 1.33 lukem mountpoint = NULL; 326 1.33 lukem dirc = 0; 327 1.14 lukem for (i = 0; i < argc; i++) { 328 1.14 lukem struct stat sb; 329 1.71 mlelstv int error; 330 1.14 lukem 331 1.71 mlelstv error = lstat(argv[i], &sb); 332 1.71 mlelstv if (Fflag || (!error && (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)))) { 333 1.71 mlelstv if (error) 334 1.74 christos quite(errno, "can't stat %s", argv[i]); 335 1.33 lukem disk = argv[i]; 336 1.33 lukem multicheck: 337 1.33 lukem if (dirc != 0) 338 1.74 christos quit("can't dump a disk or image at the same" 339 1.74 christos " time as a file list"); 340 1.14 lukem break; 341 1.14 lukem } 342 1.33 lukem if ((dt = fstabsearch(argv[i])) != NULL) { 343 1.71 mlelstv disk = argv[i]; 344 1.34 hannken mountpoint = xstrdup(dt->fs_file); 345 1.33 lukem goto multicheck; 346 1.14 lukem } 347 1.57 christos if (statvfs(argv[i], &fsbuf) == -1) 348 1.74 christos quite(errno, "can't statvfs %s", argv[i]); 349 1.33 lukem disk = fsbuf.f_mntfromname; 350 1.33 lukem if (strcmp(argv[i], fsbuf.f_mntonname) == 0) 351 1.33 lukem goto multicheck; 352 1.33 lukem if (mountpoint == NULL) { 353 1.33 lukem mountpoint = xstrdup(fsbuf.f_mntonname); 354 1.14 lukem if (uflag) { 355 1.14 lukem msg("Ignoring u flag for subdir dump\n"); 356 1.14 lukem uflag = 0; 357 1.14 lukem } 358 1.14 lukem if (level > '0') { 359 1.14 lukem msg("Subdir dump is done at level 0\n"); 360 1.14 lukem level = '0'; 361 1.14 lukem } 362 1.33 lukem msg("Dumping sub files/directories from %s\n", 363 1.33 lukem mountpoint); 364 1.14 lukem } else { 365 1.33 lukem if (strcmp(mountpoint, fsbuf.f_mntonname) != 0) 366 1.74 christos quit("%s is not on %s", argv[i], mountpoint); 367 1.14 lukem } 368 1.14 lukem msg("Dumping file/directory %s\n", argv[i]); 369 1.33 lukem dirc++; 370 1.14 lukem } 371 1.33 lukem if (mountpoint) 372 1.33 lukem free(mountpoint); 373 1.33 lukem 374 1.33 lukem if (dirc == 0) { 375 1.33 lukem argv++; 376 1.14 lukem if (argc != 1) { 377 1.14 lukem (void)fprintf(stderr, "Excess arguments to dump:"); 378 1.14 lukem while (--argc) 379 1.14 lukem (void)fprintf(stderr, " %s", *argv++); 380 1.14 lukem (void)fprintf(stderr, "\n"); 381 1.48 lukem exit(X_STARTUP); 382 1.14 lukem } 383 1.1 cgd } 384 1.1 cgd if (Tflag && uflag) { 385 1.44 lukem (void)fprintf(stderr, 386 1.1 cgd "You cannot use the T and u flags together.\n"); 387 1.48 lukem exit(X_STARTUP); 388 1.1 cgd } 389 1.1 cgd if (strcmp(tape, "-") == 0) { 390 1.1 cgd pipeout++; 391 1.1 cgd tape = "standard output"; 392 1.1 cgd } 393 1.1 cgd 394 1.1 cgd if (blocksperfile) 395 1.1 cgd blocksperfile = blocksperfile / ntrec * ntrec; /* round down */ 396 1.49 lukem else if (!unlimited) { 397 1.1 cgd /* 398 1.1 cgd * Determine how to default tape size and density 399 1.1 cgd * 400 1.44 lukem * density tape size 401 1.1 cgd * 9-track 1600 bpi (160 bytes/.1") 2300 ft. 402 1.1 cgd * 9-track 6250 bpi (625 bytes/.1") 2300 ft. 403 1.1 cgd * cartridge 8000 bpi (100 bytes/.1") 1700 ft. 404 1.1 cgd * (450*4 - slop) 405 1.1 cgd */ 406 1.1 cgd if (density == 0) 407 1.1 cgd density = cartridge ? 100 : 160; 408 1.1 cgd if (tsize == 0) 409 1.1 cgd tsize = cartridge ? 1700L*120L : 2300L*120L; 410 1.1 cgd } 411 1.1 cgd 412 1.79 rillig /* LINTED 346 "call to 'strchr' effectively discards 'const'" */ 413 1.59 christos if ((cp = strchr(tape, ':')) != NULL) { 414 1.1 cgd host = tape; 415 1.59 christos /* This is fine, because all the const strings don't have : */ 416 1.59 christos *cp++ = '\0'; 417 1.59 christos tape = cp; 418 1.1 cgd #ifdef RDUMP 419 1.1 cgd if (rmthost(host) == 0) 420 1.48 lukem exit(X_STARTUP); 421 1.1 cgd #else 422 1.3 mycroft (void)fprintf(stderr, "remote dump not enabled\n"); 423 1.48 lukem exit(X_STARTUP); 424 1.1 cgd #endif 425 1.1 cgd } 426 1.1 cgd 427 1.1 cgd if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 428 1.1 cgd signal(SIGHUP, sig); 429 1.1 cgd if (signal(SIGTRAP, SIG_IGN) != SIG_IGN) 430 1.1 cgd signal(SIGTRAP, sig); 431 1.1 cgd if (signal(SIGFPE, SIG_IGN) != SIG_IGN) 432 1.1 cgd signal(SIGFPE, sig); 433 1.1 cgd if (signal(SIGBUS, SIG_IGN) != SIG_IGN) 434 1.1 cgd signal(SIGBUS, sig); 435 1.55 fvdl #if 0 436 1.1 cgd if (signal(SIGSEGV, SIG_IGN) != SIG_IGN) 437 1.1 cgd signal(SIGSEGV, sig); 438 1.55 fvdl #endif 439 1.1 cgd if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 440 1.1 cgd signal(SIGTERM, sig); 441 1.1 cgd if (signal(SIGINT, interrupt) == SIG_IGN) 442 1.1 cgd signal(SIGINT, SIG_IGN); 443 1.14 lukem 444 1.1 cgd /* 445 1.33 lukem * disk can be either the full special file name, or 446 1.33 lukem * the file system name. 447 1.1 cgd */ 448 1.33 lukem mountpoint = NULL; 449 1.58 hannken mntinfo = mntinfosearch(disk); 450 1.33 lukem if ((dt = fstabsearch(disk)) != NULL) { 451 1.68 christos if (getfsspecname(buf, sizeof(buf), dt->fs_spec) == NULL) 452 1.74 christos quite(errno, "can't resolve mount %s (%s)", dt->fs_spec, 453 1.74 christos buf); 454 1.69 christos if (getdiskrawname(rbuf, sizeof(rbuf), buf) == NULL) 455 1.74 christos quite(errno, "can't get disk raw name for %s", buf); 456 1.69 christos disk = rbuf; 457 1.33 lukem mountpoint = dt->fs_file; 458 1.33 lukem msg("Found %s on %s in %s\n", disk, mountpoint, _PATH_FSTAB); 459 1.58 hannken } else if (mntinfo != NULL) { 460 1.69 christos if (getdiskrawname(rbuf, sizeof(rbuf), mntinfo->f_mntfromname) 461 1.69 christos == NULL) 462 1.74 christos quite(errno, "can't get disk raw name for %s", 463 1.74 christos mntinfo->f_mntfromname); 464 1.71 mlelstv disk = rbuf; 465 1.33 lukem mountpoint = mntinfo->f_mntonname; 466 1.33 lukem msg("Found %s on %s in mount table\n", disk, mountpoint); 467 1.33 lukem } 468 1.33 lukem if (mountpoint != NULL) { 469 1.33 lukem if (dirc != 0) 470 1.51 itojun (void)snprintf(spcl.c_filesys, sizeof(spcl.c_filesys), 471 1.33 lukem "a subset of %s", mountpoint); 472 1.14 lukem else 473 1.51 itojun (void)strlcpy(spcl.c_filesys, mountpoint, 474 1.51 itojun sizeof(spcl.c_filesys)); 475 1.38 lukem } else if (Fflag) { 476 1.51 itojun (void)strlcpy(spcl.c_filesys, "a file system image", 477 1.51 itojun sizeof(spcl.c_filesys)); 478 1.1 cgd } else { 479 1.51 itojun (void)strlcpy(spcl.c_filesys, "an unlisted file system", 480 1.51 itojun sizeof(spcl.c_filesys)); 481 1.1 cgd } 482 1.51 itojun (void)strlcpy(spcl.c_dev, disk, sizeof(spcl.c_dev)); 483 1.51 itojun (void)strlcpy(spcl.c_label, labelstr, sizeof(spcl.c_label)); 484 1.51 itojun (void)gethostname(spcl.c_host, sizeof(spcl.c_host)); 485 1.19 mrg spcl.c_host[sizeof(spcl.c_host) - 1] = '\0'; 486 1.18 bouyer 487 1.58 hannken if ((snap_backup != NULL || snap_internal) && mntinfo == NULL) { 488 1.58 hannken msg("WARNING: Cannot use -x or -X on unmounted file system.\n"); 489 1.58 hannken snap_backup = NULL; 490 1.58 hannken snap_internal = 0; 491 1.58 hannken } 492 1.62 perseant 493 1.62 perseant #ifdef DUMP_LFS 494 1.62 perseant sync(); 495 1.62 perseant if (snap_backup != NULL || snap_internal) { 496 1.62 perseant if (lfs_wrap_stop(mountpoint) < 0) { 497 1.62 perseant msg("Cannot stop writing on %s\n", mountpoint); 498 1.62 perseant exit(X_STARTUP); 499 1.62 perseant } 500 1.62 perseant } 501 1.62 perseant if ((diskfd = open(disk, O_RDONLY)) < 0) { 502 1.62 perseant msg("Cannot open %s\n", disk); 503 1.62 perseant exit(X_STARTUP); 504 1.62 perseant } 505 1.63 hannken disk_dev = disk; 506 1.62 perseant #else /* ! DUMP_LFS */ 507 1.58 hannken if (snap_backup != NULL || snap_internal) { 508 1.63 hannken diskfd = snap_open(mntinfo->f_mntonname, snap_backup, 509 1.63 hannken &tnow, &disk_dev); 510 1.58 hannken if (diskfd < 0) { 511 1.58 hannken msg("Cannot open snapshot of %s\n", 512 1.58 hannken mntinfo->f_mntonname); 513 1.58 hannken exit(X_STARTUP); 514 1.58 hannken } 515 1.58 hannken spcl.c_date = tnow; 516 1.58 hannken } else { 517 1.58 hannken if ((diskfd = open(disk, O_RDONLY)) < 0) { 518 1.58 hannken msg("Cannot open %s\n", disk); 519 1.58 hannken exit(X_STARTUP); 520 1.58 hannken } 521 1.63 hannken disk_dev = disk; 522 1.18 bouyer } 523 1.18 bouyer sync(); 524 1.62 perseant #endif /* ! DUMP_LFS */ 525 1.25 perseant 526 1.25 perseant needswap = fs_read_sblock(sblock_buf); 527 1.18 bouyer 528 1.66 christos /* true incremental is always a level 10 dump */ 529 1.66 christos spcl.c_level = trueinc? iswap32(10): iswap32(level - '0'); 530 1.18 bouyer spcl.c_type = iswap32(TS_TAPE); 531 1.18 bouyer spcl.c_date = iswap32(spcl.c_date); 532 1.18 bouyer spcl.c_ddate = iswap32(spcl.c_ddate); 533 1.1 cgd if (!Tflag) 534 1.44 lukem getdumptime(); /* /etc/dumpdates snarfed */ 535 1.1 cgd 536 1.18 bouyer date = iswap32(spcl.c_date); 537 1.1 cgd msg("Date of this level %c dump: %s", level, 538 1.18 bouyer spcl.c_date == 0 ? "the epoch\n" : ctime(&date)); 539 1.18 bouyer date = iswap32(spcl.c_ddate); 540 1.1 cgd msg("Date of last level %c dump: %s", lastlevel, 541 1.18 bouyer spcl.c_ddate == 0 ? "the epoch\n" : ctime(&date)); 542 1.17 lukem msg("Dumping "); 543 1.61 hannken if (snap_backup != NULL || snap_internal) 544 1.58 hannken msgtail("a snapshot of "); 545 1.33 lukem if (dirc != 0) 546 1.17 lukem msgtail("a subset of "); 547 1.17 lukem msgtail("%s (%s) ", disk, spcl.c_filesys); 548 1.1 cgd if (host) 549 1.1 cgd msgtail("to %s on host %s\n", tape, host); 550 1.1 cgd else 551 1.1 cgd msgtail("to %s\n", tape); 552 1.21 lukem msg("Label: %s\n", labelstr); 553 1.1 cgd 554 1.25 perseant ufsib = fs_parametrize(); 555 1.25 perseant 556 1.1 cgd dev_bshift = ffs(dev_bsize) - 1; 557 1.1 cgd if (dev_bsize != (1 << dev_bshift)) 558 1.26 briggs quit("dev_bsize (%ld) is not a power of 2", dev_bsize); 559 1.1 cgd tp_bshift = ffs(TP_BSIZE) - 1; 560 1.1 cgd if (TP_BSIZE != (1 << tp_bshift)) 561 1.1 cgd quit("TP_BSIZE (%d) is not a power of 2", TP_BSIZE); 562 1.25 perseant maxino = fs_maxino(); 563 1.3 mycroft mapsize = roundup(howmany(maxino, NBBY), TP_BSIZE); 564 1.33 lukem usedinomap = (char *)xcalloc((unsigned) mapsize, sizeof(char)); 565 1.33 lukem dumpdirmap = (char *)xcalloc((unsigned) mapsize, sizeof(char)); 566 1.33 lukem dumpinomap = (char *)xcalloc((unsigned) mapsize, sizeof(char)); 567 1.1 cgd tapesize = 3 * (howmany(mapsize * sizeof(char), TP_BSIZE) + 1); 568 1.1 cgd 569 1.18 bouyer nonodump = iswap32(spcl.c_level) < honorlevel; 570 1.3 mycroft 571 1.22 bouyer initcache(readcache, readblksize); 572 1.45 lukem 573 1.14 lukem (void)signal(SIGINFO, statussig); 574 1.14 lukem 575 1.1 cgd msg("mapping (Pass I) [regular files]\n"); 576 1.33 lukem anydirskipped = mapfiles(maxino, &tapesize, mountpoint, 577 1.33 lukem (dirc ? argv : NULL)); 578 1.1 cgd 579 1.1 cgd msg("mapping (Pass II) [directories]\n"); 580 1.1 cgd while (anydirskipped) { 581 1.1 cgd anydirskipped = mapdirs(maxino, &tapesize); 582 1.1 cgd } 583 1.1 cgd 584 1.49 lukem if (pipeout || unlimited) { 585 1.1 cgd tapesize += 10; /* 10 trailer blocks */ 586 1.55 fvdl msg("estimated %llu tape blocks.\n", 587 1.55 fvdl (unsigned long long)tapesize); 588 1.3 mycroft } else { 589 1.3 mycroft double fetapes; 590 1.3 mycroft 591 1.1 cgd if (blocksperfile) 592 1.3 mycroft fetapes = (double) tapesize / blocksperfile; 593 1.1 cgd else if (cartridge) { 594 1.1 cgd /* Estimate number of tapes, assuming streaming stops at 595 1.1 cgd the end of each block written, and not in mid-block. 596 1.1 cgd Assume no erroneous blocks; this can be compensated 597 1.1 cgd for with an artificially low tape size. */ 598 1.45 lukem fetapes = 599 1.48 lukem ( (double) tapesize /* blocks */ 600 1.1 cgd * TP_BSIZE /* bytes/block */ 601 1.1 cgd * (1.0/density) /* 0.1" / byte */ 602 1.1 cgd + 603 1.48 lukem (double) tapesize /* blocks */ 604 1.1 cgd * (1.0/ntrec) /* streaming-stops per block */ 605 1.1 cgd * 15.48 /* 0.1" / streaming-stop */ 606 1.1 cgd ) * (1.0 / tsize ); /* tape / 0.1" */ 607 1.1 cgd } else { 608 1.1 cgd /* Estimate number of tapes, for old fashioned 9-track 609 1.1 cgd tape */ 610 1.1 cgd int tenthsperirg = (density == 625) ? 3 : 7; 611 1.1 cgd fetapes = 612 1.1 cgd ( tapesize /* blocks */ 613 1.1 cgd * TP_BSIZE /* bytes / block */ 614 1.1 cgd * (1.0/density) /* 0.1" / byte */ 615 1.1 cgd + 616 1.1 cgd tapesize /* blocks */ 617 1.1 cgd * (1.0/ntrec) /* IRG's / block */ 618 1.1 cgd * tenthsperirg /* 0.1" / IRG */ 619 1.1 cgd ) * (1.0 / tsize ); /* tape / 0.1" */ 620 1.1 cgd } 621 1.1 cgd etapes = fetapes; /* truncating assignment */ 622 1.1 cgd etapes++; 623 1.1 cgd /* count the dumped inodes map on each additional tape */ 624 1.1 cgd tapesize += (etapes - 1) * 625 1.1 cgd (howmany(mapsize * sizeof(char), TP_BSIZE) + 1); 626 1.1 cgd tapesize += etapes + 10; /* headers + 10 trailer blks */ 627 1.55 fvdl msg("estimated %llu tape blocks on %3.2f tape(s).\n", 628 1.55 fvdl (unsigned long long)tapesize, fetapes); 629 1.3 mycroft } 630 1.17 lukem /* 631 1.17 lukem * If the user only wants an estimate of the number of 632 1.17 lukem * tapes, exit now. 633 1.17 lukem */ 634 1.17 lukem if (just_estimate) 635 1.48 lukem exit(X_FINOK); 636 1.1 cgd 637 1.1 cgd /* 638 1.3 mycroft * Allocate tape buffer. 639 1.1 cgd */ 640 1.1 cgd if (!alloctape()) 641 1.74 christos quit("can't allocate tape buffers - try a smaller" 642 1.74 christos " blocking factor."); 643 1.1 cgd 644 1.1 cgd startnewtape(1); 645 1.3 mycroft (void)time((time_t *)&(tstart_writing)); 646 1.10 lukem xferrate = 0; 647 1.3 mycroft dumpmap(usedinomap, TS_CLRI, maxino - 1); 648 1.1 cgd 649 1.1 cgd msg("dumping (Pass III) [directories]\n"); 650 1.3 mycroft dirty = 0; /* XXX just to get gcc to shut up */ 651 1.3 mycroft for (map = dumpdirmap, ino = 1; ino < maxino; ino++) { 652 1.3 mycroft if (((ino - 1) % NBBY) == 0) /* map is offset by 1 */ 653 1.1 cgd dirty = *map++; 654 1.1 cgd else 655 1.1 cgd dirty >>= 1; 656 1.1 cgd if ((dirty & 1) == 0) 657 1.1 cgd continue; 658 1.1 cgd /* 659 1.1 cgd * Skip directory inodes deleted and maybe reallocated 660 1.1 cgd */ 661 1.1 cgd dp = getino(ino); 662 1.55 fvdl if ((DIP(dp, mode) & IFMT) != IFDIR) 663 1.1 cgd continue; 664 1.3 mycroft (void)dumpino(dp, ino); 665 1.1 cgd } 666 1.1 cgd 667 1.1 cgd msg("dumping (Pass IV) [regular files]\n"); 668 1.3 mycroft for (map = dumpinomap, ino = 1; ino < maxino; ino++) { 669 1.3 mycroft int mode; 670 1.3 mycroft 671 1.3 mycroft if (((ino - 1) % NBBY) == 0) /* map is offset by 1 */ 672 1.1 cgd dirty = *map++; 673 1.1 cgd else 674 1.1 cgd dirty >>= 1; 675 1.1 cgd if ((dirty & 1) == 0) 676 1.1 cgd continue; 677 1.1 cgd /* 678 1.1 cgd * Skip inodes deleted and reallocated as directories. 679 1.1 cgd */ 680 1.1 cgd dp = getino(ino); 681 1.55 fvdl mode = DIP(dp, mode) & IFMT; 682 1.3 mycroft if (mode == IFDIR) 683 1.1 cgd continue; 684 1.3 mycroft (void)dumpino(dp, ino); 685 1.1 cgd } 686 1.1 cgd 687 1.18 bouyer spcl.c_type = iswap32(TS_END); 688 1.1 cgd for (i = 0; i < ntrec; i++) 689 1.3 mycroft writeheader(maxino - 1); 690 1.1 cgd if (pipeout) 691 1.73 bouyer msg("%lld tape blocks\n",(long long)iswap64(spcl.c_tapea)); 692 1.1 cgd else 693 1.73 bouyer msg("%lld tape blocks on %d volume%s\n", 694 1.73 bouyer (long long)iswap64(spcl.c_tapea), iswap32(spcl.c_volume), 695 1.18 bouyer (iswap32(spcl.c_volume) == 1) ? "" : "s"); 696 1.10 lukem tnow = do_stats(); 697 1.18 bouyer date = iswap32(spcl.c_date); 698 1.10 lukem msg("Date of this level %c dump: %s", level, 699 1.18 bouyer spcl.c_date == 0 ? "the epoch\n" : ctime(&date)); 700 1.10 lukem msg("Date this dump completed: %s", ctime(&tnow)); 701 1.26 briggs msg("Average transfer rate: %d KB/s\n", xferrate / tapeno); 702 1.1 cgd putdumptime(); 703 1.29 tron trewind(0); 704 1.48 lukem broadcast("DUMP IS DONE!\a\a\n"); 705 1.62 perseant #ifdef DUMP_LFS 706 1.62 perseant lfs_wrap_go(); 707 1.62 perseant #endif /* DUMP_LFS */ 708 1.1 cgd msg("DUMP IS DONE\n"); 709 1.1 cgd Exit(X_FINOK); 710 1.1 cgd /* NOTREACHED */ 711 1.15 lukem exit(X_FINOK); /* XXX: to satisfy gcc */ 712 1.1 cgd } 713 1.1 cgd 714 1.5 mycroft static void 715 1.31 lukem usage(void) 716 1.5 mycroft { 717 1.49 lukem const char *prog = getprogname(); 718 1.5 mycroft 719 1.49 lukem (void)fprintf(stderr, 720 1.67 christos "usage: %s [-0123456789aceFinStuX] [-B records] [-b blocksize]\n" 721 1.49 lukem " [-d density] [-f file] [-h level] [-k read-blocksize]\n" 722 1.67 christos " [-L label] [-l timeout] [-r cachesize] [-s feet]\n" 723 1.75 manu " [-T date] [-U dumpdev] [-x snap-backup] files-to-dump\n" 724 1.49 lukem " %s [-W | -w]\n", prog, prog); 725 1.48 lukem exit(X_STARTUP); 726 1.5 mycroft } 727 1.5 mycroft 728 1.3 mycroft /* 729 1.3 mycroft * Pick up a numeric argument. It must be nonnegative and in the given 730 1.3 mycroft * range (except that a vmax of 0 means unlimited). 731 1.3 mycroft */ 732 1.3 mycroft static long 733 1.59 christos numarg(const char *meaning, long vmin, long vmax) 734 1.3 mycroft { 735 1.5 mycroft char *p; 736 1.3 mycroft long val; 737 1.3 mycroft 738 1.5 mycroft val = strtol(optarg, &p, 10); 739 1.5 mycroft if (*p) 740 1.48 lukem errx(X_STARTUP, "illegal %s -- %s", meaning, optarg); 741 1.3 mycroft if (val < vmin || (vmax && val > vmax)) 742 1.48 lukem errx(X_STARTUP, "%s must be between %ld and %ld", 743 1.48 lukem meaning, vmin, vmax); 744 1.3 mycroft return (val); 745 1.3 mycroft } 746 1.3 mycroft 747 1.1 cgd void 748 1.32 lukem sig(int signo) 749 1.1 cgd { 750 1.32 lukem 751 1.1 cgd switch(signo) { 752 1.1 cgd case SIGALRM: 753 1.1 cgd case SIGBUS: 754 1.1 cgd case SIGFPE: 755 1.1 cgd case SIGHUP: 756 1.1 cgd case SIGTERM: 757 1.1 cgd case SIGTRAP: 758 1.1 cgd if (pipeout) 759 1.74 christos quit("Signal on pipe: cannot recover"); 760 1.35 mrg msg("Rewriting attempted as response to signal %s.\n", sys_siglist[signo]); 761 1.3 mycroft (void)fflush(stderr); 762 1.3 mycroft (void)fflush(stdout); 763 1.1 cgd close_rewind(); 764 1.3 mycroft exit(X_REWRITE); 765 1.1 cgd /* NOTREACHED */ 766 1.1 cgd case SIGSEGV: 767 1.1 cgd msg("SIGSEGV: ABORTING!\n"); 768 1.3 mycroft (void)signal(SIGSEGV, SIG_DFL); 769 1.3 mycroft (void)kill(0, SIGSEGV); 770 1.1 cgd /* NOTREACHED */ 771 1.1 cgd } 772 1.1 cgd } 773 1.1 cgd 774 1.5 mycroft /* 775 1.5 mycroft * obsolete -- 776 1.5 mycroft * Change set of key letters and ordered arguments into something 777 1.5 mycroft * getopt(3) will like. 778 1.5 mycroft */ 779 1.5 mycroft static void 780 1.32 lukem obsolete(int *argcp, char **argvp[]) 781 1.1 cgd { 782 1.5 mycroft int argc, flags; 783 1.5 mycroft char *ap, **argv, *flagsp, **nargv, *p; 784 1.5 mycroft 785 1.5 mycroft /* Setup. */ 786 1.5 mycroft argv = *argvp; 787 1.5 mycroft argc = *argcp; 788 1.5 mycroft 789 1.5 mycroft /* Return if no arguments or first argument has leading dash. */ 790 1.5 mycroft ap = argv[1]; 791 1.5 mycroft if (argc == 1 || *ap == '-') 792 1.5 mycroft return; 793 1.5 mycroft 794 1.5 mycroft /* Allocate space for new arguments. */ 795 1.33 lukem *argvp = nargv = xmalloc((argc + 1) * sizeof(char *)); 796 1.33 lukem p = flagsp = xmalloc(strlen(ap) + 2); 797 1.5 mycroft 798 1.5 mycroft *nargv++ = *argv; 799 1.5 mycroft argv += 2; 800 1.5 mycroft 801 1.5 mycroft for (flags = 0; *ap; ++ap) { 802 1.5 mycroft switch (*ap) { 803 1.5 mycroft case 'B': 804 1.5 mycroft case 'b': 805 1.5 mycroft case 'd': 806 1.5 mycroft case 'f': 807 1.5 mycroft case 'h': 808 1.5 mycroft case 's': 809 1.5 mycroft case 'T': 810 1.58 hannken case 'x': 811 1.5 mycroft if (*argv == NULL) { 812 1.5 mycroft warnx("option requires an argument -- %c", *ap); 813 1.5 mycroft usage(); 814 1.5 mycroft } 815 1.33 lukem nargv[0] = xmalloc(strlen(*argv) + 2 + 1); 816 1.5 mycroft nargv[0][0] = '-'; 817 1.5 mycroft nargv[0][1] = *ap; 818 1.17 lukem (void)strcpy(&nargv[0][2], *argv); /* XXX safe strcpy */ 819 1.5 mycroft ++argv; 820 1.5 mycroft ++nargv; 821 1.5 mycroft break; 822 1.5 mycroft default: 823 1.5 mycroft if (!flags) { 824 1.5 mycroft *p++ = '-'; 825 1.5 mycroft flags = 1; 826 1.5 mycroft } 827 1.5 mycroft *p++ = *ap; 828 1.5 mycroft break; 829 1.5 mycroft } 830 1.5 mycroft } 831 1.1 cgd 832 1.5 mycroft /* Terminate flags. */ 833 1.5 mycroft if (flags) { 834 1.5 mycroft *p = '\0'; 835 1.5 mycroft *nargv++ = flagsp; 836 1.60 christos } else 837 1.60 christos free(flagsp); 838 1.5 mycroft 839 1.5 mycroft /* Copy remaining arguments. */ 840 1.14 lukem while ((*nargv++ = *argv++) != NULL) 841 1.14 lukem ; 842 1.5 mycroft 843 1.5 mycroft /* Update argument count. */ 844 1.5 mycroft *argcp = nargv - *argvp - 1; 845 1.33 lukem } 846 1.33 lukem 847 1.33 lukem 848 1.33 lukem void * 849 1.33 lukem xcalloc(size_t number, size_t size) 850 1.33 lukem { 851 1.33 lukem void *p; 852 1.33 lukem 853 1.33 lukem p = calloc(number, size); 854 1.33 lukem if (p == NULL) 855 1.74 christos quite(errno, "Can't allocate %zu bytes", size * number); 856 1.33 lukem return (p); 857 1.33 lukem } 858 1.33 lukem 859 1.33 lukem void * 860 1.33 lukem xmalloc(size_t size) 861 1.33 lukem { 862 1.33 lukem void *p; 863 1.33 lukem 864 1.33 lukem p = malloc(size); 865 1.33 lukem if (p == NULL) 866 1.74 christos quite(errno, "Can't allocate %zu bytes", size); 867 1.33 lukem return (p); 868 1.33 lukem } 869 1.33 lukem 870 1.33 lukem char * 871 1.33 lukem xstrdup(const char *str) 872 1.33 lukem { 873 1.33 lukem char *p; 874 1.33 lukem 875 1.33 lukem p = strdup(str); 876 1.33 lukem if (p == NULL) 877 1.74 christos quite(errno, "Can't copy %s", str); 878 1.33 lukem return (p); 879 1.1 cgd } 880