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