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>
20 #ifdef IGNORE_SOME_GCC_WARNINGS
21 # pragma GCC diagnostic warning "-Wformat"
30 #include <rx/rx_queue.h>
31 #include <afs/afsint.h>
33 #include <afs/errors.h>
36 #include <afs/afssyscalls.h>
37 #include <afs/ihandle.h>
38 #include <afs/vnode.h>
39 #include <afs/volume.h>
40 #include <afs/partition.h>
41 #include <afs/viceinode.h>
42 #include <afs/afssyscalls.h>
45 #include <afs/com_err.h>
51 #define afs_putint32(p, v) *p++ = v>>24, *p++ = v>>16, *p++ = v>>8, *p++ = v
52 #define afs_putshort(p, v) *p++ = v>>8, *p++ = v
54 int VolumeChanged; /* needed by physio - leave alone */
56 static int enable_padding; /* Pad errors with NUL bytes */
58 /* Forward Declarations */
59 static void HandleVolume(struct DiskPartition64 *partP, char *name,
60 char *filename, int fromtime);
61 static Volume *AttachVolume(struct DiskPartition64 *dp, char *volname,
62 struct VolumeHeader *header);
63 static void DoMyVolDump(Volume * vp, struct DiskPartition64 *dp,
64 char *dumpfile, int fromtime);
67 #include "AFS_component_version_number.c"
70 char name[VMAXPATHLEN];
74 ReadHdr1(IHandle_t * ih, char *to, int size, u_int magic, u_int version)
78 code = IH_IREAD(ih, 0, to, size);
87 AttachVolume(struct DiskPartition64 * dp, char *volname,
88 struct VolumeHeader * header)
93 vp = (Volume *) calloc(1, sizeof(Volume));
94 vp->specialStatus = 0;
95 vp->device = dp->device;
97 IH_INIT(vp->vnodeIndex[vLarge].handle, dp->device, header->parent,
98 header->largeVnodeIndex);
99 IH_INIT(vp->vnodeIndex[vSmall].handle, dp->device, header->parent,
100 header->smallVnodeIndex);
101 IH_INIT(vp->diskDataHandle, dp->device, header->parent,
103 IH_INIT(V_linkHandle(vp), dp->device, header->parent, header->linkTable);
104 vp->cacheCheck = 0; /* XXXX */
105 vp->shuttingDown = 0;
106 vp->goingOffline = 0;
108 vp->header = calloc(1, sizeof(*vp->header));
109 ec = ReadHdr1(V_diskDataHandle(vp), (char *)&V_disk(vp),
110 sizeof(V_disk(vp)), VOLUMEINFOMAGIC, VOLUMEINFOVERSION);
112 struct IndexFileHeader iHead;
113 ec = ReadHdr1(vp->vnodeIndex[vSmall].handle, (char *)&iHead,
114 sizeof(iHead), SMALLINDEXMAGIC, SMALLINDEXVERSION);
117 struct IndexFileHeader iHead;
118 ec = ReadHdr1(vp->vnodeIndex[vLarge].handle, (char *)&iHead,
119 sizeof(iHead), LARGEINDEXMAGIC, LARGEINDEXVERSION);
123 struct versionStamp stamp;
124 ec = ReadHdr1(V_linkHandle(vp), (char *)&stamp, sizeof(stamp),
125 LINKTABLEMAGIC, LINKTABLEVERSION);
135 handleit(struct cmd_syndesc *as, void *arock)
139 afs_uint32 volumeId = 0;
141 char *fileName = NULL;
142 struct DiskPartition64 *partP = NULL;
144 char tmpPartName[20];
149 if ((ti = as->parms[0].items))
151 if ((ti = as->parms[1].items))
152 volumeId = (afs_uint32)atoi(ti->data);
153 if ((ti = as->parms[2].items))
155 if ((ti = as->parms[3].items))
157 if (as->parms[4].items && strcmp(as->parms[4].items->data, "0")) {
158 code = ktime_DateToInt32(as->parms[4].items->data, &fromtime);
160 fprintf(STDERR, "failed to parse date '%s' (error=%d))\n",
161 as->parms[4].items->data, code);
165 if (as->parms[5].items != NULL) { /* -pad-errors */
171 err = VAttachPartitions();
173 fprintf(stderr, "%d partitions had errors during attach.\n", err);
177 if (strlen(partName) == 1) {
178 if (partName[0] >= 'a' && partName[0] <= 'z') {
179 strcpy(tmpPartName, "/vicepa");
180 tmpPartName[6] = partName[0];
181 partP = VGetPartition(tmpPartName, 0);
184 partP = VGetPartition(partName, 0);
188 "%s is not an AFS partition name on this server.\n",
195 fprintf(stderr, "Must specify volume id!\n");
200 fprintf(stderr, "must specify vice partition.\n");
204 snprintf(name1, sizeof name1, VFORMAT, (unsigned long)volumeId);
205 HandleVolume(partP, name1, fileName, fromtime);
210 HandleVolume(struct DiskPartition64 *dp, char *name, char *filename, int fromtime)
212 struct VolumeHeader header;
213 struct VolumeDiskHeader diskHeader;
214 struct afs_stat status;
217 char headerName[1024];
221 snprintf(headerName, sizeof headerName, "%s" OS_DIRSEP "%s",
222 VPartitionPath(dp), name);
223 if ((fd = afs_open(headerName, O_RDONLY)) == -1
224 || afs_fstat(fd, &status) == -1) {
225 fprintf(stderr, "Cannot read volume header %s\n", name);
229 n = read(fd, &diskHeader, sizeof(diskHeader));
231 if (n != sizeof(diskHeader)
232 || diskHeader.stamp.magic != VOLUMEHEADERMAGIC) {
233 fprintf(stderr, "Error reading volume header %s\n", name);
236 if (diskHeader.stamp.version != VOLUMEHEADERVERSION) {
238 "Volume %s, version number is incorrect; volume needs salvage\n",
242 DiskToVolumeHeader(&header, &diskHeader);
245 vp = AttachVolume(dp, name, &header);
247 fprintf(stderr, "Error attaching volume header %s\n", name);
251 DoMyVolDump(vp, dp, filename, fromtime);
258 main(int argc, char **argv)
260 struct cmd_syndesc *ts;
262 VolumePackageOptions opts;
264 VOptDefaults(volumeUtility, &opts);
265 if (VInitVolumePackage2(volumeUtility, &opts)) {
266 fprintf(stderr, "errors encountered initializing volume package, but "
267 "trying to continue anyway\n");
270 ts = cmd_CreateSyntax(NULL, handleit, NULL, 0,
271 "Dump a volume to a 'vos dump' format file without using volserver");
272 cmd_AddParm(ts, "-part", CMD_LIST, CMD_OPTIONAL, "AFS partition name");
273 cmd_AddParm(ts, "-volumeid", CMD_LIST, CMD_OPTIONAL, "Volume id");
274 cmd_AddParm(ts, "-file", CMD_LIST, CMD_OPTIONAL, "Dump filename");
275 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL,
276 "Trace dump progress (very verbose)");
277 cmd_AddParm(ts, "-time", CMD_SINGLE, CMD_OPTIONAL, "dump from time");
278 cmd_AddParm(ts, "-pad-errors", CMD_FLAG, CMD_OPTIONAL,
279 "pad i/o errors with NUL bytes");
280 code = cmd_Dispatch(argc, argv);
288 DumpDouble(int dumpfd, char tag, afs_uint32 value1,
293 byte *p = (unsigned char *)tbuffer;
295 afs_putint32(p, value1);
296 afs_putint32(p, value2);
298 res = write(dumpfd, tbuffer, 9);
299 return ((res == 9) ? 0 : VOLSERDUMPERROR);
303 DumpInt32(int dumpfd, char tag, afs_uint32 value)
306 byte *p = (unsigned char *)tbuffer;
308 afs_putint32(p, value);
309 return ((write(dumpfd, tbuffer, 5) == 5) ? 0 : VOLSERDUMPERROR);
313 DumpString(int dumpfd, char tag, char *s)
317 code = write(dumpfd, &tag, 1);
319 return VOLSERDUMPERROR;
321 code = write(dumpfd, s, n);
323 return VOLSERDUMPERROR;
329 DumpArrayInt32(int dumpfd, char tag, afs_uint32 * array,
335 byte *p = (unsigned char *)tbuffer;
337 afs_putshort(p, nelem);
338 code = write(dumpfd, tbuffer, 3);
340 return VOLSERDUMPERROR;
342 p = (unsigned char *)tbuffer;
343 v = *array++; /*this was register */
346 code = write(dumpfd, tbuffer, 4);
348 return VOLSERDUMPERROR;
357 DumpDumpHeader(int dumpfd, Volume * vp, afs_int32 fromtime)
360 afs_int32 dumpTimes[2];
363 fprintf(stderr, "dumping dump header\n");
366 code = DumpDouble(dumpfd, D_DUMPHEADER, DUMPBEGINMAGIC, DUMPVERSION);
369 code = DumpInt32(dumpfd, 'v', V_id(vp));
372 code = DumpString(dumpfd, 'n', V_name(vp));
374 dumpTimes[0] = fromtime;
375 switch (V_type(vp)) {
376 case readwriteVolume:
377 dumpTimes[1] = V_updateDate(vp); /* until last update */
380 dumpTimes[1] = V_creationDate(vp); /* until clone was updated */
383 /* until backup was made */
384 dumpTimes[1] = V_backupDate(vp) != 0 ? V_backupDate(vp) :
391 code = DumpArrayInt32(dumpfd, 't', (afs_uint32 *) dumpTimes, 2);
400 return (DumpInt32(dumpfd, D_DUMPEND, DUMPENDMAGIC));
404 DumpByte(int dumpfd, char tag, byte value)
407 byte *p = (unsigned char *)tbuffer;
410 return ((write(dumpfd, tbuffer, 2) == 2) ? 0 : VOLSERDUMPERROR);
414 DumpTag(int dumpfd, int tag)
419 return ((write(dumpfd, &p, 1) == 1) ? 0 : VOLSERDUMPERROR);
424 DumpBool(int dumpfd, char tag, unsigned int value)
427 byte *p = (unsigned char *)tbuffer;
430 return ((write(dumpfd, tbuffer, 2) == 2) ? 0 : VOLSERDUMPERROR);
436 DumpVolumeHeader(int dumpfd, Volume * vp)
441 fprintf(stderr, "dumping volume header\n");
444 code = DumpTag(dumpfd, D_VOLUMEHEADER);
446 code = DumpInt32(dumpfd, 'i', V_id(vp));
448 code = DumpInt32(dumpfd, 'v', V_stamp(vp).version);
450 code = DumpString(dumpfd, 'n', V_name(vp));
452 code = DumpBool(dumpfd, 's', V_inService(vp));
454 code = DumpBool(dumpfd, 'b', V_blessed(vp));
456 code = DumpInt32(dumpfd, 'u', V_uniquifier(vp));
458 code = DumpByte(dumpfd, 't', (byte) V_type(vp));
460 code = DumpInt32(dumpfd, 'p', V_parentId(vp));
462 code = DumpInt32(dumpfd, 'c', V_cloneId(vp));
464 code = DumpInt32(dumpfd, 'q', V_maxquota(vp));
466 code = DumpInt32(dumpfd, 'm', V_minquota(vp));
468 code = DumpInt32(dumpfd, 'd', V_diskused(vp));
470 code = DumpInt32(dumpfd, 'f', V_filecount(vp));
472 code = DumpInt32(dumpfd, 'a', V_accountNumber(vp));
474 code = DumpInt32(dumpfd, 'o', V_owner(vp));
476 code = DumpInt32(dumpfd, 'C', V_creationDate(vp)); /* Rw volume creation date */
478 code = DumpInt32(dumpfd, 'A', V_accessDate(vp));
480 code = DumpInt32(dumpfd, 'U', V_updateDate(vp));
482 code = DumpInt32(dumpfd, 'E', V_expirationDate(vp));
484 code = DumpInt32(dumpfd, 'B', V_backupDate(vp)); /* Rw volume backup clone date */
486 code = DumpString(dumpfd, 'O', V_offlineMessage(vp));
489 * We do NOT dump the detailed volume statistics residing in the old
490 * motd field, since we cannot tell from the info in a dump whether
491 * statistics data has been put there. Instead, we dump a null string,
492 * just as if that was what the motd contained.
495 code = DumpString(dumpfd, 'M', "");
498 DumpArrayInt32(dumpfd, 'W', (afs_uint32 *) V_weekUse(vp),
499 sizeof(V_weekUse(vp)) / sizeof(V_weekUse(vp)[0]));
501 code = DumpInt32(dumpfd, 'D', V_dayUseDate(vp));
503 code = DumpInt32(dumpfd, 'Z', V_dayUse(vp));
508 DumpShort(int dumpfd, char tag, unsigned int value)
511 byte *p = (unsigned char *)tbuffer;
515 return ((write(dumpfd, tbuffer, 3) == 3) ? 0 : VOLSERDUMPERROR);
519 DumpByteString(int dumpfd, char tag, byte * bs, int nbytes)
523 code = write(dumpfd, &tag, 1);
525 return VOLSERDUMPERROR;
526 code = write(dumpfd, (char *)bs, nbytes);
528 return VOLSERDUMPERROR;
534 DumpFile(int dumpfd, int vnode, FdHandle_t * handleP, struct VnodeDiskObject *v)
538 afs_foff_t offset = 0;
539 afs_sfsize_t nbytes, howBig;
542 afs_foff_t howFar = 0;
547 struct afs_stat status;
549 LARGE_INTEGER fileSize;
553 #include <sys/statfs.h>
554 struct statfs tstatfs;
558 fprintf(stderr, "dumping file for vnode %d\n", vnode);
561 if (!GetFileSizeEx(handleP->fd_fd, &fileSize)) {
562 Log("DumpFile: GetFileSizeEx returned error code %d on descriptor %d\n", GetLastError(), handleP->fd_fd);
563 return VOLSERDUMPERROR;
565 howBig = fileSize.QuadPart;
569 afs_fstat(handleP->fd_fd, &status);
570 howBig = status.st_size;
573 /* Unfortunately in AIX valuable fields such as st_blksize are
574 * gone from the stat structure.
576 fstatfs(handleP->fd_fd, &tstatfs);
577 howMany = tstatfs.f_bsize;
579 howMany = status.st_blksize;
580 #endif /* AFS_AIX_ENV */
581 #endif /* AFS_NT40_ENV */
584 size = FDH_SIZE(handleP);
587 fprintf(stderr, " howBig = %u, howMany = %u, fdh size = %u\n",
588 (unsigned int) howBig, (unsigned int) howMany,
589 (unsigned int) size);
591 SplitInt64(size, hi, lo);
593 code = DumpInt32(dumpfd, 'f', lo);
595 code = DumpDouble(dumpfd, 'h', hi, lo);
599 return VOLSERDUMPERROR;
604 fprintf(stderr, "out of memory!\n");
605 return VOLSERDUMPERROR;
608 /* loop through whole file, while we still have bytes left, and no errors, in chunks of howMany bytes */
609 for (nbytes = size; (nbytes && !code); ) {
610 if (nbytes < howMany)
613 n = FDH_PREAD(handleP, p, howMany, howFar);
615 /* If read any good data and we null padded previously, log the
616 * amount that we had null padded.
618 if ((n > 0) && pad) {
619 fprintf(stderr, "Null padding file %d bytes at offset %lld\n", pad,
625 fprintf(stderr, "Error %d reading inode %s for vnode %d\n",
626 errno, PrintInode(stmp, handleP->fd_ih->ih_ino),
628 code = VOLSERDUMPERROR;
632 fprintf(stderr, "Unexpected EOF reading inode %s for vnode %d\n",
633 PrintInode(stmp, handleP->fd_ih->ih_ino), vnode);
635 code = VOLSERDUMPERROR;
638 if (code != 0 && enable_padding) {
640 * If our read failed, NUL-pad the rest of the buffer. This can
641 * happen if, for instance, the media has some bad spots. We don't
642 * want to quit the dump, so we start NUL padding.
644 memset(p, 0, howMany);
646 /* Remember the offset where we started padding, and keep a total
647 * tally of how much padding we've done. */
652 /* Pretend we read 'howMany' bytes. */
663 /* Now write the data out */
664 if (write(dumpfd, (char *)p, n) != n)
665 code = VOLSERDUMPERROR;
668 if (pad) { /* Any padding we hadn't reported yet */
669 fprintf(stderr, "Null padding file: %d bytes at offset %lld\n", pad,
679 DumpVnode(int dumpfd, struct VnodeDiskObject *v, VolumeId volid, int vnodeNumber,
680 int dumpEverything, struct Volume *vp)
688 fprintf(stderr, "dumping vnode %d\n", vnodeNumber);
690 if (!v || v->type == vNull)
693 code = DumpDouble(dumpfd, D_VNODE, vnodeNumber, v->uniquifier);
697 code = DumpByte(dumpfd, 't', (byte) v->type);
699 code = DumpShort(dumpfd, 'l', v->linkCount); /* May not need this */
701 code = DumpInt32(dumpfd, 'v', v->dataVersion);
703 code = DumpInt32(dumpfd, 'm', v->unixModifyTime);
705 code = DumpInt32(dumpfd, 'a', v->author);
707 code = DumpInt32(dumpfd, 'o', v->owner);
708 if (!code && v->group)
709 code = DumpInt32(dumpfd, 'g', v->group); /* default group is 0 */
711 code = DumpShort(dumpfd, 'b', v->modeBits);
713 code = DumpInt32(dumpfd, 'p', v->parent);
715 code = DumpInt32(dumpfd, 's', v->serverModifyTime);
716 if (v->type == vDirectory) {
717 code = acl_HtonACL(VVnodeDiskACL(v));
719 fprintf(stderr, "Skipping invalid acl in vnode %u (volume %"AFS_VOLID_FMT")\n",
720 vnodeNumber, afs_printable_VolumeId_lu(volid));
724 DumpByteString(dumpfd, 'A', (byte *) VVnodeDiskACL(v),
728 if (VNDISK_GET_INO(v)) {
729 IH_INIT(ihP, V_device(vp), V_parentId(vp), VNDISK_GET_INO(v));
733 "Unable to open inode %s for vnode %u "
734 "(volume %"AFS_VOLID_FMT"); not dumped, error %d\n",
735 PrintInode(stmp, VNDISK_GET_INO(v)), vnodeNumber,
736 afs_printable_VolumeId_lu(volid), errno);
741 fprintf(stderr, "about to dump inode %s for vnode %u\n",
742 PrintInode(stmp, VNDISK_GET_INO(v)), vnodeNumber);
743 code = DumpFile(dumpfd, vnodeNumber, fdP, v);
750 fprintf(stderr, "done dumping vnode %d\n", vnodeNumber);
756 DumpVnodeIndex(int dumpfd, Volume * vp, VnodeClass class, afs_int32 fromtime,
760 struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
761 char buf[SIZEOF_LARGEDISKVNODE];
762 struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
763 StreamHandle_t *file;
767 afs_foff_t offset = 0;
768 int vnodeIndex, nVnodes = 0;
770 fdP = IH_OPEN(vp->vnodeIndex[class].handle);
771 file = FDH_FDOPEN(fdP, "r+");
772 size = OS_SIZE(fdP->fd_fd);
773 nVnodes = (size / vcp->diskSize) - 1;
776 STREAM_ASEEK(file, vcp->diskSize);
780 nVnodes && STREAM_READ(vnode, vcp->diskSize, 1, file) == 1 && !code;
781 nVnodes--, vnodeIndex++, offset += vcp->diskSize) {
782 flag = forcedump || (vnode->serverModifyTime >= fromtime);
783 /* Note: the >= test is very important since some old volumes may not have
784 * a serverModifyTime. For an epoch dump, this results in 0>=0 test, which
785 * does dump the file! */
787 fprintf(stderr, "about to dump %s vnode %u (vnode offset = %lld)\n",
788 class == vSmall ? "vSmall" : "vLarge",
789 bitNumberToVnodeNumber(vnodeIndex, class), (long long)offset);
792 DumpVnode(dumpfd, vnode, V_id(vp),
793 bitNumberToVnodeNumber(vnodeIndex, class), flag,
803 /* A partial dump (no dump header) */
805 DumpPartial(int dumpfd, Volume * vp, afs_int32 fromtime,
811 fprintf(stderr, "about to dump the volume header\n");
813 code = DumpVolumeHeader(dumpfd, vp);
816 fprintf(stderr, "about to dump the large vnode index\n");
818 code = DumpVnodeIndex(dumpfd, vp, vLarge, fromtime, dumpAllDirs);
821 fprintf(stderr, "about to dump the small vnode index\n");
823 code = DumpVnodeIndex(dumpfd, vp, vSmall, fromtime, 0);
830 DoMyVolDump(Volume * vp, struct DiskPartition64 *dp, char *dumpfile, int fromtime)
839 afs_open(dumpfile, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR);
841 fprintf(stderr, "Failed to open dump file: %s. Exiting.\n",
842 afs_error_message(errno));
846 dumpfd = 1; /* stdout */
850 fprintf(stderr, "about to dump the dump header\n");
852 code = DumpDumpHeader(dumpfd, vp, fromtime);
855 fprintf(stderr, "about to dump volume contents\n");
857 code = DumpPartial(dumpfd, vp, fromtime, dumpAllDirs);
860 fprintf(stderr, "about to dump the dump postamble\n");
862 code = DumpEnd(dumpfd);
865 fprintf(stderr, "finished dump\n");
866 close(dumpfd); /* might be closing stdout, no harm */