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