33ecefce6aa297a26ca31f697bbb0a47ff2325b7
[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         bulkaddrs m_addrs;
64         ListAddrByAttributes m_attrs;
65         afs_int32 m_nentries;
66
67         m_attrs.Mask = VLADDR_IPADDR;
68         m_attrs.ipaddr = oentryp->serverNumber[i];
69         m_nentries = 0;
70         m_addrs.bulkaddrs_val = 0;
71         m_addrs.bulkaddrs_len = 0;
72         nentryp->serverNumber[i] = oentryp->serverNumber[i];
73         nentryp->serverPartition[i] = oentryp->serverPartition[i];
74         nentryp->serverFlags[i] = oentryp->serverFlags[i];
75     }
76     nentryp->nServers = oentryp->nServers;
77     for (i = 0; i < MAXTYPES; i++)
78         nentryp->volumeId[i] = oentryp->volumeId[i];
79     nentryp->cloneId = oentryp->cloneId;
80     nentryp->flags = oentryp->flags;
81 }
82
83 #if 0
84 /* It is here for when we need it.  Not currently used. */
85 static int
86 nvlentry_to_ovlentry(struct nvldbentry *nentryp,
87                      struct vldbentry *oentryp)
88 {
89     int i;
90
91     memset(oentryp, 0, sizeof(struct vldbentry));
92     strncpy(oentryp->name, nentryp->name, sizeof(oentryp->name));
93     if (nentryp->nServers > OMAXNSERVERS) {
94         /*
95          * The alternative is to store OMAXSERVERS but it's always better
96          * to know what's going on...
97          */
98         return VL_BADSERVER;
99     }
100     for (i = 0; i < nentryp->nServers; i++) {
101         oentryp->serverNumber[i] = nentryp->serverNumber[i];
102         oentryp->serverPartition[i] = nentryp->serverPartition[i];
103         oentryp->serverFlags[i] = nentryp->serverFlags[i];
104     }
105     oentryp->nServers = i;
106     for (i = 0; i < MAXTYPES; i++)
107         oentryp->volumeId[i] = nentryp->volumeId[i];
108     oentryp->cloneId = nentryp->cloneId;
109     oentryp->flags = nentryp->flags;
110     return 0;
111 }
112 #endif
113
114 static void
115 ovlentry_to_uvlentry(struct vldbentry *oentryp,
116                      struct uvldbentry *uentryp)
117 {
118     int i;
119
120     memset(uentryp, 0, sizeof(struct uvldbentry));
121     strncpy(uentryp->name, oentryp->name, sizeof(uentryp->name));
122     for (i = 0; i < oentryp->nServers; i++) {
123         afs_int32 vcode, m_uniq=0;
124         bulkaddrs m_addrs;
125         ListAddrByAttributes m_attrs;
126         afs_int32 m_nentries;
127
128         m_attrs.Mask = VLADDR_IPADDR;
129         m_attrs.ipaddr = oentryp->serverNumber[i];
130         m_nentries = 0;
131         m_addrs.bulkaddrs_val = 0;
132         m_addrs.bulkaddrs_len = 0;
133         vcode =
134             ubik_VL_GetAddrsU(cstruct, 0, &m_attrs,
135                                &uentryp->serverNumber[i],
136                                &m_uniq, &m_nentries,
137                                &m_addrs);
138         uentryp->serverUnique[i] = oentryp->serverNumber[i];
139         uentryp->serverPartition[i] = oentryp->serverPartition[i];
140         uentryp->serverFlags[i] = oentryp->serverFlags[i];
141     }
142     uentryp->nServers = oentryp->nServers;
143     for (i = 0; i < MAXTYPES; i++)
144         uentryp->volumeId[i] = oentryp->volumeId[i];
145     uentryp->cloneId = oentryp->cloneId;
146     uentryp->flags = oentryp->flags;
147 }
148
149 static int
150 uvlentry_to_ovlentry(struct uvldbentry *uentryp,
151                      struct vldbentry *oentryp)
152 {
153     int i;
154
155     memset(oentryp, 0, sizeof(struct vldbentry));
156     strncpy(oentryp->name, uentryp->name, sizeof(oentryp->name));
157     if (uentryp->nServers > OMAXNSERVERS) {
158         /*
159          * The alternative is to store OMAXSERVERS but it's always better
160          * to know what's going on...
161          */
162         return VL_BADSERVER;
163     }
164     for (i = 0; i < uentryp->nServers; i++) {
165         oentryp->serverNumber[i] = uentryp->serverUnique[i];
166         oentryp->serverPartition[i] = uentryp->serverPartition[i];
167         oentryp->serverFlags[i] = uentryp->serverFlags[i];
168     }
169     oentryp->nServers = i;
170     for (i = 0; i < MAXTYPES; i++)
171         oentryp->volumeId[i] = uentryp->volumeId[i];
172     oentryp->cloneId = uentryp->cloneId;
173     oentryp->flags = uentryp->flags;
174     return 0;
175 }
176
177 void
178 nvlentry_to_uvlentry(struct nvldbentry *nentryp,
179                      struct uvldbentry *uentryp)
180 {
181     int i;
182
183     memset(uentryp, 0, sizeof(struct uvldbentry));
184     strncpy(uentryp->name, nentryp->name, sizeof(uentryp->name));
185     for (i = 0; i < nentryp->nServers; i++) {
186         afs_int32 vcode, m_uniq=0;
187         bulkaddrs m_addrs;
188         ListAddrByAttributes m_attrs;
189         afs_int32 m_nentries;
190
191         m_attrs.Mask = VLADDR_IPADDR;
192         m_attrs.ipaddr = nentryp->serverNumber[i];
193         m_nentries = 0;
194         m_addrs.bulkaddrs_val = 0;
195         m_addrs.bulkaddrs_len = 0;
196         vcode =
197             ubik_VL_GetAddrsU(cstruct, 0, &m_attrs,
198                                &uentryp->serverNumber[i],
199                                &m_uniq, &m_nentries,
200                                &m_addrs);
201         uentryp->serverUnique[i] = nentryp->serverNumber[i];
202         uentryp->serverPartition[i] = nentryp->serverPartition[i];
203         uentryp->serverFlags[i] = nentryp->serverFlags[i];
204     }
205     uentryp->nServers = nentryp->nServers;
206     for (i = 0; i < MAXTYPES; i++)
207         uentryp->volumeId[i] = nentryp->volumeId[i];
208     uentryp->cloneId = nentryp->cloneId;
209     uentryp->flags = nentryp->flags;
210     uentryp->matchindex = nentryp->matchindex;
211 }
212
213 int
214 uvlentry_to_nvlentry(struct uvldbentry *uentryp,
215                      struct nvldbentry *nentryp)
216 {
217     int i;
218
219     memset(nentryp, 0, sizeof(struct vldbentry));
220     strncpy(nentryp->name, uentryp->name, sizeof(nentryp->name));
221     if (uentryp->nServers > NMAXNSERVERS) {
222         /*
223          * The alternative is to store NMAXSERVERS but it's always better
224          * to know what's going on...
225          */
226         return VL_BADSERVER;
227     }
228     for (i = 0; i < uentryp->nServers; i++) {
229         nentryp->serverNumber[i] = uentryp->serverUnique[i];
230         nentryp->serverPartition[i] = uentryp->serverPartition[i];
231         nentryp->serverFlags[i] = uentryp->serverFlags[i];
232     }
233     nentryp->nServers = i;
234     for (i = 0; i < MAXTYPES; i++)
235         nentryp->volumeId[i] = uentryp->volumeId[i];
236     nentryp->cloneId = uentryp->cloneId;
237     nentryp->flags = uentryp->flags;
238     nentryp->matchindex = uentryp->matchindex;
239     return 0;
240 }
241
242 enum _vlserver_type {
243     vltype_unknown = 0,
244     vltype_old = 1,
245     vltype_new = 2,
246     vltype_uuid = 3
247 };
248
249 static enum _vlserver_type newvlserver = vltype_unknown;
250
251 int
252 VLDB_CreateEntry(struct nvldbentry *entryp)
253 {
254     int code;
255     struct uvldbentry uentry;
256
257     nvlentry_to_uvlentry(entryp, &uentry);
258     code = VLDB_CreateEntryU(&uentry);
259     if (!code)
260         code = uvlentry_to_nvlentry(&uentry, entryp);
261     return code;
262 }
263
264 int
265 VLDB_CreateEntryU(struct uvldbentry *entryp)
266 {
267     struct nvldbentry nentry;
268     int code;
269
270     if (newvlserver == vltype_old) {
271         struct vldbentry oentry;
272       tryold:
273         code = uvlentry_to_ovlentry(entryp, &oentry);
274         if (code)
275             return code;
276         code = ubik_VL_CreateEntry(cstruct, 0, &oentry);
277         return code;
278     }
279
280     code = uvlentry_to_nvlentry(entryp, &nentry);
281     if (code)
282         return code;
283     code = ubik_VL_CreateEntryN(cstruct, 0, &nentry);
284     if (code == RXGEN_OPCODE) {
285         newvlserver = vltype_old;
286         goto tryold;
287     }
288     return code;
289 }
290
291 int
292 VLDB_GetEntryByID(afs_uint32 volid, afs_int32 voltype, struct nvldbentry *entryp)
293 {
294     int code;
295     struct uvldbentry uentry;
296
297     nvlentry_to_uvlentry(entryp, &uentry);
298     code = VLDB_GetEntryByIDU(volid, voltype, &uentry);
299     if (!code)
300         code = uvlentry_to_nvlentry(&uentry, entryp);
301     return code;
302 }
303
304 int
305 VLDB_GetEntryByIDU(afs_uint32 volid, afs_int32 voltype, struct uvldbentry *entryp)
306 {
307     struct nvldbentry nentry;
308     int code;
309
310     if (newvlserver == vltype_old) {
311         struct vldbentry oentry;
312       tryold:
313         code =
314             ubik_VL_GetEntryByID(cstruct, 0, volid, voltype, &oentry);
315         if (!code)
316             ovlentry_to_uvlentry(&oentry, entryp);
317         return code;
318     }
319
320     code = ubik_VL_GetEntryByIDN(cstruct, 0, volid, voltype, &nentry);
321     if (code == RXGEN_OPCODE) {
322         newvlserver = vltype_old;
323         goto tryold;
324     }
325     if (!code)
326         nvlentry_to_uvlentry(&nentry, entryp);
327     return code;
328 }
329
330 int
331 VLDB_GetEntryByName(char *namep, struct nvldbentry *entryp)
332 {
333     int code;
334     struct uvldbentry uentry;
335
336     nvlentry_to_uvlentry(entryp, &uentry);
337     code = VLDB_GetEntryByNameU(namep, &uentry);
338     if (!code)
339         code = uvlentry_to_nvlentry(&uentry, entryp);
340     return code;
341 }
342
343 int
344 VLDB_GetEntryByNameU(char *namep, struct uvldbentry *entryp)
345 {
346     int code;
347
348     if (newvlserver == vltype_old) {
349         struct vldbentry oentry;
350       tryold:
351         code = ubik_VL_GetEntryByNameO(cstruct, 0, namep, &oentry);
352         if (!code)
353             ovlentry_to_uvlentry(&oentry, entryp);
354         return code;
355     }
356     if (newvlserver == vltype_new) {
357         struct nvldbentry nentry;
358       trynew:
359         code = ubik_VL_GetEntryByNameN(cstruct, 0, namep, &nentry);
360         if (code == RXGEN_OPCODE) {
361             newvlserver = vltype_old;
362             goto tryold;
363         }
364         if (!code)
365             nvlentry_to_uvlentry(&nentry, entryp);
366     }
367     code = ubik_VL_GetEntryByNameU(cstruct, 0, namep, entryp);
368     if (newvlserver == vltype_unknown) {
369         if (code == RXGEN_OPCODE) {
370             newvlserver = vltype_new;
371             goto trynew;
372         } else if (!code) {
373             newvlserver = vltype_uuid;
374         }
375     }
376     return code;
377 }
378
379 int
380 VLDB_ReplaceEntry(afs_uint32 volid, afs_int32 voltype, struct nvldbentry *nentryp, afs_int32 releasetype)
381 {
382     struct uvldbentry uentry;
383     int code;
384
385     nvlentry_to_uvlentry(nentryp, &uentry);
386     code = VLDB_ReplaceEntryU(volid, voltype, &uentry, releasetype);
387     if (!code)
388         code = uvlentry_to_nvlentry(&uentry, nentryp);
389
390     return code;
391 }
392
393 int
394 VLDB_ReplaceEntryU(afs_uint32 volid, afs_int32 voltype, struct uvldbentry *entryp, afs_int32 releasetype)
395 {
396     int code;
397     struct nvldbentry nentry;
398
399     if (newvlserver == vltype_old) {
400         struct vldbentry oentry;
401       tryold:
402         code = uvlentry_to_ovlentry(entryp, &oentry);
403         if (code)
404             return code;
405         code =
406             ubik_VL_ReplaceEntry(cstruct, 0, volid, voltype, &oentry, releasetype);
407         return code;
408     }
409     code = uvlentry_to_nvlentry(entryp, &nentry);
410     if (code)
411         return code;
412     code = ubik_VL_ReplaceEntryN(cstruct, 0, volid, voltype, &nentry, releasetype);
413     if (code == RXGEN_OPCODE) {
414         newvlserver = vltype_old;
415             goto tryold;
416     }
417     return code;
418 }
419
420 static void
421 convertBulkToNBulk(bulkentries *bulk, nbulkentries *nbulk) {
422     int i;
423
424     if (bulk->bulkentries_len == 0)
425         return;
426
427     nbulk->nbulkentries_len = bulk->bulkentries_len;
428     nbulk->nbulkentries_val =
429         xdr_alloc(bulk->bulkentries_len * sizeof(struct nvldbentry));
430
431     for (i = 0; i < bulk->bulkentries_len; i++) {
432         ovlentry_to_nvlentry(&bulk->bulkentries_val[i],
433                              &nbulk->nbulkentries_val[i]);
434     }
435 }
436
437 static void
438 convertBulkToUBulk(bulkentries *bulk, ubulkentries *ubulk) {
439     int i;
440
441     if (bulk->bulkentries_len == 0)
442         return;
443
444     ubulk->ubulkentries_len = bulk->bulkentries_len;
445     ubulk->ubulkentries_val =
446         xdr_alloc(bulk->bulkentries_len * sizeof(struct uvldbentry));
447     for (i = 0; i < bulk->bulkentries_len; i++) {
448         ovlentry_to_uvlentry(&bulk->bulkentries_val[i],
449                              &ubulk->ubulkentries_val[i]);
450     }
451 }
452
453 static void
454 convertNBulkToUBulk(nbulkentries *nbulk, ubulkentries *ubulk) {
455     int i;
456
457     if (nbulk->nbulkentries_len == 0)
458         return;
459
460     ubulk->ubulkentries_len = nbulk->nbulkentries_len;
461     ubulk->ubulkentries_val =
462         xdr_alloc(nbulk->nbulkentries_len * sizeof(struct uvldbentry));
463     for (i = 0; i < nbulk->nbulkentries_len; i++) {     /* process each entry */
464         nvlentry_to_uvlentry(&nbulk->nbulkentries_val[i],
465                              &ubulk->ubulkentries_val[i]);
466     }
467 }
468
469 int
470 VLDB_ListAttributes(VldbListByAttributes *attrp,
471                     afs_int32 *entriesp,
472                     nbulkentries *blkentriesp)
473 {
474     int code;
475
476     if (newvlserver == vltype_old) {
477         bulkentries arrayEntries;
478       tryold:
479         memset(&arrayEntries, 0, sizeof(arrayEntries));
480         code =
481             ubik_VL_ListAttributes(cstruct, 0, attrp, entriesp,
482                       &arrayEntries);
483
484         if (code)
485             return code;
486
487         /* Ensure the number of entries claimed matches the no. returned */
488         if (*entriesp < 0)
489             *entriesp = 0;
490         if (*entriesp > arrayEntries.bulkentries_len)
491             *entriesp = arrayEntries.bulkentries_len;
492
493         convertBulkToNBulk(&arrayEntries, blkentriesp);
494
495         xdr_free((xdrproc_t) xdr_bulkentries, &arrayEntries);
496         return code;
497     }
498
499     code =
500         ubik_VL_ListAttributesN(cstruct, 0, attrp, entriesp, blkentriesp);
501     if (code == RXGEN_OPCODE) {
502         newvlserver = vltype_old;       /* Doesn't support new interface */
503         goto tryold;
504     }
505
506     if (code)
507         return code;
508
509     /* Ensure the number of entries claimed matches the no. returned */
510     if (*entriesp < 0)
511         *entriesp = 0;
512     if (*entriesp > blkentriesp->nbulkentries_len)
513         *entriesp = blkentriesp->nbulkentries_len;
514
515     return code;
516 }
517
518 int
519 VLDB_ListAttributesU(VldbListByAttributes *attrp,
520                     afs_int32 *entriesp,
521                     ubulkentries *blkentriesp)
522 {
523     nbulkentries narrayEntries;
524     int code;
525
526     if (newvlserver == vltype_old) {
527         bulkentries arrayEntries;
528       tryold:
529         memset(&arrayEntries, 0, sizeof(arrayEntries));
530         code =
531             ubik_VL_ListAttributes(cstruct, 0, attrp, entriesp,
532                       &arrayEntries);
533         if (code)
534             return code;
535
536         /* Ensure the number of entries claimed matches the no. returned */
537         if (*entriesp < 0)
538             *entriesp = 0;
539         if (*entriesp > arrayEntries.bulkentries_len)
540             *entriesp = arrayEntries.bulkentries_len;
541
542         convertBulkToUBulk(&arrayEntries, blkentriesp);
543
544         xdr_free((xdrproc_t) xdr_bulkentries, &arrayEntries);
545         return code;
546     }
547
548     memset(&narrayEntries, 0, sizeof(narrayEntries));
549     code =
550         ubik_VL_ListAttributesN(cstruct, 0, attrp, entriesp, &narrayEntries);
551     if (code == RXGEN_OPCODE) {
552         newvlserver = vltype_old;       /* Doesn't support new interface */
553         goto tryold;
554     }
555     if (code)
556         return code;
557
558     /* Ensure the number of entries claimed matches the no. returned */
559     if (*entriesp < 0)
560         *entriesp = 0;
561     if (*entriesp > narrayEntries.nbulkentries_len)
562         *entriesp = narrayEntries.nbulkentries_len;
563
564     convertNBulkToUBulk(&narrayEntries, blkentriesp);
565
566     xdr_free((xdrproc_t) xdr_bulkentries, &narrayEntries);
567     return code;
568 }
569
570 int
571 VLDB_ListAttributesN2(VldbListByAttributes *attrp,
572                       char *name,
573                       afs_int32 thisindex,
574                       afs_int32 *nentriesp,
575                       nbulkentries *blkentriesp,
576                       afs_int32 *nextindexp)
577 {
578     afs_int32 code = RXGEN_OPCODE;
579
580     if (newvlserver != vltype_old) {
581         code =
582             ubik_VL_ListAttributesN2(cstruct, 0, attrp, (name ? name : ""),
583                                      thisindex, nentriesp, blkentriesp, nextindexp);
584         if (code)
585             return code;
586
587         /* Ensure the number of entries claimed matches the no. returned */
588         if (*nentriesp < 0)
589             *nentriesp = 0;
590         if (*nentriesp > blkentriesp->nbulkentries_len)
591             *nentriesp = blkentriesp->nbulkentries_len;
592     }
593     return code;
594 }
595
596 int
597 VLDB_ListAttributesN2U(VldbListByAttributes *attrp,
598                       char *name,
599                       afs_int32 thisindex,
600                       afs_int32 *nentriesp,
601                       ubulkentries *blkentriesp,
602                       afs_int32 *nextindexp)
603 {
604     afs_int32 code = RXGEN_OPCODE;
605
606     if (newvlserver != vltype_old) {
607         nbulkentries narrayEntries;
608
609         memset(&narrayEntries, 0, sizeof(narrayEntries));       /*initialize to hint the stub  to alloc space */
610         code =
611             ubik_VL_ListAttributesN2(cstruct, 0, attrp, (name ? name : ""),
612                                      thisindex, nentriesp, &narrayEntries, nextindexp);
613         if (code)
614             return code;
615
616         /* Ensure the number of entries claimed matches the no. returned */
617         if (*nentriesp < 0)
618             *nentriesp = 0;
619         if (*nentriesp > narrayEntries.nbulkentries_len)
620             *nentriesp = narrayEntries.nbulkentries_len;
621
622         convertNBulkToUBulk(&narrayEntries, blkentriesp);
623
624         xdr_free((xdrproc_t) xdr_bulkentries, &narrayEntries);
625         return code;
626     }
627     return code;
628 }
629
630
631 struct cacheips {
632     afs_uint32 server;
633     afs_int32 count;
634     afs_uint32 addrs[16];
635 };
636 /*
637  * Increase cache size.  This avoids high CPU usage by the vlserver
638  * in environments where there are more than 16 fileservers in the
639  * cell.
640  */
641 #define GETADDRUCACHESIZE             64
642 struct cacheips cacheips[GETADDRUCACHESIZE];
643 int cacheip_index = 0;
644
645 int
646 VLDB_IsSameAddrs(afs_uint32 serv1, afs_uint32 serv2, afs_int32 *errorp)
647 {
648     int code;
649     ListAddrByAttributes attrs;
650     bulkaddrs addrs;
651     afs_uint32 *addrp, f1, f2;
652     afs_int32 i, j, unique, nentries;
653     afsUUID uuid;
654     static int initcache = 0;
655
656     *errorp = 0;
657
658     if (serv1 == serv2)
659         return 1;
660     if (newvlserver == vltype_old ||
661         newvlserver == vltype_new) {
662         return 0;
663     }
664     if (!initcache) {
665         for (i = 0; i < GETADDRUCACHESIZE; i++) {
666             cacheips[i].server = cacheips[i].count = 0;
667         }
668         initcache = 1;
669     }
670
671     /* See if it's cached */
672     for (i = 0; i < GETADDRUCACHESIZE; i++) {
673         f1 = f2 = 0;
674         for (j = 0; j < cacheips[i].count; j++) {
675             if (serv1 == cacheips[i].addrs[j])
676                 f1 = 1;
677             else if (serv2 == cacheips[i].addrs[j])
678                 f2 = 1;
679
680             if (f1 && f2)
681                 return 1;
682         }
683         if (f1 || f2)
684             return 0;
685         if (cacheips[i].server == serv1)
686             return 0;
687     }
688
689     memset(&attrs, 0, sizeof(attrs));
690     attrs.Mask = VLADDR_IPADDR;
691     attrs.ipaddr = serv1;
692     memset(&addrs, 0, sizeof(addrs));
693     memset(&uuid, 0, sizeof(uuid));
694     code =
695         ubik_VL_GetAddrsU(cstruct, 0, &attrs, &uuid, &unique, &nentries,
696                   &addrs);
697     if (newvlserver == vltype_unknown) {
698         if (code == RXGEN_OPCODE) {
699             newvlserver = vltype_new;
700             return 0;
701         } else if (!code) {
702             newvlserver = vltype_uuid;
703         }
704     }
705     if (code == VL_NOENT)
706         return 0;
707     if (code) {
708         *errorp = code;
709         return 0;
710     }
711
712     code = 0;
713     if (nentries > GETADDRUCACHESIZE)
714         nentries = GETADDRUCACHESIZE;   /* safety check; should not happen */
715     if (++cacheip_index >= GETADDRUCACHESIZE)
716         cacheip_index = 0;
717     cacheips[cacheip_index].server = serv1;
718     cacheips[cacheip_index].count = nentries;
719     addrp = addrs.bulkaddrs_val;
720     for (i = 0; i < nentries; i++, addrp++) {
721         cacheips[cacheip_index].addrs[i] = *addrp;
722         if (serv2 == *addrp) {
723             code = 1;
724         }
725     }
726     return code;
727 }
728
729
730 /*
731   Set encryption.  If 'cryptflag' is nonzero, encrpytion is turned on
732   for authenticated connections; if zero, encryption is turned off.
733   Calling this function always results in a level of at least rxkad_auth;
734   to get a rxkad_clear connection, simply don't call this.
735 */
736 void
737 vsu_SetCrypt(int cryptflag)
738 {
739     if (cryptflag) {
740         vsu_rxkad_level = rxkad_crypt;
741     } else {
742         vsu_rxkad_level = rxkad_auth;
743     }
744 }
745
746
747 /*
748   Get the appropriate type of ubik client structure out from the system.
749 */
750 afs_int32
751 vsu_ClientInit(int noAuthFlag, const char *confDir, char *cellName, afs_int32 sauth,
752                struct ubik_client **uclientp,
753                int (*secproc)(struct rx_securityClass *, afs_int32))
754 {
755     return ugen_ClientInit(noAuthFlag, confDir, cellName, sauth, uclientp,
756                            secproc, "vsu_ClientInit", vsu_rxkad_level,
757                            VLDB_MAXSERVERS, AFSCONF_VLDBSERVICE, 90,
758                            0, 0, USER_SERVICE_ID);
759 }
760
761
762 /*extract the name of volume <name> without readonly or backup suffixes
763  * and return the result as <rname>.
764  */
765 int
766 vsu_ExtractName(char rname[], char name[])
767 {
768     char sname[VOLSER_OLDMAXVOLNAME + 1];
769     size_t total;
770
771     strncpy(sname, name, sizeof(sname));
772     sname[sizeof(sname) - 1] = '\0';
773     total = strlen(sname);
774     if (!strcmp(&sname[total - 9], ".readonly")) {
775         /*discard the last 8 chars */
776         sname[total - 9] = '\0';
777         strcpy(rname, sname);
778         return 0;
779     } else if (!strcmp(&sname[total - 7], ".backup")) {
780         /*discard last 6 chars */
781         sname[total - 7] = '\0';
782         strcpy(rname, sname);
783         return 0;
784     } else {
785         strncpy(rname, name, VOLSER_OLDMAXVOLNAME);
786         rname[VOLSER_OLDMAXVOLNAME] = '\0';
787         return -1;
788     }
789 }
790
791 /* returns 0 if failed */
792 afs_uint32
793 vsu_GetVolumeID(char *astring, struct ubik_client *acstruct, afs_int32 *errp)
794 {
795     char volname[VOLSER_OLDMAXVOLNAME + 1];
796     struct uvldbentry entry;
797     afs_int32 vcode = 0;
798     size_t total;
799
800     *errp = 0;
801
802     if (isdigit(astring[0])) {
803         char *end;
804         afs_uint32 result;
805         result = strtoul(astring, &end, 10);
806         if (result != UINT_MAX && *end == '\0')
807             return result;
808     }
809
810     /* It was not a volume number but something else */
811     total = strlen(astring);
812     vsu_ExtractName(volname, astring);
813     vcode = VLDB_GetEntryByNameU(volname, &entry);
814     if (!vcode) {
815       if ((total >= 9) && (!strcmp(&astring[total - 9], ".readonly")))
816         return entry.volumeId[ROVOL];
817       else if ((total >= 7) && (!strcmp(&astring[total - 7], ".backup")))
818         return entry.volumeId[BACKVOL];
819       else
820         return (entry.volumeId[RWVOL]);
821     }
822     *errp = vcode;
823     return 0;           /* can't find volume */
824 }