|
|
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 <types.h>
9: #include <discbuf.h>
10: #include <dumptape.h>
11: #include <canon.h>
12: #include <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 %D ", 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: %D inodes, ", ninodes);
139: fprintf(stderr, "%D real blocks, ", nblocks);
140: fprintf(stderr, "%D 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: /*
269: * Normally pipes stay in core,
270: * and are not in directories. Just to be
271: * safe we pretend any pipe is a clear
272: * inode.
273: */
274: if ((dinode.di_mode&IFMT) == IFPIPE)
275: return (0);
276: map[ino-1] |= DD_BUSY;
277: if ((dinode.di_mode&IFMT) != IFDIR) {
278: if (level==0 || dinode.di_ctime>ddate) {
279: map[ino-1] |= DD_DUMP;
280: return (1);
281: }
282: return (0);
283: }
284: map[ino-1] |= DD_DEJA|DD_DIR;
285: flag = dirb = 0;
286: cansize(dinode.di_size);
287: while (dinode.di_size != 0) {
288: if ((pb = imap(&dinode, dirb++)) == 0) {
289: dinode.di_size -= BUFSIZ;
290: continue;
291: }
292: /*
293: * Writing the code is this
294: * strange fashon makes it require 1 cache
295: * buffer, not 1 per level.
296: */
297: dbp = dbread(pb);
298: nent = 0;
299: ndir = BUFSIZ / sizeof(struct direct);
300: if (dinode.di_size < BUFSIZ)
301: ndir = dinode.di_size / sizeof(struct direct);
302: dirp = (struct direct *) (dbp->db_data);
303: while (ndir--) {
304: if (dirp->d_ino != 0) {
305: ent[nent] = dirp->d_ino;
306: canino(ent[nent]);
307: ++nent;
308: }
309: ++dirp;
310: dinode.di_size -= sizeof(struct direct);
311: }
312: dbfree(dbp, 0);
313: while (nent--) {
314: if (walk(ent[nent]))
315: flag = 1;
316: }
317: }
318: if (flag!=0 || level==0 || dinode.di_ctime>ddate)
319: map[ino-1] |= DD_DUMP;
320: map[ino-1] &= ~DD_DEJA;
321: return (flag);
322: }
323:
324: /*
325: * Read in an inode.
326: * Leave it in the buffer in disc
327: * (that is, cannonical) format.
328: */
329: ireadin(diop, ino)
330: register struct dinode *diop;
331: ino_t ino;
332: {
333: register struct dinode *diip;
334: DISCBUF *dbp;
335:
336: dbp = dbread((long)((ino-1)/INOPB + INODEI));
337: diip = (struct dinode *)(dbp->db_data) + (ino-1)%INOPB;
338: *diop = *diip; /* Structure assignment */
339: dbfree(dbp, 0);
340: }
341:
342: /*
343: * Map logical block `lb' in the
344: * file whose in core inode is pointed to
345: * by `ip' to the associated physical
346: * block. Return 0 if the block will not
347: * map.
348: */
349: daddr_t
350: imap(ip, lb)
351: register struct dinode *ip;
352: daddr_t lb;
353: {
354: register il;
355: daddr_t bpos, pb;
356: DISCBUF *dbp;
357: register daddr_t *bp;
358: register daddr_t addrs[NADDR];
359:
360: l3tol(addrs, ip->di_addr, NADDR);
361: for (il=0; il<4; il++)
362: if (lb < ranges[il]) {
363: if (il != 0)
364: lb -= ranges[il-1];
365: bpos = lb/coeff[il];
366: lb %= coeff[il];
367: bp = &addrs[(int)bpos + offsets[il]];
368: if ((pb = *bp) != 0) {
369: while (il-- > 0) {
370: dbp = dbread((long) pb);
371: bpos = lb/coeff[il];
372: lb %= coeff[il];
373: bp = (daddr_t *)(dbp->db_data) + bpos;
374: dbfree(dbp, 0);
375: if ((pb = *bp) == 0)
376: break;
377: candaddr(pb);
378: }
379: }
380: return (pb);
381: }
382: return (0);
383: }
384:
385:
386: /*
387: * Dump out the map.
388: * The map is packed into ordinary
389: * tape blocks.
390: */
391: dumpinomap()
392: {
393: register ino_t ibase;
394: register char *imapp;
395: register nmap;
396: union dumpdata *ddp;
397:
398: ibase = 0;
399: while ((nmap = isize-ibase) > 0) {
400: ddp = ddnextbuf();
401: ddp->dd_type = DD_MAP;
402: ddp->dd_ino = ibase+1;
403: if (nmap > BUFSIZ)
404: nmap = BUFSIZ;
405: ddp->dd_nmap = nmap;
406: canint(ddp->dd_type);
407: canino(ddp->dd_ino);
408: canint(ddp->dd_nmap);
409: imapp = &ddp->dd_map[0];
410: do {
411: *imapp++ = map[ibase++];
412: } while (--nmap);
413: }
414: }
415:
416: /*
417: * Fabricate a dump header and
418: * write it to the dump file. All the
419: * stuff in the header is in the
420: * usual canonical format. This makes it
421: * a little easier to move tapes from
422: * one machine to another.
423: */
424: dumpheader()
425: {
426: register char *p;
427: register checksum;
428:
429: dh.dh_magic = DH_MAG;
430: dh.dh_nino = isize;
431: dh.dh_bdate = bdate;
432: dh.dh_ddate = ddate;
433: dh.dh_level = level;
434: dh.dh_reel = reel++;
435: dh.dh_blocking = block;
436: dh.dh_nbyte = Sflag ? length : 0;
437: strncpy(dh.dh_dev, dev, DIRSIZ);
438: strncpy(dh.dh_fname, fname, 6);
439: strncpy(dh.dh_fpack, fpack, 6);
440: p = (char *) &dh;
441: checksum = 0;
442: while (p < (char *) &dh.dh_checksum)
443: checksum += (*p++) & 0377;
444: dh.dh_checksum = checksum;
445: canint(dh.dh_magic);
446: canino(dh.dh_nino);
447: cantime(dh.dh_bdate);
448: cantime(dh.dh_ddate);
449: canint(dh.dh_level);
450: canint(dh.dh_reel);
451: canint(dh.dh_blocking);
452: cansize(dh.dh_nbyte);
453: canint(dh.dh_checksum);
454: if (write(fileno(dtp), &dh, sizeof dh) != sizeof dh)
455: fatal("header write error");
456: }
457:
458: /*
459: * Put out the end of tape item
460: * and the very end of the very last
461: * dump tape.
462: */
463: dumpfinish()
464: {
465: register union dumpdata *ddp;
466:
467: ddp = ddnextbuf();
468: ddp->dd_type = DD_EOT;
469: canint(ddp->dd_type);
470: ddflush();
471: }
472:
473: /*
474: * Dump out all inodes with
475: * the appropriate flags set in the
476: * map.
477: */
478: dump(flag)
479: register flag;
480: {
481: register ino_t i;
482: register mapentry;
483:
484: for (i=0; i<isize; ++i) {
485: mapentry = map[i];
486: if ((mapentry&DD_DUMP)!=0 && (mapentry&DD_DIR)==flag) {
487: dumpi(i+1);
488: map[i] = 0;
489: }
490: }
491: }
492:
493: /*
494: * Dump an inode.
495: */
496: dumpi(ino)
497: ino_t ino;
498: {
499: struct dinode dinode;
500: register union dumpdata *ddp;
501: register DISCBUF *dbp;
502: daddr_t lb, pb;
503: int size;
504:
505: ++ninodes;
506: ireadin(&dinode, ino);
507: ddp = ddnextbuf();
508: ddp->dd_type = DD_INO;
509: ddp->dd_ino = ino;
510: canint(ddp->dd_type);
511: canino(ddp->dd_ino);
512: copyb(&ddp->dd_dinode, &dinode, sizeof(struct dinode));
513: lb = 0;
514: cansize(dinode.di_size);
515: while (dinode.di_size != 0) {
516: pb = imap(&dinode, lb);
517: size = dinode.di_size<BUFSIZ ? dinode.di_size : BUFSIZ;
518: if (pb != 0) {
519: dbp = dbread(pb);
520: if (allzeros(dbp->db_data, size) == 0) {
521: ++nblocks;
522: ddp = ddnextbuf();
523: ddp->dd_type = DD_DATA;
524: ddp->dd_ino = ino;
525: ddp->dd_block = lb;
526: ddp->dd_size = size;
527: canint(ddp->dd_type);
528: canino(ddp->dd_ino);
529: candaddr(ddp->dd_block);
530: canint(ddp->dd_size);
531: copyb(ddp->dd_data, dbp->db_data, size);
532: } else
533: ++nsparse;
534: dbfree(dbp, 0);
535: }
536: dinode.di_size -= size;
537: ++lb;
538: }
539: }
540:
541: /*
542: * Check if a disc block is all
543: * zero bytes. True return if it is.
544: */
545: allzeros(cp, nb)
546: register char *cp;
547: register int nb;
548: {
549: do {
550: if (*cp++ != 0)
551: return (0);
552: } while (--nb);
553: return (1);
554: }
555:
556: /*
557: * Copy a block of bytes.
558: */
559: copyb(atp, afp, anb)
560: char *atp, *afp;
561: {
562: register char *tp, *fp;
563: register nb;
564:
565: if ((nb = anb) != 0) {
566: tp = atp;
567: fp = afp;
568: do {
569: *tp++ = *fp++;
570: } while (--nb);
571: }
572: }
573:
574: /*
575: * Return a pointer to the
576: * next data buffer.
577: */
578: union dumpdata *
579: ddnextbuf()
580: {
581: register char *p;
582: register n;
583:
584: if (ddbuf == NULL) {
585: ddnbuf = block * sizeof(union dumpdata);
586: if ((ddbuf = malloc(ddnbuf)) == NULL)
587: fatal("out of memory (buffer)");
588: ddend = &ddbuf[ddnbuf];
589: ddptr = (union dumpdata *) ddbuf;
590: }
591: if ((char *) ddptr == ddend) {
592: ddflush();
593: ddptr = (union dumpdata *) ddbuf;
594: }
595: if ((char *) ddptr == ddbuf) {
596: p = ddbuf;
597: n = ddnbuf;
598: do {
599: *p++ = 0;
600: } while (--n);
601: }
602: return (ddptr++);
603: }
604:
605: /*
606: * Write out the big data buffer.
607: */
608: ddflush()
609: {
610: used += ddlen(ddnbuf);
611: if (used >= length) {
612: nextvol();
613: used += ddlen(ddnbuf);
614: }
615: if (write(fileno(dtp), ddbuf, ddnbuf) != ddnbuf)
616: fatal("dump write error");
617: }
618:
619: /*
620: * Request next dump volume.
621: */
622: nextvol()
623: {
624: char buf[40];
625:
626: if (Sflag != 0 || reel != 1) {
627: fclose(dtp);
628: fprintf(stderr, "dump: mount %s %d, type return key ...",
629: Sflag ? "volume" : "reel", reel);
630: if (gets(buf) == NULL)
631: exit(1);
632: if ((dtp = fopen(dtn, "w")) == NULL)
633: fatal("%s: cannot open dump file", dtn);
634: }
635: dumpheader();
636: used = ddlen(sizeof(dh));
637: }
638:
639: /*
640: * Given a record size in bytes,
641: * return the number of inches/100 of tape
642: * that will get used.
643: * For blocked devices, the granularity is
644: * actually in bytes.
645: */
646: long
647: ddlen(nbytes)
648: {
649: if (Sflag)
650: return (nbytes);
651: return (100L*((nbytes+density-1)/density) + 75);
652: }
653:
654: /*
655: * Update the dump date in the
656: * dump date file. The date used is the
657: * date at the beginning of the dump.
658: */
659: putddate()
660: {
661: register FILE *ddfp;
662: struct idates id;
663:
664: if ((ddfp = fopen(DDATE, "r+w")) == NULL) {
665: fprintf(stderr, "dump: cannot update dump date\n");
666: return;
667: }
668: while (fread(&id, sizeof(id), 1, ddfp) == 1) {
669: if (strncmp(id.id_name, dev, DIRSIZ) == 0
670: && id.id_incno==level) {
671: fseek(ddfp, (long)-sizeof(id), 1);
672: break;
673: }
674: }
675: strncpy(id.id_name, dev, DIRSIZ);
676: id.id_incno = level;
677: id.id_ddate = bdate;
678: if (fwrite(&id, sizeof(id), 1, ddfp) != 1)
679: fprintf(stderr, "dump: error updating date file\n");
680: fclose(ddfp);
681: }
682:
683: /*
684: * Get dump date.
685: */
686: long
687: getddate()
688: {
689: register FILE *ddfp;
690: register long ddate;
691: struct idates id;
692:
693: ddate = 0;
694: if ((ddfp = fopen(DDATE, "r")) != NULL) {
695: while (fread(&id, sizeof(id), 1, ddfp) == 1) {
696: if (strncmp(id.id_name, dev, DIRSIZ)==0
697: && id.id_incno<level
698: && id.id_ddate>ddate)
699: ddate = id.id_ddate;
700: }
701: fclose(ddfp);
702: }
703: return (ddate);
704: }
705:
706: /*
707: * Print out a fatal diagnostic
708: * and die.
709: */
710: fatal(a)
711: {
712: fprintf(stderr, "dump: %r", &a);
713: fprintf(stderr, "\n");
714: exit(1);
715: }
716:
717: /*
718: * Print out a usage message and
719: * exit. If you can figure out how to use
720: * dump from the usage message you are
721: * a better man than I.
722: */
723: usage()
724: {
725: fprintf(stderr, helpmessage);
726: exit(1);
727: }
728:
729: /*
730: * Squash off any structure
731: * before the last part of a file
732: * name and put it in the supplied
733: * buffer.
734: */
735: squash(tp, fp)
736: register char *tp, *fp;
737: {
738: register char *np;
739:
740: np = fp;
741: while (*fp != '\0') {
742: if (*fp == '/')
743: np = fp+1;
744: ++fp;
745: }
746: while (*tp++ = *np++)
747: ;
748: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.