dafs-20060317
[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 RCSID
14     ("$Header$");
15
16 #include <rx/xdr.h>
17 #include <afs/afsint.h>
18 #include <stdio.h>
19 #ifdef AFS_PTHREAD_ENV
20 #include <assert.h>
21 #else /* AFS_PTHREAD_ENV */
22 #include <afs/assert.h>
23 #endif /* AFS_PTHREAD_ENV */
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <errno.h>
27 #if defined(AFS_SUN5_ENV) || defined(AFS_NT40_ENV)
28 #include <string.h>
29 #else
30 #include <strings.h>
31 #endif
32
33 #include <afs/assert.h>
34 #include "nfs.h"
35 #include "lwp.h"
36 #include "lock.h"
37 #include <afs/afssyscalls.h>
38 #include "ihandle.h"
39 #include "vnode.h"
40 #include "volume.h"
41 #include "partition.h"
42 #include "viceinode.h"
43 #include "salvage.h"
44 #include "daemon_com.h"
45 #include "fssync.h"
46
47 #ifdef O_LARGEFILE
48 #define afs_stat        stat64
49 #else /* !O_LARGEFILE */
50 #define afs_stat        stat
51 #endif /* !O_LARGEFILE */
52
53 /*@printflike@*/ extern void Log(const char *format, ...);
54
55
56 struct Lock localLock;
57 char *vol_DevName();
58
59 #define MAXATONCE       100
60 /* structure containing neatly packed set of inodes and the # of times we'll have
61  * to idec them in order to reclaim their storage.  NukeProc, called by ListViceInodes,
62  * builds this list for us.
63  */
64 struct ilist {
65     struct ilist *next;
66     afs_int32 freePtr;          /* first free index in this table */
67     Inode inode[MAXATONCE];     /* inode # */
68     afs_int32 count[MAXATONCE]; /* link count */
69 };
70
71 /* called with a structure specifying info about the inode, and our rock (which
72  * is the volume ID.  Returns true if we should keep this inode, otherwise false.
73  * Note that ainfo->u.param[0] is always the volume ID, for any vice inode.
74  */
75 static int
76 NukeProc(struct ViceInodeInfo *ainfo, afs_int32 avolid, struct ilist *allInodes)
77 {
78     struct ilist *ti;
79     register afs_int32 i;
80
81 #ifndef AFS_PTHREAD_ENV
82     IOMGR_Poll();               /* poll so we don't kill the RPC connection */
83 #endif /* !AFS_PTHREAD_ENV */
84
85     /* check if this is the volume we're looking for */
86     if (ainfo->u.param[0] != avolid)
87         return 0;               /* don't want this one */
88     /* record the info */
89     if (!allInodes || allInodes->freePtr >= MAXATONCE) {
90         ti = (struct ilist *)malloc(sizeof(struct ilist));
91         memset(ti, 0, sizeof(*ti));
92         ti->next = allInodes;
93         allInodes = ti;
94     } else
95         ti = allInodes;         /* use the one with space */
96     i = ti->freePtr++;          /* find our slot in this mess */
97     ti->inode[i] = ainfo->inodeNumber;
98     ti->count[i] = ainfo->linkCount;
99     return 0;                   /* don't care if anything's written out, actually */
100 }
101
102 /* function called with partition name and volid ID, and which removes all
103  * inodes marked with the specified volume ID.  If the volume is a read-only
104  * clone, we'll only remove the header inodes, since they're the only inodes
105  * marked with that volume ID.  If you want to reclaim all the data, you should
106  * nuke the read-write volume ID.
107  *
108  * Note also that nuking a read-write volume effectively nukes all RO volumes
109  * cloned from that RW volume ID, too, since everything except for their
110  * indices will be gone.
111  */
112 int
113 nuke(char *aname, afs_int32 avolid)
114 {
115     /* first process the partition containing this junk */
116     struct afs_stat tstat;
117     struct ilist *ti, *ni, *li=NULL;
118     register afs_int32 code;
119     int i, forceSal;
120     char devName[64], wpath[100];
121     char *lastDevComp;
122 #ifdef AFS_NAMEI_ENV
123 #ifdef AFS_NT40_ENV
124     char path[MAX_PATH];
125 #else
126     char *path;
127     namei_t ufs_name;
128 #endif
129 #endif /* AFS_NAMEI_ENV */
130     IHandle_t *fileH;
131     struct ilist *allInodes = 0;
132
133     if (avolid == 0)
134         return EINVAL;
135     code = afs_stat(aname, &tstat);
136     if (code) {
137         printf("volnuke: partition %s does not exist.\n", aname);
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 #ifdef AFS_NAMEI_ENV
172     code =
173         ListViceInodes(lastDevComp, aname, NULL, NukeProc, avolid, &forceSal,
174                        0, wpath, allInodes);
175 #else
176     code =
177         ListViceInodes(lastDevComp, aname, "/tmp/vNukeXX", NukeProc, avolid,
178                        &forceSal, 0, wpath, allInodes);
179     unlink("/tmp/vNukeXX");     /* clean it up now */
180 #endif
181     if (code == 0) {
182         /* actually do the idecs now */
183         for (ti = allInodes; ti; ti = ti->next) {
184             for (i = 0; i < ti->freePtr; i++) {
185 #ifndef AFS_PTHREAD_ENV
186                 IOMGR_Poll();   /* keep RPC running */
187 #endif /* !AFS_PTHREAD_ENV */
188                 /* idec this inode into oblivion */
189 #ifdef AFS_NAMEI_ENV
190 #ifdef AFS_NT40_ENV
191                 IH_INIT(fileH, (int)(*lastDevComp - 'A'), avolid,
192                         ti->inode[i]);
193                 nt_HandleToName(path, fileH);
194 #else
195                 IH_INIT(fileH, (int)volutil_GetPartitionID(aname), avolid,
196                         ti->inode[i]);
197                 namei_HandleToName(&ufs_name, fileH);
198                 path = ufs_name.n_path;
199 #endif /* AFS_NT40_ENV */
200                 IH_RELEASE(fileH);
201                 if (unlink(path) < 0) {
202                     Log("Nuke: Failed to remove %s\n", path);
203                 }
204 #else /* AFS_NAMEI_ENV */
205                 IH_INIT(fileH, (int)tstat.st_dev, avolid, ti->inode[i]);
206                 {
207                     int j;
208                     for (j = 0; j < ti->count[i]; j++) {
209                         code = IH_DEC(fileH, ti->inode[i], avolid);
210                     }
211                 }
212                 IH_RELEASE(fileH);
213 #endif /* AFS_NAMEI_ENV */
214             }
215             ni = ti->next;
216             if (li) free(li);
217             li = ti;
218         }
219         if (li) free(li);
220         code = 0;               /* we really don't care about it except for debugging */
221         allInodes = NULL;
222
223         /* at this point, we should try to remove the volume header file itself.
224          * the volume header file is the file named VNNNNN.vol in the UFS file
225          * system, and is a normal file.  As such, it is not stamped with the
226          * volume's ID in its inode, and has to be removed explicitly.
227          */
228         /* reuse devName buffer now */
229 #ifdef AFS_NT40_ENV
230         afs_snprintf(devName, sizeof devName, "%c:\\%s", *lastDevComp,
231                      VolumeExternalName(avolid));
232 #else
233         afs_snprintf(devName, sizeof devName, "%s/%s", aname,
234                      VolumeExternalName(avolid));
235 #endif /* AFS_NT40_ENV */
236         code = unlink(devName);
237         if (code)
238             code = errno;
239     } else {
240         /* just free things */
241         for (ti = allInodes; ti; ti = ni) {
242             ni = ti->next;
243             if (li) free(li);
244             li = ti;
245         }
246         if (li) free(li);
247         allInodes = NULL;
248     }
249     ReleaseWriteLock(&localLock);
250     return code;
251 }