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