libroken: Build on windows
[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 #include <roken.h>
14
15 #include <afs/stds.h>
16 #include <string.h>
17 #include <ctype.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     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     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     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_uint32 volid, afs_int32 voltype, struct nvldbentry *entryp)
132 {
133     struct vldbentry oentry;
134     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     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_uint32 volid, afs_int32 voltype, struct nvldbentry *entryp, afs_int32 releasetype)
183 {
184     struct vldbentry oentry;
185     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     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_uint32 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_uint32 serv1, afs_uint32 serv2, afs_int32 *errorp)
286 {
287     int code;
288     ListAddrByAttributes attrs;
289     bulkaddrs addrs;
290     afs_uint32 *addrp, i, j, f1, f2;
291     afs_int32 unique, nentries;
292     afsUUID uuid;
293     static int initcache = 0;
294
295     *errorp = 0;
296
297     if (serv1 == serv2)
298         return 1;
299     if (vlserverv4 == 1) {
300         return 0;
301     }
302     if (!initcache) {
303         for (i = 0; i < GETADDRUCACHESIZE; i++) {
304             cacheips[i].server = cacheips[i].count = 0;
305         }
306         initcache = 1;
307     }
308
309     /* See if it's cached */
310     for (i = 0; i < GETADDRUCACHESIZE; i++) {
311         f1 = f2 = 0;
312         for (j = 0; j < cacheips[i].count; j++) {
313             if (serv1 == cacheips[i].addrs[j])
314                 f1 = 1;
315             else if (serv2 == cacheips[i].addrs[j])
316                 f2 = 1;
317
318             if (f1 && f2)
319                 return 1;
320         }
321         if (f1 || f2)
322             return 0;
323         if (cacheips[i].server == serv1)
324             return 0;
325     }
326
327     memset(&attrs, 0, sizeof(attrs));
328     attrs.Mask = VLADDR_IPADDR;
329     attrs.ipaddr = serv1;
330     memset(&addrs, 0, sizeof(addrs));
331     memset(&uuid, 0, sizeof(uuid));
332     code =
333         ubik_VL_GetAddrsU(cstruct, 0, &attrs, &uuid, &unique, &nentries,
334                   &addrs);
335     if (vlserverv4 == -1) {
336         if (code == RXGEN_OPCODE) {
337             vlserverv4 = 1;     /* Doesn't support new interface */
338             return 0;
339         } else if (!code) {
340             vlserverv4 = 2;
341         }
342     }
343     if (code == VL_NOENT)
344         return 0;
345     if (code) {
346         *errorp = code;
347         return 0;
348     }
349
350     code = 0;
351     if (nentries > GETADDRUCACHESIZE)
352         nentries = GETADDRUCACHESIZE;   /* safety check; should not happen */
353     if (++cacheip_index >= GETADDRUCACHESIZE)
354         cacheip_index = 0;
355     cacheips[cacheip_index].server = serv1;
356     cacheips[cacheip_index].count = nentries;
357     addrp = addrs.bulkaddrs_val;
358     for (i = 0; i < nentries; i++, addrp++) {
359         cacheips[cacheip_index].addrs[i] = *addrp;
360         if (serv2 == *addrp) {
361             code = 1;
362         }
363     }
364     return code;
365 }
366
367
368 /*
369   Set encryption.  If 'cryptflag' is nonzero, encrpytion is turned on
370   for authenticated connections; if zero, encryption is turned off.
371   Calling this function always results in a level of at least rxkad_auth;
372   to get a rxkad_clear connection, simply don't call this.
373 */
374 void
375 vsu_SetCrypt(int cryptflag)
376 {
377     if (cryptflag) {
378         vsu_rxkad_level = rxkad_crypt;
379     } else {
380         vsu_rxkad_level = rxkad_auth;
381     }
382 }
383
384
385 /*
386   Get the appropriate type of ubik client structure out from the system.
387 */
388 afs_int32
389 vsu_ClientInit(int noAuthFlag, const char *confDir, char *cellName, afs_int32 sauth,
390                struct ubik_client **uclientp,
391                int (*secproc)(struct rx_securityClass *, afs_int32))
392 {
393     return ugen_ClientInit(noAuthFlag, confDir, cellName, sauth, uclientp,
394                            secproc, "vsu_ClientInit", vsu_rxkad_level,
395                            VLDB_MAXSERVERS, AFSCONF_VLDBSERVICE, 90,
396                            0, 0, USER_SERVICE_ID);
397 }
398
399
400 /*extract the name of volume <name> without readonly or backup suffixes
401  * and return the result as <rname>.
402  */
403 int
404 vsu_ExtractName(char rname[], char name[])
405 {
406     char sname[VOLSER_OLDMAXVOLNAME + 1];
407     int total;
408
409     strncpy(sname, name, sizeof(sname));
410     sname[sizeof(sname) - 1] = '\0';
411     total = strlen(sname);
412     if (!strcmp(&sname[total - 9], ".readonly")) {
413         /*discard the last 8 chars */
414         sname[total - 9] = '\0';
415         strcpy(rname, sname);
416         return 0;
417     } else if (!strcmp(&sname[total - 7], ".backup")) {
418         /*discard last 6 chars */
419         sname[total - 7] = '\0';
420         strcpy(rname, sname);
421         return 0;
422     } else {
423         strncpy(rname, name, VOLSER_OLDMAXVOLNAME);
424         rname[VOLSER_OLDMAXVOLNAME] = '\0';
425         return -1;
426     }
427 }
428
429 /* returns 0 if failed */
430 afs_uint32
431 vsu_GetVolumeID(char *astring, struct ubik_client *acstruct, afs_int32 *errp)
432 {
433     char volname[VOLSER_OLDMAXVOLNAME + 1];
434     struct nvldbentry entry;
435     afs_int32 vcode = 0;
436     int total;
437
438     *errp = 0;
439
440     if (isdigit(astring[0])) {
441         char *end;
442         afs_uint32 result;
443         result = strtoul(astring, &end, 10);
444         if (result != UINT_MAX && *end == '\0')
445             return result;
446     }
447
448     /* It was not a volume number but something else */
449     total = strlen(astring);
450     vsu_ExtractName(volname, astring);
451     vcode = VLDB_GetEntryByName(volname, &entry);
452     if (!vcode) {
453       if ((total >= 9) && (!strcmp(&astring[total - 9], ".readonly")))
454         return entry.volumeId[ROVOL];
455       else if ((total >= 7) && (!strcmp(&astring[total - 7], ".backup")))
456         return entry.volumeId[BACKVOL];
457       else
458         return (entry.volumeId[RWVOL]);
459     }
460     *errp = vcode;
461     return 0;           /* can't find volume */
462 }