vol: remove empty directories left by vos zap -force
[openafs.git] / src / vol / nuke.c
index bd8687d..6b35db8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
 #include <afsconfig.h>
 #include <afs/param.h>
 
-RCSID
-    ("$Header$");
+#include <roken.h>
 
-#include <rx/xdr.h>
+#include <afs/opr.h>
 #include <afs/afsint.h>
-#include <stdio.h>
-#ifdef AFS_PTHREAD_ENV
-#include <assert.h>
-#else /* AFS_PTHREAD_ENV */
-#include <afs/assert.h>
-#endif /* AFS_PTHREAD_ENV */
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#if defined(AFS_SUN5_ENV) || defined(AFS_NT40_ENV)
-#include <string.h>
-#else
-#include <strings.h>
-#endif
+#include <rx/rx_queue.h>
+
+#include <afs/afsutil.h>
 
-#include <afs/assert.h>
 #include "nfs.h"
 #include "lwp.h"
 #include "lock.h"
@@ -41,19 +28,11 @@ RCSID
 #include "partition.h"
 #include "viceinode.h"
 #include "salvage.h"
+#include "daemon_com.h"
 #include "fssync.h"
-
-#ifdef O_LARGEFILE
-#define afs_stat       stat64
-#else /* !O_LARGEFILE */
-#define afs_stat       stat
-#endif /* !O_LARGEFILE */
-
-/*@printflike@*/ extern void Log(const char *format, ...);
-
+#include "common.h"
 
 struct Lock localLock;
-char *vol_DevName();
 
 #define MAXATONCE      100
 /* structure containing neatly packed set of inodes and the # of times we'll have
@@ -65,33 +44,45 @@ struct ilist {
     afs_int32 freePtr;         /* first free index in this table */
     Inode inode[MAXATONCE];    /* inode # */
     afs_int32 count[MAXATONCE];        /* link count */
-} *allInodes = 0;
+};
 
 /* called with a structure specifying info about the inode, and our rock (which
  * is the volume ID.  Returns true if we should keep this inode, otherwise false.
- * Note that ainfo->u.param[0] is always the volume ID, for any vice inode.
  */
 static int
-NukeProc(struct ViceInodeInfo *ainfo, afs_int32 avolid)
+NukeProc(struct ViceInodeInfo *ainfo, VolumeId avolid, void *arock)
 {
+    struct ilist **allInodes = (struct ilist **)arock;
     struct ilist *ti;
-    register afs_int32 i;
+    afs_int32 i;
 
 #ifndef AFS_PTHREAD_ENV
     IOMGR_Poll();              /* poll so we don't kill the RPC connection */
 #endif /* !AFS_PTHREAD_ENV */
 
     /* check if this is the volume we're looking for */
-    if (ainfo->u.param[0] != avolid)
-       return 0;               /* don't want this one */
+    if (ainfo->u.vnode.vnodeNumber == INODESPECIAL) {
+       /* For special inodes, look at both the volume id and the parent id.
+        * If we were given an RW vol id to nuke, we should delete the special
+        * inodes for all volumes in the VG, since we're deleting all of the
+        * regular inodes, too. If we don't do this, on namei would be
+        * impossible to nuke the special inodes for a non-RW volume. */
+       if (ainfo->u.special.volumeId != avolid && ainfo->u.special.parentId != avolid) {
+           return 0;
+       }
+    } else {
+       if (ainfo->u.vnode.volumeId != avolid) {
+           return 0;           /* don't want this one */
+       }
+    }
+
     /* record the info */
-    if (!allInodes || allInodes->freePtr >= MAXATONCE) {
-       ti = (struct ilist *)malloc(sizeof(struct ilist));
-       memset(ti, 0, sizeof(*ti));
-       ti->next = allInodes;
-       allInodes = ti;
+    if (!*allInodes || (*allInodes)->freePtr >= MAXATONCE) {
+       ti = calloc(1, sizeof(struct ilist));
+       ti->next = *allInodes;
+       *allInodes = ti;
     } else
-       ti = allInodes;         /* use the one with space */
+       ti = *allInodes;                /* use the one with space */
     i = ti->freePtr++;         /* find our slot in this mess */
     ti->inode[i] = ainfo->inodeNumber;
     ti->count[i] = ainfo->linkCount;
@@ -109,30 +100,35 @@ NukeProc(struct ViceInodeInfo *ainfo, afs_int32 avolid)
  * indices will be gone.
  */
 int
-nuke(char *aname, afs_int32 avolid)
+nuke(char *aname, VolumeId avolid)
 {
     /* first process the partition containing this junk */
-    struct afs_stat tstat;
-    struct ilist *ti, *ni;
-    register afs_int32 code;
+    struct afs_stat_st tstat;
+    struct ilist *ti, *ni, *li=NULL;
+    afs_int32 code;
     int i, forceSal;
-    char devName[64], wpath[100];
+    char wpath[100];
     char *lastDevComp;
+    struct DiskPartition64 *dp;
 #ifdef AFS_NAMEI_ENV
-#ifdef AFS_NT40_ENV
-    char path[MAX_PATH];
-#else
     char *path;
+
     namei_t ufs_name;
-#endif
 #endif /* AFS_NAMEI_ENV */
+#ifndef AFS_NAMEI_ENV
+    char devName[64];
+#endif /* !AFS_NAMEI_ENV */
     IHandle_t *fileH;
+    struct ilist *allInodes = 0;
 
     if (avolid == 0)
        return EINVAL;
     code = afs_stat(aname, &tstat);
-    if (code) {
+    if (code || (dp = VGetPartition(aname, 0)) == NULL) {
        printf("volnuke: partition %s does not exist.\n", aname);
+       if (!code) {
+           code = EINVAL;
+       }
        return code;
     }
     /* get the device name for the partition */
@@ -144,15 +140,15 @@ nuke(char *aname, afs_int32 avolid)
     *lastDevComp = toupper(*lastDevComp);
 #else
     {
-    char *tfile = vol_DevName(tstat.st_dev, wpath);
-    if (!tfile) {
-       printf("volnuke: can't find %s's device.\n", aname);
-       return 1;
-    }
-    strcpy(devName, tfile);    /* save this from the static buffer */
+       char *tfile = vol_DevName(tstat.st_dev, wpath);
+       if (!tfile) {
+           printf("volnuke: can't find %s's device.\n", aname);
+           return 1;
+       }
+       strcpy(devName, tfile); /* save this from the static buffer */
     }
     /* aim lastDevComp at the 'foo' of '/dev/foo' */
-    lastDevComp = strrchr(devName, '/');
+    lastDevComp = strrchr(devName, OS_DIRSEPC);
     /* either points at slash, or there is no slash; adjust appropriately */
     if (lastDevComp)
        lastDevComp++;
@@ -166,16 +162,9 @@ nuke(char *aname, afs_int32 avolid)
      * all we need to do to call ListViceInodes is find the inodes for the
      * volume we're nuking.
      */
-#ifdef AFS_NAMEI_ENV
     code =
-       ListViceInodes(lastDevComp, aname, NULL, NukeProc, avolid, &forceSal,
-                      0, wpath);
-#else
-    code =
-       ListViceInodes(lastDevComp, aname, "/tmp/vNukeXX", NukeProc, avolid,
-                      &forceSal, 0, wpath);
-    unlink("/tmp/vNukeXX");    /* clean it up now */
-#endif
+       ListViceInodes(lastDevComp, aname, INVALID_FD, NukeProc, avolid, &forceSal,
+                      0, wpath, &allInodes);
     if (code == 0) {
        /* actually do the idecs now */
        for (ti = allInodes; ti; ti = ti->next) {
@@ -188,56 +177,55 @@ nuke(char *aname, afs_int32 avolid)
 #ifdef AFS_NT40_ENV
                IH_INIT(fileH, (int)(*lastDevComp - 'A'), avolid,
                        ti->inode[i]);
-               nt_HandleToName(path, fileH);
 #else
                IH_INIT(fileH, (int)volutil_GetPartitionID(aname), avolid,
                        ti->inode[i]);
+#endif /* AFS_NT40_ENV */
                namei_HandleToName(&ufs_name, fileH);
                path = ufs_name.n_path;
-#endif /* AFS_NT40_ENV */
                IH_RELEASE(fileH);
-               if (unlink(path) < 0) {
+               if (OS_UNLINK(path) < 0) {
                    Log("Nuke: Failed to remove %s\n", path);
                }
 #else /* AFS_NAMEI_ENV */
                IH_INIT(fileH, (int)tstat.st_dev, avolid, ti->inode[i]);
-        {
-        int j;
-        for (j = 0; j < ti->count[i]; j++) {
-                  code = IH_DEC(fileH, ti->inode[i], avolid);
-        }
-        }
+               {
+                   int j;
+                   for (j = 0; j < ti->count[i]; j++) {
+                       code = IH_DEC(fileH, ti->inode[i], avolid);
+                   }
+               }
                IH_RELEASE(fileH);
 #endif /* AFS_NAMEI_ENV */
            }
-           ni = ti->next;
-           free(ti);
+           if (li) free(li);
+           li = ti;
        }
-       code = 0;               /* we really don't care about it except for debugging */
+       if (li) free(li);
+
        allInodes = NULL;
 
+#ifdef AFS_NAMEI_ENV
+       if (namei_RemoveDirectories(aname, avolid)) {
+           Log("Nuke: Could not remove some empty directories associated with "
+               "volume %u\n", avolid);
+       }
+#endif
+
        /* at this point, we should try to remove the volume header file itself.
         * the volume header file is the file named VNNNNN.vol in the UFS file
         * system, and is a normal file.  As such, it is not stamped with the
         * volume's ID in its inode, and has to be removed explicitly.
         */
-       /* reuse devName buffer now */
-#ifdef AFS_NT40_ENV
-       afs_snprintf(devName, sizeof devName, "%c:\\%s", *lastDevComp,
-                    VolumeExternalName(avolid));
-#else
-       afs_snprintf(devName, sizeof devName, "%s/%s", aname,
-                    VolumeExternalName(avolid));
-#endif /* AFS_NT40_ENV */
-       code = unlink(devName);
-       if (code)
-           code = errno;
+       code = VDestroyVolumeDiskHeader(dp, avolid, 0);
     } else {
        /* just free things */
        for (ti = allInodes; ti; ti = ni) {
            ni = ti->next;
-           free(ti);
+           if (li) free(li);
+           li = ti;
        }
+       if (li) free(li);
        allInodes = NULL;
     }
     ReleaseWriteLock(&localLock);