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