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