vos: avoid 'half-locked' volume after interrupted 'vos rename'
[openafs.git] / src / volser / vsutils.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 #include <afs/stds.h>
13
14 #include <roken.h>
15
16 #include <ctype.h>
17 #ifdef AFS_AIX_ENV
18 #include <sys/statfs.h>
19 #endif
20
21 #include <lock.h>
22 #include <rx/xdr.h>
23 #include <rx/rx.h>
24 #include <rx/rx_globals.h>
25 #include <afs/nfs.h>
26 #include <afs/vlserver.h>
27 #include <afs/cellconfig.h>
28 #include <afs/keys.h>
29 #include <ubik.h>
30 #include <afs/afsint.h>
31 #include <afs/cmd.h>
32 #include <rx/rxkad.h>
33
34 #include "volser.h"
35 #include "volint.h"
36 #include "lockdata.h"
37
38 #include "vsutils_prototypes.h"
39
40 struct ubik_client *cstruct;
41
42 static void
43 ovlentry_to_nvlentry(struct vldbentry *oentryp,
44                      struct nvldbentry *nentryp)
45 {
46     int i;
47
48     memset(nentryp, 0, sizeof(struct nvldbentry));
49     strncpy(nentryp->name, oentryp->name, sizeof(nentryp->name));
50     for (i = 0; i < oentryp->nServers; i++) {
51         nentryp->serverNumber[i] = oentryp->serverNumber[i];
52         nentryp->serverPartition[i] = oentryp->serverPartition[i];
53         nentryp->serverFlags[i] = oentryp->serverFlags[i];
54     }
55     nentryp->nServers = oentryp->nServers;
56     for (i = 0; i < MAXTYPES; i++)
57         nentryp->volumeId[i] = oentryp->volumeId[i];
58     nentryp->cloneId = oentryp->cloneId;
59     nentryp->flags = oentryp->flags;
60 }
61
62 static int
63 nvlentry_to_ovlentry(struct nvldbentry *nentryp,
64                      struct vldbentry *oentryp)
65 {
66     int i;
67
68     memset(oentryp, 0, sizeof(struct vldbentry));
69     strncpy(oentryp->name, nentryp->name, sizeof(oentryp->name));
70     if (nentryp->nServers > OMAXNSERVERS) {
71         /*
72          * The alternative is to store OMAXSERVERS but it's always better
73          * to know what's going on...
74          */
75         return VL_BADSERVER;
76     }
77     for (i = 0; i < nentryp->nServers; i++) {
78         oentryp->serverNumber[i] = nentryp->serverNumber[i];
79         oentryp->serverPartition[i] = nentryp->serverPartition[i];
80         oentryp->serverFlags[i] = nentryp->serverFlags[i];
81     }
82     oentryp->nServers = i;
83     for (i = 0; i < MAXTYPES; i++)
84         oentryp->volumeId[i] = nentryp->volumeId[i];
85     oentryp->cloneId = nentryp->cloneId;
86     oentryp->flags = nentryp->flags;
87     return 0;
88 }
89
90 enum _vlserver_type {
91     vltype_unknown = 0,
92     vltype_old = 1,
93     vltype_new = 2,
94     vltype_uuid = 3
95 };
96
97 static enum _vlserver_type newvlserver = vltype_unknown;
98
99 int
100 VLDB_CreateEntry(struct nvldbentry *entryp)
101 {
102     struct vldbentry oentry;
103     int code;
104
105     if (newvlserver == vltype_old) {
106       tryold:
107         code = nvlentry_to_ovlentry(entryp, &oentry);
108         if (code)
109             return code;
110         code = ubik_VL_CreateEntry(cstruct, 0, &oentry);
111         return code;
112     }
113     code = ubik_VL_CreateEntryN(cstruct, 0, entryp);
114     if (newvlserver == vltype_unknown) {
115         if (code == RXGEN_OPCODE) {
116             newvlserver = vltype_old;   /* Doesn't support new interface */
117             goto tryold;
118         } else if (!code) {
119             newvlserver = vltype_new;
120         }
121     }
122     return code;
123 }
124
125 int
126 VLDB_GetEntryByID(afs_uint32 volid, afs_int32 voltype, struct nvldbentry *entryp)
127 {
128     struct vldbentry oentry;
129     int code;
130
131     if (newvlserver == vltype_old) {
132       tryold:
133         code =
134             ubik_VL_GetEntryByID(cstruct, 0, volid, voltype, &oentry);
135         if (!code)
136             ovlentry_to_nvlentry(&oentry, entryp);
137         return code;
138     }
139     memset(entryp, 0, sizeof(*entryp));     /* ensure padding is cleared */
140     code = ubik_VL_GetEntryByIDN(cstruct, 0, volid, voltype, entryp);
141     if (newvlserver == vltype_unknown) {
142         if (code == RXGEN_OPCODE) {
143             newvlserver = vltype_old;   /* Doesn't support new interface */
144             goto tryold;
145         } else if (!code) {
146             newvlserver = vltype_new;
147         }
148     }
149     return code;
150 }
151
152 int
153 VLDB_GetEntryByName(char *namep, struct nvldbentry *entryp)
154 {
155     struct vldbentry oentry;
156     int code;
157
158     if (newvlserver == vltype_old) {
159       tryold:
160         code = ubik_VL_GetEntryByNameO(cstruct, 0, namep, &oentry);
161         if (!code)
162             ovlentry_to_nvlentry(&oentry, entryp);
163         return code;
164     }
165     memset(entryp, 0, sizeof(*entryp));     /* ensure padding is cleared */
166     code = ubik_VL_GetEntryByNameN(cstruct, 0, namep, entryp);
167     if (newvlserver == vltype_unknown) {
168         if (code == RXGEN_OPCODE) {
169             newvlserver = vltype_old;   /* Doesn't support new interface */
170             goto tryold;
171         } else if (!code) {
172             newvlserver = vltype_new;
173         }
174     }
175     return code;
176 }
177
178 int
179 VLDB_ReplaceEntry(afs_uint32 volid, afs_int32 voltype, struct nvldbentry *entryp, afs_int32 releasetype)
180 {
181     struct vldbentry oentry;
182     int code;
183
184     if (newvlserver == vltype_old) {
185       tryold:
186         code = nvlentry_to_ovlentry(entryp, &oentry);
187         if (code)
188             return code;
189         code =
190             ubik_VL_ReplaceEntry(cstruct, 0, volid, voltype, &oentry,
191                       releasetype);
192         return code;
193     }
194     code =
195         ubik_VL_ReplaceEntryN(cstruct, 0, volid, voltype, entryp,
196                   releasetype);
197     if (newvlserver == vltype_unknown) {
198         if (code == RXGEN_OPCODE) {
199             newvlserver = vltype_old;   /* Doesn't support new interface */
200             goto tryold;
201         } else if (!code) {
202             newvlserver = vltype_new;
203         }
204     }
205     return code;
206 }
207
208 static void
209 convertBulkToNBulk(bulkentries *bulk, nbulkentries *nbulk) {
210     unsigned int i;
211
212     if (bulk->bulkentries_len == 0)
213         return;
214
215     nbulk->nbulkentries_len = bulk->bulkentries_len;
216     nbulk->nbulkentries_val =
217         xdr_alloc(bulk->bulkentries_len * sizeof(struct nvldbentry));
218
219     for (i = 0; i < bulk->bulkentries_len; i++) {
220         ovlentry_to_nvlentry(&bulk->bulkentries_val[i],
221                              &nbulk->nbulkentries_val[i]);
222     }
223 }
224
225 int
226 VLDB_ListAttributes(VldbListByAttributes *attrp,
227                     afs_int32 *entriesp,
228                     nbulkentries *blkentriesp)
229 {
230     bulkentries arrayEntries;
231     int code;
232
233     if (newvlserver == vltype_old) {
234       tryold:
235         memset(&arrayEntries, 0, sizeof(arrayEntries));
236         code =
237             ubik_VL_ListAttributes(cstruct, 0, attrp, entriesp,
238                       &arrayEntries);
239
240         if (code)
241             return code;
242
243         /* Ensure the number of entries claimed matches the no. returned */
244         if (*entriesp < 0)
245             *entriesp = 0;
246         if (*entriesp > arrayEntries.bulkentries_len)
247             *entriesp = arrayEntries.bulkentries_len;
248
249         convertBulkToNBulk(&arrayEntries, blkentriesp);
250
251         xdr_free((xdrproc_t) xdr_bulkentries, &arrayEntries);
252         return code;
253     }
254     code =
255         ubik_VL_ListAttributesN(cstruct, 0, attrp, entriesp, blkentriesp);
256     if (newvlserver == vltype_unknown) {
257         if (code == RXGEN_OPCODE) {
258             newvlserver = vltype_old;   /* Doesn't support new interface */
259             goto tryold;
260         } else if (!code) {
261             newvlserver = vltype_new;
262         }
263     }
264
265     /* Ensure the number of entries claimed matches the no. returned */
266     if (*entriesp < 0)
267         *entriesp = 0;
268     if (*entriesp > blkentriesp->nbulkentries_len)
269         *entriesp = blkentriesp->nbulkentries_len;
270
271     return code;
272 }
273
274 int
275 VLDB_ListAttributesN2(VldbListByAttributes *attrp,
276                       char *name,
277                       afs_int32 thisindex,
278                       afs_int32 *nentriesp,
279                       nbulkentries *blkentriesp,
280                       afs_int32 *nextindexp)
281 {
282     afs_int32 code = RXGEN_OPCODE;
283
284     if (newvlserver != vltype_old) {
285         code =
286             ubik_VL_ListAttributesN2(cstruct, 0, attrp, (name ? name : ""),
287                                      thisindex, nentriesp, blkentriesp, nextindexp);
288         if (code)
289             return code;
290
291         /* Ensure the number of entries claimed matches the no. returned */
292         if (*nentriesp < 0)
293             *nentriesp = 0;
294         if (*nentriesp > blkentriesp->nbulkentries_len)
295             *nentriesp = blkentriesp->nbulkentries_len;
296     }
297     return code;
298 }
299
300 struct cacheips {
301     afs_uint32 server;
302     afs_uint32 count;
303     afs_uint32 addrs[16];
304 };
305 /*
306  * Increase cache size.  This avoids high CPU usage by the vlserver
307  * in environments where there are more than 16 fileservers in the
308  * cell.
309  */
310 #define GETADDRUCACHESIZE             64
311 struct cacheips cacheips[GETADDRUCACHESIZE];
312 int cacheip_index = 0;
313
314 int
315 VLDB_IsSameAddrs(afs_uint32 serv1, afs_uint32 serv2, afs_int32 *errorp)
316 {
317     int code;
318     ListAddrByAttributes attrs;
319     bulkaddrs addrs;
320     afs_uint32 *addrp, j, f1, f2;
321     afs_int32 unique, nentries, i;
322     afsUUID uuid;
323     static int initcache = 0;
324
325     *errorp = 0;
326
327     if (serv1 == serv2)
328         return 1;
329     if (newvlserver == vltype_old || newvlserver == vltype_new) {
330         return 0;
331     }
332     if (!initcache) {
333         for (i = 0; i < GETADDRUCACHESIZE; i++) {
334             cacheips[i].server = cacheips[i].count = 0;
335         }
336         initcache = 1;
337     }
338
339     /* See if it's cached */
340     for (i = 0; i < GETADDRUCACHESIZE; i++) {
341         f1 = f2 = 0;
342         for (j = 0; j < cacheips[i].count; j++) {
343             if (serv1 == cacheips[i].addrs[j])
344                 f1 = 1;
345             else if (serv2 == cacheips[i].addrs[j])
346                 f2 = 1;
347
348             if (f1 && f2)
349                 return 1;
350         }
351         if (f1 || f2)
352             return 0;
353         if (cacheips[i].server == serv1)
354             return 0;
355     }
356
357     memset(&attrs, 0, sizeof(attrs));
358     attrs.Mask = VLADDR_IPADDR;
359     attrs.ipaddr = serv1;
360     memset(&addrs, 0, sizeof(addrs));
361     memset(&uuid, 0, sizeof(uuid));
362     code =
363         ubik_VL_GetAddrsU(cstruct, 0, &attrs, &uuid, &unique, &nentries,
364                   &addrs);
365     if (newvlserver == vltype_unknown) {
366         if (code == RXGEN_OPCODE) {
367             return 0;
368         } else if (!code) {
369             newvlserver = vltype_uuid;
370         }
371     }
372     if (code == VL_NOENT)
373         return 0;
374     if (code) {
375         *errorp = code;
376         return 0;
377     }
378
379     code = 0;
380     if (nentries > GETADDRUCACHESIZE)
381         nentries = GETADDRUCACHESIZE;   /* safety check; should not happen */
382     if (++cacheip_index >= GETADDRUCACHESIZE)
383         cacheip_index = 0;
384     cacheips[cacheip_index].server = serv1;
385     cacheips[cacheip_index].count = nentries;
386     addrp = addrs.bulkaddrs_val;
387     for (i = 0; i < nentries; i++, addrp++) {
388         cacheips[cacheip_index].addrs[i] = *addrp;
389         if (serv2 == *addrp) {
390             code = 1;
391         }
392     }
393     return code;
394 }
395
396 /*
397   Get the appropriate type of ubik client structure out from the system.
398 */
399 int
400 vsu_ClientInit(const char *confDir, char *cellName, int secFlags,
401                ugen_secproc_func secproc,
402                struct ubik_client **uclientp)
403 {
404     return ugen_ClientInitFlags(confDir, cellName, secFlags, uclientp,
405                                 secproc, VLDB_MAXSERVERS, AFSCONF_VLDBSERVICE,
406                                 90);
407 }
408
409 /*extract the name of volume <name> without readonly or backup suffixes
410  * and return the result as <rname>.
411  */
412 int
413 vsu_ExtractName(char rname[], char name[])
414 {
415     char sname[VOLSER_OLDMAXVOLNAME + 1];
416     size_t total;
417
418     strncpy(sname, name, sizeof(sname));
419     sname[sizeof(sname) - 1] = '\0';
420     total = strlen(sname);
421     if (!strcmp(&sname[total - 9], ".readonly")) {
422         /*discard the last 8 chars */
423         sname[total - 9] = '\0';
424         strcpy(rname, sname);
425         return 0;
426     } else if (!strcmp(&sname[total - 7], ".backup")) {
427         /*discard last 6 chars */
428         sname[total - 7] = '\0';
429         strcpy(rname, sname);
430         return 0;
431     } else {
432         strncpy(rname, name, VOLSER_OLDMAXVOLNAME);
433         rname[VOLSER_OLDMAXVOLNAME] = '\0';
434         return -1;
435     }
436 }
437
438 /* returns 0 if failed */
439 afs_uint32
440 vsu_GetVolumeID(char *astring, struct ubik_client *acstruct, afs_int32 *errp)
441 {
442     char volname[VOLSER_OLDMAXVOLNAME + 1];
443     struct nvldbentry entry;
444     afs_int32 vcode = 0;
445     size_t total;
446
447     *errp = 0;
448
449     if (isdigit(astring[0])) {
450         char *end;
451         afs_uint32 result;
452         result = strtoul(astring, &end, 10);
453         if (result != UINT_MAX && *end == '\0')
454             return result;
455     }
456
457     /* It was not a volume number but something else */
458     total = strlen(astring);
459     vsu_ExtractName(volname, astring);
460     vcode = VLDB_GetEntryByName(volname, &entry);
461     if (!vcode) {
462       if ((total >= 9) && (!strcmp(&astring[total - 9], ".readonly")))
463         return entry.volumeId[ROVOL];
464       else if ((total >= 7) && (!strcmp(&astring[total - 7], ".backup")))
465         return entry.volumeId[BACKVOL];
466       else
467         return (entry.volumeId[RWVOL]);
468     }
469     *errp = vcode;
470     return 0;           /* can't find volume */
471 }