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