2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
13 Institution: The Information Technology Center, Carnegie-Mellon University
17 #include <afsconfig.h>
18 #include <afs/param.h>
33 #include <sys/param.h>
40 #include <afs/afsint.h>
42 #include <afs/errors.h>
45 #include <afs/afssyscalls.h>
49 #include "partition.h"
50 #include "viceinode.h"
51 #include <afs/afssyscalls.h>
72 #include "volser/volser.h"
73 #include "volser/volint.h"
74 #include "volser/dump.h"
76 #define putint32(p, v) *p++ = v>>24, *p++ = v>>16, *p++ = v>>8, *p++ = v
77 #define putshort(p, v) *p++ = v>>8, *p++ = v
80 #define afs_stat stat64
81 #define afs_fstat fstat64
82 #define afs_open open64
83 #else /* !O_LARGEFILE */
85 #define afs_fstat fstat
87 #endif /* !O_LARGEFILE */
89 int VolumeChanged; /* needed by physio - leave alone */
92 /* Forward Declarations */
93 void HandleVolume(struct DiskPartition64 *partP, char *name, char *filename);
94 Volume *AttachVolume(struct DiskPartition64 *dp, char *volname,
95 register struct VolumeHeader *header);
96 static void DoMyVolDump(Volume * vp, struct DiskPartition64 *dp,
100 #include "AFS_component_version_number.c"
103 char name[VMAXPATHLEN];
107 ReadHdr1(IHandle_t * ih, char *to, int size, u_int magic, u_int version)
112 code = IH_IREAD(ih, 0, to, size);
121 AttachVolume(struct DiskPartition64 * dp, char *volname,
122 register struct VolumeHeader * header)
127 vp = (Volume *) calloc(1, sizeof(Volume));
128 vp->specialStatus = 0;
129 vp->device = dp->device;
131 IH_INIT(vp->vnodeIndex[vLarge].handle, dp->device, header->parent,
132 header->largeVnodeIndex);
133 IH_INIT(vp->vnodeIndex[vSmall].handle, dp->device, header->parent,
134 header->smallVnodeIndex);
135 IH_INIT(vp->diskDataHandle, dp->device, header->parent,
137 IH_INIT(V_linkHandle(vp), dp->device, header->parent, header->linkTable);
138 vp->cacheCheck = 0; /* XXXX */
139 vp->shuttingDown = 0;
140 vp->goingOffline = 0;
142 vp->header = (struct volHeader *)calloc(1, sizeof(*vp->header));
143 ec = ReadHdr1(V_diskDataHandle(vp), (char *)&V_disk(vp),
144 sizeof(V_disk(vp)), VOLUMEINFOMAGIC, VOLUMEINFOVERSION);
146 struct IndexFileHeader iHead;
147 ec = ReadHdr1(vp->vnodeIndex[vSmall].handle, (char *)&iHead,
148 sizeof(iHead), SMALLINDEXMAGIC, SMALLINDEXVERSION);
151 struct IndexFileHeader iHead;
152 ec = ReadHdr1(vp->vnodeIndex[vLarge].handle, (char *)&iHead,
153 sizeof(iHead), LARGEINDEXMAGIC, LARGEINDEXVERSION);
157 struct versionStamp stamp;
158 ec = ReadHdr1(V_linkHandle(vp), (char *)&stamp, sizeof(stamp),
159 LINKTABLEMAGIC, LINKTABLEVERSION);
169 handleit(struct cmd_syndesc *as, void *arock)
171 register struct cmd_item *ti;
175 char *fileName = NULL;
176 struct DiskPartition64 *partP = NULL;
178 char tmpPartName[20];
183 if (geteuid() != 0) {
184 fprintf(stderr, "voldump must be run as root; sorry\n");
190 if ((ti = as->parms[0].items))
192 if ((ti = as->parms[1].items))
193 volumeId = atoi(ti->data);
194 if ((ti = as->parms[2].items))
196 if ((ti = as->parms[3].items))
201 err = VAttachPartitions();
203 fprintf(stderr, "%d partitions had errors during attach.\n", err);
207 if (strlen(partName) == 1) {
208 if (partName[0] >= 'a' && partName[0] <= 'z') {
209 strcpy(tmpPartName, "/vicepa");
210 tmpPartName[6] = partName[0];
211 partP = VGetPartition(tmpPartName, 0);
214 partP = VGetPartition(partName, 0);
218 "%s is not an AFS partition name on this server.\n",
225 fprintf(stderr, "Must specify volume id!\n");
230 fprintf(stderr, "must specify vice partition.\n");
234 (void)afs_snprintf(name1, sizeof name1, VFORMAT, (unsigned long)volumeId);
235 HandleVolume(partP, name1, fileName);
240 HandleVolume(struct DiskPartition64 *dp, char *name, char *filename)
242 struct VolumeHeader header;
243 struct VolumeDiskHeader diskHeader;
244 struct afs_stat status, stat;
248 char headerName[1024];
252 (void)afs_snprintf(headerName, sizeof headerName, "%s/%s",
253 VPartitionPath(dp), name);
254 if ((fd = afs_open(headerName, O_RDONLY)) == -1
255 || afs_fstat(fd, &status) == -1) {
256 fprintf(stderr, "Cannot read volume header %s\n", name);
260 n = read(fd, &diskHeader, sizeof(diskHeader));
262 if (n != sizeof(diskHeader)
263 || diskHeader.stamp.magic != VOLUMEHEADERMAGIC) {
264 fprintf(stderr, "Error reading volume header %s\n", name);
267 if (diskHeader.stamp.version != VOLUMEHEADERVERSION) {
269 "Volume %s, version number is incorrect; volume needs salvage\n",
273 DiskToVolumeHeader(&header, &diskHeader);
276 vp = AttachVolume(dp, name, &header);
278 fprintf(stderr, "Error attaching volume header %s\n", name);
282 DoMyVolDump(vp, dp, filename);
287 main(int argc, char **argv)
289 register struct cmd_syndesc *ts;
292 VInitVolumePackage(volumeUtility, 5, 5, DONT_CONNECT_FS, 0);
294 ts = cmd_CreateSyntax(NULL, handleit, NULL,
295 "Dump a volume to a 'vos dump' format file without using volserver");
296 cmd_AddParm(ts, "-part", CMD_LIST, CMD_OPTIONAL, "AFS partition name");
297 cmd_AddParm(ts, "-volumeid", CMD_LIST, CMD_OPTIONAL, "Volume id");
298 cmd_AddParm(ts, "-file", CMD_LIST, CMD_OPTIONAL, "Dump filename");
299 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL,
300 "Trace dump progress (very verbose)");
301 code = cmd_Dispatch(argc, argv);
309 DumpDouble(int dumpfd, char tag, register afs_uint32 value1,
310 register afs_uint32 value2)
314 register byte *p = (unsigned char *)tbuffer;
319 res = write(dumpfd, tbuffer, 9);
320 return ((res == 9) ? 0 : VOLSERDUMPERROR);
324 DumpInt32(int dumpfd, char tag, register afs_uint32 value)
327 register byte *p = (unsigned char *)tbuffer;
330 return ((write(dumpfd, tbuffer, 5) == 5) ? 0 : VOLSERDUMPERROR);
334 DumpString(int dumpfd, char tag, register char *s)
338 code = write(dumpfd, &tag, 1);
340 return VOLSERDUMPERROR;
342 code = write(dumpfd, s, n);
344 return VOLSERDUMPERROR;
350 DumpArrayInt32(int dumpfd, char tag, register afs_uint32 * array,
354 register afs_uint32 v;
356 register byte *p = (unsigned char *)tbuffer;
359 code = write(dumpfd, tbuffer, 3);
361 return VOLSERDUMPERROR;
363 p = (unsigned char *)tbuffer;
364 v = *array++; /*this was register */
367 code = write(dumpfd, tbuffer, 4);
369 return VOLSERDUMPERROR;
378 DumpDumpHeader(int dumpfd, register Volume * vp, afs_int32 fromtime)
381 afs_int32 dumpTimes[2];
384 fprintf(stderr, "dumping dump header\n");
387 code = DumpDouble(dumpfd, D_DUMPHEADER, DUMPBEGINMAGIC, DUMPVERSION);
390 code = DumpInt32(dumpfd, 'v', V_id(vp));
393 code = DumpString(dumpfd, 'n', V_name(vp));
395 dumpTimes[0] = fromtime;
396 dumpTimes[1] = V_backupDate(vp); /* Until the time the clone was made */
398 code = DumpArrayInt32(dumpfd, 't', (afs_uint32 *) dumpTimes, 2);
407 return (DumpInt32(dumpfd, D_DUMPEND, DUMPENDMAGIC));
411 DumpByte(int dumpfd, char tag, byte value)
414 register byte *p = (unsigned char *)tbuffer;
417 return ((write(dumpfd, tbuffer, 2) == 2) ? 0 : VOLSERDUMPERROR);
421 DumpTag(int dumpfd, register int tag)
426 return ((write(dumpfd, &p, 1) == 1) ? 0 : VOLSERDUMPERROR);
431 DumpBool(int dumpfd, char tag, unsigned int value)
434 register byte *p = (unsigned char *)tbuffer;
437 return ((write(dumpfd, tbuffer, 2) == 2) ? 0 : VOLSERDUMPERROR);
443 DumpVolumeHeader(int dumpfd, register Volume * vp)
448 fprintf(stderr, "dumping volume header\n");
451 code = DumpTag(dumpfd, D_VOLUMEHEADER);
453 code = DumpInt32(dumpfd, 'i', V_id(vp));
455 code = DumpInt32(dumpfd, 'v', V_stamp(vp).version);
457 code = DumpString(dumpfd, 'n', V_name(vp));
459 code = DumpBool(dumpfd, 's', V_inService(vp));
461 code = DumpBool(dumpfd, 'b', V_blessed(vp));
463 code = DumpInt32(dumpfd, 'u', V_uniquifier(vp));
465 code = DumpByte(dumpfd, 't', (byte) V_type(vp));
467 code = DumpInt32(dumpfd, 'p', V_parentId(vp));
469 code = DumpInt32(dumpfd, 'c', V_cloneId(vp));
471 code = DumpInt32(dumpfd, 'q', V_maxquota(vp));
473 code = DumpInt32(dumpfd, 'm', V_minquota(vp));
475 code = DumpInt32(dumpfd, 'd', V_diskused(vp));
477 code = DumpInt32(dumpfd, 'f', V_filecount(vp));
479 code = DumpInt32(dumpfd, 'a', V_accountNumber(vp));
481 code = DumpInt32(dumpfd, 'o', V_owner(vp));
483 code = DumpInt32(dumpfd, 'C', V_creationDate(vp)); /* Rw volume creation date */
485 code = DumpInt32(dumpfd, 'A', V_accessDate(vp));
487 code = DumpInt32(dumpfd, 'U', V_updateDate(vp));
489 code = DumpInt32(dumpfd, 'E', V_expirationDate(vp));
491 code = DumpInt32(dumpfd, 'B', V_backupDate(vp)); /* Rw volume backup clone date */
493 code = DumpString(dumpfd, 'O', V_offlineMessage(vp));
496 * We do NOT dump the detailed volume statistics residing in the old
497 * motd field, since we cannot tell from the info in a dump whether
498 * statistics data has been put there. Instead, we dump a null string,
499 * just as if that was what the motd contained.
502 code = DumpString(dumpfd, 'M', "");
505 DumpArrayInt32(dumpfd, 'W', (afs_uint32 *) V_weekUse(vp),
506 sizeof(V_weekUse(vp)) / sizeof(V_weekUse(vp)[0]));
508 code = DumpInt32(dumpfd, 'D', V_dayUseDate(vp));
510 code = DumpInt32(dumpfd, 'Z', V_dayUse(vp));
512 code = DumpInt32(dumpfd, 'V', V_volUpCounter(vp));
517 DumpShort(int dumpfd, char tag, unsigned int value)
520 register byte *p = (unsigned char *)tbuffer;
524 return ((write(dumpfd, tbuffer, 3) == 3) ? 0 : VOLSERDUMPERROR);
528 DumpByteString(int dumpfd, char tag, register byte * bs, register int nbytes)
532 code = write(dumpfd, &tag, 1);
534 return VOLSERDUMPERROR;
535 code = write(dumpfd, (char *)bs, nbytes);
537 return VOLSERDUMPERROR;
543 DumpFile(int dumpfd, int vnode, FdHandle_t * handleP, struct VnodeDiskObject *v)
545 int code = 0, failed_seek = 0, failed_write = 0;
547 afs_int32 offset = 0;
548 afs_sfsize_t n, nbytes, howMany, howBig;
551 struct afs_stat status;
553 afs_sfsize_t size, tmpsize;
555 #include <sys/statfs.h>
556 struct statfs tstatfs;
560 fprintf(stderr, "dumping file for vnode %d\n", vnode);
563 howBig = _filelength(handleP->fd_fd);
567 afs_fstat(handleP->fd_fd, &status);
568 howBig = status.st_size;
571 /* Unfortunately in AIX valuable fields such as st_blksize are
572 * gone from the stat structure.
574 fstatfs(handleP->fd_fd, &tstatfs);
575 howMany = tstatfs.f_bsize;
577 howMany = status.st_blksize;
578 #endif /* AFS_AIX_ENV */
579 #endif /* AFS_NT40_ENV */
582 size = FDH_SIZE(handleP);
585 fprintf(stderr, " howBig = %u, howMany = %u, fdh size = %u\n",
586 howBig, howMany, size);
588 #ifdef AFS_LARGEFILE_ENV
591 SplitInt64(size, hi, lo);
593 code = DumpInt32(dumpfd, 'f', lo);
595 code = DumpDouble(dumpfd, 'h', hi, lo);
598 #else /* !AFS_LARGEFILE_ENV */
599 code = DumpInt32(dumpfd, 'f', size);
600 #endif /* !AFS_LARGEFILE_ENV */
602 return VOLSERDUMPERROR;
605 p = (unsigned char *)malloc(howMany);
607 fprintf(stderr, "out of memory!\n");
608 return VOLSERDUMPERROR;
611 /* loop through whole file, while we still have bytes left, and no errors, in chunks of howMany bytes */
612 for (nbytes = size; (nbytes && !failed_write); nbytes -= howMany) {
613 if (nbytes < howMany)
616 /* Read the data - unless we know we can't */
617 n = (failed_seek ? 0 : FDH_READ(handleP, p, howMany));
619 /* If read any good data and we null padded previously, log the
620 * amount that we had null padded.
622 if ((n > 0) && pad) {
623 fprintf(stderr, "Null padding file %d bytes at offset %u\n", pad,
628 /* If didn't read enough data, null padd the rest of the buffer. This
629 * can happen if, for instance, the media has some bad spots. We don't
630 * want to quit the dump, so we start null padding.
634 if (verbose) fprintf(stderr, " read %u instead of %u bytes.\n", n, howMany);
636 /* Record the read error */
639 fprintf(stderr, "Error %d reading inode %s for vnode %d\n",
640 errno, PrintInode(NULL, handleP->fd_ih->ih_ino),
643 fprintf(stderr, "Error reading inode %s for vnode %d\n",
644 PrintInode(NULL, handleP->fd_ih->ih_ino), vnode);
647 /* Pad the rest of the buffer with zeros. Remember offset we started
648 * padding. Keep total tally of padding.
650 memset(p + n, 0, howMany - n);
652 offset = (howBig - nbytes) + n;
653 pad += (howMany - n);
655 /* Now seek over the data we could not get. An error here means we
656 * can't do the next read.
658 failed_seek = FDH_SEEK(handleP, ((size - nbytes) + howMany), SEEK_SET);
659 if (failed_seek != ((size - nbytes) + howMany)) {
660 if (failed_seek < 0) {
662 "Error %d seeking in inode %s for vnode %d\n",
663 errno, PrintInode(NULL, handleP->fd_ih->ih_ino),
667 "Error seeking in inode %s for vnode %d\n",
668 PrintInode(NULL, handleP->fd_ih->ih_ino), vnode);
676 /* Now write the data out */
677 if (write(dumpfd, (char *)p, howMany) != howMany)
678 failed_write = VOLSERDUMPERROR;
681 if (pad) { /* Any padding we hadn't reported yet */
682 fprintf(stderr, "Null padding file: %d bytes at offset %u\n", pad,
692 DumpVnode(int dumpfd, struct VnodeDiskObject *v, int volid, int vnodeNumber,
693 int dumpEverything, struct Volume *vp)
700 fprintf(stderr, "dumping vnode %d\n", vnodeNumber);
702 if (!v || v->type == vNull)
705 code = DumpDouble(dumpfd, D_VNODE, vnodeNumber, v->uniquifier);
709 code = DumpByte(dumpfd, 't', (byte) v->type);
711 code = DumpShort(dumpfd, 'l', v->linkCount); /* May not need this */
713 code = DumpInt32(dumpfd, 'v', v->dataVersion);
715 code = DumpInt32(dumpfd, 'm', v->unixModifyTime);
717 code = DumpInt32(dumpfd, 'a', v->author);
719 code = DumpInt32(dumpfd, 'o', v->owner);
720 if (!code && v->group)
721 code = DumpInt32(dumpfd, 'g', v->group); /* default group is 0 */
723 code = DumpShort(dumpfd, 'b', v->modeBits);
725 code = DumpInt32(dumpfd, 'p', v->parent);
727 code = DumpInt32(dumpfd, 's', v->serverModifyTime);
728 if (v->type == vDirectory) {
729 acl_HtonACL(VVnodeDiskACL(v));
732 DumpByteString(dumpfd, 'A', (byte *) VVnodeDiskACL(v),
736 if (VNDISK_GET_INO(v)) {
737 IH_INIT(ihP, V_device(vp), V_parentId(vp), VNDISK_GET_INO(v));
741 "Unable to open inode %s for vnode %u (volume %i); not dumped, error %d\n",
742 PrintInode(NULL, VNDISK_GET_INO(v)), vnodeNumber, volid,
748 fprintf(stderr, "about to dump inode %s for vnode %u\n",
749 PrintInode(NULL, VNDISK_GET_INO(v)), vnodeNumber);
750 code = DumpFile(dumpfd, vnodeNumber, fdP, v);
757 fprintf(stderr, "done dumping vnode %d\n", vnodeNumber);
763 DumpVnodeIndex(int dumpfd, Volume * vp, VnodeClass class, afs_int32 fromtime,
766 register int code = 0;
767 register struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
768 char buf[SIZEOF_LARGEDISKVNODE];
769 struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
770 StreamHandle_t *file;
775 register int vnodeIndex, nVnodes = 0;
777 fdP = IH_OPEN(vp->vnodeIndex[class].handle);
778 file = FDH_FDOPEN(fdP, "r+");
779 size = OS_SIZE(fdP->fd_fd);
780 nVnodes = (size / vcp->diskSize) - 1;
783 STREAM_SEEK(file, vcp->diskSize, 0);
787 nVnodes && STREAM_READ(vnode, vcp->diskSize, 1, file) == 1 && !code;
788 nVnodes--, vnodeIndex++, offset += vcp->diskSize) {
789 flag = forcedump || (vnode->serverModifyTime >= fromtime);
790 /* Note: the >= test is very important since some old volumes may not have
791 * a serverModifyTime. For an epoch dump, this results in 0>=0 test, which
792 * does dump the file! */
794 fprintf(stderr, "about to dump %s vnode %u (vnode offset = %u)\n",
795 class == vSmall ? "vSmall" : "vLarge",
796 bitNumberToVnodeNumber(vnodeIndex, class), offset);
799 DumpVnode(dumpfd, vnode, V_id(vp),
800 bitNumberToVnodeNumber(vnodeIndex, class), flag,
810 /* A partial dump (no dump header) */
812 DumpPartial(int dumpfd, register Volume * vp, afs_int32 fromtime,
818 fprintf(stderr, "about to dump the volume header\n");
820 code = DumpVolumeHeader(dumpfd, vp);
823 fprintf(stderr, "about to dump the large vnode index\n");
825 code = DumpVnodeIndex(dumpfd, vp, vLarge, fromtime, dumpAllDirs);
828 fprintf(stderr, "about to dump the small vnode index\n");
830 code = DumpVnodeIndex(dumpfd, vp, vSmall, fromtime, 0);
837 DoMyVolDump(Volume * vp, struct DiskPartition64 *dp, char *dumpfile)
847 open(dumpfile, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR);
849 fprintf(stderr, "Failed to open dump file! Exiting.\n");
853 dumpfd = 1; /* stdout */
857 fprintf(stderr, "about to dump the dump header\n");
859 code = DumpDumpHeader(dumpfd, vp, fromtime);
862 fprintf(stderr, "about to dump volume contents\n");
864 code = DumpPartial(dumpfd, vp, fromtime, dumpAllDirs);
867 fprintf(stderr, "about to dump the dump postamble\n");
869 code = DumpEnd(dumpfd);
872 fprintf(stderr, "finished dump\n");
873 close(dumpfd); /* might be closing stdout, no harm */