|
|
1.1 root 1: /*
2: * Dump a filesystem onto a
3: * tape. Dump only those files that
4: * have checked since the last
5: * dump.
6: */
7: #include <stdio.h>
8: #include <sys/types.h>
9: #include <discbuf.h>
10: #include <dumptape.h>
11: #include <canon.h>
12: #include <sys/filsys.h>
13:
14: char *dtn = DTAPE; /* Tape name */
15: FILE *dtp; /* Tape file pointer */
16: char *fsn = DFSYS; /* File system name */
17: int block = 20; /* Blocking factor */
18: int density = 1600; /* Tape density, bpi */
19: long length = 2300L*12L*100L; /* Length of tape, inches/100 */
20: long used; /* Tape used, inches/100 */
21: struct dumpheader dh; /* Dump header */
22: int reel = 1; /* Reel # */
23: int uflag = 1; /* Update dates file flag */
24: int vflag; /* Verbose flag */
25: int Sflag; /* Set when sizes are in blocks */
26: int level = 9; /* Dump level */
27: time_t bdate; /* Date at beginning of dump */
28: time_t ddate; /* Dump since date */
29: char *map; /* Map pointer */
30: char *ddbuf; /* Dump data buffer */
31: char *ddend; /* Dump data buffer end pointer */
32: int ddnbuf; /* Buffer size */
33: union dumpdata *ddptr; /* Pointer to current item */
34: ino_t isize; /* # of inodes */
35: char dev[DIRSIZ+1]; /* Name of device, squashed */
36: char fname[6]; /* File system name */
37: char fpack[6]; /* File system pack name */
38: long ninodes; /* # of inodes dumped */
39: long nblocks; /* # of blocks of data */
40: long nsparse; /* # of sparse blocks deleted */
41: char helpmessage[] = "\
42: Usage: dump [bdfsuvS0123456789 [args]] filesystem ...\n\
43: ";
44:
45: /*
46: * Tables used by imap.
47: * This effectively implements
48: * the access polynomial for the indirect
49: * blocks.
50: */
51: daddr_t ranges[] = {
52: ND,
53: ND+(daddr_t)1*NBN,
54: ND+(daddr_t)1*NBN + (daddr_t)1*NBN*NBN,
55: ND+(daddr_t)1*NBN + (daddr_t)1*NBN*NBN + (daddr_t)1*NBN*NBN*NBN
56: };
57:
58: char offsets[] = {
59: 0,
60: ND,
61: ND+1,
62: ND+1+1
63: };
64:
65: daddr_t coeff[] = {
66: 1,
67: (daddr_t) NBN,
68: (daddr_t) NBN*NBN,
69: (daddr_t) NBN*NBN*NBN
70: };
71:
72: /*
73: * One pass compilers are
74: * such fun.
75: */
76: long time();
77: long ddlen();
78: union dumpdata *ddnextbuf();
79: long getddate();
80: char *ctime();
81: daddr_t imap();
82: char *calloc();
83:
84: main(argc, argv)
85: char *argv[];
86: {
87: register DISCBUF *dbp;
88: register struct filsys *fsp;
89: unsigned fi;
90:
91: init(argc, argv);
92: if (*fsn == 0)
93: fatal("no filesystem specified");
94: if ((dbfp=fopen(fsn, "r")) == NULL)
95: fatal("%s: cannot open filesystem", fsn);
96: if ((dtp=fopen(dtn, "w")) == NULL)
97: fatal("%s: cannot open dump file", dtn);
98: squash(dev, fsn);
99: bdate = time((long *) 0);
100: ddate = getddate();
101: if (vflag) {
102: if (ddate == 0)
103: fprintf(stderr, "dump: since epoch\n");
104: else
105: fprintf(stderr, "dump: since %s", ctime(&ddate));
106: }
107: dbclaim(5);
108: sync();
109: dbp = dbread((long) SUPERI);
110: fsp = (struct filsys *) (dbp->db_data);
111: fi = fsp->s_isize;
112: canshort(fi);
113: isize = (fi-INODEI)*INOPB;
114: strncpy(fname, fsp->s_fname, sizeof(fname));
115: strncpy(fpack, fsp->s_fpack, sizeof(fpack));
116: dbfree(dbp, 0);
117: if ((map=calloc(isize, sizeof(char))) == NULL)
118: fatal("out of memory (map)");
119: walk((ino_t) ROOTIN);
120: nextvol();
121: dumpinomap();
122: dump(DD_DIR); /* Directories */
123: dump(0); /* Files */
124: dumpfinish();
125: if (uflag)
126: putddate();
127: if (vflag) {
128: if (Sflag)
129: used /= 512; else
130: used /= 100*12;
131: fprintf(stderr, "dump: length is %ld ", used);
132: if (Sflag)
133: fprintf(stderr, "blocks\n");
134: else if (used == 1)
135: fprintf(stderr, "foot\n");
136: else
137: fprintf(stderr, "feet\n");
138: fprintf(stderr, "dump: %ld inodes, ", ninodes);
139: fprintf(stderr, "%ld real blocks, ", nblocks);
140: fprintf(stderr, "%ld sparse blocks\n", nsparse);
141: }
142: exit(0);
143: }
144:
145: /*
146: * Scan the command line and
147: * set options. Perhaps reset the name
148: * of the filesystem, the dump tape
149: * and the dump origin.
150: */
151: init(argc, argv)
152: char *argv[];
153: {
154: register char *p;
155: register c, i;
156:
157: if (argc > 1) {
158: uflag = 0;
159: i = 1;
160: p = argv[1];
161: while ((c = *p++) != '\0') {
162: switch (c) {
163:
164: case 'f':
165: if (++i >= argc)
166: usage();
167: dtn = argv[i];
168: break;
169:
170: case 'u':
171: uflag = 1;
172: break;
173:
174: case 'v':
175: vflag = 1;
176: break;
177:
178: case 's':
179: if (++i >= argc)
180: usage();
181: length = (long)12*100*num(argv[i], "length",
182: 600, 4800);
183: break;
184:
185: case 'S':
186: if (++i >= argc)
187: usage();
188: Sflag++;
189: length = (long)512 * num(argv[i], "block size",
190: 0, (unsigned)65535L);
191: break;
192:
193: case 'b':
194: if (++i >= argc)
195: usage();
196: block = num(argv[i], "blocking", 1, 20);
197: break;
198:
199: case 'd':
200: if (++i >= argc)
201: usage();
202: density = num(argv[i], "density", 800, 6250);
203: break;
204:
205: case '0':
206: case '1':
207: case '2':
208: case '3':
209: case '4':
210: case '5':
211: case '6':
212: case '7':
213: case '8':
214: case '9':
215: level = c-'0';
216: break;
217:
218: default:
219: usage();
220: }
221: }
222: if (++i < argc)
223: fsn = argv[i];
224: }
225: }
226:
227: /*
228: * Collect and range check
229: * numeric arguments.
230: */
231: num(s, msg, ll, hl)
232: register char *s;
233: char *msg;
234: unsigned ll, hl;
235: {
236: register c, n;
237:
238: n = 0;
239: while ((c=*s++)>='0' && c<='9')
240: n = 10*n + c - '0';
241: if (c!='\0' || n<ll || n>hl)
242: fatal("bad %s specification", msg);
243: return (n);
244: }
245:
246: /*
247: * Walk down the file system,
248: * looking for files that should be
249: * dumped. Mark them in the map.
250: * All directories that lead to changed
251: * inodes are forced to be dumped.
252: */
253: walk(ino)
254: ino_t ino;
255: {
256: register DISCBUF *dbp;
257: register struct direct *dirp;
258: int flag, nent, ndir;
259: long pb, dirb;
260: struct dinode dinode;
261: ino_t ent[BUFSIZ/sizeof(struct direct)];
262:
263: if ((map[ino-1]&DD_DEJA) != 0)
264: return (0);
265: ireadin(&dinode, ino);
266: canshort(dinode.di_mode);
267: cantime(dinode.di_ctime);
268: cantime(dinode.di_mtime);
269: /*
270: * Normally pipes stay in core,
271: * and are not in directories. Just to be
272: * safe we pretend any pipe is a clear
273: * inode.
274: */
275: if ((dinode.di_mode&IFMT) == IFPIPE)
276: return (0);
277: map[ino-1] |= DD_BUSY;
278: if ((dinode.di_mode&IFMT) != IFDIR) {
279: if (level==0||dinode.di_mtime>ddate||dinode.di_ctime>ddate) {
280: map[ino-1] |= DD_DUMP;
281: return (1);
282: }
283: return (0);
284: }
285: map[ino-1] |= DD_DEJA|DD_DIR;
286: flag = dirb = 0;
287: cansize(dinode.di_size);
288: while (dinode.di_size != 0) {
289: if ((pb = imap(&dinode, dirb++)) == 0) {
290: dinode.di_size -= BUFSIZ;
291: continue;
292: }
293: /*
294: * Writing the code is this
295: * strange fashon makes it require 1 cache
296: * buffer, not 1 per level.
297: */
298: dbp = dbread(pb);
299: nent = 0;
300: ndir = BUFSIZ / sizeof(struct direct);
301: if (dinode.di_size < BUFSIZ)
302: ndir = dinode.di_size / sizeof(struct direct);
303: dirp = (struct direct *) (dbp->db_data);
304: while (ndir--) {
305: if (dirp->d_ino != 0) {
306: ent[nent] = dirp->d_ino;
307: canino(ent[nent]);
308: ++nent;
309: }
310: ++dirp;
311: dinode.di_size -= sizeof(struct direct);
312: }
313: dbfree(dbp, 0);
314: while (nent--) {
315: if (walk(ent[nent]))
316: flag = 1;
317: }
318: }
319: if (flag!=0 || level==0 || dinode.di_ctime>ddate)
320: map[ino-1] |= DD_DUMP;
321: map[ino-1] &= ~DD_DEJA;
322: return (flag);
323: }
324:
325: /*
326: * Read in an inode.
327: * Leave it in the buffer in disc
328: * (that is, cannonical) format.
329: */
330: ireadin(diop, ino)
331: register struct dinode *diop;
332: ino_t ino;
333: {
334: register struct dinode *diip;
335: DISCBUF *dbp;
336:
337: dbp = dbread((long)((ino-1)/INOPB + INODEI));
338: diip = (struct dinode *)(dbp->db_data) + (ino-1)%INOPB;
339: *diop = *diip; /* Structure assignment */
340: dbfree(dbp, 0);
341: }
342:
343: /*
344: * Map logical block `lb' in the
345: * file whose in core inode is pointed to
346: * by `ip' to the associated physical
347: * block. Return 0 if the block will not
348: * map.
349: */
350: daddr_t
351: imap(ip, lb)
352: register struct dinode *ip;
353: daddr_t lb;
354: {
355: register il;
356: daddr_t bpos, pb;
357: DISCBUF *dbp;
358: register daddr_t *bp;
359: register daddr_t addrs[NADDR];
360:
361: l3tol(addrs, ip->di_addr, NADDR);
362: for (il=0; il<4; il++)
363: if (lb < ranges[il]) {
364: if (il != 0)
365: lb -= ranges[il-1];
366: bpos = lb/coeff[il];
367: lb %= coeff[il];
368: bp = &addrs[(int)bpos + offsets[il]];
369: if ((pb = *bp) != 0) {
370: while (il-- > 0) {
371: dbp = dbread((long) pb);
372: bpos = lb/coeff[il];
373: lb %= coeff[il];
374: bp = (daddr_t *)(dbp->db_data) + bpos;
375: dbfree(dbp, 0);
376: if ((pb = *bp) == 0)
377: break;
378: candaddr(pb);
379: }
380: }
381: return (pb);
382: }
383: return (0);
384: }
385:
386:
387: /*
388: * Dump out the map.
389: * The map is packed into ordinary
390: * tape blocks.
391: */
392: dumpinomap()
393: {
394: register ino_t ibase;
395: register char *imapp;
396: register nmap;
397: union dumpdata *ddp;
398:
399: ibase = 0;
400: while ((nmap = isize-ibase) > 0) {
401: ddp = ddnextbuf();
402: ddp->dd_type = DD_MAP;
403: ddp->dd_ino = ibase+1;
404: if (nmap > BUFSIZ)
405: nmap = BUFSIZ;
406: ddp->dd_nmap = nmap;
407: canint(ddp->dd_type);
408: canino(ddp->dd_ino);
409: canint(ddp->dd_nmap);
410: imapp = &ddp->dd_map[0];
411: do {
412: *imapp++ = map[ibase++];
413: } while (--nmap);
414: }
415: }
416:
417: /*
418: * Fabricate a dump header and
419: * write it to the dump file. All the
420: * stuff in the header is in the
421: * usual canonical format. This makes it
422: * a little easier to move tapes from
423: * one machine to another.
424: */
425: dumpheader()
426: {
427: register char *p;
428: register checksum;
429:
430: dh.dh_magic = DH_MAG;
431: dh.dh_nino = isize;
432: dh.dh_bdate = bdate;
433: dh.dh_ddate = ddate;
434: dh.dh_level = level;
435: dh.dh_reel = reel++;
436: dh.dh_blocking = block;
437: dh.dh_nbyte = Sflag ? length : 0;
438: strncpy(dh.dh_dev, dev, DIRSIZ);
439: strncpy(dh.dh_fname, fname, 6);
440: strncpy(dh.dh_fpack, fpack, 6);
441: p = (char *) &dh;
442: checksum = 0;
443: while (p < (char *) &dh.dh_checksum)
444: checksum += (*p++) & 0377;
445: dh.dh_checksum = checksum;
446: canint(dh.dh_magic);
447: canino(dh.dh_nino);
448: cantime(dh.dh_bdate);
449: cantime(dh.dh_ddate);
450: canint(dh.dh_level);
451: canint(dh.dh_reel);
452: canint(dh.dh_blocking);
453: cansize(dh.dh_nbyte);
454: canint(dh.dh_checksum);
455: if (write(fileno(dtp), &dh, sizeof dh) != sizeof dh)
456: fatal("header write error");
457: }
458:
459: /*
460: * Put out the end of tape item
461: * and the very end of the very last
462: * dump tape.
463: */
464: dumpfinish()
465: {
466: register union dumpdata *ddp;
467:
468: ddp = ddnextbuf();
469: ddp->dd_type = DD_EOT;
470: canint(ddp->dd_type);
471: ddflush();
472: }
473:
474: /*
475: * Dump out all inodes with
476: * the appropriate flags set in the
477: * map.
478: */
479: dump(flag)
480: register flag;
481: {
482: register ino_t i;
483: register mapentry;
484:
485: for (i=0; i<isize; ++i) {
486: mapentry = map[i];
487: if ((mapentry&DD_DUMP)!=0 && (mapentry&DD_DIR)==flag) {
488: dumpi(i+1);
489: map[i] = 0;
490: }
491: }
492: }
493:
494: /*
495: * Dump an inode.
496: */
497: dumpi(ino)
498: ino_t ino;
499: {
500: struct dinode dinode;
501: register union dumpdata *ddp;
502: register DISCBUF *dbp;
503: daddr_t lb, pb;
504: int size;
505:
506: ++ninodes;
507: ireadin(&dinode, ino);
508: ddp = ddnextbuf();
509: ddp->dd_type = DD_INO;
510: ddp->dd_ino = ino;
511: canint(ddp->dd_type);
512: canino(ddp->dd_ino);
513: copyb(&ddp->dd_dinode, &dinode, sizeof(struct dinode));
514: lb = 0;
515: cansize(dinode.di_size);
516: while (dinode.di_size != 0) {
517: pb = imap(&dinode, lb);
518: size = dinode.di_size<BUFSIZ ? dinode.di_size : BUFSIZ;
519: if (pb != 0) {
520: dbp = dbread(pb);
521: if (allzeros(dbp->db_data, size) == 0) {
522: ++nblocks;
523: ddp = ddnextbuf();
524: ddp->dd_type = DD_DATA;
525: ddp->dd_ino = ino;
526: ddp->dd_block = lb;
527: ddp->dd_size = size;
528: canint(ddp->dd_type);
529: canino(ddp->dd_ino);
530: candaddr(ddp->dd_block);
531: canint(ddp->dd_size);
532: copyb(ddp->dd_data, dbp->db_data, size);
533: } else
534: ++nsparse;
535: dbfree(dbp, 0);
536: }
537: dinode.di_size -= size;
538: ++lb;
539: }
540: }
541:
542: /*
543: * Check if a disc block is all
544: * zero bytes. True return if it is.
545: */
546: allzeros(cp, nb)
547: register char *cp;
548: register int nb;
549: {
550: do {
551: if (*cp++ != 0)
552: return (0);
553: } while (--nb);
554: return (1);
555: }
556:
557: /*
558: * Copy a block of bytes.
559: */
560: copyb(atp, afp, anb)
561: char *atp, *afp;
562: {
563: register char *tp, *fp;
564: register nb;
565:
566: if ((nb = anb) != 0) {
567: tp = atp;
568: fp = afp;
569: do {
570: *tp++ = *fp++;
571: } while (--nb);
572: }
573: }
574:
575: /*
576: * Return a pointer to the
577: * next data buffer.
578: */
579: union dumpdata *
580: ddnextbuf()
581: {
582: register char *p;
583: register n;
584:
585: if (ddbuf == NULL) {
586: ddnbuf = block * sizeof(union dumpdata);
587: if ((ddbuf = malloc(ddnbuf)) == NULL)
588: fatal("out of memory (buffer)");
589: ddend = &ddbuf[ddnbuf];
590: ddptr = (union dumpdata *) ddbuf;
591: }
592: if ((char *) ddptr == ddend) {
593: ddflush();
594: ddptr = (union dumpdata *) ddbuf;
595: }
596: if ((char *) ddptr == ddbuf) {
597: p = ddbuf;
598: n = ddnbuf;
599: do {
600: *p++ = 0;
601: } while (--n);
602: }
603: return (ddptr++);
604: }
605:
606: /*
607: * Write out the big data buffer.
608: */
609: ddflush()
610: {
611: used += ddlen(ddnbuf);
612: if (used >= length) {
613: nextvol();
614: used += ddlen(ddnbuf);
615: }
616: if (write(fileno(dtp), ddbuf, ddnbuf) != ddnbuf)
617: fatal("dump write error");
618: }
619:
620: /*
621: * Request next dump volume.
622: */
623: nextvol()
624: {
625: char buf[40];
626:
627: if (Sflag != 0 || reel != 1) {
628: fclose(dtp);
629: fprintf(stderr, "dump: mount %s %d, type return key ...",
630: Sflag ? "volume" : "reel", reel);
631: if (gets(buf) == NULL)
632: exit(1);
633: if ((dtp = fopen(dtn, "w")) == NULL)
634: fatal("%s: cannot open dump file", dtn);
635: }
636: dumpheader();
637: used = ddlen(sizeof(dh));
638: }
639:
640: /*
641: * Given a record size in bytes,
642: * return the number of inches/100 of tape
643: * that will get used.
644: * For blocked devices, the granularity is
645: * actually in bytes.
646: */
647: long
648: ddlen(nbytes)
649: {
650: if (Sflag)
651: return (nbytes);
652: return (100L*((nbytes+density-1)/density) + 75);
653: }
654:
655: /*
656: * Update the dump date in the
657: * dump date file. The date used is the
658: * date at the beginning of the dump.
659: */
660: putddate()
661: {
662: register FILE *ddfp;
663: struct idates id;
664:
665: if ((ddfp = fopen(DDATE, "r+w")) == NULL) {
666: fprintf(stderr, "dump: cannot update dump date\n");
667: return;
668: }
669: while (fread(&id, sizeof(id), 1, ddfp) == 1) {
670: if (strncmp(id.id_name, dev, DIRSIZ) == 0
671: && id.id_incno==level) {
672: fseek(ddfp, (long)-sizeof(id), 1);
673: break;
674: }
675: }
676: strncpy(id.id_name, dev, DIRSIZ);
677: id.id_incno = level;
678: id.id_ddate = bdate;
679: if (fwrite(&id, sizeof(id), 1, ddfp) != 1)
680: fprintf(stderr, "dump: error updating date file\n");
681: fclose(ddfp);
682: }
683:
684: /*
685: * Get dump date.
686: */
687: long
688: getddate()
689: {
690: register FILE *ddfp;
691: register long ddate;
692: struct idates id;
693:
694: ddate = 0;
695: if ((ddfp = fopen(DDATE, "r")) != NULL) {
696: while (fread(&id, sizeof(id), 1, ddfp) == 1) {
697: if (strncmp(id.id_name, dev, DIRSIZ)==0
698: && id.id_incno<level
699: && id.id_ddate>ddate)
700: ddate = id.id_ddate;
701: }
702: fclose(ddfp);
703: }
704: return (ddate);
705: }
706:
707: /*
708: * Print out a fatal diagnostic
709: * and die.
710: */
711: fatal(a)
712: {
713: fprintf(stderr, "dump: %r", &a);
714: fprintf(stderr, "\n");
715: exit(1);
716: }
717:
718: /*
719: * Print out a usage message and
720: * exit. If you can figure out how to use
721: * dump from the usage message you are
722: * a better man than I.
723: */
724: usage()
725: {
726: fprintf(stderr, helpmessage);
727: exit(1);
728: }
729:
730: /*
731: * Squash off any structure
732: * before the last part of a file
733: * name and put it in the supplied
734: * buffer.
735: */
736: squash(tp, fp)
737: register char *tp, *fp;
738: {
739: register char *np;
740:
741: np = fp;
742: while (*fp != '\0') {
743: if (*fp == '/')
744: np = fp+1;
745: ++fp;
746: }
747: while (*tp++ = *np++)
748: ;
749: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.