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