Avoid 'salvageserver -client -showlog' segfault
[openafs.git] / src / vol / vol-salvage.c
index 37a4057..e5daf80 100644 (file)
@@ -86,8 +86,6 @@ Vnodes with 0 inode pointers in RW volumes are now deleted.
 #include <afsconfig.h>
 #include <afs/param.h>
 
-RCSID
-    ("$Header$");
 
 #ifndef AFS_NT40_ENV
 #include <sys/param.h>
@@ -167,6 +165,7 @@ RCSID
 #include <afs/osi_inode.h>
 #endif
 #include <afs/cmd.h>
+#include <afs/dir.h>
 #include <afs/afsutil.h>
 #include <afs/fileutil.h>
 #include <afs/procmgmt.h>      /* signal(), kill(), wait(), etc. */
@@ -189,6 +188,8 @@ RCSID
 #include "salvage.h"
 #include "volinodes.h"         /* header magic number, etc. stuff */
 #include "vol-salvage.h"
+#include "vol_internal.h"
+
 #ifdef AFS_NT40_ENV
 #include <pthread.h>
 #endif
@@ -336,13 +337,13 @@ childJob_t myjob = { SALVAGER_MAGIC, NOT_CHILD, "" };
 void
 ObtainSalvageLock(void)
 {
-    int salvageLock;
+    FD_t salvageLock;
 
 #ifdef AFS_NT40_ENV
     salvageLock =
-       (int)CreateFile(AFSDIR_SERVER_SLVGLOCK_FILEPATH, 0, 0, NULL,
+       (FD_t)CreateFile(AFSDIR_SERVER_SLVGLOCK_FILEPATH, 0, 0, NULL,
                        OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
-    if (salvageLock == (int)INVALID_HANDLE_VALUE) {
+    if (salvageLock == INVALID_FD) {
        fprintf(stderr,
                "salvager:  There appears to be another salvager running!  Aborted.\n");
        Exit(1);
@@ -790,7 +791,7 @@ SalvageFileSys1(struct DiskPartition64 *partP, VolumeId singleVolumeNumber)
      * modified to actually do that so that the NT crt can be used there.
      */
     inodeFd =
-       _open_osfhandle((long)nt_open(inodeListPath, O_RDWR, 0), O_RDWR);
+       _open_osfhandle((intptr_t)nt_open(inodeListPath, O_RDWR, 0), O_RDWR);
     nt_unlink(inodeListPath);  /* NT's crt unlink won't if file is open. */
 #else
     inodeFd = afs_open(inodeListPath, O_RDONLY);
@@ -873,10 +874,16 @@ SalvageFileSys1(struct DiskPartition64 *partP, VolumeId singleVolumeNumber)
 void
 DeleteExtraVolumeHeaderFile(register struct VolumeSummary *vsp)
 {
+    char path[64];
+    sprintf(path, "%s/%s", fileSysPath, vsp->fileName);
+
     if (!Showmode)
-       Log("The volume header file %s is not associated with any actual data (%sdeleted)\n", vsp->fileName, (Testing ? "would have been " : ""));
-    if (!Testing)
-       unlink(vsp->fileName);
+       Log("The volume header file %s is not associated with any actual data (%sdeleted)\n", path, (Testing ? "would have been " : ""));
+    if (!Testing) {
+       if (unlink(path)) {
+           Log("Unable to unlink %s (errno = %d)\n", path, errno);
+       }
+    }
     vsp->fileName = 0;
 }
 
@@ -1262,9 +1269,12 @@ GetVolumeSummary(VolumeId singleVolumeNumber)
            if (error) {
                if (!singleVolumeNumber) {
                    if (!Showmode)
-                       Log("%s/%s is not a legitimate volume header file; %sdeleted\n", fileSysPathName, dp->d_name, (Testing ? "it would have been " : ""));
-                   if (!Testing)
-                       unlink(dp->d_name);
+                       Log("%s is not a legitimate volume header file; %sdeleted\n", name, (Testing ? "it would have been " : ""));
+                   if (!Testing) {
+                       if (unlink(name)) {
+                           Log("Unable to unlink %s (errno = %d)\n", name, errno);
+                       }
+                   }
                }
            } else {
                char nameShouldBe[64];
@@ -1293,15 +1303,18 @@ GetVolumeSummary(VolumeId singleVolumeNumber)
                    || (vsp->header.id == singleVolumeNumber
                        || vsp->header.parent == singleVolumeNumber)) {
                    (void)afs_snprintf(nameShouldBe, sizeof nameShouldBe,
-                                      VFORMAT, afs_cast_uint32(vsp->header.id));
+                                      VFORMAT, afs_printable_uint32_lu(vsp->header.id));
                    if (singleVolumeNumber 
                        && vsp->header.id != singleVolumeNumber)
                        AskOffline(vsp->header.id, fileSysPartition->name);
                    if (strcmp(nameShouldBe, dp->d_name)) {
                        if (!Showmode)
-                           Log("Volume header file %s is incorrectly named; %sdeleted (it will be recreated later, if necessary)\n", dp->d_name, (Testing ? "it would have been " : ""));
-                       if (!Testing)
-                           unlink(dp->d_name);
+                           Log("Volume header file %s is incorrectly named; %sdeleted (it will be recreated later, if necessary)\n", name, (Testing ? "it would have been " : ""));
+                       if (!Testing) {
+                           if (unlink(name)) {
+                               Log("Unable to unlink %s (errno = %d)\n", name, errno);
+                           }
+                       }
                    } else {
                        vsp->fileName = ToString(dp->d_name);
                        nVolumes++;
@@ -1744,7 +1757,7 @@ SalvageVolumeHeaderFile(register struct InodeSummary *isp,
     if (isp->volSummary == NULL) {
        char path[64];
        char headerName[64];
-       (void)afs_snprintf(headerName, sizeof headerName, VFORMAT, afs_cast_uint32(isp->volumeId));
+       (void)afs_snprintf(headerName, sizeof headerName, VFORMAT, afs_printable_uint32_lu(isp->volumeId));
        (void)afs_snprintf(path, sizeof path, "%s/%s", fileSysPath, headerName);
        if (check) {
            Log("No header file for volume %u\n", isp->volumeId);
@@ -1773,7 +1786,7 @@ SalvageVolumeHeaderFile(register struct InodeSummary *isp,
            if (isp->volSummary->fileName) {
                strcpy(headerName, isp->volSummary->fileName);
            } else {
-               (void)afs_snprintf(headerName, sizeof headerName, VFORMAT, afs_cast_uint32(isp->volumeId));
+               (void)afs_snprintf(headerName, sizeof headerName, VFORMAT, afs_printable_uint32_lu(isp->volumeId));
                isp->volSummary->fileName = ToString(headerName);
            }
            (void)afs_snprintf(path, sizeof path, "%s/%s", fileSysPath, headerName);
@@ -2414,9 +2427,10 @@ CopyAndSalvage(register struct DirSummary *dir)
 }
 
 int
-JudgeEntry(struct DirSummary *dir, char *name, VnodeId vnodeNumber,
-          Unique unique)
+JudgeEntry(void *dirVal, char *name, afs_int32 vnodeNumber,
+          afs_int32 unique)
 {
+    struct DirSummary *dir = (struct DirSummary *)dirVal;
     struct VnodeEssence *vnodeEssence;
     afs_int32 dirOrphaned, todelete;
 
@@ -2487,7 +2501,7 @@ JudgeEntry(struct DirSummary *dir, char *name, VnodeId vnodeNumber,
            Log("dir vnode %u: %s/%s (vnode %u): unique changed from %u to %u %s\n", dir->vnodeNumber, (dir->name ? dir->name : "??"), name, vnodeNumber, unique, vnodeEssence->unique, (!todelete ? "" : (Testing ? "-- would have deleted" : "-- deleted")));
        }
        if (!Testing) {
-           ViceFid fid;
+           AFSFid fid;
            fid.Vnode = vnodeNumber;
            fid.Unique = vnodeEssence->unique;
            CopyOnWrite(dir);
@@ -2501,7 +2515,7 @@ JudgeEntry(struct DirSummary *dir, char *name, VnodeId vnodeNumber,
 
     if (strcmp(name, ".") == 0) {
        if (dir->vnodeNumber != vnodeNumber || (dir->unique != unique)) {
-           ViceFid fid;
+           AFSFid fid;
            if (!Showmode)
                Log("directory vnode %u.%u: bad '.' entry (was %u.%u); fixed\n", dir->vnodeNumber, dir->unique, vnodeNumber, unique);
            if (!Testing) {
@@ -2518,7 +2532,7 @@ JudgeEntry(struct DirSummary *dir, char *name, VnodeId vnodeNumber,
        }
        dir->haveDot = 1;
     } else if (strcmp(name, "..") == 0) {
-       ViceFid pa;
+       AFSFid pa;
        if (dir->parent) {
            struct VnodeEssence *dotdot;
            pa.Vnode = dir->parent;
@@ -2714,8 +2728,16 @@ DistilVnodeEssence(VolumeId rwVId, VnodeClass class, Inode ino, Unique * maxu)
            vep->owner = vnode->owner;
            vep->group = vnode->group;
            if (vnode->type == vDirectory) {
-               assert(class == vLarge);
-               vip->inodes[vnodeIndex] = VNDISK_GET_INO(vnode);
+               if (class != vLarge) {
+                   VnodeId vnodeNumber = bitNumberToVnodeNumber(vnodeIndex, class);
+                   vip->nAllocatedVnodes--;
+                   memset(vnode, 0, sizeof(vnode));
+                   IH_IWRITE(vnodeInfo[vSmall].handle,
+                             vnodeIndexOffset(vcp, vnodeNumber),
+                             (char *)&vnode, sizeof(vnode));
+                   VolumeChanged = 1;
+               } else
+                   vip->inodes[vnodeIndex] = VNDISK_GET_INO(vnode);
            }
        }
     }
@@ -2869,7 +2891,7 @@ SalvageVolume(register struct InodeSummary *rwIsp, IHandle_t * alinkH)
     afs_int32 v, pv;
     IHandle_t *h;
     afs_sfsize_t nBytes;
-    ViceFid pa;
+    AFSFid pa;
     VnodeId LFVnode, ThisVnode;
     Unique LFUnique, ThisUnique;
     char npath[128];
@@ -2953,7 +2975,7 @@ SalvageVolume(register struct InodeSummary *rwIsp, IHandle_t * alinkH)
                 * won't be visible there.
                 */
                if (class == vLarge) {
-                   ViceFid pa;
+                   AFSFid pa;
                    DirHandle dh;
 
                    /* Remove and recreate the ".." entry in this orphaned directory */
@@ -3187,8 +3209,13 @@ MaybeZapVolume(register struct InodeSummary *isp, char *message, int deleteMe,
                if (!Showmode)
                    Log("it will be deleted instead.  It should be recloned.\n");
            }
-           if (!Testing)
-               unlink(isp->volSummary->fileName);
+           if (!Testing) {
+               char path[64];
+               sprintf(path, "%s/%s", fileSysPath, isp->volSummary->fileName);
+               if (unlink(path)) {
+                   Log("Unable to unlink %s (errno = %d)\n", path, errno);
+               }
+           }
        }
     } else if (!check) {
        Log("%s salvage was unsuccessful: read-write volume %u\n", message,
@@ -3235,6 +3262,61 @@ AskOffline(VolumeId volumeId, char * partition)
        Log("AskOffline:  request for fileserver to take volume offline failed; salvage aborting.\n");
        Abort("Salvage aborted\n");
     }
+
+#ifdef AFS_DEMAND_ATTACH_FS
+    /* set inUse = programType in the volume header. We do this in case
+     * the fileserver restarts/crashes while we are salvaging.
+     * Otherwise, the fileserver could attach the volume again on
+     * startup while we are salvaging, which would be very bad, or
+     * schedule another salvage while we are salvaging, which would be
+     * annoying. */
+    if (!Testing) {
+       int fd;
+       IHandle_t *h;
+       char name[VMAXPATHLEN];
+       struct VolumeHeader header;
+       struct VolumeDiskHeader diskHeader;
+       struct VolumeDiskData volHeader;
+
+       afs_snprintf(name, sizeof(name), "%s/" VFORMAT, fileSysPathName,
+           afs_printable_uint32_lu(volumeId));
+
+       fd = afs_open(name, O_RDONLY);
+       if (fd < 0) {
+           return;
+       }
+       if (read(fd, &diskHeader, sizeof(diskHeader)) != sizeof(diskHeader) ||
+           diskHeader.stamp.magic != VOLUMEHEADERMAGIC) {
+
+           close(fd);
+           return;
+       }
+       close(fd);
+
+       DiskToVolumeHeader(&header, &diskHeader);
+
+       IH_INIT(h, fileSysDevice, header.parent, header.volumeInfo);
+       if (IH_IREAD(h, 0, (char*)&volHeader, sizeof(volHeader)) != sizeof(volHeader) ||
+           volHeader.stamp.magic != VOLUMEINFOMAGIC) {
+
+           IH_RELEASE(h);
+           return;
+       }
+
+       volHeader.inUse = programType;
+
+       /* If we can't re-write the header, bail out and error. We don't
+        * assert when reading the header, since it's possible the
+        * header isn't really there (when there's no data associated
+        * with the volume; we just delete the vol header file in that
+        * case). But if it's there enough that we can read it, but
+        * somehow we cannot write to it to signify we're salvaging it,
+        * we've got a big problem and we cannot continue. */
+       assert(IH_IWRITE(h, 0, (char*)&volHeader, sizeof(volHeader)) == sizeof(volHeader));
+
+       IH_RELEASE(h);
+    }
+#endif /* AFS_DEMAND_ATTACH_FS */
 }
 
 void
@@ -3481,8 +3563,10 @@ showlog(void)
     }
 #endif
 
-    rewind(logFile);
-    fclose(logFile);
+    if (logFile) {
+       rewind(logFile);
+       fclose(logFile);
+    }
 
     logFile = afs_fopen(AFSDIR_SERVER_SLVGLOG_FILEPATH, "r");