volinfo: fix bad format string
[openafs.git] / src / vol / vol-info.c
index f0f3124..9e19390 100644 (file)
 
 #include <afs/cmd.h>
 #include <afs/dir.h>
-
-#include <rx/xdr.h>
 #include <afs/afsint.h>
-#include "nfs.h"
 #include <afs/errors.h>
+#include <opr/queue.h>
+
+#include "nfs.h"
 #include "lock.h"
-#include "lwp.h"
-#include <afs/afssyscalls.h>
 #include "ihandle.h"
 #include "vnode.h"
 #include "volume.h"
 #include "partition.h"
-#include "viceinode.h"
-#include <afs/afssyscalls.h>
-#include <afs/afsutil.h>
 
 #ifndef AFS_NT40_ENV
 #include "AFS_component_version_number.c"
@@ -66,8 +61,18 @@ typedef enum {
     P_FILENAMES
 } volinfo_parm_t;
 
+/* Vnode details for vnode handling procedures */
+struct VnodeDetails {
+    Volume *vp;
+    VnodeClass class;
+    VnodeDiskObject *vnode;
+    VnodeId vnodeNumber;
+    afs_foff_t offset;
+    int index;
+};
+
 /* Modes */
-static int DumpInfo = 1;            /**< Dump volume information, defualt mode*/
+static int DumpInfo = 0;            /**< Dump volume information */
 static int DumpHeader = 0;          /**< Dump volume header files info */
 static int DumpVnodes = 0;          /**< Dump vnode info */
 static int DumpInodeNumber = 0;     /**< Dump inode numbers with vnodes */
@@ -98,6 +103,16 @@ static struct sizeTotals partitionTotals = { 0, 0, 0, 0, 0, 0 };
 static struct sizeTotals serverTotals = { 0, 0, 0, 0, 0, 0 };
 static int PrintingVolumeSizes = 0;    /*print volume size lines */
 
+/**
+ * List of procedures to call when scanning vnodes.
+ */
+struct VnodeScanProc {
+    struct opr_queue link;
+    const char *heading;
+    void (*proc) (struct VnodeDetails * vdp);
+};
+static struct opr_queue VnodeScanLists[nVNODECLASSES];
+
 /* Forward Declarations */
 void PrintHeader(Volume * vp);
 void HandleAllPart(void);
@@ -106,9 +121,10 @@ void HandleVolume(struct DiskPartition64 *partP, char *name);
 struct DiskPartition64 *FindCurrentPartition(void);
 Volume *AttachVolume(struct DiskPartition64 *dp, char *volname,
                     struct VolumeHeader *header);
-void PrintVnode(afs_foff_t offset, VnodeDiskObject * vnode, VnodeId vnodeNumber,
-               Inode ino, Volume * vp);
 void HandleVnodes(Volume * vp, VnodeClass class);
+static void AddVnodeToSizeTotals(struct VnodeDetails *vdp);
+static void SaveInode(struct VnodeDetails *vdp);
+static void PrintVnode(struct VnodeDetails *vdp);
 
 /**
  * Format time as a timestamp string
@@ -170,6 +186,25 @@ NT_date(FILETIME * ft)
 #endif
 
 /**
+ * Add vnode size to the running volume totals.
+ *
+ * @param[in]  vdp   vnode details object
+ *
+ * @return none
+ */
+static void
+AddVnodeToSizeTotals(struct VnodeDetails *vdp)
+{
+    afs_fsize_t fileLength;
+
+    VNDISK_GET_LEN(fileLength, vdp->vnode);
+    if (fileLength > 0) {
+       volumeTotals.vnodesize += fileLength;
+       volumeTotals.vnodesize_k += fileLength / 1024;
+    }
+}
+
+/**
  * Print the volume size table heading line, if needed.
  *
  * @return none
@@ -300,11 +335,10 @@ ReadHdr1(IHandle_t * ih, char *to, int size, u_int magic, u_int version)
                    "%s: Write failed for inode %s; header left in damaged state\n",
                    progname, PrintInode(NULL, ih->ih_ino));
        }
-    } else {
-       if (DumpInfo) {
-           printf("Inode %s: Good magic %x and version %x\n",
-                  PrintInode(NULL, ih->ih_ino), magic, version);
-       }
+    }
+    if (!bad && DumpInfo) {
+       printf("Inode %s: Good magic %x and version %x\n",
+              PrintInode(NULL, ih->ih_ino), magic, version);
     }
     return 0;
 }
@@ -326,6 +360,10 @@ AttachVolume(struct DiskPartition64 * dp, char *volname,
     afs_int32 ec = 0;
 
     vp = (Volume *) calloc(1, sizeof(Volume));
+    if (!vp) {
+       fprintf(stderr, "%s: Failed to allocate volume object.\n", progname);
+       return NULL;
+    }
     vp->specialStatus = 0;
     vp->device = dp->device;
     vp->partition = dp;
@@ -341,6 +379,11 @@ AttachVolume(struct DiskPartition64 * dp, char *volname,
     vp->goingOffline = 0;
     vp->nUsers = 1;
     vp->header = (struct volHeader *)calloc(1, sizeof(*vp->header));
+    if (!vp->header) {
+       fprintf(stderr, "%s: Failed to allocate volume header.\n", progname);
+       free(vp);
+       return NULL;
+    }
     ec = ReadHdr1(V_diskDataHandle(vp), (char *)&V_disk(vp),
                  sizeof(V_disk(vp)), VOLUMEINFOMAGIC, VOLUMEINFOVERSION);
     if (!ec) {
@@ -366,6 +409,24 @@ AttachVolume(struct DiskPartition64 * dp, char *volname,
 }
 
 /**
+ * Simplified detach volume
+ *
+ * param[in] vp       volume object from AttachVolume
+ *
+ * @return none
+ */
+static void
+DetachVolume(Volume * vp)
+{
+    IH_RELEASE(vp->vnodeIndex[vLarge].handle);
+    IH_RELEASE(vp->vnodeIndex[vSmall].handle);
+    IH_RELEASE(vp->diskDataHandle);
+    IH_RELEASE(V_linkHandle(vp));
+    free(vp->header);
+    free(vp);
+}
+
+/**
  * Convert the partition device number into a partition name.
  *
  * @param[in]   partId      partition number, 0 to 254
@@ -406,24 +467,27 @@ GetPartitionName(afs_uint32 partId, char *partName, afs_size_t partNameSize)
 }
 
 /**
- * Process command line options and start scanning
+ * Scan the volumes in the partitions
  *
- * @param[in] as     command syntax object
- * @param[in] arock  opaque object; not used
+ * Scan the specified volume in the specified partition if both
+ * are given. Scan all the volumes in the specified partition if
+ * only the partition is given.  If neither a partition nor volume
+ * is given, scan all the volumes in all the partitions.  If only
+ * the volume is given, attempt to find it in the current working
+ * directory.
  *
- * @return error code
+ * @param[in] partNameOrId   partition name or id to be scannned
+ * @param[in] volumeId       volume id to be scanned
+ *
+ * @return 0 if successful
  */
 static int
-handleit(struct cmd_syndesc *as, void *arock)
+ScanPartitions(char *partNameOrId, afs_uint32 volumeId)
 {
-    struct cmd_item *ti;
     int err = 0;
-    afs_uint32 volumeId = 0;
-    char *partNameOrId = 0;
     char partName[64] = "";
     struct DiskPartition64 *partP = NULL;
 
-
 #ifndef AFS_NT40_ENV
     if (geteuid() != 0) {
        fprintf(stderr, "%s: Must be run as root; sorry\n", progname);
@@ -431,6 +495,103 @@ handleit(struct cmd_syndesc *as, void *arock)
     }
 #endif
 
+    DInit(10);
+
+    /* Allow user to specify partition by name or id. */
+    if (partNameOrId) {
+       afs_uint32 partId = volutil_GetPartitionID(partNameOrId);
+       if (partId == -1) {
+           fprintf(stderr, "%s: Could not parse '%s' as a partition name.\n",
+                   progname, partNameOrId);
+           return 1;
+       }
+       if (GetPartitionName(partId, partName, sizeof(partName))) {
+           fprintf(stderr,
+                   "%s: Could not format '%s' as a partition name.\n",
+                   progname, partNameOrId);
+           return 1;
+       }
+    }
+
+    err = VAttachPartitions();
+    if (err) {
+       fprintf(stderr, "%s: %d partitions had errors during attach.\n",
+               progname, err);
+       return 1;
+    }
+
+    if (partName[0]) {
+       partP = VGetPartition(partName, 0);
+       if (!partP) {
+           fprintf(stderr,
+                   "%s: %s is not an AFS partition name on this server.\n",
+                   progname, partName);
+           return 1;
+       }
+    }
+
+    if (!volumeId) {
+       if (!partP) {
+           HandleAllPart();
+       } else {
+           HandlePart(partP);
+       }
+    } else {
+       char name1[128];
+
+       if (!partP) {
+           partP = FindCurrentPartition();
+           if (!partP) {
+               fprintf(stderr,
+                       "%s: Current partition is not a vice partition.\n",
+                       progname);
+               return 1;
+           }
+       }
+       snprintf(name1, sizeof name1, VFORMAT,
+                afs_printable_uint32_lu(volumeId));
+       HandleVolume(partP, name1);
+    }
+
+    return 0;
+}
+
+/**
+ * Add a vnode scanning procedure
+ *
+ * @param[in]   class   vnode class for this handler
+ * @param[in]   proc    handler proc to be called by HandleVnodes
+ * @param[in]   heading optional string to pring before scanning vnodes
+ *
+ * @return none
+ */
+static void
+AddVnodeHandler(VnodeClass class, void (*proc) (struct VnodeDetails * vdp),
+               const char *heading)
+{
+    struct VnodeScanProc *entry = malloc(sizeof(struct VnodeScanProc));
+    entry->proc = proc;
+    entry->heading = heading;
+    opr_queue_Append(&VnodeScanLists[class], (struct opr_queue *)entry);
+}
+
+/**
+ * Process command line options and start scanning
+ *
+ * @param[in] as     command syntax object
+ * @param[in] arock  opaque object; not used
+ *
+ * @return error code
+ */
+static int
+handleit(struct cmd_syndesc *as, void *arock)
+{
+    struct cmd_item *ti;
+    afs_uint32 volumeId = 0;
+    char *partNameOrId = NULL;
+
+    DumpInfo = 1;              /* volinfo default mode */
+
     if (as->parms[P_ONLINE].items) {
        fprintf(stderr, "%s: -online not supported\n", progname);
        return 1;
@@ -491,63 +652,21 @@ handleit(struct cmd_syndesc *as, void *arock)
 #endif
     }
 
-    /* Allow user to specify partition by name or id. */
-    if (partNameOrId) {
-       afs_uint32 partId = volutil_GetPartitionID(partNameOrId);
-       if (partId == -1) {
-           fprintf(stderr, "%s: Could not parse '%s' as a partition name.\n",
-                   progname, partNameOrId);
-           return 1;
-       }
-       if (GetPartitionName(partId, partName, sizeof(partName))) {
-           fprintf(stderr,
-                   "%s: Could not format '%s' as a partition name.\n",
-                   progname, partNameOrId);
-           return 1;
-       }
+    if (SaveInodes) {
+       AddVnodeHandler(vSmall, SaveInode,
+                       "Saving all volume files to current directory ...\n");
     }
-
-    DInit(10);
-
-    err = VAttachPartitions();
-    if (err) {
-       fprintf(stderr, "%s: %d partitions had errors during attach.\n",
-               progname, err);
+    if (ShowSizes) {
+       AddVnodeHandler(vLarge, AddVnodeToSizeTotals, NULL);
+       AddVnodeHandler(vSmall, AddVnodeToSizeTotals, NULL);
     }
-
-    if (partName[0]) {
-       partP = VGetPartition(partName, 0);
-       if (!partP) {
-           fprintf(stderr,
-                   "%s: %s is not an AFS partition name on this server.\n",
-                   progname, partName);
-           return 1;
-       }
+    if (DumpVnodes) {
+       AddVnodeHandler(vLarge, PrintVnode, "\nLarge vnodes (directories)\n");
+       AddVnodeHandler(vSmall, PrintVnode,
+                       "\nSmall vnodes(files, symbolic links)\n");
     }
 
-    if (!volumeId) {
-       if (!partP) {
-           HandleAllPart();
-       } else {
-           HandlePart(partP);
-       }
-    } else {
-       char name1[128];
-
-       if (!partP) {
-           partP = FindCurrentPartition();
-           if (!partP) {
-               fprintf(stderr,
-                       "%s: Current partition is not a vice partition.\n",
-                       progname);
-               return 1;
-           }
-       }
-       snprintf(name1, sizeof name1, VFORMAT,
-                afs_printable_uint32_lu(volumeId));
-       HandleVolume(partP, name1);
-    }
-    return 0;
+    return ScanPartitions(partNameOrId, volumeId);
 }
 
 /**
@@ -617,7 +736,9 @@ HandleAllPart(void)
 
 
     for (partP = DiskPartitionList; partP; partP = partP->next) {
-       printf("Processing Partition %s:\n", partP->name);
+       if (DumpInfo || SaveInodes || ShowSizes) {
+           printf("Processing Partition %s:\n", partP->name);
+       }
        HandlePart(partP);
        if (ShowSizes) {
            AddSizeTotals(&serverTotals, &partitionTotals);
@@ -790,7 +911,7 @@ HandleVolume(struct DiskPartition64 *dp, char *name)
     struct VolumeHeader header;
     struct VolumeDiskHeader diskHeader;
     FD_t fd = INVALID_FD;
-    Volume *vp;
+    Volume *vp = NULL;
     char headerName[1024];
     afs_sfsize_t n;
 
@@ -798,58 +919,63 @@ HandleVolume(struct DiskPartition64 *dp, char *name)
             VPartitionPath(dp), name);
     if ((fd = OS_OPEN(headerName, O_RDONLY, 0666)) == INVALID_FD) {
        fprintf(stderr, "%s: Cannot open volume header %s\n", progname, name);
-       return;
+       goto cleanup;
     }
     if (OS_SIZE(fd) < 0) {
        fprintf(stderr, "%s: Cannot read volume header %s\n", progname, name);
-       OS_CLOSE(fd);
-       return;
+       goto cleanup;
     }
     n = OS_READ(fd, &diskHeader, sizeof(diskHeader));
     if (n != sizeof(diskHeader)
        || diskHeader.stamp.magic != VOLUMEHEADERMAGIC) {
        fprintf(stderr, "%s: Error reading volume header %s\n", progname,
                name);
-       OS_CLOSE(fd);
-       return;
+       goto cleanup;
     }
     if (diskHeader.stamp.version != VOLUMEHEADERVERSION) {
        fprintf(stderr,
                "%s: Volume %s, version number is incorrect; volume needs to be salvaged\n",
                progname, name);
-       OS_CLOSE(fd);
-       return;
+       goto cleanup;
     }
+
     DiskToVolumeHeader(&header, &diskHeader);
     if (DumpHeader || ShowSizes) {
        HandleHeaderFiles(dp, fd, &header);
     }
-    OS_CLOSE(fd);
+
     vp = AttachVolume(dp, name, &header);
     if (!vp) {
        fprintf(stderr, "%s: Error attaching volume header %s\n",
                progname, name);
-       return;
+       goto cleanup;
     }
+
     if (DumpInfo) {
        PrintHeader(vp);
     }
-    if (DumpVnodes || ShowSizes || ShowOrphaned) {
-       HandleVnodes(vp, vLarge);
-    }
-    if (DumpVnodes || ShowSizes || SaveInodes || ShowOrphaned) {
-       HandleVnodes(vp, vSmall);
-    }
+
+    HandleVnodes(vp, vLarge);
+    HandleVnodes(vp, vSmall);
+
     if (ShowSizes) {
        volumeTotals.diskused_k = V_diskused(vp);
        volumeTotals.size_k =
            volumeTotals.auxsize_k + volumeTotals.vnodesize_k;
+       if (SaveInodes) {
+           PrintingVolumeSizes = 0;    /* print heading again */
+       }
        PrintVolumeSizes(vp);
     }
-    free(vp->header);
-    free(vp);
-}
 
+  cleanup:
+    if (fd != INVALID_FD) {
+       OS_CLOSE(fd);
+    }
+    if (vp) {
+       DetachVolume(vp);
+    }
+}
 
 /**
  * volinfo program entry
@@ -860,6 +986,9 @@ main(int argc, char **argv)
     struct cmd_syndesc *ts;
     afs_int32 code;
 
+    opr_queue_Init(&VnodeScanLists[vLarge]);
+    opr_queue_Init(&VnodeScanLists[vSmall]);
+
     ts = cmd_CreateSyntax(NULL, handleit, NULL,
                          "Dump volume's internal state");
     cmd_AddParmAtOffset(ts, P_ONLINE, "-online", CMD_FLAG, CMD_OPTIONAL,
@@ -898,7 +1027,21 @@ main(int argc, char **argv)
     return code;
 }
 
-#define typestring(type) (type == RWVOL? "read/write": type == ROVOL? "readonly": type == BACKVOL? "backup": "unknown")
+/**
+ * Return a display string for the volume type.
+ *
+ * @param[in]  type  volume type
+ *
+ * @return volume type description string
+ */
+static_inline char *
+volumeTypeString(int type)
+{
+    return
+       (type == RWVOL ? "read/write" :
+        (type == ROVOL ? "readonly" :
+         (type == BACKVOL ? "backup" : "unknown")));
+}
 
 /**
  * Print the volume header information
@@ -919,7 +1062,7 @@ PrintHeader(Volume * vp)
         V_dontSalvage(vp));
     printf
        ("type = %d (%s), uniquifier = %u, needsCallback = %d, destroyMe = %x\n",
-        V_type(vp), typestring(V_type(vp)), V_uniquifier(vp),
+        V_type(vp), volumeTypeString(V_type(vp)), V_uniquifier(vp),
         V_needsCallback(vp), V_destroyMe(vp));
     printf
        ("id = %u, parentId = %u, cloneId = %u, backupId = %u, restoredFromId = %u\n",
@@ -994,14 +1137,12 @@ GetFileInfo(FD_t fd, afs_sfsize_t * size, char **ctime, char **mtime,
 /**
  * Copy the inode data to a file in the current directory.
  *
- * @param[in] vp     volume object
- * @param[in] vnode  vnode object
- * @param[in] inode  inode of the source file
+ * @param[in] vdp     vnode details object
  *
  * @return none
  */
 static void
-SaveInode(Volume * vp, struct VnodeDiskObject *vnode, Inode ino)
+SaveInode(struct VnodeDetails *vdp)
 {
     IHandle_t *ih;
     FdHandle_t *fdP;
@@ -1009,12 +1150,13 @@ SaveInode(Volume * vp, struct VnodeDiskObject *vnode, Inode ino)
     int ofd = 0;
     afs_foff_t total;
     ssize_t len;
+    Inode ino = VNDISK_GET_INO(vdp->vnode);
 
     if (!VALID_INO(ino)) {
-        return;
+       return;
     }
 
-    IH_INIT(ih, V_device(vp), V_parentId(vp), ino);
+    IH_INIT(ih, V_device(vdp->vp), V_parentId(vdp->vp), ino);
     fdP = IH_OPEN(ih);
     if (fdP == NULL) {
        fprintf(stderr,
@@ -1089,27 +1231,21 @@ HandleVnodes(Volume * vp, VnodeClass class)
     int vnodeIndex;
     afs_sfsize_t nVnodes;
     afs_foff_t offset = 0;
-    Inode ino;
     IHandle_t *ih = vp->vnodeIndex[class].handle;
     FdHandle_t *fdP = NULL;
     afs_sfsize_t size;
     char *ctime, *atime, *mtime;
+    struct opr_queue *scanList = &VnodeScanLists[class];
+    struct opr_queue *cursor;
 
-    /* print vnode table heading */
-    if (class == vLarge) {
-       if (DumpInfo) {
-           printf("\nLarge vnodes (directories)\n");
-       }
-    } else {
-       if (DumpInfo) {
-           printf("\nSmall vnodes(files, symbolic links)\n");
-           fflush(stdout);
-       }
-       if (SaveInodes) {
-           printf("Saving all volume files to current directory ...\n");
-           if (ShowSizes) {
-               PrintingVolumeSizes = 0;        /* print heading again */
-           }
+    if (opr_queue_IsEmpty(scanList)) {
+       return;
+    }
+
+    for (opr_queue_Scan(scanList, cursor)) {
+       struct VnodeScanProc *entry = (struct VnodeScanProc *)cursor;
+       if (entry->heading) {
+           printf("%s", entry->heading);
        }
     }
 
@@ -1143,23 +1279,21 @@ HandleVnodes(Volume * vp, VnodeClass class)
         nVnodes && STREAM_READ(vnode, diskSize, 1, file) == 1;
         nVnodes--, vnodeIndex++, offset += diskSize) {
 
-       ino = VNDISK_GET_INO(vnode);
-       if (ShowSizes) {
-           afs_fsize_t fileLength;
+       struct VnodeDetails vnodeDetails;
+
+       vnodeDetails.vp = vp;
+       vnodeDetails.class = class;
+       vnodeDetails.vnode = vnode;
+       vnodeDetails.vnodeNumber = bitNumberToVnodeNumber(vnodeIndex, class);
+       vnodeDetails.offset = offset;
+       vnodeDetails.index = vnodeIndex;
 
-           VNDISK_GET_LEN(fileLength, vnode);
-           if (fileLength > 0) {
-               volumeTotals.vnodesize += fileLength;
-               volumeTotals.vnodesize_k += fileLength / 1024;
+       for (opr_queue_Scan(scanList, cursor)) {
+           struct VnodeScanProc *entry = (struct VnodeScanProc *)cursor;
+           if (entry->proc) {
+               (*entry->proc) (&vnodeDetails);
            }
        }
-       if (SaveInodes && (class == vSmall)) {
-           SaveInode(vp, vnode, ino);
-       }
-       if (DumpVnodes || ShowOrphaned) {
-           PrintVnode(offset, vnode,
-                      bitNumberToVnodeNumber(vnodeIndex, class), ino, vp);
-       }
     }
 
   error:
@@ -1174,24 +1308,23 @@ HandleVnodes(Volume * vp, VnodeClass class)
 /**
  * Print vnode information
  *
- * @param[in] offset       index offset of this vnode
- * @param[in] vnode        vnode object to be printed
- * @param[in] vnodeNumber  vnode number
- * @param[in] ino          fileserver inode number
- * @param[in] vp           parent volume of the vnode
+ * @param[in] vdp          vnode details object
  *
  * @return none
  */
 void
-PrintVnode(afs_foff_t offset, VnodeDiskObject * vnode, VnodeId vnodeNumber,
-          Inode ino, Volume * vp)
+PrintVnode(struct VnodeDetails *vdp)
 {
 #if defined(AFS_NAMEI_ENV)
     IHandle_t *ihtmpp;
     namei_t filename;
 #endif
+    afs_foff_t offset = vdp->offset;
+    VnodeDiskObject *vnode = vdp->vnode;
     afs_fsize_t fileLength;
+    Inode ino;
 
+    ino = VNDISK_GET_INO(vnode);
     VNDISK_GET_LEN(fileLength, vnode);
 
     /* The check for orphaned vnodes is currently limited to non-empty
@@ -1202,16 +1335,16 @@ PrintVnode(afs_foff_t offset, VnodeDiskObject * vnode, VnodeId vnodeNumber,
 
     printf
        ("%10lld Vnode %u.%u.%u cloned: %u, length: %llu linkCount: %d parent: %u",
-        (long long)offset, vnodeNumber, vnode->uniquifier, vnode->dataVersion,
-        vnode->cloned, (afs_uintmax_t) fileLength, vnode->linkCount,
-        vnode->parent);
+        (long long)offset, vdp->vnodeNumber, vnode->uniquifier,
+        vnode->dataVersion, vnode->cloned, (afs_uintmax_t) fileLength,
+        vnode->linkCount, vnode->parent);
     if (DumpInodeNumber)
        printf(" inode: %s", PrintInode(NULL, ino));
     if (DumpDate)
        printf(" ServerModTime: %s", date(vnode->serverModifyTime));
 #if defined(AFS_NAMEI_ENV)
     if (PrintFileNames) {
-       IH_INIT(ihtmpp, V_device(vp), V_parentId(vp), ino);
+       IH_INIT(ihtmpp, V_device(vdp->vp), V_parentId(vdp->vp), ino);
        namei_HandleToName(&filename, ihtmpp);
 #if !defined(AFS_NT40_ENV)
        printf(" UFS-Filename: %s", filename.n_path);