merge ntops and namei
[openafs.git] / src / vol / nuke.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
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
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13
14 #include <rx/xdr.h>
15 #include <afs/afsint.h>
16 #include <stdio.h>
17 #include <afs/afs_assert.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <errno.h>
21 #if defined(AFS_SUN5_ENV) || defined(AFS_NT40_ENV)
22 #include <string.h>
23 #else
24 #include <strings.h>
25 #endif
26 #ifndef AFS_NT40_ENV
27 #include <unistd.h>
28 #endif
29
30 #include <afs/afsutil.h>
31
32 #include "nfs.h"
33 #include "lwp.h"
34 #include "lock.h"
35 #include <afs/afssyscalls.h>
36 #include "ihandle.h"
37 #include "vnode.h"
38 #include "volume.h"
39 #include "partition.h"
40 #include "viceinode.h"
41 #include "salvage.h"
42 #include "daemon_com.h"
43 #include "fssync.h"
44 #include "common.h"
45
46 #ifdef O_LARGEFILE
47 #define afs_stat        stat64
48 #else /* !O_LARGEFILE */
49 #define afs_stat        stat
50 #endif /* !O_LARGEFILE */
51
52 struct Lock localLock;
53
54 #define MAXATONCE       100
55 /* structure containing neatly packed set of inodes and the # of times we'll have
56  * to idec them in order to reclaim their storage.  NukeProc, called by ListViceInodes,
57  * builds this list for us.
58  */
59 struct ilist {
60     struct ilist *next;
61     afs_int32 freePtr;          /* first free index in this table */
62     Inode inode[MAXATONCE];     /* inode # */
63     afs_int32 count[MAXATONCE]; /* link count */
64 };
65
66 /* called with a structure specifying info about the inode, and our rock (which
67  * is the volume ID.  Returns true if we should keep this inode, otherwise false.
68  * Note that ainfo->u.param[0] is always the volume ID, for any vice inode.
69  */
70 static int
71 NukeProc(struct ViceInodeInfo *ainfo, afs_uint32 avolid, void *arock)
72 {
73     struct ilist **allInodes = (struct ilist **)arock;
74     struct ilist *ti;
75     afs_int32 i;
76
77 #ifndef AFS_PTHREAD_ENV
78     IOMGR_Poll();               /* poll so we don't kill the RPC connection */
79 #endif /* !AFS_PTHREAD_ENV */
80
81     /* check if this is the volume we're looking for */
82     if (ainfo->u.param[0] != avolid)
83         return 0;               /* don't want this one */
84     /* record the info */
85     if (!*allInodes || (*allInodes)->freePtr >= MAXATONCE) {
86         ti = (struct ilist *)malloc(sizeof(struct ilist));
87         memset(ti, 0, sizeof(*ti));
88         ti->next = *allInodes;
89         *allInodes = ti;
90     } else
91         ti = *allInodes;                /* use the one with space */
92     i = ti->freePtr++;          /* find our slot in this mess */
93     ti->inode[i] = ainfo->inodeNumber;
94     ti->count[i] = ainfo->linkCount;
95     return 0;                   /* don't care if anything's written out, actually */
96 }
97
98 /* function called with partition name and volid ID, and which removes all
99  * inodes marked with the specified volume ID.  If the volume is a read-only
100  * clone, we'll only remove the header inodes, since they're the only inodes
101  * marked with that volume ID.  If you want to reclaim all the data, you should
102  * nuke the read-write volume ID.
103  *
104  * Note also that nuking a read-write volume effectively nukes all RO volumes
105  * cloned from that RW volume ID, too, since everything except for their
106  * indices will be gone.
107  */
108 int
109 nuke(char *aname, afs_int32 avolid)
110 {
111     /* first process the partition containing this junk */
112     struct afs_stat tstat;
113     struct ilist *ti, *ni, *li=NULL;
114     afs_int32 code;
115     int i, forceSal;
116     char wpath[100];
117     char *lastDevComp;
118     struct DiskPartition64 *dp;
119 #ifdef AFS_NAMEI_ENV
120     char *path;
121
122     namei_t ufs_name;
123 #endif /* AFS_NAMEI_ENV */
124 #ifndef AFS_NAMEI_ENV
125     char devName[64];
126 #endif /* !AFS_NAMEI_ENV */
127     IHandle_t *fileH;
128     struct ilist *allInodes = 0;
129
130     if (avolid == 0)
131         return EINVAL;
132     code = afs_stat(aname, &tstat);
133     if (code || (dp = VGetPartition(aname, 0)) == NULL) {
134         printf("volnuke: partition %s does not exist.\n", aname);
135         if (!code) {
136             code = EINVAL;
137         }
138         return code;
139     }
140     /* get the device name for the partition */
141 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
142     lastDevComp = aname;
143 #else
144 #ifdef AFS_NT40_ENV
145     lastDevComp = &aname[strlen(aname) - 1];
146     *lastDevComp = toupper(*lastDevComp);
147 #else
148     {
149         char *tfile = vol_DevName(tstat.st_dev, wpath);
150         if (!tfile) {
151             printf("volnuke: can't find %s's device.\n", aname);
152             return 1;
153         }
154         strcpy(devName, tfile); /* save this from the static buffer */
155     }
156     /* aim lastDevComp at the 'foo' of '/dev/foo' */
157     lastDevComp = strrchr(devName, '/');
158     /* either points at slash, or there is no slash; adjust appropriately */
159     if (lastDevComp)
160         lastDevComp++;
161     else
162         lastDevComp = devName;
163 #endif /* AFS_NT40_ENV */
164 #endif /* AFS_NAMEI_ENV && !AFS_NT40_ENV */
165
166     ObtainWriteLock(&localLock);
167     /* OK, we have the mounted on place, aname, the device name (in devName).
168      * all we need to do to call ListViceInodes is find the inodes for the
169      * volume we're nuking.
170      */
171     code =
172         ListViceInodes(lastDevComp, aname, NULL, NukeProc, avolid, &forceSal,
173                        0, wpath, &allInodes);
174     if (code == 0) {
175         /* actually do the idecs now */
176         for (ti = allInodes; ti; ti = ti->next) {
177             for (i = 0; i < ti->freePtr; i++) {
178 #ifndef AFS_PTHREAD_ENV
179                 IOMGR_Poll();   /* keep RPC running */
180 #endif /* !AFS_PTHREAD_ENV */
181                 /* idec this inode into oblivion */
182 #ifdef AFS_NAMEI_ENV
183 #ifdef AFS_NT40_ENV
184                 IH_INIT(fileH, (int)(*lastDevComp - 'A'), avolid,
185                         ti->inode[i]);
186 #else
187                 IH_INIT(fileH, (int)volutil_GetPartitionID(aname), avolid,
188                         ti->inode[i]);
189 #endif /* AFS_NT40_ENV */
190                 namei_HandleToName(&ufs_name, fileH);
191                 path = ufs_name.n_path;
192                 IH_RELEASE(fileH);
193                 if (OS_UNLINK(path) < 0) {
194                     Log("Nuke: Failed to remove %s\n", path);
195                 }
196 #else /* AFS_NAMEI_ENV */
197                 IH_INIT(fileH, (int)tstat.st_dev, avolid, ti->inode[i]);
198                 {
199                     int j;
200                     for (j = 0; j < ti->count[i]; j++) {
201                         code = IH_DEC(fileH, ti->inode[i], avolid);
202                     }
203                 }
204                 IH_RELEASE(fileH);
205 #endif /* AFS_NAMEI_ENV */
206             }
207             ni = ti->next;
208             if (li) free(li);
209             li = ti;
210         }
211         if (li) free(li);
212         code = 0;               /* we really don't care about it except for debugging */
213         allInodes = NULL;
214
215         /* at this point, we should try to remove the volume header file itself.
216          * the volume header file is the file named VNNNNN.vol in the UFS file
217          * system, and is a normal file.  As such, it is not stamped with the
218          * volume's ID in its inode, and has to be removed explicitly.
219          */
220         code = VDestroyVolumeDiskHeader(dp, avolid, 0);
221     } else {
222         /* just free things */
223         for (ti = allInodes; ti; ti = ni) {
224             ni = ti->next;
225             if (li) free(li);
226             li = ti;
227         }
228         if (li) free(li);
229         allInodes = NULL;
230     }
231     ReleaseWriteLock(&localLock);
232     return code;
233 }