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