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>
32 #include <sys/param.h>
39 #include <afs/afsint.h>
41 #include <afs/errors.h>
44 #include <afs/afssyscalls.h>
48 #include "partition.h"
49 #include "viceinode.h"
50 #include "volinodes.h"
51 #include <afs/afssyscalls.h>
59 int DumpVnodes = 0; /* Dump everything, i.e. summary of all vnodes */
60 int DumpInodeNumber = 0; /* Dump inode numbers with vnodes */
61 int DumpDate = 0; /* Dump vnode date (server modify date) with vnode */
62 int InodeTimes = 0; /* Dump some of the dates associated with inodes */
63 #if defined(AFS_NAMEI_ENV)
64 int PrintFileNames = 0;
68 int dsizeOnly = 0, totvolsize=0, Vauxsize = 0, Vdiskused = 0, Vvnodesize = 0;
69 int Totvolsize=0, TVauxsize = 0, TVdiskused = 0, TVvnodesize = 0;
70 int Stotvolsize=0, SVauxsize = 0, SVdiskused = 0, SVvnodesize = 0;
71 int fixheader = 0, saveinodes = 0, orphaned=0;
74 /* Forward Declarations */
75 void PrintHeader(register Volume *vp);
76 void HandleAllPart(void);
77 void HandlePart(struct DiskPartition *partP);
78 void HandleVolume(struct DiskPartition *partP, char *name);
79 struct DiskPartition *FindCurrentPartition(void);
80 Volume *AttachVolume(struct DiskPartition *dp, char *volname,
81 register struct VolumeHeader *header);
82 #if defined(AFS_NAMEI_ENV)
83 void PrintVnode(int offset, VnodeDiskObject *vnode, int vnodeNumber,
84 Inode ino, Volume* vp);
86 void PrintVnode(int offset, VnodeDiskObject *vnode, int vnodeNumber,
89 void PrintVnodes(Volume *vp, VnodeClass class);
91 char *date(time_t date)
93 static char results[8][100];
95 struct tm *tm = localtime(&date);
98 strftime (buf, 32, "%Y/%m/%d.%H:%M:%S", tm); /* NT does not have %T */
99 sprintf(results[next = (next+1)&7], "%lu (%s)", (unsigned long) date, buf);
100 return results[next];
104 #include "AFS_component_version_number.c"
107 char name[VMAXPATHLEN];
111 int ReadHdr1(IHandle_t *ih, char *to, int size, u_int magic, u_int version)
113 struct versionStamp *vsn;
117 vsn = (struct versionStamp *) to;
119 code = IH_IREAD(ih, 0, to, size);
123 if (vsn->magic != magic) {
125 printf("Inode %s: Bad magic %x (%x): IGNORED\n",
126 PrintInode(NULL, ih->ih_ino), vsn->magic, magic);
129 /* Check is conditional, in case caller wants to inspect version himself */
130 if (version && vsn->version != version) {
132 printf("Inode %s: Bad version %x (%x): IGNORED\n",
133 PrintInode(NULL, ih->ih_ino), vsn->version, version);
135 if (bad && fixheader) {
137 vsn->version = version;
138 printf("Special index inode %s has a bad header. Reconstructing...\n",
139 PrintInode(NULL, ih->ih_ino));
140 code = IH_IWRITE(ih, 0, to, size);
142 printf("Write failed; header left in damaged state\n");
145 if (!dsizeOnly && !saveinodes) {
146 printf("Inode %s: Good magic %x and version %x\n",
147 PrintInode(NULL, ih->ih_ino), magic, version);
154 Volume *AttachVolume(struct DiskPartition *dp, char *volname,
155 register struct VolumeHeader *header)
160 vp = (Volume *) calloc(1, sizeof(Volume));
161 vp->specialStatus = 0;
162 vp->device = dp->device;
164 IH_INIT(vp->vnodeIndex[vLarge].handle, dp->device, header->parent,
165 header->largeVnodeIndex);
166 IH_INIT(vp->vnodeIndex[vSmall].handle, dp->device, header->parent,
167 header->smallVnodeIndex);
168 IH_INIT(vp->diskDataHandle, dp->device, header->parent,
170 IH_INIT(V_linkHandle(vp), dp->device, header->parent,
172 vp->cacheCheck = 0; /* XXXX */
173 vp->shuttingDown = 0;
174 vp->goingOffline = 0;
176 vp->header = (struct volHeader *) calloc(1, sizeof(*vp->header));
177 ec = ReadHdr1(V_diskDataHandle(vp),
178 (char *)&V_disk(vp), sizeof(V_disk(vp)),
179 VOLUMEINFOMAGIC, VOLUMEINFOVERSION);
181 struct IndexFileHeader iHead;
182 ec = ReadHdr1(vp->vnodeIndex[vSmall].handle,
183 (char *)&iHead, sizeof(iHead),
184 SMALLINDEXMAGIC, SMALLINDEXVERSION);
187 struct IndexFileHeader iHead;
188 ec = ReadHdr1(vp->vnodeIndex[vLarge].handle,
189 (char *)&iHead, sizeof(iHead),
190 LARGEINDEXMAGIC, LARGEINDEXVERSION);
194 struct versionStamp stamp;
195 ec = ReadHdr1(V_linkHandle(vp),
196 (char *)&stamp, sizeof(stamp),
197 LINKTABLEMAGIC, LINKTABLEVERSION);
200 if (ec) return (Volume *)0;
205 static int handleit(struct cmd_syndesc *as)
207 register struct cmd_item *ti;
211 struct DiskPartition *partP= NULL;
215 if (geteuid() != 0) {
216 printf("vol-info must be run as root; sorry\n");
221 if (as->parms[0].items)
225 if (as->parms[1].items)
229 if (as->parms[2].items)
233 if (as->parms[3].items)
237 if (as->parms[4].items)
241 if ((ti = as->parms[5].items))
243 if ((ti = as->parms[6].items))
244 volumeId = atoi(ti->data);
245 if (as->parms[7].items)
249 if (as->parms[8].items) {
255 if (as->parms[9].items) {
259 if (as->parms[10].items) {
265 if (as->parms[11].items) {
269 #if defined(AFS_NAMEI_ENV)
270 if (as->parms[12].items) {
279 err = VAttachPartitions();
281 printf("%d partitions had errors during attach.\n", err);
285 partP = VGetPartition(partName, 0);
287 printf("%s is not an AFS partition name on this server.\n",
303 partP = FindCurrentPartition();
305 printf("Current partition is not a vice partition.\n");
309 sprintf(name1,VFORMAT,volumeId);
310 if (dsizeOnly && !saveinodes)
311 printf("Volume-Id\t Volsize Auxsize Inodesize AVolsize SizeDiff (VolName)\n");
312 HandleVolume(partP, name1);
319 struct DiskPartition *FindCurrentPartition()
321 int dr = _getdrive();
322 struct DiskPartition *dp;
325 for(dp = DiskPartitionList; dp; dp = dp->next) {
326 if (*dp->devName - 'A' == dr)
330 printf("Current drive is not a valid vice partition.\n");
335 struct DiskPartition *FindCurrentPartition()
340 struct DiskPartition *dp;
342 if (!getcwd(partName, 1023)) {
346 p = strchr(&partName[1], '/');
351 if (!(dp = VGetPartition(partName, 0))) {
353 printf("%s is not a valid vice partition.\n", partName);
360 void HandleAllPart(void)
362 struct DiskPartition *partP;
365 for (partP = DiskPartitionList; partP; partP = partP->next) {
366 printf("Processing Partition %s:\n", partP->name);
368 Stotvolsize += Totvolsize;
369 SVauxsize += TVauxsize;
370 SVvnodesize += TVvnodesize;
371 SVdiskused += TVdiskused;
375 printf("\nServer Totals%12d%9d%10d%10d%9d\n",
376 SVdiskused, SVauxsize, SVvnodesize, Stotvolsize,
377 Stotvolsize-SVdiskused);
382 void HandlePart(struct DiskPartition *partP)
390 (void) sprintf(pname, "%s\\", VPartitionPath(partP));
392 char *p = VPartitionPath(partP);
395 if (chdir(p) == -1) {
396 printf("Can't chdir to partition %s; giving up\n", p);
399 if ((dirp = opendir(".")) == NULL) {
400 printf("Can't read directory %s; giving up\n", p);
403 if (dsizeOnly && !saveinodes)
404 printf("Volume-Id\t Volsize Auxsize Inodesize AVolsize SizeDiff (VolName)\n");
405 while (dp = readdir(dirp)) {
406 p = (char *)strrchr(dp->d_name, '.');
407 if (p != NULL && strcmp(p, VHDREXT) == 0) {
408 HandleVolume(partP, dp->d_name);
409 Totvolsize += totvolsize;
410 TVauxsize += Vauxsize;
411 TVvnodesize += Vvnodesize;
412 TVdiskused += Vdiskused;
418 printf("\nPart Totals %12d%9d%10d%10d%9d (%d volumes)\n\n",
419 TVdiskused, TVauxsize, TVvnodesize, Totvolsize,
420 Totvolsize-TVdiskused, nvols);
425 void HandleVolume(struct DiskPartition *dp, char *name)
427 struct VolumeHeader header;
428 struct VolumeDiskHeader diskHeader;
429 struct stat status, stat;
433 char headerName[1024];
436 printf("volinfo: -online not supported\n");
441 (void) sprintf(headerName, "%s/%s", VPartitionPath(dp), name);
442 if ((fd = open(headerName, O_RDONLY)) == -1
443 || fstat(fd,&status) == -1) {
444 printf("Volinfo: Cannot read volume header %s\n", name);
448 n = read(fd, &diskHeader, sizeof (diskHeader));
450 if (n != sizeof (diskHeader)
451 || diskHeader.stamp.magic != VOLUMEHEADERMAGIC) {
452 printf("Volinfo: Error reading volume header %s\n", name);
455 if (diskHeader.stamp.version != VOLUMEHEADERVERSION) {
456 printf("Volinfo: Volume %s, version number is incorrect; volume needs salvage\n",name);
459 DiskToVolumeHeader(&header, &diskHeader);
466 if (fstat(fd, &stat) == -1) {
470 if (!dsizeOnly && !saveinodes) {
471 printf("Volume header (size = %d):\n", size = stat.st_size);
472 printf("\tstamp\t= 0x%x\n", header.stamp.version);
473 printf("\tVolId\t= %d\n", header.id);
476 IH_INIT(ih, dp->device , header.id, header.volumeInfo);
479 perror("opening volume info");
482 code = FDH_SIZE(fdP);
487 FDH_REALLYCLOSE(fdP);
490 if (!dsizeOnly && !saveinodes) {
491 printf("\tparent\t= %d\n", header.parent);
492 printf("\tInfo inode\t= %s (size = %d)\n",
493 PrintInode(NULL, header.volumeInfo), code);
496 IH_INIT(ih, dp->device , header.id, header.smallVnodeIndex);
499 perror("opening small vnode index");
502 code = FDH_SIZE(fdP);
507 FDH_REALLYCLOSE(fdP);
510 if (!dsizeOnly && !saveinodes) {
511 printf("\tSmall inode\t= %s (size = %d)\n",
512 PrintInode(NULL, header.smallVnodeIndex), code);
515 IH_INIT(ih, dp->device, header.id, header.largeVnodeIndex);
518 perror("opening large vnode index");
521 code = FDH_SIZE(fdP);
526 FDH_REALLYCLOSE(fdP);
529 if (!dsizeOnly && !saveinodes) {
530 printf("\tLarge inode\t= %s (size = %d)\n",
531 PrintInode(NULL, header.largeVnodeIndex), code);
533 printf("Total aux volume size = %d\n\n", size);
537 IH_INIT(ih, dp->device, header.id, header.linkTable);
540 perror("opening link table index");
543 code = FDH_SIZE(fdP);
548 FDH_REALLYCLOSE(fdP);
551 if (!dsizeOnly && !saveinodes) {
552 printf("\tLink inode\t= %s (size = %d)\n",
553 PrintInode(NULL, header.linkTable), code);
554 printf("Total aux volume size = %d\n\n", size);
560 vp = AttachVolume(dp, name, &header);
562 printf("Volinfo: Error attaching volume header %s\n", name);
568 if (!dsizeOnly && !saveinodes)
569 printf("\nLarge vnodes (directories)\n");
570 PrintVnodes(vp, vLarge);
571 if (!dsizeOnly && !saveinodes) {
572 printf("\nSmall vnodes(files, symbolic links)\n");
576 printf("Saving all volume files to current directory ...\n");
577 PrintVnodes(vp, vSmall);
580 Vauxsize = Vauxsize/1024;
581 Vvnodesize = Vvnodesize/1024;
582 totvolsize = Vauxsize + Vvnodesize;
584 printf("Volume-Id\t Volsize Auxsize Inodesize AVolsize SizeDiff (VolName)\n");
586 printf("%d\t%9d%9d%10d%10d%9d\t%24s\n",
587 V_id(vp), Vdiskused, Vauxsize, Vvnodesize, totvolsize,
588 totvolsize-Vdiskused, V_name(vp));
596 register struct cmd_syndesc *ts;
599 ts = cmd_CreateSyntax(NULL, handleit, 0, "Dump volume's internal state");
600 cmd_AddParm(ts, "-online", CMD_FLAG, CMD_OPTIONAL, "Get info from running fileserver");
601 cmd_AddParm(ts, "-vnode", CMD_FLAG, CMD_OPTIONAL, "Dump vnode info");
602 cmd_AddParm(ts, "-date", CMD_FLAG, CMD_OPTIONAL, "Also dump vnode's mod date");
603 cmd_AddParm(ts, "-inode", CMD_FLAG, CMD_OPTIONAL, "Dump vnode's inode number");
604 cmd_AddParm(ts, "-itime", CMD_FLAG, CMD_OPTIONAL, "Dump special inode's mod times");
605 cmd_AddParm(ts, "-part", CMD_LIST, CMD_OPTIONAL, "AFS partition name (default current partition)");
606 cmd_AddParm(ts, "-volumeid", CMD_LIST, CMD_OPTIONAL, "Volume id");
607 cmd_AddParm(ts, "-header", CMD_FLAG, CMD_OPTIONAL, "Dump volume's header info");
608 cmd_AddParm(ts, "-sizeOnly", CMD_FLAG, CMD_OPTIONAL, "Dump volume's size");
609 cmd_AddParm(ts, "-fixheader", CMD_FLAG, CMD_OPTIONAL, "Try to fix header");
610 cmd_AddParm(ts, "-saveinodes", CMD_FLAG, CMD_OPTIONAL, "Try to save all inodes");
611 cmd_AddParm(ts, "-orphaned", CMD_FLAG, CMD_OPTIONAL, "List all dir/files without a parent");
612 #if defined(AFS_NAMEI_ENV)
613 cmd_AddParm(ts, "-filenames", CMD_FLAG, CMD_OPTIONAL, "Print filenames");
615 code = cmd_Dispatch(argc, argv);
619 #define typestring(type) (type == RWVOL? "read/write": type == ROVOL? "readonly": type == BACKVOL? "backup": "unknown")
621 void PrintHeader(register Volume *vp)
623 Vdiskused = V_diskused(vp);
624 if (dsizeOnly || saveinodes) return;
625 printf("Volume header for volume %u (%s)\n", V_id(vp), V_name(vp));
626 printf("stamp.magic = %x, stamp.version = %u\n", V_stamp(vp).magic,
627 V_stamp(vp).version);
628 printf("inUse = %d, inService = %d, blessed = %d, needsSalvaged = %d, dontSalvage = %d\n",
629 V_inUse(vp), V_inService(vp), V_blessed(vp), V_needsSalvaged(vp), V_dontSalvage(vp));
630 printf("type = %d (%s), uniquifier = %u, needsCallback = %d, destroyMe = %x\n",
631 V_type(vp), typestring(V_type(vp)), V_uniquifier(vp), V_needsCallback(vp),
633 printf("id = %u, parentId = %u, cloneId = %u, backupId = %u, restoredFromId = %u\n",
634 V_id(vp), V_parentId(vp), V_cloneId(vp), V_backupId(vp), V_restoredFromId(vp));
635 printf("maxquota = %d, minquota = %d, maxfiles = %d, filecount = %d, diskused = %d\n",
636 V_maxquota(vp), V_minquota(vp), V_maxfiles(vp), V_filecount(vp), V_diskused(vp));
637 printf("creationDate = %s, copyDate = %s\n", date(V_creationDate(vp)), date(V_copyDate(vp)));
638 printf("backupDate = %s, expirationDate = %s\n", date(V_backupDate(vp)), date(V_expirationDate(vp)));
639 printf("accessDate = %s, updateDate = %s\n", date(V_accessDate(vp)), date(V_updateDate(vp)));
640 printf("owner = %u, accountNumber = %u\n", V_owner(vp), V_accountNumber(vp));
641 printf("dayUse = %u; week = (%u, %u, %u, %u, %u, %u, %u), dayUseDate = %s\n",
642 V_dayUse(vp), V_weekUse(vp)[0], V_weekUse(vp)[1], V_weekUse(vp)[2],
643 V_weekUse(vp)[3],V_weekUse(vp)[4],V_weekUse(vp)[5],V_weekUse(vp)[6],
644 date(V_dayUseDate(vp)));
648 * OS independent file info. Die on failure.
651 char *NT_date(FILETIME *ft)
653 static char result[8][64];
658 if (!FileTimeToLocalFileTime(ft, &lft) ||
659 !FileTimeToSystemTime(&lft, &st)) {
660 printf("Time conversion failed.\n");
663 sprintf(result[next = ((next+1)&7)], "%4d/%02d/%02d.%2d:%2d:%2d",
664 st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute,
670 static void GetFileInfo(FD_t fd, int *size, char **ctime, char **mtime,
674 BY_HANDLE_FILE_INFORMATION fi;
675 if (!GetFileInformationByHandle(fd, &fi)) {
676 printf("GetFileInformationByHandle failed, exiting\n");
679 *size = (int)fi.nFileSizeLow;
681 *mtime = NT_date(&fi.ftLastWriteTime);
682 *atime = NT_date(&fi.ftLastAccessTime);
685 if (fstat(fd, &status) == -1) {
686 printf("fstat failed %d\n", errno);
689 *size = (int)status.st_size;
690 *ctime = date(status.st_ctime);
691 *mtime = date(status.st_mtime);
692 *atime = date(status.st_atime);
696 void PrintVnodes(Volume *vp, VnodeClass class)
698 afs_int32 diskSize = (class == vSmall ?
699 SIZEOF_SMALLDISKVNODE : SIZEOF_LARGEDISKVNODE);
700 char buf[SIZEOF_LARGEDISKVNODE];
701 struct VnodeDiskObject *vnode = (struct VnodeDiskObject *) buf;
702 StreamHandle_t *file;
703 register int vnodeIndex, nVnodes, offset=0;
705 IHandle_t *ih = vp->vnodeIndex[class].handle;
708 char *ctime, *atime, *mtime;
709 char nfile[50], buffer[256];
710 int total, ofd, len, code, bad=0;
714 printf("open failed\n");
718 file = FDH_FDOPEN(fdP, "r");
720 printf("fdopen failed\n");
724 GetFileInfo(fdP->fd_fd, &size, &ctime, &atime, &mtime);
725 if (InodeTimes && !dsizeOnly) {
726 printf("ichanged : %s\nimodified: %s\niaccessed: %s\n\n",
727 ctime, mtime, atime);
730 nVnodes = (size / diskSize) - 1;
732 STREAM_SEEK(file, diskSize, 0);
736 for (vnodeIndex = 0; nVnodes && STREAM_READ(vnode, diskSize, 1, file) == 1;
737 nVnodes--, vnodeIndex++, offset += diskSize) {
739 ino = VNDISK_GET_INO(vnode);
741 if (VALID_INO(ino) && (class == vSmall)) {
744 IH_INIT(ih1, V_device(vp), V_parentId(vp), ino);
747 printf("Can't open inode %s error %d (ignored)\n",
748 PrintInode(NULL, ino), errno);
751 sprintf(nfile, "TmpInode.%s", PrintInode(NULL, ino));
752 ofd = open(nfile, O_CREAT | O_RDWR | O_TRUNC, 0600);
754 printf("Can't create file %s; error %d (ignored)\n", nfile, errno);
759 len = FDH_READ(fdP1, buffer, sizeof(buffer));
761 FDH_REALLYCLOSE(fdP1);
765 printf("Error while reading from inode %s (%d - ignored)\n",
766 PrintInode(NULL, ino), errno);
770 if (len == 0) break; /* No more input */
771 code = write(ofd, buffer, len);
773 FDH_REALLYCLOSE(fdP1);
777 printf("Error while writing to \"%s\" (%d - ignored)\n", nfile, errno);
784 FDH_REALLYCLOSE(fdP1);
787 printf("... Copied inode %d to file %s (%d bytes)\n",
791 #if defined(AFS_NAMEI_ENV)
792 PrintVnode(offset, vnode,
793 bitNumberToVnodeNumber(vnodeIndex, class), ino, vp);
795 PrintVnode(offset, vnode,
796 bitNumberToVnodeNumber(vnodeIndex, class), ino);
804 #if defined(AFS_NAMEI_ENV)
805 void PrintVnode(int offset, VnodeDiskObject *vnode, int vnodeNumber, Inode ino, Volume *vp)
807 void PrintVnode(int offset, VnodeDiskObject *vnode, int vnodeNumber, Inode ino)
810 #if defined(AFS_NAMEI_ENV)
812 #if !defined(AFS_NT40_ENV)
815 char filename[MAX_PATH];
818 afs_fsize_t fileLength;
820 VNDISK_GET_LEN(fileLength, vnode);
821 Vvnodesize += fileLength;
822 if (dsizeOnly) return;
823 if (orphaned && (fileLength ==0 || vnode->parent || !offset)) return;
824 printf("%10d Vnode %u.%u.%u cloned: %d, length: %d linkCount: %d parent: %d",
825 offset, vnodeNumber, vnode->uniquifier, vnode->dataVersion, vnode->cloned, fileLength, vnode->linkCount, vnode->parent);
827 printf(" inode: %s", PrintInode(NULL, ino));
829 printf(" ServerModTime: %s", date(vnode->serverModifyTime));
830 #if defined(AFS_NAMEI_ENV)
832 IH_INIT(ihtmpp, V_device(vp), V_parentId(vp), ino);
833 #if !defined(AFS_NT40_ENV)
834 namei_HandleToName(&filename, ihtmpp);
835 printf(" UFS-Filename: %s",filename.n_path);
837 nt_HandleToName(filename, ihtmpp);
838 printf(" NTFS-Filename: %s",filename);