ubik: Introduce ugen_secproc_func
[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     code = ubik_VL_GetEntryByIDN(cstruct, 0, volid, voltype, entryp);
140     if (newvlserver == vltype_unknown) {
141         if (code == RXGEN_OPCODE) {
142             newvlserver = vltype_old;   /* Doesn't support new interface */
143             goto tryold;
144         } else if (!code) {
145             newvlserver = vltype_new;
146         }
147     }
148     return code;
149 }
150
151 int
152 VLDB_GetEntryByName(char *namep, struct nvldbentry *entryp)
153 {
154     struct vldbentry oentry;
155     int code;
156
157     if (newvlserver == vltype_old) {
158       tryold:
159         code = ubik_VL_GetEntryByNameO(cstruct, 0, namep, &oentry);
160         if (!code)
161             ovlentry_to_nvlentry(&oentry, entryp);
162         return code;
163     }
164     code = ubik_VL_GetEntryByNameN(cstruct, 0, namep, entryp);
165     if (newvlserver == vltype_unknown) {
166         if (code == RXGEN_OPCODE) {
167             newvlserver = vltype_old;   /* Doesn't support new interface */
168             goto tryold;
169         } else if (!code) {
170             newvlserver = vltype_new;
171         }
172     }
173     return code;
174 }
175
176 int
177 VLDB_ReplaceEntry(afs_uint32 volid, afs_int32 voltype, struct nvldbentry *entryp, afs_int32 releasetype)
178 {
179     struct vldbentry oentry;
180     int code;
181
182     if (newvlserver == vltype_old) {
183       tryold:
184         code = nvlentry_to_ovlentry(entryp, &oentry);
185         if (code)
186             return code;
187         code =
188             ubik_VL_ReplaceEntry(cstruct, 0, volid, voltype, &oentry,
189                       releasetype);
190         return code;
191     }
192     code =
193         ubik_VL_ReplaceEntryN(cstruct, 0, volid, voltype, entryp,
194                   releasetype);
195     if (newvlserver == vltype_unknown) {
196         if (code == RXGEN_OPCODE) {
197             newvlserver = vltype_old;   /* Doesn't support new interface */
198             goto tryold;
199         } else if (!code) {
200             newvlserver = vltype_new;
201         }
202     }
203     return code;
204 }
205
206 static void
207 convertBulkToNBulk(bulkentries *bulk, nbulkentries *nbulk) {
208     unsigned int i;
209
210     if (bulk->bulkentries_len == 0)
211         return;
212
213     nbulk->nbulkentries_len = bulk->bulkentries_len;
214     nbulk->nbulkentries_val =
215         xdr_alloc(bulk->bulkentries_len * sizeof(struct nvldbentry));
216
217     for (i = 0; i < bulk->bulkentries_len; i++) {
218         ovlentry_to_nvlentry(&bulk->bulkentries_val[i],
219                              &nbulk->nbulkentries_val[i]);
220     }
221 }
222
223 int
224 VLDB_ListAttributes(VldbListByAttributes *attrp,
225                     afs_int32 *entriesp,
226                     nbulkentries *blkentriesp)
227 {
228     bulkentries arrayEntries;
229     int code;
230
231     if (newvlserver == vltype_old) {
232       tryold:
233         memset(&arrayEntries, 0, sizeof(arrayEntries));
234         code =
235             ubik_VL_ListAttributes(cstruct, 0, attrp, entriesp,
236                       &arrayEntries);
237
238         if (code)
239             return code;
240
241         /* Ensure the number of entries claimed matches the no. returned */
242         if (*entriesp < 0)
243             *entriesp = 0;
244         if (*entriesp > arrayEntries.bulkentries_len)
245             *entriesp = arrayEntries.bulkentries_len;
246
247         convertBulkToNBulk(&arrayEntries, blkentriesp);
248
249         xdr_free((xdrproc_t) xdr_bulkentries, &arrayEntries);
250         return code;
251     }
252     code =
253         ubik_VL_ListAttributesN(cstruct, 0, attrp, entriesp, blkentriesp);
254     if (newvlserver == vltype_unknown) {
255         if (code == RXGEN_OPCODE) {
256             newvlserver = vltype_old;   /* Doesn't support new interface */
257             goto tryold;
258         } else if (!code) {
259             newvlserver = vltype_new;
260         }
261     }
262
263     /* Ensure the number of entries claimed matches the no. returned */
264     if (*entriesp < 0)
265         *entriesp = 0;
266     if (*entriesp > blkentriesp->nbulkentries_len)
267         *entriesp = blkentriesp->nbulkentries_len;
268
269     return code;
270 }
271
272 int
273 VLDB_ListAttributesN2(VldbListByAttributes *attrp,
274                       char *name,
275                       afs_int32 thisindex,
276                       afs_int32 *nentriesp,
277                       nbulkentries *blkentriesp,
278                       afs_int32 *nextindexp)
279 {
280     afs_int32 code = RXGEN_OPCODE;
281
282     if (newvlserver != vltype_old) {
283         code =
284             ubik_VL_ListAttributesN2(cstruct, 0, attrp, (name ? name : ""),
285                                      thisindex, nentriesp, blkentriesp, nextindexp);
286         if (code)
287             return code;
288
289         /* Ensure the number of entries claimed matches the no. returned */
290         if (*nentriesp < 0)
291             *nentriesp = 0;
292         if (*nentriesp > blkentriesp->nbulkentries_len)
293             *nentriesp = blkentriesp->nbulkentries_len;
294     }
295     return code;
296 }
297
298 struct cacheips {
299     afs_uint32 server;
300     afs_uint32 count;
301     afs_uint32 addrs[16];
302 };
303 /*
304  * Increase cache size.  This avoids high CPU usage by the vlserver
305  * in environments where there are more than 16 fileservers in the
306  * cell.
307  */
308 #define GETADDRUCACHESIZE             64
309 struct cacheips cacheips[GETADDRUCACHESIZE];
310 int cacheip_index = 0;
311
312 int
313 VLDB_IsSameAddrs(afs_uint32 serv1, afs_uint32 serv2, afs_int32 *errorp)
314 {
315     int code;
316     ListAddrByAttributes attrs;
317     bulkaddrs addrs;
318     afs_uint32 *addrp, j, f1, f2;
319     afs_int32 unique, nentries, i;
320     afsUUID uuid;
321     static int initcache = 0;
322
323     *errorp = 0;
324
325     if (serv1 == serv2)
326         return 1;
327     if (newvlserver == vltype_old || newvlserver == vltype_new) {
328         return 0;
329     }
330     if (!initcache) {
331         for (i = 0; i < GETADDRUCACHESIZE; i++) {
332             cacheips[i].server = cacheips[i].count = 0;
333         }
334         initcache = 1;
335     }
336
337     /* See if it's cached */
338     for (i = 0; i < GETADDRUCACHESIZE; i++) {
339         f1 = f2 = 0;
340         for (j = 0; j < cacheips[i].count; j++) {
341             if (serv1 == cacheips[i].addrs[j])
342                 f1 = 1;
343             else if (serv2 == cacheips[i].addrs[j])
344                 f2 = 1;
345
346             if (f1 && f2)
347                 return 1;
348         }
349         if (f1 || f2)
350             return 0;
351         if (cacheips[i].server == serv1)
352             return 0;
353     }
354
355     memset(&attrs, 0, sizeof(attrs));
356     attrs.Mask = VLADDR_IPADDR;
357     attrs.ipaddr = serv1;
358     memset(&addrs, 0, sizeof(addrs));
359     memset(&uuid, 0, sizeof(uuid));
360     code =
361         ubik_VL_GetAddrsU(cstruct, 0, &attrs, &uuid, &unique, &nentries,
362                   &addrs);
363     if (newvlserver == vltype_unknown) {
364         if (code == RXGEN_OPCODE) {
365             return 0;
366         } else if (!code) {
367             newvlserver = vltype_uuid;
368         }
369     }
370     if (code == VL_NOENT)
371         return 0;
372     if (code) {
373         *errorp = code;
374         return 0;
375     }
376
377     code = 0;
378     if (nentries > GETADDRUCACHESIZE)
379         nentries = GETADDRUCACHESIZE;   /* safety check; should not happen */
380     if (++cacheip_index >= GETADDRUCACHESIZE)
381         cacheip_index = 0;
382     cacheips[cacheip_index].server = serv1;
383     cacheips[cacheip_index].count = nentries;
384     addrp = addrs.bulkaddrs_val;
385     for (i = 0; i < nentries; i++, addrp++) {
386         cacheips[cacheip_index].addrs[i] = *addrp;
387         if (serv2 == *addrp) {
388             code = 1;
389         }
390     }
391     return code;
392 }
393
394 /*
395   Get the appropriate type of ubik client structure out from the system.
396 */
397 int
398 vsu_ClientInit(const char *confDir, char *cellName, int secFlags,
399                ugen_secproc_func secproc,
400                struct ubik_client **uclientp)
401 {
402     return ugen_ClientInitFlags(confDir, cellName, secFlags, uclientp,
403                                 secproc, VLDB_MAXSERVERS, AFSCONF_VLDBSERVICE,
404                                 90);
405 }
406
407 /*extract the name of volume <name> without readonly or backup suffixes
408  * and return the result as <rname>.
409  */
410 int
411 vsu_ExtractName(char rname[], char name[])
412 {
413     char sname[VOLSER_OLDMAXVOLNAME + 1];
414     size_t total;
415
416     strncpy(sname, name, sizeof(sname));
417     sname[sizeof(sname) - 1] = '\0';
418     total = strlen(sname);
419     if (!strcmp(&sname[total - 9], ".readonly")) {
420         /*discard the last 8 chars */
421         sname[total - 9] = '\0';
422         strcpy(rname, sname);
423         return 0;
424     } else if (!strcmp(&sname[total - 7], ".backup")) {
425         /*discard last 6 chars */
426         sname[total - 7] = '\0';
427         strcpy(rname, sname);
428         return 0;
429     } else {
430         strncpy(rname, name, VOLSER_OLDMAXVOLNAME);
431         rname[VOLSER_OLDMAXVOLNAME] = '\0';
432         return -1;
433     }
434 }
435
436 /* returns 0 if failed */
437 afs_uint32
438 vsu_GetVolumeID(char *astring, struct ubik_client *acstruct, afs_int32 *errp)
439 {
440     char volname[VOLSER_OLDMAXVOLNAME + 1];
441     struct nvldbentry entry;
442     afs_int32 vcode = 0;
443     size_t total;
444
445     *errp = 0;
446
447     if (isdigit(astring[0])) {
448         char *end;
449         afs_uint32 result;
450         result = strtoul(astring, &end, 10);
451         if (result != UINT_MAX && *end == '\0')
452             return result;
453     }
454
455     /* It was not a volume number but something else */
456     total = strlen(astring);
457     vsu_ExtractName(volname, astring);
458     vcode = VLDB_GetEntryByName(volname, &entry);
459     if (!vcode) {
460       if ((total >= 9) && (!strcmp(&astring[total - 9], ".readonly")))
461         return entry.volumeId[ROVOL];
462       else if ((total >= 7) && (!strcmp(&astring[total - 7], ".backup")))
463         return entry.volumeId[BACKVOL];
464       else
465         return (entry.volumeId[RWVOL]);
466     }
467     *errp = vcode;
468     return 0;           /* can't find volume */
469 }