cb61fef5e5d6909b19d2c330f6b547aff47790eb
[openafs.git] / src / vlserver / vlprocs.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 <sys/types.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <lock.h>
19 #include <afs/afsutil.h>
20 #include <ubik.h>
21 #include <rx/xdr.h>
22 #include <rx/rx.h>
23 #include <rx/rxkad.h>
24 #ifdef AFS_NT40_ENV
25 #include <winsock2.h>
26 #else
27 #include <netinet/in.h>
28 #endif
29 #include <afs/keys.h>
30 #include <afs/cellconfig.h>
31 #include "vlserver.h"
32 #include "vlserver_internal.h"
33 #include "afs/audit.h"
34 #ifndef AFS_NT40_ENV
35 #include <unistd.h>
36 #endif
37 #ifdef HAVE_POSIX_REGEX         /* use POSIX regexp library */
38 #include <regex.h>
39 #endif
40
41 extern int smallMem;
42 extern int extent_mod;
43 extern struct afsconf_dir *vldb_confdir;
44 extern struct ubik_dbase *VL_dbase;
45 int maxnservers;
46 #define ABORT(c) { errorcode = (c); goto abort; }
47 #undef END
48 #define END(c) { errorcode = (c); goto end; }
49
50 #define VLDBALLOCLIMIT  10000
51 #define VLDBALLOCINCR   2048
52
53 static int put_attributeentry(struct vl_ctx *ctx,
54                               struct vldbentry **, struct vldbentry **,
55                               struct vldbentry **, bulkentries *,
56                               struct nvlentry *, afs_int32 *, afs_int32 *);
57 static int put_nattributeentry(struct vl_ctx *ctx,
58                                struct nvldbentry **, struct nvldbentry **,
59                                struct nvldbentry **, nbulkentries *,
60                                struct nvlentry *, afs_int32, afs_int32,
61                                afs_int32 *, afs_int32 *);
62 static int RemoveEntry(struct vl_ctx *ctx, afs_int32 entryptr,
63                        struct nvlentry *tentry);
64 static void ReleaseEntry(struct nvlentry *tentry, afs_int32 releasetype);
65 static int check_vldbentry(struct vldbentry *aentry);
66 static int check_nvldbentry(struct nvldbentry *aentry);
67 static int vldbentry_to_vlentry(struct vl_ctx *ctx,
68                                 struct vldbentry *VldbEntry,
69                                 struct nvlentry *VlEntry);
70 static int nvldbentry_to_vlentry(struct vl_ctx *ctx,
71                                  struct nvldbentry *VldbEntry,
72                                  struct nvlentry *VlEntry);
73 static int get_vldbupdateentry(struct vl_ctx *ctx, afs_int32 blockindex,
74                                struct VldbUpdateEntry *updateentry,
75                                struct nvlentry *VlEntry);
76 static int repsite_exists(struct nvlentry *VlEntry, int server, int partition);
77 static void repsite_compress(struct nvlentry *VlEntry, int offset);
78 static void vlentry_to_vldbentry(struct vl_ctx *ctx,
79                                  struct nvlentry *VlEntry,
80                                  struct vldbentry *VldbEntry);
81 static void vlentry_to_nvldbentry(struct vl_ctx *ctx,
82                                   struct nvlentry *VlEntry,
83                                   struct nvldbentry *VldbEntry);
84 static void vlentry_to_uvldbentry(struct vl_ctx *ctx,
85                                   struct nvlentry *VlEntry,
86                                   struct uvldbentry *VldbEntry);
87 static int InvalidVolname(char *volname);
88 static int InvalidVoltype(afs_int32 voltype);
89 static int InvalidOperation(afs_int32 voloper);
90 static int InvalidReleasetype(afs_int32 releasetype);
91 static int IpAddrToRelAddr(struct vl_ctx *ctx, afs_uint32 ipaddr, int create);
92 static int ChangeIPAddr(struct vl_ctx *ctx, afs_uint32 ipaddr1,
93                         afs_uint32 ipaddr2);
94
95 #define AFS_RXINFO_LEN 128
96 static char *
97 rxinfo(char * str, struct rx_call *rxcall)
98 {
99     int code;
100     struct rx_connection *tconn;
101     char tname[64] = "";
102     char tinst[64] = "";
103     char tcell[64] = "";
104     afs_uint32 exp;
105     struct in_addr hostAddr;
106
107     tconn = rx_ConnectionOf(rxcall);
108     hostAddr.s_addr = rx_HostOf(rx_PeerOf(tconn));
109     code =
110         rxkad_GetServerInfo(rxcall->conn, NULL, &exp, tname, tinst, tcell,
111                             NULL);
112     if (!code)
113         sprintf(str, "%s %s%s%s%s%s", inet_ntoa(hostAddr), tname,
114                 (tinst[0] == '\0') ? "" : ".",
115                 (tinst[0] == '\0') ? "" : tinst,
116                 (tcell[0] == '\0') ? "" : "@",
117                 (tcell[0] == '\0') ? "" : tcell);
118     else
119         sprintf(str, "%s noauth", inet_ntoa(hostAddr));
120     return (str);
121 }
122
123 /* This is called to initialize the database, set the appropriate locks and make sure that the vldb header is valid */
124 int
125 Init_VLdbase(struct vl_ctx *ctx,
126              int locktype,      /* indicate read or write transaction */
127              int this_op)
128 {
129     int errorcode = 0, pass, wl;
130
131     for (pass = 1; pass <= 3; pass++) {
132         if (pass == 2) {        /* take write lock to rebuild the db */
133             errorcode = ubik_BeginTrans(VL_dbase, UBIK_WRITETRANS, &ctx->trans);
134             wl = 1;
135         } else if (locktype == LOCKREAD) {
136             errorcode =
137                 ubik_BeginTransReadAnyWrite(VL_dbase, UBIK_READTRANS, &ctx->trans);
138             wl = 0;
139         } else {
140             errorcode = ubik_BeginTrans(VL_dbase, UBIK_WRITETRANS, &ctx->trans);
141             wl = 1;
142         }
143         if (errorcode)
144             return errorcode;
145
146         errorcode = ubik_SetLock(ctx->trans, 1, 1, locktype);
147         if (errorcode) {
148             COUNT_ABO;
149             ubik_AbortTrans(ctx->trans);
150             return errorcode;
151         }
152
153         /* check that dbase is initialized and setup cheader */
154         /* 2nd pass we try to rebuild the header */
155         errorcode = CheckInit(ctx->trans, ((pass == 2) ? 1 : 0));
156         if (!errorcode && wl && extent_mod)
157             errorcode = readExtents(ctx->trans);        /* Fix the mh extent blocks */
158         if (errorcode) {
159             COUNT_ABO;
160             ubik_AbortTrans(ctx->trans);
161             /* Only rebuld if the database is empty */
162             /* Exit if can't rebuild */
163             if ((pass == 1) && (errorcode != VL_EMPTY))
164                 return errorcode;
165             if (pass == 2)
166                 return errorcode;
167         } else {                /* No errorcode */
168             if (pass == 2) {
169                 ubik_EndTrans(ctx->trans);      /* Rebuilt db. End trans, then retake original lock */
170             } else {
171                 break;          /* didn't rebuild and successful - exit */
172             }
173         }
174     }
175     if (errorcode == 0) {
176         errorcode = vlsetcache(ctx, locktype);
177     }
178     return errorcode;
179 }
180
181
182 /* Create a new vldb entry; both new volume id and name must be unique
183  * (non-existant in vldb).
184  */
185
186 afs_int32
187 SVL_CreateEntry(struct rx_call *rxcall, struct vldbentry *newentry)
188 {
189     struct vl_ctx ctx;
190     afs_int32 errorcode, blockindex;
191     struct nvlentry tentry;
192     char rxstr[AFS_RXINFO_LEN];
193
194     COUNT_REQ(VLCREATEENTRY);
195     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL)) {
196         errorcode = VL_PERM;
197         goto end;
198     }
199
200     /* Do some validity tests on new entry */
201     if ((errorcode = check_vldbentry(newentry))
202         || (errorcode = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
203         goto end;
204
205     VLog(1,
206          ("OCreate Volume %d %s\n", newentry->volumeId[RWVOL],
207           rxinfo(rxstr, rxcall)));
208     if (EntryIDExists(&ctx, newentry->volumeId, MAXTYPES, &errorcode)) {
209         /* at least one of the specified IDs already exists; we fail */
210         errorcode = VL_IDEXIST;
211         goto abort;
212     } else if (errorcode) {
213         goto abort;
214     }
215
216     /* Is this following check (by volume name) necessary?? */
217     /* If entry already exists, we fail */
218     if (FindByName(&ctx, newentry->name, &tentry, &errorcode)) {
219         errorcode = VL_NAMEEXIST;
220         goto abort;
221     } else if (errorcode) {
222         goto abort;
223     }
224
225     blockindex = AllocBlock(&ctx, &tentry);
226     if (blockindex == 0) {
227         errorcode = VL_CREATEFAIL;
228         goto abort;
229     }
230
231     memset(&tentry, 0, sizeof(struct nvlentry));
232     /* Convert to its internal representation; both in host byte order */
233     if ((errorcode = vldbentry_to_vlentry(&ctx, newentry, &tentry))) {
234         FreeBlock(&ctx, blockindex);
235         goto abort;
236     }
237
238     /* Actually insert the entry in vldb */
239     errorcode = ThreadVLentry(&ctx, blockindex, &tentry);
240     if (errorcode) {
241         FreeBlock(&ctx, blockindex);
242         goto abort;
243     } else {
244         errorcode = ubik_EndTrans(ctx.trans);
245         goto end;
246     }
247
248   abort:
249     COUNT_ABO;
250     ubik_AbortTrans(ctx.trans);
251
252   end:
253     osi_auditU(rxcall, VLCreateEntryEvent, errorcode, AUD_STR,
254                (newentry ? newentry->name : NULL), AUD_END);
255     return errorcode;
256 }
257
258
259 afs_int32
260 SVL_CreateEntryN(struct rx_call *rxcall, struct nvldbentry *newentry)
261 {
262     struct vl_ctx ctx;
263     afs_int32 errorcode, blockindex;
264     struct nvlentry tentry;
265     char rxstr[AFS_RXINFO_LEN];
266
267     COUNT_REQ(VLCREATEENTRYN);
268     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL)) {
269         errorcode = VL_PERM;
270         goto end;
271     }
272
273     /* Do some validity tests on new entry */
274     if ((errorcode = check_nvldbentry(newentry))
275         || (errorcode = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
276         goto end;
277
278     VLog(1,
279          ("Create Volume %d %s\n", newentry->volumeId[RWVOL],
280           rxinfo(rxstr, rxcall)));
281     if (EntryIDExists(&ctx, newentry->volumeId, MAXTYPES, &errorcode)) {
282         /* at least one of the specified IDs already exists; we fail */
283         errorcode = VL_IDEXIST;
284         goto abort;
285     } else if (errorcode) {
286         goto abort;
287     }
288
289     /* Is this following check (by volume name) necessary?? */
290     /* If entry already exists, we fail */
291     if (FindByName(&ctx, newentry->name, &tentry, &errorcode)) {
292         errorcode = VL_NAMEEXIST;
293         goto abort;
294     } else if (errorcode) {
295         goto abort;
296     }
297
298     blockindex = AllocBlock(&ctx, &tentry);
299     if (blockindex == 0) {
300         errorcode = VL_CREATEFAIL;
301         goto abort;
302     }
303
304     memset(&tentry, 0, sizeof(struct nvlentry));
305     /* Convert to its internal representation; both in host byte order */
306     if ((errorcode = nvldbentry_to_vlentry(&ctx, newentry, &tentry))) {
307         FreeBlock(&ctx, blockindex);
308         goto abort;
309     }
310
311     /* Actually insert the entry in vldb */
312     errorcode = ThreadVLentry(&ctx, blockindex, &tentry);
313     if (errorcode) {
314         FreeBlock(&ctx, blockindex);
315         goto abort;
316     } else {
317         errorcode = ubik_EndTrans(ctx.trans);
318         goto end;
319     }
320
321   abort:
322     COUNT_ABO;
323     ubik_AbortTrans(ctx.trans);
324
325   end:
326     osi_auditU(rxcall, VLCreateEntryEvent, errorcode, AUD_STR,
327                (newentry ? newentry->name : NULL), AUD_END);
328     return errorcode;
329 }
330
331
332 afs_int32
333 SVL_ChangeAddr(struct rx_call *rxcall, afs_uint32 ip1, afs_uint32 ip2)
334 {
335     struct vl_ctx ctx;
336     afs_int32 errorcode;
337     char rxstr[AFS_RXINFO_LEN];
338
339     COUNT_REQ(VLCHANGEADDR);
340     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL)) {
341         errorcode = VL_PERM;
342         goto end;
343     }
344
345     if ((errorcode = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
346         goto end;
347
348     VLog(1, ("Change Addr %u -> %u %s\n", ip1, ip2, rxinfo(rxstr, rxcall)));
349     if ((errorcode = ChangeIPAddr(&ctx, ip1, ip2)))
350         goto abort;
351     else {
352         errorcode = ubik_EndTrans(ctx.trans);
353         goto end;
354     }
355
356   abort:
357     COUNT_ABO;
358     ubik_AbortTrans(ctx.trans);
359
360   end:
361     osi_auditU(rxcall, VLChangeAddrEvent, errorcode, AUD_LONG, ip1, AUD_LONG,
362                ip2, AUD_END);
363     return errorcode;
364 }
365
366 /* Delete a vldb entry given the volume id. */
367 afs_int32
368 SVL_DeleteEntry(struct rx_call *rxcall, afs_uint32 volid, afs_int32 voltype)
369 {
370     struct vl_ctx ctx;
371     afs_int32 blockindex, errorcode;
372     struct nvlentry tentry;
373     char rxstr[AFS_RXINFO_LEN];
374
375     COUNT_REQ(VLDELETEENTRY);
376     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL))
377         END(VL_PERM);
378
379     if ((voltype != -1) && (InvalidVoltype(voltype)))
380         END(VL_BADVOLTYPE);
381
382     if ((errorcode = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
383         goto end;
384
385     VLog(1, ("Delete Volume %u %s\n", volid, rxinfo(rxstr, rxcall)));
386     blockindex = FindByID(&ctx, volid, voltype, &tentry, &errorcode);
387     if (blockindex == 0) {      /* volid not found */
388         if (!errorcode)
389             errorcode = VL_NOENT;
390         goto abort;
391     }
392
393     if (tentry.flags & VLDELETED) {     /* Already deleted; return */
394         ABORT(VL_ENTDELETED);
395     }
396     if ((errorcode = RemoveEntry(&ctx, blockindex, &tentry))) {
397         goto abort;
398     }
399     errorcode = (ubik_EndTrans(ctx.trans));
400     goto end;
401
402   abort:
403     COUNT_ABO;
404     ubik_AbortTrans(ctx.trans);
405
406   end:
407     osi_auditU(rxcall, VLDeleteEntryEvent, errorcode, AUD_LONG, volid,
408                AUD_END);
409     return errorcode;
410 }
411
412
413 /* Get a vldb entry given its volume id; make sure it's not a deleted entry. */
414 int
415 GetEntryByID(struct rx_call *rxcall,
416              afs_uint32 volid,
417              afs_int32 voltype,
418              char *aentry,      /* entry data copied here */
419              afs_int32 new,
420              afs_int32 this_op)
421 {
422     struct vl_ctx ctx;
423     afs_int32 blockindex, errorcode;
424     struct nvlentry tentry;
425     char rxstr[AFS_RXINFO_LEN];
426
427     if ((voltype != -1) && (InvalidVoltype(voltype)))
428         return VL_BADVOLTYPE;
429     if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op)))
430         return errorcode;
431
432     VLog(5, ("GetVolumeByID %u (%d) %s\n", volid, new,
433              rxinfo(rxstr, rxcall)));
434     blockindex = FindByID(&ctx, volid, voltype, &tentry, &errorcode);
435     if (blockindex == 0) {      /* entry not found */
436         if (!errorcode)
437             errorcode = VL_NOENT;
438         COUNT_ABO;
439         ubik_AbortTrans(ctx.trans);
440         return errorcode;
441     }
442     if (tentry.flags & VLDELETED) {     /* Entry is deleted! */
443         COUNT_ABO;
444         ubik_AbortTrans(ctx.trans);
445         return VL_ENTDELETED;
446     }
447     /* Convert from the internal to external form */
448     if (new == 1)
449         vlentry_to_nvldbentry(&ctx, &tentry, (struct nvldbentry *)aentry);
450     else if (new == 2)
451         vlentry_to_uvldbentry(&ctx, &tentry, (struct uvldbentry *)aentry);
452     else
453         vlentry_to_vldbentry(&ctx, &tentry, (struct vldbentry *)aentry);
454     return (ubik_EndTrans(ctx.trans));
455 }
456
457 afs_int32
458 SVL_GetEntryByID(struct rx_call *rxcall,
459                  afs_uint32 volid,
460                  afs_int32 voltype,
461                  vldbentry *aentry)             /* entry data copied here */
462 {
463     COUNT_REQ(VLGETENTRYBYID);
464     return (GetEntryByID(rxcall, volid, voltype, (char *)aentry, 0, this_op));
465 }
466
467 afs_int32
468 SVL_GetEntryByIDN(struct rx_call *rxcall,
469                   afs_uint32 volid,
470                   afs_int32 voltype,
471                   nvldbentry *aentry)   /* entry data copied here */
472 {
473     COUNT_REQ(VLGETENTRYBYIDN);
474     return (GetEntryByID(rxcall, volid, voltype, (char *)aentry, 1, this_op));
475 }
476
477 afs_int32
478 SVL_GetEntryByIDU(struct rx_call *rxcall,
479                   afs_uint32 volid,
480                   afs_int32 voltype,
481                   uvldbentry *aentry)   /* entry data copied here */
482 {
483     COUNT_REQ(VLGETENTRYBYIDU);
484     return (GetEntryByID(rxcall, volid, voltype, (char *)aentry, 2, this_op));
485 }
486
487
488
489 /* returns true if the id is a decimal integer, in which case we interpret
490  * it as an id.  make the cache manager much simpler */
491 static int
492 NameIsId(char *aname)
493 {
494     int tc;
495     while ((tc = *aname++)) {
496         if (tc > '9' || tc < '0')
497             return 0;
498     }
499     return 1;
500 }
501
502 /* Get a vldb entry given the volume's name; of course, very similar to
503  * VLGetEntryByID() above. */
504 afs_int32
505 GetEntryByName(struct rx_call *rxcall,
506                char *volname,
507                char *aentry,            /* entry data copied here */
508                int new,
509                int this_op)
510 {
511     struct vl_ctx ctx;
512     afs_int32 blockindex, errorcode;
513     struct nvlentry tentry;
514     char rxstr[AFS_RXINFO_LEN];
515
516     if (NameIsId(volname)) {
517         return GetEntryByID(rxcall, atoi(volname), -1, aentry, new, this_op);
518     }
519     if (InvalidVolname(volname))
520         return VL_BADNAME;
521     if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op)))
522         return errorcode;
523     VLog(5, ("GetVolumeByName %s (%d) %s\n", volname, new, rxinfo(rxstr, rxcall)));
524     blockindex = FindByName(&ctx, volname, &tentry, &errorcode);
525     if (blockindex == 0) {      /* entry not found */
526         if (!errorcode)
527             errorcode = VL_NOENT;
528         COUNT_ABO;
529         ubik_AbortTrans(ctx.trans);
530         return errorcode;
531     }
532     if (tentry.flags & VLDELETED) {     /* Entry is deleted */
533         COUNT_ABO;
534         ubik_AbortTrans(ctx.trans);
535         return VL_ENTDELETED;
536     }
537     /* Convert to external entry representation */
538     if (new == 1)
539         vlentry_to_nvldbentry(&ctx, &tentry, (struct nvldbentry *)aentry);
540     else if (new == 2)
541         vlentry_to_uvldbentry(&ctx, &tentry, (struct uvldbentry *)aentry);
542     else
543         vlentry_to_vldbentry(&ctx, &tentry, (struct vldbentry *)aentry);
544     return (ubik_EndTrans(ctx.trans));
545 }
546
547 afs_int32
548 SVL_GetEntryByNameO(struct rx_call *rxcall,
549                     char *volname,
550                     struct vldbentry *aentry)   /* entry data copied here */
551 {
552     COUNT_REQ(VLGETENTRYBYNAME);
553     return (GetEntryByName(rxcall, volname, (char *)aentry, 0, this_op));
554 }
555
556
557 afs_int32
558 SVL_GetEntryByNameN(struct rx_call *rxcall,
559                     char *volname,
560                     struct nvldbentry *aentry)  /* entry data copied here */
561 {
562     COUNT_REQ(VLGETENTRYBYNAMEN);
563     return (GetEntryByName(rxcall, volname, (char *)aentry, 1, this_op));
564 }
565
566 afs_int32
567 SVL_GetEntryByNameU(struct rx_call *rxcall,
568                     char *volname,
569                     struct uvldbentry *aentry)  /* entry data copied here */
570 {
571     COUNT_REQ(VLGETENTRYBYNAMEU);
572     return (GetEntryByName(rxcall, volname, (char *)aentry, 2, this_op));
573 }
574
575
576
577 /* Get the current value of the maximum volume id and bump the volume id counter by Maxvolidbump. */
578 afs_int32
579 SVL_GetNewVolumeId(struct rx_call *rxcall, afs_uint32 Maxvolidbump,
580                    afs_uint32 *newvolumeid)
581 {
582     afs_int32 errorcode;
583     afs_uint32 maxvolumeid;
584     struct vl_ctx ctx;
585     char rxstr[AFS_RXINFO_LEN];
586
587     COUNT_REQ(VLGETNEWVOLUMEID);
588     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL))
589         END(VL_PERM);
590
591     if (Maxvolidbump < 0 || Maxvolidbump > MAXBUMPCOUNT)
592         END(VL_BADVOLIDBUMP);
593
594     if ((errorcode = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
595         goto end;
596
597     *newvolumeid = maxvolumeid = NextUnusedID(&ctx,
598         ntohl(ctx.cheader->vital_header.MaxVolumeId), Maxvolidbump, &errorcode);
599     if (errorcode) {
600         goto abort;
601     }
602
603     maxvolumeid += Maxvolidbump;
604     VLog(1, ("GetNewVolid newmax=%u %s\n", maxvolumeid, rxinfo(rxstr, rxcall)));
605     ctx.cheader->vital_header.MaxVolumeId = htonl(maxvolumeid);
606     if (write_vital_vlheader(&ctx)) {
607         ABORT(VL_IO);
608     }
609     errorcode = (ubik_EndTrans(ctx.trans));
610     goto end;
611
612   abort:
613     COUNT_ABO;
614     ubik_AbortTrans(ctx.trans);
615
616   end:
617     osi_auditU(rxcall, VLGetNewVolumeIdEvent, errorcode, AUD_END);
618     return errorcode;
619 }
620
621
622 /* Simple replace the contents of the vldb entry, volid, with
623  * newentry. No individual checking/updating per field (alike
624  * VLUpdateEntry) is done. */
625
626 afs_int32
627 SVL_ReplaceEntry(struct rx_call *rxcall, afs_uint32 volid, afs_int32 voltype,
628                  struct vldbentry *newentry, afs_int32 releasetype)
629 {
630     struct vl_ctx ctx;
631     afs_int32 blockindex, errorcode, typeindex;
632     int hashnewname;
633     int hashVol[MAXTYPES];
634     struct nvlentry tentry;
635     afs_uint32 checkids[MAXTYPES];
636     char rxstr[AFS_RXINFO_LEN];
637
638     COUNT_REQ(VLREPLACEENTRY);
639     for (typeindex = 0; typeindex < MAXTYPES; typeindex++)
640         hashVol[typeindex] = 0;
641     hashnewname = 0;
642     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL))
643         END(VL_PERM);
644
645     if ((errorcode = check_vldbentry(newentry)))
646         goto end;
647
648     if (voltype != -1 && InvalidVoltype(voltype))
649         END(VL_BADVOLTYPE);
650
651     if (releasetype && InvalidReleasetype(releasetype))
652         END(VL_BADRELLOCKTYPE);
653     if ((errorcode = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
654         goto end;
655
656     VLog(1, ("OReplace Volume %u %s\n", volid, rxinfo(rxstr, rxcall)));
657     /* find vlentry we're changing */
658     blockindex = FindByID(&ctx, volid, voltype, &tentry, &errorcode);
659     if (blockindex == 0) {      /* entry not found */
660         if (!errorcode)
661             errorcode = VL_NOENT;
662         goto abort;
663     }
664
665     /* check that we're not trying to change the RW vol ID */
666     if (newentry->volumeId[RWVOL] != tentry.volumeId[RWVOL]) {
667         ABORT(VL_BADENTRY);
668     }
669
670     /* make sure none of the IDs we are changing to are already in use */
671     memset(&checkids, 0, sizeof(checkids));
672     for (typeindex = ROVOL; typeindex < MAXTYPES; typeindex++) {
673         if (tentry.volumeId[typeindex] != newentry->volumeId[typeindex]) {
674             checkids[typeindex] = newentry->volumeId[typeindex];
675         }
676     }
677     if (EntryIDExists(&ctx, checkids, MAXTYPES, &errorcode)) {
678         ABORT(VL_IDEXIST);
679     } else if (errorcode) {
680         goto abort;
681     }
682
683     /* make sure the name we're changing to doesn't already exist */
684     if (strcmp(newentry->name, tentry.name)) {
685         struct nvlentry tmp_entry;
686         if (FindByName(&ctx, newentry->name, &tmp_entry, &errorcode)) {
687             ABORT(VL_NAMEEXIST);
688         } else if (errorcode) {
689             goto abort;
690         }
691     }
692
693     /* unhash volid entries if they're disappearing or changing.
694      * Remember if we need to hash in the new value (we don't have to
695      * rehash if volid stays same */
696     for (typeindex = ROVOL; typeindex <= BACKVOL; typeindex++) {
697         if (tentry.volumeId[typeindex] != newentry->volumeId[typeindex]) {
698             if (tentry.volumeId[typeindex])
699                 if ((errorcode =
700                     UnhashVolid(&ctx, typeindex, blockindex, &tentry))) {
701                     goto abort;
702                 }
703             /* we must rehash new id if the id is different and the ID is nonzero */
704             hashVol[typeindex] = 1;     /* must rehash this guy if he exists */
705         }
706     }
707
708     /* Rehash volname if it changes */
709     if (strcmp(newentry->name, tentry.name)) {  /* Name changes; redo hashing */
710         if ((errorcode = UnhashVolname(&ctx, blockindex, &tentry))) {
711             goto abort;
712         }
713         hashnewname = 1;
714     }
715
716     /* after this, tentry is new entry, not old one.  vldbentry_to_vlentry
717      * doesn't touch hash chains */
718     if ((errorcode = vldbentry_to_vlentry(&ctx, newentry, &tentry))) {
719         goto abort;
720     }
721
722     for (typeindex = ROVOL; typeindex <= BACKVOL; typeindex++) {
723         if (hashVol[typeindex] && tentry.volumeId[typeindex]) {
724             if ((errorcode = HashVolid(&ctx, typeindex, blockindex, &tentry))) {
725                 goto abort;
726             }
727         }
728     }
729
730     if (hashnewname)
731         HashVolname(&ctx, blockindex, &tentry);
732
733     if (releasetype)
734         ReleaseEntry(&tentry, releasetype);     /* Unlock entry if necessary */
735     if (vlentrywrite(ctx.trans, blockindex, &tentry, sizeof(tentry))) {
736         ABORT(VL_IO);
737     }
738
739     END(ubik_EndTrans(ctx.trans));
740
741   abort:
742     COUNT_ABO;
743     ubik_AbortTrans(ctx.trans);
744
745   end:
746     osi_auditU(rxcall, VLReplaceVLEntryEvent, errorcode, AUD_LONG, volid,
747                AUD_END);
748     return errorcode;
749 }
750
751 afs_int32
752 SVL_ReplaceEntryN(struct rx_call *rxcall, afs_uint32 volid, afs_int32 voltype,
753                   struct nvldbentry *newentry, afs_int32 releasetype)
754 {
755     struct vl_ctx ctx;
756     afs_int32 blockindex, errorcode, typeindex;
757     int hashnewname;
758     int hashVol[MAXTYPES];
759     struct nvlentry tentry;
760     char rxstr[AFS_RXINFO_LEN];
761
762     COUNT_REQ(VLREPLACEENTRYN);
763     for (typeindex = 0; typeindex < MAXTYPES; typeindex++)
764         hashVol[typeindex] = 0;
765     hashnewname = 0;
766     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL))
767         END(VL_PERM);
768
769     if ((errorcode = check_nvldbentry(newentry)))
770         goto end;
771
772     if (voltype != -1 && InvalidVoltype(voltype))
773         END(VL_BADVOLTYPE);
774
775     if (releasetype && InvalidReleasetype(releasetype))
776         END(VL_BADRELLOCKTYPE);
777     if ((errorcode = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
778         goto end;
779
780     VLog(1, ("Replace Volume %u %s\n", volid, rxinfo(rxstr, rxcall)));
781     /* find vlentry we're changing */
782     blockindex = FindByID(&ctx, volid, voltype, &tentry, &errorcode);
783     if (blockindex == 0) {      /* entry not found */
784         if (!errorcode)
785             errorcode = VL_NOENT;
786         goto abort;
787     }
788
789     /* check that we're not trying to change the RW vol ID */
790     if (newentry->volumeId[RWVOL] != tentry.volumeId[RWVOL]) {
791         ABORT(VL_BADENTRY);
792     }
793
794     /* unhash volid entries if they're disappearing or changing.
795      * Remember if we need to hash in the new value (we don't have to
796      * rehash if volid stays same */
797     for (typeindex = ROVOL; typeindex <= BACKVOL; typeindex++) {
798         if (tentry.volumeId[typeindex] != newentry->volumeId[typeindex]) {
799             if (tentry.volumeId[typeindex])
800                 if ((errorcode =
801                     UnhashVolid(&ctx, typeindex, blockindex, &tentry))) {
802                     goto abort;
803                 }
804             /* we must rehash new id if the id is different and the ID is nonzero */
805             hashVol[typeindex] = 1;     /* must rehash this guy if he exists */
806         }
807     }
808
809     /* Rehash volname if it changes */
810     if (strcmp(newentry->name, tentry.name)) {  /* Name changes; redo hashing */
811         if ((errorcode = UnhashVolname(&ctx, blockindex, &tentry))) {
812             goto abort;
813         }
814         hashnewname = 1;
815     }
816
817     /* after this, tentry is new entry, not old one.  vldbentry_to_vlentry
818      * doesn't touch hash chains */
819     if ((errorcode = nvldbentry_to_vlentry(&ctx, newentry, &tentry))) {
820         goto abort;
821     }
822
823     for (typeindex = ROVOL; typeindex <= BACKVOL; typeindex++) {
824         if (hashVol[typeindex] && tentry.volumeId[typeindex]) {
825             if ((errorcode = HashVolid(&ctx, typeindex, blockindex, &tentry))) {
826                 goto abort;
827             }
828         }
829     }
830
831     if (hashnewname)
832         HashVolname(&ctx, blockindex, &tentry);
833
834     if (releasetype)
835         ReleaseEntry(&tentry, releasetype);     /* Unlock entry if necessary */
836     if (vlentrywrite(ctx.trans, blockindex, &tentry, sizeof(tentry))) {
837         ABORT(VL_IO);
838     }
839
840     END(ubik_EndTrans(ctx.trans));
841
842   abort:
843     COUNT_ABO;
844     ubik_AbortTrans(ctx.trans);
845
846   end:
847     osi_auditU(rxcall, VLReplaceVLEntryEvent, errorcode, AUD_LONG, volid,
848                AUD_END);
849     return errorcode;
850 }
851
852
853 /* Update a vldb entry (accessed thru its volume id). Almost all of the
854  * entry's fields can be modified in a single call by setting the
855  * appropriate bits in the Mask field in VldbUpdateentry. */
856 /* this routine may never have been tested; use replace entry instead
857  * unless you're brave */
858 afs_int32
859 SVL_UpdateEntry(struct rx_call *rxcall,
860                 afs_uint32 volid,
861                 afs_int32 voltype,
862                 struct VldbUpdateEntry *updateentry,    /* Update entry copied here */
863                 afs_int32 releasetype)
864 {
865     struct vl_ctx ctx;
866     afs_int32 blockindex, errorcode;
867     struct nvlentry tentry;
868     char rxstr[AFS_RXINFO_LEN];
869
870     COUNT_REQ(VLUPDATEENTRY);
871     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL))
872         END(VL_PERM);
873     if ((voltype != -1) && (InvalidVoltype(voltype)))
874         END(VL_BADVOLTYPE);
875     if (releasetype && InvalidReleasetype(releasetype))
876         END(VL_BADRELLOCKTYPE);
877     if ((errorcode = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
878         goto end;
879
880     VLog(1, ("Update Volume %u %s\n", volid, rxinfo(rxstr, rxcall)));
881     blockindex = FindByID(&ctx, volid, voltype, &tentry, &errorcode);
882     if (blockindex == 0) {      /* entry not found */
883         if (!errorcode)
884             errorcode = VL_NOENT;
885         goto abort;
886     }
887
888     /* Do the actual updating of the entry, tentry. */
889     if ((errorcode =
890         get_vldbupdateentry(&ctx, blockindex, updateentry, &tentry))) {
891         goto abort;
892     }
893     if (releasetype)
894         ReleaseEntry(&tentry, releasetype);     /* Unlock entry if necessary */
895     if (vlentrywrite(ctx.trans, blockindex, &tentry, sizeof(tentry))) {
896         ABORT(VL_IO);
897     }
898     END(ubik_EndTrans(ctx.trans));
899
900   abort:
901     COUNT_ABO;
902     ubik_AbortTrans(ctx.trans);
903
904   end:
905     osi_auditU(rxcall, VLUpdateEntryEvent, errorcode, AUD_LONG, volid,
906                AUD_END);
907     return errorcode;
908 }
909
910
911 afs_int32
912 SVL_UpdateEntryByName(struct rx_call *rxcall,
913                       char *volname,
914                       struct VldbUpdateEntry *updateentry, /* Update entry copied here */
915                       afs_int32 releasetype)
916 {
917     struct vl_ctx ctx;
918     afs_int32 blockindex, errorcode;
919     struct nvlentry tentry;
920
921     COUNT_REQ(VLUPDATEENTRYBYNAME);
922     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL))
923         END(VL_PERM);
924     if (releasetype && InvalidReleasetype(releasetype))
925         END(VL_BADRELLOCKTYPE);
926     if ((errorcode = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
927         goto end;
928
929     blockindex = FindByName(&ctx, volname, &tentry, &errorcode);
930     if (blockindex == 0) {      /* entry not found */
931         if (!errorcode)
932             errorcode = VL_NOENT;
933         goto abort;
934     }
935
936     /* Do the actual updating of the entry, tentry. */
937     if ((errorcode =
938         get_vldbupdateentry(&ctx, blockindex, updateentry, &tentry))) {
939         goto abort;
940     }
941     if (releasetype)
942         ReleaseEntry(&tentry, releasetype);     /* Unlock entry if necessary */
943     if (vlentrywrite(ctx.trans, blockindex, &tentry, sizeof(tentry))) {
944         ABORT(VL_IO);
945     }
946     END(ubik_EndTrans(ctx.trans));
947
948   abort:
949     COUNT_ABO;
950     ubik_AbortTrans(ctx.trans);
951
952   end:
953     osi_auditU(rxcall, VLUpdateEntryEvent, errorcode, AUD_LONG, -1, AUD_END);
954     return errorcode;
955 }
956
957
958 /* Set a lock to the vldb entry for volid (of type voltype if not -1). */
959 afs_int32
960 SVL_SetLock(struct rx_call *rxcall, afs_uint32 volid, afs_int32 voltype,
961             afs_int32 voloper)
962 {
963     afs_int32 timestamp, blockindex, errorcode;
964     struct vl_ctx ctx;
965     struct nvlentry tentry;
966     char rxstr[AFS_RXINFO_LEN];
967
968     COUNT_REQ(VLSETLOCK);
969     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL))
970         END(VL_PERM);
971     if ((voltype != -1) && (InvalidVoltype(voltype)))
972         END(VL_BADVOLTYPE);
973     if (InvalidOperation(voloper))
974         END(VL_BADVOLOPER);
975     if ((errorcode = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
976         goto end;
977
978     VLog(1, ("SetLock Volume %u %s\n", volid, rxinfo(rxstr, rxcall)));
979     blockindex = FindByID(&ctx, volid, voltype, &tentry, &errorcode);
980     if (blockindex == NULLO) {
981         if (!errorcode)
982             errorcode = VL_NOENT;
983         goto abort;
984     }
985     if (tentry.flags & VLDELETED) {
986         ABORT(VL_ENTDELETED);
987     }
988     timestamp = FT_ApproxTime();
989
990     /* Check if entry is already locked; note that we unlock any entry
991      * locked more than MAXLOCKTIME seconds */
992     if ((tentry.LockTimestamp)
993         && ((timestamp - tentry.LockTimestamp) < MAXLOCKTIME)) {
994         ABORT(VL_ENTRYLOCKED);
995     }
996
997     /* Consider it an unlocked entry: set current timestamp, caller
998      * and active vol operation */
999     tentry.LockTimestamp = timestamp;
1000     tentry.LockAfsId = 0;       /* Not implemented yet */
1001     if (tentry.flags & VLOP_RELEASE) {
1002         ABORT(VL_RERELEASE);
1003     }
1004     tentry.flags &= ~VLOP_ALLOPERS;     /* Clear any possible older operation bit */
1005     tentry.flags |= voloper;
1006
1007     if (vlentrywrite(ctx.trans, blockindex, &tentry, sizeof(tentry))) {
1008         ABORT(VL_IO);
1009     }
1010     END(ubik_EndTrans(ctx.trans));
1011
1012   abort:
1013     COUNT_ABO;
1014     ubik_AbortTrans(ctx.trans);
1015
1016   end:
1017     osi_auditU(rxcall, VLSetLockEvent, errorcode, AUD_LONG, volid, AUD_END);
1018     return errorcode;
1019 }
1020
1021
1022 /* Release an already locked vldb entry. Releasetype determines what
1023  * fields (afsid and/or volume operation) will be cleared along with
1024  * the lock time stamp. */
1025
1026 afs_int32
1027 SVL_ReleaseLock(struct rx_call *rxcall, afs_uint32 volid, afs_int32 voltype,
1028                 afs_int32 releasetype)
1029 {
1030     afs_int32 blockindex, errorcode;
1031     struct vl_ctx ctx;
1032     struct nvlentry tentry;
1033     char rxstr[AFS_RXINFO_LEN];
1034
1035     COUNT_REQ(VLRELEASELOCK);
1036     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL))
1037         END(VL_PERM);
1038     if ((voltype != -1) && (InvalidVoltype(voltype)))
1039         END(VL_BADVOLTYPE);
1040     if (releasetype && InvalidReleasetype(releasetype))
1041         END(VL_BADRELLOCKTYPE);
1042     if ((errorcode = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
1043         goto end;
1044
1045     VLog(1, ("ReleaseLock Volume %u %s\n", volid, rxinfo(rxstr, rxcall)));
1046     blockindex = FindByID(&ctx, volid, voltype, &tentry, &errorcode);
1047     if (blockindex == NULLO) {
1048         if (!errorcode)
1049             errorcode = VL_NOENT;
1050         goto abort;
1051     }
1052     if (tentry.flags & VLDELETED) {
1053         ABORT(VL_ENTDELETED);
1054     }
1055     if (releasetype)
1056         ReleaseEntry(&tentry, releasetype);     /* Unlock the appropriate fields */
1057     if (vlentrywrite(ctx.trans, blockindex, &tentry, sizeof(tentry))) {
1058         ABORT(VL_IO);
1059     }
1060     END(ubik_EndTrans(ctx.trans));
1061
1062   abort:
1063     COUNT_ABO;
1064     ubik_AbortTrans(ctx.trans);
1065
1066   end:
1067     osi_auditU(rxcall, VLReleaseLockEvent, errorcode, AUD_LONG, volid,
1068                AUD_END);
1069     return errorcode;
1070 }
1071
1072
1073 /* ListEntry returns a single vldb entry, aentry, with offset previous_index;
1074  * the remaining parameters (i.e. next_index) are used so that sequential
1075  * calls to this routine will get the next (all) vldb entries.
1076  */
1077 afs_int32
1078 SVL_ListEntry(struct rx_call *rxcall, afs_int32 previous_index,
1079               afs_int32 *count, afs_int32 *next_index,
1080               struct vldbentry *aentry)
1081 {
1082     int errorcode;
1083     struct vl_ctx ctx;
1084     struct nvlentry tentry;
1085     char rxstr[AFS_RXINFO_LEN];
1086
1087     COUNT_REQ(VLLISTENTRY);
1088     if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op)))
1089         return errorcode;
1090     VLog(25, ("OListEntry index=%d %s\n", previous_index,
1091               rxinfo(rxstr, rxcall)));
1092     *next_index = NextEntry(&ctx, previous_index, &tentry, count);
1093     if (*next_index)
1094         vlentry_to_vldbentry(&ctx, &tentry, aentry);
1095     return (ubik_EndTrans(ctx.trans));
1096 }
1097
1098 /* ListEntry returns a single vldb entry, aentry, with offset previous_index;
1099  * the remaining parameters (i.e. next_index) are used so that sequential
1100  * calls to this routine will get the next (all) vldb entries.
1101  */
1102 afs_int32
1103 SVL_ListEntryN(struct rx_call *rxcall, afs_int32 previous_index,
1104                afs_int32 *count, afs_int32 *next_index,
1105                struct nvldbentry *aentry)
1106 {
1107     int errorcode;
1108     struct vl_ctx ctx;
1109     struct nvlentry tentry;
1110     char rxstr[AFS_RXINFO_LEN];
1111
1112     COUNT_REQ(VLLISTENTRYN);
1113     if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op)))
1114         return errorcode;
1115     VLog(25, ("ListEntry index=%d %s\n", previous_index, rxinfo(rxstr, rxcall)));
1116     *next_index = NextEntry(&ctx, previous_index, &tentry, count);
1117     if (*next_index)
1118         vlentry_to_nvldbentry(&ctx, &tentry, aentry);
1119     return (ubik_EndTrans(ctx.trans));
1120 }
1121
1122
1123 /* Retrieves in vldbentries all vldb entries that match the specified
1124  * attributes (by server number, partition, volume type, and flag); if volume
1125  * id is specified then the associated list for that entry is returned.
1126  * CAUTION: This could be a very expensive call since in most cases
1127  * sequential search of all vldb entries is performed.
1128  */
1129 afs_int32
1130 SVL_ListAttributes(struct rx_call *rxcall,
1131                    struct VldbListByAttributes *attributes,
1132                    afs_int32 *nentries,
1133                    bulkentries *vldbentries)
1134 {
1135     int errorcode, allocCount = 0;
1136     struct vl_ctx ctx;
1137     struct nvlentry tentry;
1138     struct vldbentry *Vldbentry = 0, *VldbentryFirst = 0, *VldbentryLast = 0;
1139     int pollcount = 0;
1140     char rxstr[AFS_RXINFO_LEN];
1141
1142     COUNT_REQ(VLLISTATTRIBUTES);
1143     vldbentries->bulkentries_val = 0;
1144     vldbentries->bulkentries_len = *nentries = 0;
1145     if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op)))
1146         return errorcode;
1147     allocCount = VLDBALLOCCOUNT;
1148     Vldbentry = VldbentryFirst = vldbentries->bulkentries_val =
1149         (vldbentry *) malloc(allocCount * sizeof(vldbentry));
1150     if (Vldbentry == NULL) {
1151         COUNT_ABO;
1152         ubik_AbortTrans(ctx.trans);
1153         return VL_NOMEM;
1154     }
1155     VldbentryLast = VldbentryFirst + allocCount;
1156     /* Handle the attribute by volume id totally separate of the rest
1157      * (thus additional Mask values are ignored if VLLIST_VOLUMEID is set!) */
1158     if (attributes->Mask & VLLIST_VOLUMEID) {
1159         afs_int32 blockindex;
1160
1161         blockindex =
1162             FindByID(&ctx, attributes->volumeid, -1, &tentry, &errorcode);
1163         if (blockindex == 0) {
1164             if (!errorcode)
1165                 errorcode = VL_NOENT;
1166             COUNT_ABO;
1167             ubik_AbortTrans(ctx.trans);
1168             if (vldbentries->bulkentries_val)
1169                 free((char *)vldbentries->bulkentries_val);
1170             vldbentries->bulkentries_val = 0;
1171             vldbentries->bulkentries_len = 0;
1172             return errorcode;
1173         }
1174         if ((errorcode =
1175             put_attributeentry(&ctx, &Vldbentry, &VldbentryFirst, &VldbentryLast,
1176                                vldbentries, &tentry, nentries, &allocCount))) {
1177             COUNT_ABO;
1178             ubik_AbortTrans(ctx.trans);
1179             if (vldbentries->bulkentries_val)
1180                 free((char *)vldbentries->bulkentries_val);
1181             vldbentries->bulkentries_val = 0;
1182             vldbentries->bulkentries_len = 0;
1183             return VL_SIZEEXCEEDED;
1184         }
1185     } else {
1186         afs_int32 nextblockindex = 0, count = 0, k = 0, match = 0;
1187         while ((nextblockindex =
1188                NextEntry(&ctx, nextblockindex, &tentry, &count))) {
1189             if (++pollcount > 50) {
1190 #ifndef AFS_PTHREAD_ENV
1191                 IOMGR_Poll();
1192 #endif
1193                 pollcount = 0;
1194             }
1195             match = 0;
1196             if (attributes->Mask & VLLIST_SERVER) {
1197                 int serverindex;
1198                 if ((serverindex =
1199                      IpAddrToRelAddr(&ctx, attributes->server, 0)) == -1)
1200                     continue;
1201                 for (k = 0; k < OMAXNSERVERS; k++) {
1202                     if (tentry.serverNumber[k] == BADSERVERID)
1203                         break;
1204                     if (tentry.serverNumber[k] == serverindex) {
1205                         match = 1;
1206                         break;
1207                     }
1208                 }
1209                 if (!match)
1210                     continue;
1211             }
1212             if (attributes->Mask & VLLIST_PARTITION) {
1213                 if (match) {
1214                     if (tentry.serverPartition[k] != attributes->partition)
1215                         continue;
1216                 } else {
1217                     for (k = 0; k < OMAXNSERVERS; k++) {
1218                         if (tentry.serverNumber[k] == BADSERVERID)
1219                             break;
1220                         if (tentry.serverPartition[k] ==
1221                             attributes->partition) {
1222                             match = 1;
1223                             break;
1224                         }
1225                     }
1226                     if (!match)
1227                         continue;
1228                 }
1229             }
1230
1231             if (attributes->Mask & VLLIST_FLAG) {
1232                 if (!(tentry.flags & attributes->flag))
1233                     continue;
1234             }
1235             if ((errorcode =
1236                 put_attributeentry(&ctx, &Vldbentry, &VldbentryFirst,
1237                                    &VldbentryLast, vldbentries, &tentry,
1238                                    nentries, &allocCount))) {
1239                 COUNT_ABO;
1240                 ubik_AbortTrans(ctx.trans);
1241                 if (vldbentries->bulkentries_val)
1242                     free((char *)vldbentries->bulkentries_val);
1243                 vldbentries->bulkentries_val = 0;
1244                 vldbentries->bulkentries_len = 0;
1245                 return errorcode;
1246             }
1247         }
1248     }
1249     if (vldbentries->bulkentries_len
1250         && (allocCount > vldbentries->bulkentries_len)) {
1251
1252         vldbentries->bulkentries_val =
1253             (vldbentry *) realloc(vldbentries->bulkentries_val,
1254                                   vldbentries->bulkentries_len *
1255                                   sizeof(vldbentry));
1256         if (vldbentries->bulkentries_val == NULL) {
1257             COUNT_ABO;
1258             ubik_AbortTrans(ctx.trans);
1259             return VL_NOMEM;
1260         }
1261     }
1262     VLog(5,
1263          ("ListAttrs nentries=%d %s\n", vldbentries->bulkentries_len,
1264           rxinfo(rxstr, rxcall)));
1265     return (ubik_EndTrans(ctx.trans));
1266 }
1267
1268 afs_int32
1269 SVL_ListAttributesN(struct rx_call *rxcall,
1270                     struct VldbListByAttributes *attributes,
1271                     afs_int32 *nentries,
1272                     nbulkentries *vldbentries)
1273 {
1274     int errorcode, allocCount = 0;
1275     struct vl_ctx ctx;
1276     struct nvlentry tentry;
1277     struct nvldbentry *Vldbentry = 0, *VldbentryFirst = 0, *VldbentryLast = 0;
1278     int pollcount = 0;
1279     char rxstr[AFS_RXINFO_LEN];
1280
1281     COUNT_REQ(VLLISTATTRIBUTESN);
1282     vldbentries->nbulkentries_val = 0;
1283     vldbentries->nbulkentries_len = *nentries = 0;
1284     if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op)))
1285         return errorcode;
1286     allocCount = VLDBALLOCCOUNT;
1287     Vldbentry = VldbentryFirst = vldbentries->nbulkentries_val =
1288         (nvldbentry *) malloc(allocCount * sizeof(nvldbentry));
1289     if (Vldbentry == NULL) {
1290         COUNT_ABO;
1291         ubik_AbortTrans(ctx.trans);
1292         return VL_NOMEM;
1293     }
1294     VldbentryLast = VldbentryFirst + allocCount;
1295     /* Handle the attribute by volume id totally separate of the rest
1296      * (thus additional Mask values are ignored if VLLIST_VOLUMEID is set!) */
1297     if (attributes->Mask & VLLIST_VOLUMEID) {
1298         afs_int32 blockindex;
1299
1300         blockindex =
1301             FindByID(&ctx, attributes->volumeid, -1, &tentry, &errorcode);
1302         if (blockindex == 0) {
1303             if (!errorcode)
1304                 errorcode = VL_NOENT;
1305             COUNT_ABO;
1306             ubik_AbortTrans(ctx.trans);
1307             if (vldbentries->nbulkentries_val)
1308                 free((char *)vldbentries->nbulkentries_val);
1309             vldbentries->nbulkentries_val = 0;
1310             vldbentries->nbulkentries_len = 0;
1311             return errorcode;
1312         }
1313         if ((errorcode =
1314             put_nattributeentry(&ctx, &Vldbentry, &VldbentryFirst, &VldbentryLast,
1315                                 vldbentries, &tentry, 0, 0, nentries,
1316                                 &allocCount))) {
1317             COUNT_ABO;
1318             ubik_AbortTrans(ctx.trans);
1319             if (vldbentries->nbulkentries_val)
1320                 free((char *)vldbentries->nbulkentries_val);
1321             vldbentries->nbulkentries_val = 0;
1322             vldbentries->nbulkentries_len = 0;
1323             return VL_SIZEEXCEEDED;
1324         }
1325     } else {
1326         afs_int32 nextblockindex = 0, count = 0, k = 0, match = 0;
1327         while ((nextblockindex =
1328                NextEntry(&ctx, nextblockindex, &tentry, &count))) {
1329             if (++pollcount > 50) {
1330 #ifndef AFS_PTHREAD_ENV
1331                 IOMGR_Poll();
1332 #endif
1333                 pollcount = 0;
1334             }
1335
1336             match = 0;
1337             if (attributes->Mask & VLLIST_SERVER) {
1338                 int serverindex;
1339                 if ((serverindex =
1340                      IpAddrToRelAddr(&ctx, attributes->server, 0)) == -1)
1341                     continue;
1342                 for (k = 0; k < NMAXNSERVERS; k++) {
1343                     if (tentry.serverNumber[k] == BADSERVERID)
1344                         break;
1345                     if (tentry.serverNumber[k] == serverindex) {
1346                         match = 1;
1347                         break;
1348                     }
1349                 }
1350                 if (!match)
1351                     continue;
1352             }
1353             if (attributes->Mask & VLLIST_PARTITION) {
1354                 if (match) {
1355                     if (tentry.serverPartition[k] != attributes->partition)
1356                         continue;
1357                 } else {
1358                     for (k = 0; k < NMAXNSERVERS; k++) {
1359                         if (tentry.serverNumber[k] == BADSERVERID)
1360                             break;
1361                         if (tentry.serverPartition[k] ==
1362                             attributes->partition) {
1363                             match = 1;
1364                             break;
1365                         }
1366                     }
1367                     if (!match)
1368                         continue;
1369                 }
1370             }
1371
1372             if (attributes->Mask & VLLIST_FLAG) {
1373                 if (!(tentry.flags & attributes->flag))
1374                     continue;
1375             }
1376             if ((errorcode =
1377                 put_nattributeentry(&ctx, &Vldbentry, &VldbentryFirst,
1378                                     &VldbentryLast, vldbentries, &tentry, 0,
1379                                     0, nentries, &allocCount))) {
1380                 COUNT_ABO;
1381                 ubik_AbortTrans(ctx.trans);
1382                 if (vldbentries->nbulkentries_val)
1383                     free((char *)vldbentries->nbulkentries_val);
1384                 vldbentries->nbulkentries_val = 0;
1385                 vldbentries->nbulkentries_len = 0;
1386                 return errorcode;
1387             }
1388         }
1389     }
1390     if (vldbentries->nbulkentries_len
1391         && (allocCount > vldbentries->nbulkentries_len)) {
1392
1393         vldbentries->nbulkentries_val =
1394             (nvldbentry *) realloc(vldbentries->nbulkentries_val,
1395                                    vldbentries->nbulkentries_len *
1396                                    sizeof(nvldbentry));
1397         if (vldbentries->nbulkentries_val == NULL) {
1398             COUNT_ABO;
1399             ubik_AbortTrans(ctx.trans);
1400             return VL_NOMEM;
1401         }
1402     }
1403     VLog(5,
1404          ("NListAttrs nentries=%d %s\n", vldbentries->nbulkentries_len,
1405           rxinfo(rxstr, rxcall)));
1406     return (ubik_EndTrans(ctx.trans));
1407 }
1408
1409
1410 afs_int32
1411 SVL_ListAttributesN2(struct rx_call *rxcall,
1412                      struct VldbListByAttributes *attributes,
1413                      char *name,                /* Wildcarded volume name */
1414                      afs_int32 startindex,
1415                      afs_int32 *nentries,
1416                      nbulkentries *vldbentries,
1417                      afs_int32 *nextstartindex)
1418 {
1419     int errorcode = 0, maxCount = VLDBALLOCCOUNT;
1420     struct vl_ctx ctx;
1421     struct nvlentry tentry;
1422     struct nvldbentry *Vldbentry = 0, *VldbentryFirst = 0, *VldbentryLast = 0;
1423     afs_int32 blockindex = 0, count = 0, k, match;
1424     afs_int32 matchindex = 0;
1425     int serverindex = -1;       /* no server found */
1426     int findserver = 0, findpartition = 0, findflag = 0, findname = 0;
1427     int pollcount = 0;
1428     int namematchRWBK, namematchRO, thismatch;
1429     int matchtype = 0;
1430     char volumename[VL_MAXNAMELEN+2]; /* regex anchors */
1431     char rxstr[AFS_RXINFO_LEN];
1432 #ifdef HAVE_POSIX_REGEX
1433     regex_t re;
1434     int need_regfree = 0;
1435 #else
1436     char *t;
1437 #endif
1438
1439     COUNT_REQ(VLLISTATTRIBUTESN2);
1440     vldbentries->nbulkentries_val = 0;
1441     vldbentries->nbulkentries_len = 0;
1442     *nentries = 0;
1443     *nextstartindex = -1;
1444
1445     errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op);
1446     if (errorcode)
1447         return errorcode;
1448
1449     Vldbentry = VldbentryFirst = vldbentries->nbulkentries_val =
1450         (nvldbentry *) malloc(maxCount * sizeof(nvldbentry));
1451     if (Vldbentry == NULL) {
1452         COUNT_ABO;
1453         ubik_AbortTrans(ctx.trans);
1454         return VL_NOMEM;
1455     }
1456
1457     VldbentryLast = VldbentryFirst + maxCount;
1458
1459     /* Handle the attribute by volume id totally separate of the rest
1460      * (thus additional Mask values are ignored if VLLIST_VOLUMEID is set!)
1461      */
1462     if (attributes->Mask & VLLIST_VOLUMEID) {
1463         blockindex =
1464             FindByID(&ctx, attributes->volumeid, -1, &tentry, &errorcode);
1465         if (blockindex == 0) {
1466             if (!errorcode)
1467                 errorcode = VL_NOENT;
1468         } else {
1469             errorcode =
1470                 put_nattributeentry(&ctx, &Vldbentry, &VldbentryFirst,
1471                                     &VldbentryLast, vldbentries, &tentry, 0,
1472                                     0, nentries, &maxCount);
1473             if (errorcode)
1474                 goto done;
1475         }
1476     }
1477
1478     /* Search each entry in the database and return all entries
1479      * that match the request. It checks volumename (with
1480      * wildcarding), entry flags, server, and partition.
1481      */
1482     else {
1483         /* Get the server index for matching server address */
1484         if (attributes->Mask & VLLIST_SERVER) {
1485             serverindex =
1486                 IpAddrToRelAddr(&ctx, attributes->server, 0);
1487             if (serverindex == -1)
1488                 goto done;
1489             findserver = 1;
1490         }
1491         findpartition = ((attributes->Mask & VLLIST_PARTITION) ? 1 : 0);
1492         findflag = ((attributes->Mask & VLLIST_FLAG) ? 1 : 0);
1493         if (name && (strcmp(name, ".*") != 0) && (strcmp(name, "") != 0)) {
1494             sprintf(volumename, "^%s$", name);
1495 #ifdef HAVE_POSIX_REGEX
1496             if (regcomp(&re, volumename, REG_NOSUB) != 0) {
1497                 errorcode = VL_BADNAME;
1498                 goto done;
1499             }
1500             need_regfree = 1;
1501 #else
1502             t = (char *)re_comp(volumename);
1503             if (t) {
1504                 errorcode = VL_BADNAME;
1505                 goto done;
1506             }
1507 #endif
1508             findname = 1;
1509         }
1510
1511         /* Read each entry and see if it is the one we want */
1512         blockindex = startindex;
1513         while ((blockindex = NextEntry(&ctx, blockindex, &tentry, &count))) {
1514             if (++pollcount > 50) {
1515 #ifndef AFS_PTHREAD_ENV
1516                 IOMGR_Poll();
1517 #endif
1518                 pollcount = 0;
1519             }
1520
1521             /* Step through each server index searching for a match.
1522              * Match to an existing RW, BK, or RO volume name (preference
1523              * is in this order). Remember which index we matched against.
1524              */
1525             namematchRWBK = namematchRO = 0;    /* 0->notTried; 1->match; 2->noMatch */
1526             match = 0;
1527             for (k = 0;
1528                  (k < NMAXNSERVERS
1529                   && (tentry.serverNumber[k] != BADSERVERID)); k++) {
1530                 thismatch = 0;  /* does this index match */
1531
1532                 /* Match against the RW or BK volume name. Remember
1533                  * results in namematchRWBK. Prefer RW over BK.
1534                  */
1535                 if (tentry.serverFlags[k] & VLSF_RWVOL) {
1536                     /* Does the name match the RW name */
1537                     if (tentry.flags & VLF_RWEXISTS) {
1538                         if (findname) {
1539                             sprintf(volumename, "%s", tentry.name);
1540 #ifdef HAVE_POSIX_REGEX
1541                             if (regexec(&re, volumename, 0, NULL, 0) == 0) {
1542                                 thismatch = VLSF_RWVOL;
1543                             }
1544 #else
1545                             if (re_exec(volumename)) {
1546                                 thismatch = VLSF_RWVOL;
1547                             }
1548 #endif
1549                         } else {
1550                             thismatch = VLSF_RWVOL;
1551                         }
1552                     }
1553
1554                     /* Does the name match the BK name */
1555                     if (!thismatch && (tentry.flags & VLF_BACKEXISTS)) {
1556                         if (findname) {
1557                             sprintf(volumename, "%s.backup", tentry.name);
1558 #ifdef HAVE_POSIX_REGEX
1559                             if (regexec(&re, volumename, 0, NULL, 0) == 0) {
1560                                 thismatch = VLSF_BACKVOL;
1561                             }
1562 #else
1563                             if (re_exec(volumename)) {
1564                                 thismatch = VLSF_BACKVOL;
1565                             }
1566 #endif
1567                         } else {
1568                             thismatch = VLSF_BACKVOL;
1569                         }
1570                     }
1571
1572                     namematchRWBK = (thismatch ? 1 : 2);
1573                 }
1574
1575                 /* Match with the RO volume name. Compare once and
1576                  * remember results in namematchRO. Note that this will
1577                  * pick up entries marked NEWREPSITEs and DONTUSE.
1578                  */
1579                 else {
1580                     if (tentry.flags & VLF_ROEXISTS) {
1581                         if (findname) {
1582                             if (namematchRO) {
1583                                 thismatch =
1584                                     ((namematchRO == 1) ? VLSF_ROVOL : 0);
1585                             } else {
1586                                 sprintf(volumename, "%s.readonly",
1587                                         tentry.name);
1588 #ifdef HAVE_POSIX_REGEX
1589                             if (regexec(&re, volumename, 0, NULL, 0) == 0) {
1590                                 thismatch = VLSF_ROVOL;
1591                             }
1592 #else
1593                                 if (re_exec(volumename))
1594                                     thismatch = VLSF_ROVOL;
1595 #endif
1596                             }
1597                         } else {
1598                             thismatch = VLSF_ROVOL;
1599                         }
1600                     }
1601                     namematchRO = (thismatch ? 1 : 2);
1602                 }
1603
1604                 /* Is there a server match */
1605                 if (thismatch && findserver
1606                     && (tentry.serverNumber[k] != serverindex))
1607                     thismatch = 0;
1608
1609                 /* Is there a partition match */
1610                 if (thismatch && findpartition
1611                     && (tentry.serverPartition[k] != attributes->partition))
1612                     thismatch = 0;
1613
1614                 /* Is there a flag match */
1615                 if (thismatch && findflag
1616                     && !(tentry.flags & attributes->flag))
1617                     thismatch = 0;
1618
1619                 /* We found a match. Remember the index, and type */
1620                 if (thismatch) {
1621                     match = 1;
1622                     matchindex = k;
1623                     matchtype = thismatch;
1624                 }
1625
1626                 /* Since we prefer RW and BK volume matches over RO matches,
1627                  * if we have already checked the RWBK name, then we already
1628                  * found the best match and so end the search.
1629                  *
1630                  * If we tried matching against the RW, BK, and RO volume names
1631                  * and both failed, then we end the search (none will match).
1632                  */
1633                 if ((match && namematchRWBK)
1634                     || ((namematchRWBK == 2) && (namematchRO == 2)))
1635                     break;
1636             }
1637
1638             /* Passed all the tests. Take it */
1639             if (match) {
1640                 errorcode =
1641                     put_nattributeentry(&ctx, &Vldbentry, &VldbentryFirst,
1642                                         &VldbentryLast, vldbentries, &tentry,
1643                                         matchtype, matchindex, nentries,
1644                                         &maxCount);
1645                 if (errorcode)
1646                     goto done;
1647
1648                 if (*nentries >= maxCount)
1649                     break;      /* collected the max */
1650             }
1651         }
1652         *nextstartindex = (blockindex ? blockindex : -1);
1653     }
1654
1655   done:
1656 #ifdef HAVE_POSIX_REGEX
1657     if (need_regfree)
1658         regfree(&re);
1659 #endif
1660
1661     if (errorcode) {
1662         COUNT_ABO;
1663         ubik_AbortTrans(ctx.trans);
1664         if (vldbentries->nbulkentries_val)
1665             free((char *)vldbentries->nbulkentries_val);
1666         vldbentries->nbulkentries_val = 0;
1667         vldbentries->nbulkentries_len = 0;
1668         *nextstartindex = -1;
1669         return errorcode;
1670     } else {
1671         VLog(5,
1672              ("N2ListAttrs nentries=%d %s\n", vldbentries->nbulkentries_len,
1673               rxinfo(rxstr, rxcall)));
1674         return (ubik_EndTrans(ctx.trans));
1675     }
1676 }
1677
1678
1679 /* Retrieves in vldbentries all vldb entries that match the specified
1680  * attributes (by server number, partition, volume type, and flag); if
1681  * volume id is specified then the associated list for that entry is
1682  * returned. CAUTION: This could be a very expensive call since in most
1683  * cases sequential search of all vldb entries is performed.
1684  */
1685 afs_int32
1686 SVL_LinkedList(struct rx_call *rxcall,
1687                struct VldbListByAttributes *attributes,
1688                afs_int32 *nentries,
1689                vldb_list *vldbentries)
1690 {
1691     int errorcode;
1692     struct vl_ctx ctx;
1693     struct nvlentry tentry;
1694     vldblist vllist, *vllistptr;
1695     afs_int32 blockindex, count, match;
1696     afs_int32 k = 0;
1697     int serverindex;
1698     int pollcount = 0;
1699
1700     COUNT_REQ(VLLINKEDLIST);
1701     if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op)))
1702         return errorcode;
1703
1704     *nentries = 0;
1705     vldbentries->node = NULL;
1706     vllistptr = &vldbentries->node;
1707
1708     /* List by volumeid */
1709     if (attributes->Mask & VLLIST_VOLUMEID) {
1710         blockindex =
1711             FindByID(&ctx, attributes->volumeid, -1, &tentry, &errorcode);
1712         if (!blockindex) {
1713             COUNT_ABO;
1714             ubik_AbortTrans(ctx.trans);
1715             return (errorcode ? errorcode : VL_NOENT);
1716         }
1717
1718         vllist = (single_vldbentry *) malloc(sizeof(single_vldbentry));
1719         if (vllist == NULL) {
1720             COUNT_ABO;
1721             ubik_AbortTrans(ctx.trans);
1722             return VL_NOMEM;
1723         }
1724         vlentry_to_vldbentry(&ctx, &tentry, &vllist->VldbEntry);
1725         vllist->next_vldb = NULL;
1726
1727         *vllistptr = vllist;    /* Thread onto list */
1728         vllistptr = &vllist->next_vldb;
1729         (*nentries)++;
1730     }
1731
1732     /* Search by server, partition, and flags */
1733     else {
1734         for (blockindex = NextEntry(&ctx, 0, &tentry, &count); blockindex;
1735              blockindex = NextEntry(&ctx, blockindex, &tentry, &count)) {
1736             match = 0;
1737
1738             if (++pollcount > 50) {
1739 #ifndef AFS_PTHREAD_ENV
1740                 IOMGR_Poll();
1741 #endif
1742                 pollcount = 0;
1743             }
1744
1745             /* Does this volume exist on the desired server */
1746             if (attributes->Mask & VLLIST_SERVER) {
1747                 serverindex =
1748                     IpAddrToRelAddr(&ctx, attributes->server, 0);
1749                 if (serverindex == -1)
1750                     continue;
1751                 for (k = 0; k < OMAXNSERVERS; k++) {
1752                     if (tentry.serverNumber[k] == BADSERVERID)
1753                         break;
1754                     if (tentry.serverNumber[k] == serverindex) {
1755                         match = 1;
1756                         break;
1757                     }
1758                 }
1759                 if (!match)
1760                     continue;
1761             }
1762
1763             /* Does this volume exist on the desired partition */
1764             if (attributes->Mask & VLLIST_PARTITION) {
1765                 if (match) {
1766                     if (tentry.serverPartition[k] != attributes->partition)
1767                         match = 0;
1768                 } else {
1769                     for (k = 0; k < OMAXNSERVERS; k++) {
1770                         if (tentry.serverNumber[k] == BADSERVERID)
1771                             break;
1772                         if (tentry.serverPartition[k] ==
1773                             attributes->partition) {
1774                             match = 1;
1775                             break;
1776                         }
1777                     }
1778                 }
1779                 if (!match)
1780                     continue;
1781             }
1782
1783             /* Does this volume have the desired flags */
1784             if (attributes->Mask & VLLIST_FLAG) {
1785                 if (!(tentry.flags & attributes->flag))
1786                     continue;
1787             }
1788
1789             vllist = (single_vldbentry *) malloc(sizeof(single_vldbentry));
1790             if (vllist == NULL) {
1791                 COUNT_ABO;
1792                 ubik_AbortTrans(ctx.trans);
1793                 return VL_NOMEM;
1794             }
1795             vlentry_to_vldbentry(&ctx, &tentry, &vllist->VldbEntry);
1796             vllist->next_vldb = NULL;
1797
1798             *vllistptr = vllist;        /* Thread onto list */
1799             vllistptr = &vllist->next_vldb;
1800             (*nentries)++;
1801             if (smallMem && (*nentries >= VLDBALLOCCOUNT)) {
1802                 COUNT_ABO;
1803                 ubik_AbortTrans(ctx.trans);
1804                 return VL_SIZEEXCEEDED;
1805             }
1806         }
1807     }
1808     *vllistptr = NULL;
1809     return (ubik_EndTrans(ctx.trans));
1810 }
1811
1812 afs_int32
1813 SVL_LinkedListN(struct rx_call *rxcall,
1814                 struct VldbListByAttributes *attributes,
1815                 afs_int32 *nentries,
1816                 nvldb_list *vldbentries)
1817 {
1818     int errorcode;
1819     struct vl_ctx ctx;
1820     struct nvlentry tentry;
1821     nvldblist vllist, *vllistptr;
1822     afs_int32 blockindex, count, match;
1823     afs_int32 k = 0;
1824     int serverindex;
1825     int pollcount = 0;
1826
1827     COUNT_REQ(VLLINKEDLISTN);
1828     if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op)))
1829         return errorcode;
1830
1831     *nentries = 0;
1832     vldbentries->node = NULL;
1833     vllistptr = &vldbentries->node;
1834
1835     /* List by volumeid */
1836     if (attributes->Mask & VLLIST_VOLUMEID) {
1837         blockindex =
1838             FindByID(&ctx, attributes->volumeid, -1, &tentry, &errorcode);
1839         if (!blockindex) {
1840             COUNT_ABO;
1841             ubik_AbortTrans(ctx.trans);
1842             return (errorcode ? errorcode : VL_NOENT);
1843         }
1844
1845         vllist = (single_nvldbentry *) malloc(sizeof(single_nvldbentry));
1846         if (vllist == NULL) {
1847             COUNT_ABO;
1848             ubik_AbortTrans(ctx.trans);
1849             return VL_NOMEM;
1850         }
1851         vlentry_to_nvldbentry(&ctx, &tentry, &vllist->VldbEntry);
1852         vllist->next_vldb = NULL;
1853
1854         *vllistptr = vllist;    /* Thread onto list */
1855         vllistptr = &vllist->next_vldb;
1856         (*nentries)++;
1857     }
1858
1859     /* Search by server, partition, and flags */
1860     else {
1861         for (blockindex = NextEntry(&ctx, 0, &tentry, &count); blockindex;
1862              blockindex = NextEntry(&ctx, blockindex, &tentry, &count)) {
1863             match = 0;
1864
1865             if (++pollcount > 50) {
1866 #ifndef AFS_PTHREAD_ENV
1867                 IOMGR_Poll();
1868 #endif
1869                 pollcount = 0;
1870             }
1871
1872             /* Does this volume exist on the desired server */
1873             if (attributes->Mask & VLLIST_SERVER) {
1874                 serverindex =
1875                     IpAddrToRelAddr(&ctx, attributes->server, 0);
1876                 if (serverindex == -1)
1877                     continue;
1878                 for (k = 0; k < NMAXNSERVERS; k++) {
1879                     if (tentry.serverNumber[k] == BADSERVERID)
1880                         break;
1881                     if (tentry.serverNumber[k] == serverindex) {
1882                         match = 1;
1883                         break;
1884                     }
1885                 }
1886                 if (!match)
1887                     continue;
1888             }
1889
1890             /* Does this volume exist on the desired partition */
1891             if (attributes->Mask & VLLIST_PARTITION) {
1892                 if (match) {
1893                     if (tentry.serverPartition[k] != attributes->partition)
1894                         match = 0;
1895                 } else {
1896                     for (k = 0; k < NMAXNSERVERS; k++) {
1897                         if (tentry.serverNumber[k] == BADSERVERID)
1898                             break;
1899                         if (tentry.serverPartition[k] ==
1900                             attributes->partition) {
1901                             match = 1;
1902                             break;
1903                         }
1904                     }
1905                 }
1906                 if (!match)
1907                     continue;
1908             }
1909
1910             /* Does this volume have the desired flags */
1911             if (attributes->Mask & VLLIST_FLAG) {
1912                 if (!(tentry.flags & attributes->flag))
1913                     continue;
1914             }
1915
1916             vllist = (single_nvldbentry *) malloc(sizeof(single_nvldbentry));
1917             if (vllist == NULL) {
1918                 COUNT_ABO;
1919                 ubik_AbortTrans(ctx.trans);
1920                 return VL_NOMEM;
1921             }
1922             vlentry_to_nvldbentry(&ctx, &tentry, &vllist->VldbEntry);
1923             vllist->next_vldb = NULL;
1924
1925             *vllistptr = vllist;        /* Thread onto list */
1926             vllistptr = &vllist->next_vldb;
1927             (*nentries)++;
1928             if (smallMem && (*nentries >= VLDBALLOCCOUNT)) {
1929                 COUNT_ABO;
1930                 ubik_AbortTrans(ctx.trans);
1931                 return VL_SIZEEXCEEDED;
1932             }
1933         }
1934     }
1935     *vllistptr = NULL;
1936     return (ubik_EndTrans(ctx.trans));
1937 }
1938
1939 /* Get back vldb header statistics (allocs, frees, maxvolumeid,
1940  * totalentries, etc) and dynamic statistics (number of requests and/or
1941  * aborts per remote procedure call, etc)
1942  */
1943 afs_int32
1944 SVL_GetStats(struct rx_call *rxcall,
1945              vldstats *stats,
1946              vital_vlheader *vital_header)
1947 {
1948     afs_int32 errorcode;
1949     struct vl_ctx ctx;
1950     char rxstr[AFS_RXINFO_LEN];
1951
1952     COUNT_REQ(VLGETSTATS);
1953 #ifdef  notdef
1954     /* Allow users to get statistics freely */
1955     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL)) /* Must be in 'UserList' to use */
1956         return VL_PERM;
1957 #endif
1958     if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op)))
1959         return errorcode;
1960     VLog(5, ("GetStats %s\n", rxinfo(rxstr, rxcall)));
1961     memcpy((char *)vital_header, (char *)&ctx.cheader->vital_header,
1962            sizeof(vital_vlheader));
1963     memcpy((char *)stats, (char *)&dynamic_statistics, sizeof(vldstats));
1964     return (ubik_EndTrans(ctx.trans));
1965 }
1966
1967 /* Get the list of file server addresses from the VLDB.  Currently it's pretty
1968  * easy to do.  In the future, it might require a little bit of grunging
1969  * through the VLDB, but that's life.
1970  */
1971 afs_int32
1972 SVL_GetAddrs(struct rx_call *rxcall,
1973              afs_int32 Handle,
1974              afs_int32 spare2,
1975              struct VLCallBack *spare3,
1976              afs_int32 *nentries,
1977              bulkaddrs *addrsp)
1978 {
1979     afs_int32 errorcode;
1980     struct vl_ctx ctx;
1981     int nservers, i;
1982     afs_uint32 *taddrp;
1983
1984     COUNT_REQ(VLGETADDRS);
1985     addrsp->bulkaddrs_len = *nentries = 0;
1986     addrsp->bulkaddrs_val = 0;
1987     memset(spare3, 0, sizeof(struct VLCallBack));
1988
1989     if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op)))
1990         return errorcode;
1991
1992     VLog(5, ("GetAddrs\n"));
1993     addrsp->bulkaddrs_val = taddrp =
1994         (afs_uint32 *) malloc(sizeof(afs_int32) * (MAXSERVERID + 1));
1995     nservers = *nentries = addrsp->bulkaddrs_len = 0;
1996
1997     if (!taddrp) {
1998         COUNT_ABO;
1999         ubik_AbortTrans(ctx.trans);
2000         return VL_NOMEM;
2001     }
2002
2003     for (i = 0; i <= MAXSERVERID; i++) {
2004         if ((*taddrp = ntohl(ctx.cheader->IpMappedAddr[i]))) {
2005             taddrp++;
2006             nservers++;
2007         }
2008     }
2009
2010     addrsp->bulkaddrs_len = *nentries = nservers;
2011     return (ubik_EndTrans(ctx.trans));
2012 }
2013
2014 #define PADDR(addr) VLog(0,("%d.%d.%d.%d", (addr>>24)&0xff, (addr>>16)&0xff, (addr>>8) &0xff, addr&0xff));
2015
2016 afs_int32
2017 SVL_RegisterAddrs(struct rx_call *rxcall, afsUUID *uuidp, afs_int32 spare1,
2018                   bulkaddrs *addrsp)
2019 {
2020     afs_int32 code;
2021     struct vl_ctx ctx;
2022     int cnt, h, i, j, k, m, base, index;
2023     struct extentaddr *exp = 0, *tex;
2024     afsUUID tuuid;
2025     afs_uint32 addrs[VL_MAXIPADDRS_PERMH];
2026     afs_int32 fbase;
2027     int count, willChangeEntry, foundUuidEntry, willReplaceCnt;
2028     int WillReplaceEntry, WillChange[MAXSERVERID + 1];
2029     int FoundUuid = 0;
2030     int ReplaceEntry = 0;
2031     int srvidx, mhidx;
2032
2033     COUNT_REQ(VLREGADDR);
2034     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL))
2035         return (VL_PERM);
2036     if ((code = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
2037         return code;
2038
2039     /* Eliminate duplicates from IP address list */
2040     for (k = 0, cnt = 0; k < addrsp->bulkaddrs_len; k++) {
2041         if (addrsp->bulkaddrs_val[k] == 0)
2042             continue;
2043         for (m = 0; m < cnt; m++) {
2044             if (addrs[m] == addrsp->bulkaddrs_val[k])
2045                 break;
2046         }
2047         if (m == cnt) {
2048             if (m == VL_MAXIPADDRS_PERMH) {
2049                 VLog(0,
2050                      ("Number of addresses exceeds %d. Cannot register IP addr 0x%x in VLDB\n",
2051                       VL_MAXIPADDRS_PERMH, addrsp->bulkaddrs_val[k]));
2052             } else {
2053                 addrs[m] = addrsp->bulkaddrs_val[k];
2054                 cnt++;
2055             }
2056         }
2057     }
2058     if (cnt <= 0) {
2059         ubik_AbortTrans(ctx.trans);
2060         return VL_INDEXERANGE;
2061     }
2062
2063     count = 0;
2064     willReplaceCnt = 0;
2065     foundUuidEntry = 0;
2066     /* For each server registered within the VLDB */
2067     for (srvidx = 0; srvidx <= MAXSERVERID; srvidx++) {
2068         willChangeEntry = 0;
2069         WillReplaceEntry = 1;
2070         if ((ctx.hostaddress[srvidx] & 0xff000000) == 0xff000000) {
2071             /* The server is registered as a multihomed */
2072             base = (ctx.hostaddress[srvidx] >> 16) & 0xff;
2073             index = ctx.hostaddress[srvidx] & 0x0000ffff;
2074             if (base >= VL_MAX_ADDREXTBLKS) {
2075                 VLog(0,
2076                      ("Internal error: Multihome extent base is too large. Base %d index %d\n",
2077                       base, index));
2078                 continue;
2079             }
2080             if (index >= VL_MHSRV_PERBLK) {
2081                 VLog(0,
2082                      ("Internal error: Multihome extent index is too large. Base %d index %d\n",
2083                       base, index));
2084                 continue;
2085             }
2086             if (!ctx.ex_addr[base]) {
2087                 VLog(0,
2088                      ("Internal error: Multihome extent does not exist. Base %d\n",
2089                       base));
2090                 continue;
2091             }
2092
2093             /* See if the addresses to register will change this server entry */
2094             exp = &ctx.ex_addr[base][index];
2095             tuuid = exp->ex_hostuuid;
2096             afs_ntohuuid(&tuuid);
2097             if (afs_uuid_equal(uuidp, &tuuid)) {
2098                 foundUuidEntry = 1;
2099                 FoundUuid = srvidx;
2100             } else {
2101                 for (mhidx = 0; mhidx < VL_MAXIPADDRS_PERMH; mhidx++) {
2102                     if (!exp->ex_addrs[mhidx])
2103                         continue;
2104                     for (k = 0; k < cnt; k++) {
2105                         if (ntohl(exp->ex_addrs[mhidx]) == addrs[k]) {
2106                             willChangeEntry = 1;
2107                             WillChange[count] = srvidx;
2108                             break;
2109                         }
2110                     }
2111                     if (k >= cnt)
2112                         WillReplaceEntry = 0;
2113                 }
2114             }
2115         } else {
2116             /* The server is not registered as a multihomed.
2117              * See if the addresses to register will replace this server entry.
2118              */
2119             for (k = 0; k < cnt; k++) {
2120                 if (ctx.hostaddress[srvidx] == addrs[k]) {
2121                     willChangeEntry = 1;
2122                     WillChange[count] = srvidx;
2123                     WillReplaceEntry = 1;
2124                     break;
2125                 }
2126             }
2127         }
2128         if (willChangeEntry) {
2129             if (WillReplaceEntry) {
2130                 willReplaceCnt++;
2131                 ReplaceEntry = srvidx;
2132             }
2133             count++;
2134         }
2135     }
2136
2137     /* If we found the uuid in the VLDB and if we are replacing another
2138      * entire entry, then complain and fail. Also, if we did not find
2139      * the uuid in the VLDB and the IP addresses being registered was
2140      * found in more than one other entry, then we don't know which one
2141      * to replace and will complain and fail.
2142      */
2143     if ((foundUuidEntry && (willReplaceCnt > 0))
2144         || (!foundUuidEntry && (count > 1))) {
2145         VLog(0,
2146              ("The following fileserver is being registered in the VLDB:\n"));
2147         VLog(0, ("      ["));
2148         for (k = 0; k < cnt; k++) {
2149             if (k > 0)
2150                 VLog(0,(" "));
2151             PADDR(addrs[k]);
2152         }
2153         VLog(0,("]\n"));
2154
2155         if (foundUuidEntry) {
2156             VLog(0,
2157                  ("   It would have replaced the existing VLDB server entry:\n"));
2158             VLog(0, ("      entry %d: [", FoundUuid));
2159             base = (ctx.hostaddress[FoundUuid] >> 16) & 0xff;
2160             index = ctx.hostaddress[FoundUuid] & 0x0000ffff;
2161             exp = &ctx.ex_addr[base][index];
2162             for (mhidx = 0; mhidx < VL_MAXIPADDRS_PERMH; mhidx++) {
2163                 if (!exp->ex_addrs[mhidx])
2164                     continue;
2165                 if (mhidx > 0)
2166                     VLog(0,(" "));
2167                 PADDR(ntohl(exp->ex_addrs[mhidx]));
2168             }
2169             VLog(0, ("]\n"));
2170         }
2171
2172         if (count == 1)
2173             VLog(0, ("   Yet another VLDB server entry exists:\n"));
2174         else
2175             VLog(0, ("   Yet other VLDB server entries exist:\n"));
2176         for (j = 0; j < count; j++) {
2177             srvidx = WillChange[j];
2178             VLog(0, ("      entry %d: ", srvidx));
2179             if ((ctx.hostaddress[srvidx] & 0xff000000) == 0xff000000) {
2180                 VLog(0, ("["));
2181                 base = (ctx.hostaddress[srvidx] >> 16) & 0xff;
2182                 index = ctx.hostaddress[srvidx] & 0x0000ffff;
2183                 exp = &ctx.ex_addr[base][index];
2184                 for (mhidx = 0; mhidx < VL_MAXIPADDRS_PERMH; mhidx++) {
2185                     if (!exp->ex_addrs[mhidx])
2186                         continue;
2187                     if (mhidx > 0)
2188                         VLog(0, (" "));
2189                     PADDR(ntohl(exp->ex_addrs[mhidx]));
2190                 }
2191                 VLog(0, ("]"));
2192             } else {
2193                 PADDR(ctx.hostaddress[srvidx]);
2194             }
2195             VLog(0, ("\n"));
2196         }
2197
2198         if (count == 1)
2199             VLog(0, ("   You must 'vos changeaddr' this other server entry\n"));
2200         else
2201             VLog(0,
2202                 ("   You must 'vos changeaddr' these other server entries\n"));
2203         if (foundUuidEntry)
2204             VLog(0,
2205                 ("   and/or remove the sysid file from the registering fileserver\n"));
2206         VLog(0, ("   before the fileserver can be registered in the VLDB.\n"));
2207
2208         ubik_AbortTrans(ctx.trans);
2209         return VL_MULTIPADDR;
2210     }
2211
2212     /* Passed the checks. Now find and update the existing mh entry, or create
2213      * a new mh entry.
2214      */
2215     if (foundUuidEntry) {
2216         /* Found the entry with same uuid. See if we need to change it */
2217         int change = 0;
2218
2219         fbase = (ctx.hostaddress[FoundUuid] >> 16) & 0xff;
2220         index = ctx.hostaddress[FoundUuid] & 0x0000ffff;
2221         exp = &ctx.ex_addr[fbase][index];
2222
2223         /* Determine if the entry has changed */
2224         for (k = 0; ((k < cnt) && !change); k++) {
2225             if (ntohl(exp->ex_addrs[k]) != addrs[k])
2226                 change = 1;
2227         }
2228         for (; ((k < VL_MAXIPADDRS_PERMH) && !change); k++) {
2229             if (exp->ex_addrs[k] != 0)
2230                 change = 1;
2231         }
2232         if (!change) {
2233             return (ubik_EndTrans(ctx.trans));
2234         }
2235     }
2236
2237     VLog(0, ("The following fileserver is being registered in the VLDB:\n"));
2238     VLog(0, ("      ["));
2239     for (k = 0; k < cnt; k++) {
2240         if (k > 0)
2241             VLog(0, (" "));
2242         PADDR(addrs[k]);
2243     }
2244     VLog(0, ("]\n"));
2245
2246     if (foundUuidEntry) {
2247         VLog(0,
2248             ("   It will replace the following existing entry in the VLDB (same uuid):\n"));
2249         VLog(0, ("      entry %d: [", FoundUuid));
2250         for (k = 0; k < VL_MAXIPADDRS_PERMH; k++) {
2251             if (exp->ex_addrs[k] == 0)
2252                 continue;
2253             if (k > 0)
2254                 VLog(0, (" "));
2255             PADDR(ntohl(exp->ex_addrs[k]));
2256         }
2257         VLog(0, ("]\n"));
2258     } else if (willReplaceCnt || (count == 1)) {
2259         /* If we are not replacing an entry and there is only one entry to change,
2260          * then we will replace that entry.
2261          */
2262         if (!willReplaceCnt) {
2263             ReplaceEntry = WillChange[0];
2264             willReplaceCnt++;
2265         }
2266
2267         /* Have an entry that needs to be replaced */
2268         if ((ctx.hostaddress[ReplaceEntry] & 0xff000000) == 0xff000000) {
2269             fbase = (ctx.hostaddress[ReplaceEntry] >> 16) & 0xff;
2270             index = ctx.hostaddress[ReplaceEntry] & 0x0000ffff;
2271             exp = &ctx.ex_addr[fbase][index];
2272
2273             VLog(0,
2274                 ("   It will replace the following existing entry in the VLDB (new uuid):\n"));
2275             VLog(0, ("      entry %d: [", ReplaceEntry));
2276             for (k = 0; k < VL_MAXIPADDRS_PERMH; k++) {
2277                 if (exp->ex_addrs[k] == 0)
2278                     continue;
2279                 if (k > 0)
2280                     VLog(0, (" "));
2281                 PADDR(ntohl(exp->ex_addrs[k]));
2282             }
2283             VLog(0, ("]\n"));
2284         } else {
2285             /* Not a mh entry. So we have to create a new mh entry and
2286              * put it on the ReplaceEntry slot of the ctx.hostaddress array.
2287              */
2288             VLog(0, ("   It will replace existing entry %d, ", ReplaceEntry));
2289             PADDR(ctx.hostaddress[ReplaceEntry]);
2290             VLog(0,(", in the VLDB (new uuid):\n"));
2291
2292             code =
2293                 FindExtentBlock(&ctx, uuidp, 1, ReplaceEntry, &exp, &fbase);
2294             if (code || !exp) {
2295                 ubik_AbortTrans(ctx.trans);
2296                 return (code ? code : VL_IO);
2297             }
2298         }
2299     } else {
2300         /* There is no entry for this server, must create a new mh entry as
2301          * well as use a new slot of the ctx.hostaddress array.
2302          */
2303         VLog(0, ("   It will create a new entry in the VLDB.\n"));
2304         code = FindExtentBlock(&ctx, uuidp, 1, -1, &exp, &fbase);
2305         if (code || !exp) {
2306             ubik_AbortTrans(ctx.trans);
2307             return (code ? code : VL_IO);
2308         }
2309     }
2310
2311     /* Now we have a mh entry to fill in. Update the uuid, bump the
2312      * uniquifier, and fill in its IP addresses.
2313      */
2314     tuuid = *uuidp;
2315     afs_htonuuid(&tuuid);
2316     exp->ex_hostuuid = tuuid;
2317     exp->ex_uniquifier = htonl(ntohl(exp->ex_uniquifier) + 1);
2318     for (k = 0; k < cnt; k++) {
2319         exp->ex_addrs[k] = htonl(addrs[k]);
2320     }
2321     for (; k < VL_MAXIPADDRS_PERMH; k++) {
2322         exp->ex_addrs[k] = 0;
2323     }
2324
2325     /* Write the new mh entry out */
2326     if (vlwrite
2327         (ctx.trans,
2328          DOFFSET(ntohl(ctx.ex_addr[0]->ex_contaddrs[fbase]),
2329                  (char *)ctx.ex_addr[fbase], (char *)exp), (char *)exp,
2330          sizeof(*exp))) {
2331         ubik_AbortTrans(ctx.trans);
2332         return VL_IO;
2333     }
2334
2335     /* Remove any common addresses from other mh entres. We know these entries
2336      * are being changed and not replaced so they are mh entries.
2337      */
2338     m = 0;
2339     for (i = 0; i < count; i++) {
2340         afs_int32 doff;
2341
2342         /* Skip the entry we replaced */
2343         if (willReplaceCnt && (WillChange[i] == ReplaceEntry))
2344             continue;
2345
2346         base = (ctx.hostaddress[WillChange[i]] >> 16) & 0xff;
2347         index = ctx.hostaddress[WillChange[i]] & 0x0000ffff;
2348         tex = &ctx.ex_addr[fbase][index];
2349
2350         if (++m == 1)
2351             VLog(0,
2352                 ("   The following existing entries in the VLDB will be updated:\n"));
2353
2354         VLog(0, ("      entry %d: [", WillChange[i]));
2355         for (h = j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
2356             if (tex->ex_addrs[j]) {
2357                 if (j > 0)
2358                     printf(" ");
2359                 PADDR(ntohl(tex->ex_addrs[j]));
2360             }
2361
2362             for (k = 0; k < cnt; k++) {
2363                 if (ntohl(tex->ex_addrs[j]) == addrs[k])
2364                     break;
2365             }
2366             if (k >= cnt) {
2367                 /* Not found, so we keep it */
2368                 tex->ex_addrs[h] = tex->ex_addrs[j];
2369                 h++;
2370             }
2371         }
2372         for (j = h; j < VL_MAXIPADDRS_PERMH; j++) {
2373             tex->ex_addrs[j] = 0;       /* zero rest of mh entry */
2374         }
2375         VLog(0, ("]\n"));
2376
2377         /* Write out the modified mh entry */
2378         tex->ex_uniquifier = htonl(ntohl(tex->ex_uniquifier) + 1);
2379         doff =
2380             DOFFSET(ntohl(ctx.ex_addr[0]->ex_contaddrs[base]),
2381                     (char *)ctx.ex_addr[base], (char *)tex);
2382         if (vlwrite(ctx.trans, doff, (char *)tex, sizeof(*tex))) {
2383             ubik_AbortTrans(ctx.trans);
2384             return VL_IO;
2385         }
2386     }
2387
2388     return (ubik_EndTrans(ctx.trans));
2389 }
2390
2391 afs_int32
2392 SVL_GetAddrsU(struct rx_call *rxcall,
2393               struct ListAddrByAttributes *attributes,
2394               afsUUID *uuidpo,
2395               afs_int32 *uniquifier,
2396               afs_int32 *nentries,
2397               bulkaddrs *addrsp)
2398 {
2399     afs_int32 errorcode, index = -1, offset;
2400     struct vl_ctx ctx;
2401     int nservers, i, j, base = 0;
2402     struct extentaddr *exp = 0;
2403     afsUUID tuuid;
2404     afs_uint32 *taddrp, taddr;
2405     char rxstr[AFS_RXINFO_LEN];
2406
2407     COUNT_REQ(VLGETADDRSU);
2408     addrsp->bulkaddrs_len = *nentries = 0;
2409     addrsp->bulkaddrs_val = 0;
2410     VLog(5, ("GetAddrsU %s\n", rxinfo(rxstr, rxcall)));
2411     if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op)))
2412         return errorcode;
2413
2414     if (attributes->Mask & VLADDR_IPADDR) {
2415         if (attributes->Mask & (VLADDR_INDEX | VLADDR_UUID)) {
2416             ubik_AbortTrans(ctx.trans);
2417             return VL_BADMASK;
2418         }
2419         for (base = 0; base < VL_MAX_ADDREXTBLKS; base++) {
2420             if (!ctx.ex_addr[base])
2421                 break;
2422             for (i = 1; i < VL_MHSRV_PERBLK; i++) {
2423                 exp = &ctx.ex_addr[base][i];
2424                 tuuid = exp->ex_hostuuid;
2425                 afs_ntohuuid(&tuuid);
2426                 if (afs_uuid_is_nil(&tuuid))
2427                     continue;
2428                 for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
2429                     if (exp->ex_addrs[j]
2430                         && (ntohl(exp->ex_addrs[j]) == attributes->ipaddr)) {
2431                         break;
2432                     }
2433                 }
2434                 if (j < VL_MAXIPADDRS_PERMH)
2435                     break;
2436             }
2437             if (i < VL_MHSRV_PERBLK)
2438                 break;
2439         }
2440         if (base >= VL_MAX_ADDREXTBLKS) {
2441             ubik_AbortTrans(ctx.trans);
2442             return VL_NOENT;
2443         }
2444     } else if (attributes->Mask & VLADDR_INDEX) {
2445         if (attributes->Mask & (VLADDR_IPADDR | VLADDR_UUID)) {
2446             ubik_AbortTrans(ctx.trans);
2447             return VL_BADMASK;
2448         }
2449         index = attributes->index;
2450         if (index < 1 || index >= (VL_MAX_ADDREXTBLKS * VL_MHSRV_PERBLK)) {
2451             ubik_AbortTrans(ctx.trans);
2452             return VL_INDEXERANGE;
2453         }
2454         base = index / VL_MHSRV_PERBLK;
2455         offset = index % VL_MHSRV_PERBLK;
2456         if (offset == 0) {
2457             ubik_AbortTrans(ctx.trans);
2458             return VL_NOENT;
2459         }
2460         if (!ctx.ex_addr[base]) {
2461             ubik_AbortTrans(ctx.trans);
2462             return VL_INDEXERANGE;
2463         }
2464         exp = &ctx.ex_addr[base][offset];
2465     } else if (attributes->Mask & VLADDR_UUID) {
2466         if (attributes->Mask & (VLADDR_IPADDR | VLADDR_INDEX)) {
2467             ubik_AbortTrans(ctx.trans);
2468             return VL_BADMASK;
2469         }
2470         if (!ctx.ex_addr[0]) {  /* mh servers probably aren't setup on this vldb */
2471             ubik_AbortTrans(ctx.trans);
2472             return VL_NOENT;
2473         }
2474         if ((errorcode =
2475             FindExtentBlock(&ctx, &attributes->uuid, 0, -1, &exp, &base))) {
2476             ubik_AbortTrans(ctx.trans);
2477             return errorcode;
2478         }
2479     } else {
2480         ubik_AbortTrans(ctx.trans);
2481         return VL_BADMASK;
2482     }
2483
2484     if (exp == NULL) {
2485         ubik_AbortTrans(ctx.trans);
2486         return VL_NOENT;
2487     }
2488     addrsp->bulkaddrs_val = taddrp =
2489         (afs_uint32 *) malloc(sizeof(afs_int32) * (MAXSERVERID + 1));
2490     nservers = *nentries = addrsp->bulkaddrs_len = 0;
2491     if (!taddrp) {
2492         COUNT_ABO;
2493         ubik_AbortTrans(ctx.trans);
2494         return VL_NOMEM;
2495     }
2496     tuuid = exp->ex_hostuuid;
2497     afs_ntohuuid(&tuuid);
2498     if (afs_uuid_is_nil(&tuuid)) {
2499         ubik_AbortTrans(ctx.trans);
2500         return VL_NOENT;
2501     }
2502     if (uuidpo)
2503         *uuidpo = tuuid;
2504     if (uniquifier)
2505         *uniquifier = ntohl(exp->ex_uniquifier);
2506     for (i = 0; i < VL_MAXIPADDRS_PERMH; i++) {
2507         if (exp->ex_addrs[i]) {
2508             taddr = ntohl(exp->ex_addrs[i]);
2509             /* Weed out duplicates */
2510             for (j = 0; j < nservers; j++) {
2511                 if (taddrp[j] == taddr)
2512                     break;
2513             }
2514             if ((j == nservers) && (j <= MAXSERVERID)) {
2515                 taddrp[nservers] = taddr;
2516                 nservers++;
2517             }
2518         }
2519     }
2520     addrsp->bulkaddrs_len = *nentries = nservers;
2521     return (ubik_EndTrans(ctx.trans));
2522 }
2523
2524 /* ============> End of Exported vldb RPC functions <============= */
2525
2526
2527 /* Routine that copies the given vldb entry to the output buffer, vldbentries. */
2528 static int
2529 put_attributeentry(struct vl_ctx *ctx,
2530                    struct vldbentry **Vldbentry,
2531                    struct vldbentry **VldbentryFirst,
2532                    struct vldbentry **VldbentryLast,
2533                    bulkentries *vldbentries,
2534                    struct nvlentry *entry,
2535                    afs_int32 *nentries,
2536                    afs_int32 *alloccnt)
2537 {
2538     vldbentry *reall;
2539     afs_int32 allo;
2540
2541     if (*Vldbentry == *VldbentryLast) {
2542         if (smallMem)
2543             return VL_SIZEEXCEEDED;     /* no growing if smallMem defined */
2544
2545         /* Allocate another set of memory; each time allocate twice as
2546          * many blocks as the last time. When we reach VLDBALLOCLIMIT,
2547          * then grow in increments of VLDBALLOCINCR.
2548          */
2549         allo = (*alloccnt > VLDBALLOCLIMIT) ? VLDBALLOCINCR : *alloccnt;
2550         reall =
2551             (vldbentry *) realloc(*VldbentryFirst,
2552                                   (*alloccnt + allo) * sizeof(vldbentry));
2553         if (reall == NULL)
2554             return VL_NOMEM;
2555
2556         *VldbentryFirst = vldbentries->bulkentries_val = reall;
2557         *Vldbentry = *VldbentryFirst + *alloccnt;
2558         *VldbentryLast = *Vldbentry + allo;
2559         *alloccnt += allo;
2560     }
2561     vlentry_to_vldbentry(ctx, entry, *Vldbentry);
2562     (*Vldbentry)++;
2563     (*nentries)++;
2564     vldbentries->bulkentries_len++;
2565     return 0;
2566 }
2567
2568 static int
2569 put_nattributeentry(struct vl_ctx *ctx,
2570                     struct nvldbentry **Vldbentry,
2571                     struct nvldbentry **VldbentryFirst,
2572                     struct nvldbentry **VldbentryLast,
2573                     nbulkentries *vldbentries,
2574                     struct nvlentry *entry,
2575                     afs_int32 matchtype,
2576                     afs_int32 matchindex,
2577                     afs_int32 *nentries,
2578                     afs_int32 *alloccnt)
2579 {
2580     nvldbentry *reall;
2581     afs_int32 allo;
2582
2583     if (*Vldbentry == *VldbentryLast) {
2584         if (smallMem)
2585             return VL_SIZEEXCEEDED;     /* no growing if smallMem defined */
2586
2587         /* Allocate another set of memory; each time allocate twice as
2588          * many blocks as the last time. When we reach VLDBALLOCLIMIT,
2589          * then grow in increments of VLDBALLOCINCR.
2590          */
2591         allo = (*alloccnt > VLDBALLOCLIMIT) ? VLDBALLOCINCR : *alloccnt;
2592         reall =
2593             (nvldbentry *) realloc(*VldbentryFirst,
2594                                    (*alloccnt + allo) * sizeof(nvldbentry));
2595         if (reall == NULL)
2596             return VL_NOMEM;
2597
2598         *VldbentryFirst = vldbentries->nbulkentries_val = reall;
2599         *Vldbentry = *VldbentryFirst + *alloccnt;
2600         *VldbentryLast = *Vldbentry + allo;
2601         *alloccnt += allo;
2602     }
2603     vlentry_to_nvldbentry(ctx, entry, *Vldbentry);
2604     (*Vldbentry)->matchindex = (matchtype << 16) + matchindex;
2605     (*Vldbentry)++;
2606     (*nentries)++;
2607     vldbentries->nbulkentries_len++;
2608     return 0;
2609 }
2610
2611
2612 /* Common code to actually remove a vldb entry from the database. */
2613 static int
2614 RemoveEntry(struct vl_ctx *ctx, afs_int32 entryptr,
2615             struct nvlentry *tentry)
2616 {
2617     int errorcode;
2618
2619     if ((errorcode = UnthreadVLentry(ctx, entryptr, tentry)))
2620         return errorcode;
2621     if ((errorcode = FreeBlock(ctx, entryptr)))
2622         return errorcode;
2623     return 0;
2624 }
2625
2626 static void
2627 ReleaseEntry(struct nvlentry *tentry, afs_int32 releasetype)
2628 {
2629     if (releasetype & LOCKREL_TIMESTAMP)
2630         tentry->LockTimestamp = 0;
2631     if (releasetype & LOCKREL_OPCODE)
2632         tentry->flags &= ~VLOP_ALLOPERS;
2633     if (releasetype & LOCKREL_AFSID)
2634         tentry->LockAfsId = 0;
2635 }
2636
2637
2638 /* Verify that the incoming vldb entry is valid; multi type of error codes
2639  * are returned. */
2640 static int
2641 check_vldbentry(struct vldbentry *aentry)
2642 {
2643     afs_int32 i;
2644
2645     if (InvalidVolname(aentry->name))
2646         return VL_BADNAME;
2647     if (aentry->nServers <= 0 || aentry->nServers > OMAXNSERVERS)
2648         return VL_BADSERVER;
2649     for (i = 0; i < aentry->nServers; i++) {
2650 /*      if (aentry->serverNumber[i] < 0 || aentry->serverNumber[i] > MAXSERVERID)
2651             return VL_BADSERVER;        */
2652         if (aentry->serverPartition[i] < 0
2653             || aentry->serverPartition[i] > MAXPARTITIONID)
2654             return VL_BADPARTITION;
2655         if (aentry->serverFlags[i] < 0
2656             || aentry->serverFlags[i] > MAXSERVERFLAG)
2657             return VL_BADSERVERFLAG;
2658     }
2659     return 0;
2660 }
2661
2662 static int
2663 check_nvldbentry(struct nvldbentry *aentry)
2664 {
2665     afs_int32 i;
2666
2667     if (InvalidVolname(aentry->name))
2668         return VL_BADNAME;
2669     if (aentry->nServers <= 0 || aentry->nServers > NMAXNSERVERS)
2670         return VL_BADSERVER;
2671     for (i = 0; i < aentry->nServers; i++) {
2672 /*      if (aentry->serverNumber[i] < 0 || aentry->serverNumber[i] > MAXSERVERID)
2673             return VL_BADSERVER;        */
2674         if (aentry->serverPartition[i] < 0
2675             || aentry->serverPartition[i] > MAXPARTITIONID)
2676             return VL_BADPARTITION;
2677         if (aentry->serverFlags[i] < 0
2678             || aentry->serverFlags[i] > MAXSERVERFLAG)
2679             return VL_BADSERVERFLAG;
2680     }
2681     return 0;
2682 }
2683
2684
2685 /* Convert from the external vldb entry representation to its internal
2686    (more compact) form.  This call should not change the hash chains! */
2687 static int
2688 vldbentry_to_vlentry(struct vl_ctx *ctx,
2689                      struct vldbentry *VldbEntry,
2690                      struct nvlentry *VlEntry)
2691 {
2692     int i, serverindex;
2693
2694     if (strcmp(VlEntry->name, VldbEntry->name))
2695         strncpy(VlEntry->name, VldbEntry->name, sizeof(VlEntry->name));
2696     for (i = 0; i < VldbEntry->nServers; i++) {
2697         serverindex = IpAddrToRelAddr(ctx, VldbEntry->serverNumber[i], 1);
2698         if (serverindex == -1)
2699             return VL_BADSERVER;
2700         VlEntry->serverNumber[i] = serverindex;
2701         VlEntry->serverPartition[i] = VldbEntry->serverPartition[i];
2702         VlEntry->serverFlags[i] = VldbEntry->serverFlags[i];
2703     }
2704     for (; i < OMAXNSERVERS; i++)
2705         VlEntry->serverNumber[i] = VlEntry->serverPartition[i] =
2706             VlEntry->serverFlags[i] = BADSERVERID;
2707     for (i = 0; i < MAXTYPES; i++)
2708         VlEntry->volumeId[i] = VldbEntry->volumeId[i];
2709     VlEntry->cloneId = VldbEntry->cloneId;
2710     VlEntry->flags = VldbEntry->flags;
2711     return 0;
2712 }
2713
2714 static int
2715 nvldbentry_to_vlentry(struct vl_ctx *ctx,
2716                       struct nvldbentry *VldbEntry,
2717                       struct nvlentry *VlEntry)
2718 {
2719     int i, serverindex;
2720
2721     if (strcmp(VlEntry->name, VldbEntry->name))
2722         strncpy(VlEntry->name, VldbEntry->name, sizeof(VlEntry->name));
2723     for (i = 0; i < VldbEntry->nServers; i++) {
2724         serverindex = IpAddrToRelAddr(ctx, VldbEntry->serverNumber[i], 1);
2725         if (serverindex == -1)
2726             return VL_BADSERVER;
2727         VlEntry->serverNumber[i] = serverindex;
2728         VlEntry->serverPartition[i] = VldbEntry->serverPartition[i];
2729         VlEntry->serverFlags[i] = VldbEntry->serverFlags[i];
2730     }
2731     for (; i < NMAXNSERVERS; i++)
2732         VlEntry->serverNumber[i] = VlEntry->serverPartition[i] =
2733             VlEntry->serverFlags[i] = BADSERVERID;
2734     for (i = 0; i < MAXTYPES; i++)
2735         VlEntry->volumeId[i] = VldbEntry->volumeId[i];
2736     VlEntry->cloneId = VldbEntry->cloneId;
2737     VlEntry->flags = VldbEntry->flags;
2738     return 0;
2739 }
2740
2741
2742 /* Update the vldb entry with the new fields as indicated by the value of
2743  * the Mask entry in the updateentry structure. All necessary validation
2744  * checks are performed.
2745  */
2746 static int
2747 get_vldbupdateentry(struct vl_ctx *ctx,
2748                     afs_int32 blockindex,
2749                     struct VldbUpdateEntry *updateentry,
2750                     struct nvlentry *VlEntry)
2751 {
2752     int i, j, errorcode, serverindex;
2753     afs_uint32 checkids[MAXTYPES];
2754
2755     /* check if any specified new IDs are already present in the db. Do
2756      * this check before doing anything else, so we don't get a half-
2757      * updated entry. */
2758     memset(&checkids, 0, sizeof(checkids));
2759     if (updateentry->Mask & VLUPDATE_RWID) {
2760         checkids[RWVOL] = updateentry->spares3; /* rw id */
2761     }
2762     if (updateentry->Mask & VLUPDATE_READONLYID) {
2763         checkids[ROVOL] = updateentry->ReadOnlyId;
2764     }
2765     if (updateentry->Mask & VLUPDATE_BACKUPID) {
2766         checkids[BACKVOL] = updateentry->BackupId;
2767     }
2768
2769     if (EntryIDExists(ctx, checkids, MAXTYPES, &errorcode)) {
2770         return VL_IDEXIST;
2771     } else if (errorcode) {
2772         return errorcode;
2773     }
2774
2775     if (updateentry->Mask & VLUPDATE_VOLUMENAME) {
2776         struct nvlentry tentry;
2777
2778         if (InvalidVolname(updateentry->name))
2779             return VL_BADNAME;
2780
2781         if (FindByName(ctx, updateentry->name, &tentry, &errorcode)) {
2782             return VL_NAMEEXIST;
2783         } else if (errorcode) {
2784             return errorcode;
2785         }
2786
2787         if ((errorcode = UnhashVolname(ctx, blockindex, VlEntry)))
2788             return errorcode;
2789         strncpy(VlEntry->name, updateentry->name, sizeof(VlEntry->name));
2790         HashVolname(ctx, blockindex, VlEntry);
2791     }
2792
2793     if (updateentry->Mask & VLUPDATE_VOLNAMEHASH) {
2794         if ((errorcode = UnhashVolname(ctx, blockindex, VlEntry))) {
2795             if (errorcode != VL_NOENT)
2796                 return errorcode;
2797         }
2798         HashVolname(ctx, blockindex, VlEntry);
2799     }
2800
2801     if (updateentry->Mask & VLUPDATE_FLAGS) {
2802         VlEntry->flags = updateentry->flags;
2803     }
2804     if (updateentry->Mask & VLUPDATE_CLONEID) {
2805         VlEntry->cloneId = updateentry->cloneId;
2806     }
2807     if (updateentry->Mask & VLUPDATE_RWID) {
2808         if ((errorcode = UnhashVolid(ctx, RWVOL, blockindex, VlEntry))) {
2809             if (errorcode != VL_NOENT)
2810                 return errorcode;
2811         }
2812         VlEntry->volumeId[RWVOL] = updateentry->spares3;        /* rw id */
2813         if ((errorcode = HashVolid(ctx, RWVOL, blockindex, VlEntry)))
2814             return errorcode;
2815     }
2816     if (updateentry->Mask & VLUPDATE_READONLYID) {
2817         if ((errorcode = UnhashVolid(ctx, ROVOL, blockindex, VlEntry))) {
2818             if (errorcode != VL_NOENT)
2819                 return errorcode;
2820         }
2821         VlEntry->volumeId[ROVOL] = updateentry->ReadOnlyId;
2822         if ((errorcode = HashVolid(ctx, ROVOL, blockindex, VlEntry)))
2823             return errorcode;
2824     }
2825     if (updateentry->Mask & VLUPDATE_BACKUPID) {
2826         if ((errorcode = UnhashVolid(ctx, BACKVOL, blockindex, VlEntry))) {
2827             if (errorcode != VL_NOENT)
2828                 return errorcode;
2829         }
2830         VlEntry->volumeId[BACKVOL] = updateentry->BackupId;
2831         if ((errorcode = HashVolid(ctx, BACKVOL, blockindex, VlEntry)))
2832             return errorcode;
2833     }
2834     if (updateentry->Mask & VLUPDATE_REPSITES) {
2835         if (updateentry->nModifiedRepsites <= 0
2836             || updateentry->nModifiedRepsites > OMAXNSERVERS)
2837             return VL_BADSERVER;
2838         for (i = 0; i < updateentry->nModifiedRepsites; i++) {
2839 /*          if (updateentry->RepsitesTargetServer[i] < 0 || updateentry->RepsitesTargetServer[i] > MAXSERVERID)
2840                 return VL_BADSERVER;    */
2841             if (updateentry->RepsitesTargetPart[i] < 0
2842                 || updateentry->RepsitesTargetPart[i] > MAXPARTITIONID)
2843                 return VL_BADPARTITION;
2844             if (updateentry->RepsitesMask[i] & VLUPDATE_REPS_DELETE) {
2845                 if ((j =
2846                      repsite_exists(VlEntry,
2847                                     IpAddrToRelAddr(ctx, updateentry->
2848                                                     RepsitesTargetServer[i],
2849                                                     1),
2850                                     updateentry->RepsitesTargetPart[i])) !=
2851                     -1)
2852                     repsite_compress(VlEntry, j);
2853                 else
2854                     return VL_NOREPSERVER;
2855             }
2856             if (updateentry->RepsitesMask[i] & VLUPDATE_REPS_ADD) {
2857 /*              if (updateentry->RepsitesNewServer[i] < 0 || updateentry->RepsitesNewServer[i] > MAXSERVERID)
2858                     return VL_BADSERVER;                */
2859                 if (updateentry->RepsitesNewPart[i] < 0
2860                     || updateentry->RepsitesNewPart[i] > MAXPARTITIONID)
2861                     return VL_BADPARTITION;
2862                 if (repsite_exists
2863                     (VlEntry,
2864                      IpAddrToRelAddr(ctx, updateentry->RepsitesNewServer[i], 1),
2865                      updateentry->RepsitesNewPart[i]) != -1)
2866                     return VL_DUPREPSERVER;
2867                 for (j = 0;
2868                      VlEntry->serverNumber[j] != BADSERVERID
2869                      && j < OMAXNSERVERS; j++);
2870                 if (j >= OMAXNSERVERS)
2871                     return VL_REPSFULL;
2872                 if ((serverindex =
2873                      IpAddrToRelAddr(ctx, updateentry->RepsitesNewServer[i],
2874                                      1)) == -1)
2875                     return VL_BADSERVER;
2876                 VlEntry->serverNumber[j] = serverindex;
2877                 VlEntry->serverPartition[j] = updateentry->RepsitesNewPart[i];
2878                 if (updateentry->RepsitesNewFlags[i] < 0
2879                     || updateentry->RepsitesNewFlags[i] > MAXSERVERFLAG)
2880                     return VL_BADSERVERFLAG;
2881                 VlEntry->serverFlags[j] = updateentry->RepsitesNewFlags[i];
2882             }
2883             if (updateentry->RepsitesMask[i] & VLUPDATE_REPS_MODSERV) {
2884 /*n             if (updateentry->RepsitesNewServer[i] < 0 || updateentry->RepsitesNewServer[i] > MAXSERVERID)
2885                     return VL_BADSERVER;            */
2886                 if ((j =
2887                      repsite_exists(VlEntry,
2888                                     IpAddrToRelAddr(ctx, updateentry->
2889                                                     RepsitesTargetServer[i],
2890                                                     1),
2891                                     updateentry->RepsitesTargetPart[i])) !=
2892                     -1) {
2893                     VlEntry->serverNumber[j] =
2894                         IpAddrToRelAddr(ctx, updateentry->RepsitesNewServer[i],
2895                                         1);
2896                 } else
2897                     return VL_NOREPSERVER;
2898             }
2899             if (updateentry->RepsitesMask[i] & VLUPDATE_REPS_MODPART) {
2900                 if (updateentry->RepsitesNewPart[i] < 0
2901                     || updateentry->RepsitesNewPart[i] > MAXPARTITIONID)
2902                     return VL_BADPARTITION;
2903                 if ((j =
2904                      repsite_exists(VlEntry,
2905                                     IpAddrToRelAddr(ctx, updateentry->
2906                                                     RepsitesTargetServer[i],
2907                                                     1),
2908                                     updateentry->RepsitesTargetPart[i])) !=
2909                     -1)
2910                     VlEntry->serverPartition[j] =
2911                         updateentry->RepsitesNewPart[i];
2912                 else
2913                     return VL_NOREPSERVER;
2914             }
2915             if (updateentry->RepsitesMask[i] & VLUPDATE_REPS_MODFLAG) {
2916                 if ((j =
2917                      repsite_exists(VlEntry,
2918                                     IpAddrToRelAddr(ctx, updateentry->
2919                                                     RepsitesTargetServer[i],
2920                                                     1),
2921                                     updateentry->RepsitesTargetPart[i])) !=
2922                     -1) {
2923                     if (updateentry->RepsitesNewFlags[i] < 0
2924                         || updateentry->RepsitesNewFlags[i] > MAXSERVERFLAG)
2925                         return VL_BADSERVERFLAG;
2926                     VlEntry->serverFlags[j] =
2927                         updateentry->RepsitesNewFlags[i];
2928                 } else
2929                     return VL_NOREPSERVER;
2930             }
2931         }
2932     }
2933     return 0;
2934 }
2935
2936
2937 /* Check if the specified [server,partition] entry is found in the vldb
2938  * entry's repsite table; it's offset in the table is returned, if it's
2939  * present there. */
2940 static int
2941 repsite_exists(struct nvlentry *VlEntry, int server, int partition)
2942 {
2943     int i;
2944
2945     for (i = 0; VlEntry->serverNumber[i] != BADSERVERID && i < OMAXNSERVERS;
2946          i++) {
2947         if ((VlEntry->serverNumber[i] == server)
2948             && (VlEntry->serverPartition[i] == partition))
2949             return i;
2950     }
2951     return -1;
2952 }
2953
2954
2955
2956 /* Repsite table compression: used when deleting a repsite entry so that
2957  * all active repsite entries are on the top of the table. */
2958 static void
2959 repsite_compress(struct nvlentry *VlEntry, int offset)
2960 {
2961     int repsite_offset = offset;
2962     for (;
2963          VlEntry->serverNumber[repsite_offset] != BADSERVERID
2964          && repsite_offset < OMAXNSERVERS - 1; repsite_offset++) {
2965         VlEntry->serverNumber[repsite_offset] =
2966             VlEntry->serverNumber[repsite_offset + 1];
2967         VlEntry->serverPartition[repsite_offset] =
2968             VlEntry->serverPartition[repsite_offset + 1];
2969         VlEntry->serverFlags[repsite_offset] =
2970             VlEntry->serverFlags[repsite_offset + 1];
2971     }
2972     VlEntry->serverNumber[repsite_offset] = BADSERVERID;
2973 }
2974
2975
2976 /* Convert from the internal (compacted) vldb entry to the external
2977  * representation used by the interface. */
2978 static void
2979 vlentry_to_vldbentry(struct vl_ctx *ctx, struct nvlentry *VlEntry,
2980                      struct vldbentry *VldbEntry)
2981 {
2982     int i, j;
2983
2984     memset(VldbEntry, 0, sizeof(struct vldbentry));
2985     strncpy(VldbEntry->name, VlEntry->name, sizeof(VldbEntry->name));
2986     for (i = 0; i < OMAXNSERVERS; i++) {
2987         if (VlEntry->serverNumber[i] == BADSERVERID)
2988             break;
2989         if ((ctx->hostaddress[j = VlEntry->serverNumber[i]] & 0xff000000) ==
2990             0xff000000) {
2991             struct extentaddr *exp;
2992             int base, index;
2993
2994             base = (ctx->hostaddress[j] >> 16) & 0xff;
2995             index = ctx->hostaddress[j] & 0x0000ffff;
2996             exp = &ctx->ex_addr[base][index];
2997             /* For now return the first ip address back */
2998             for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
2999                 if (exp->ex_addrs[j]) {
3000                     VldbEntry->serverNumber[i] = ntohl(exp->ex_addrs[j]);
3001                     break;
3002                 }
3003             }
3004         } else
3005             VldbEntry->serverNumber[i] =
3006                 ctx->hostaddress[VlEntry->serverNumber[i]];
3007         VldbEntry->serverPartition[i] = VlEntry->serverPartition[i];
3008         VldbEntry->serverFlags[i] = VlEntry->serverFlags[i];
3009     }
3010     VldbEntry->nServers = i;
3011     for (i = 0; i < MAXTYPES; i++)
3012         VldbEntry->volumeId[i] = VlEntry->volumeId[i];
3013     VldbEntry->cloneId = VlEntry->cloneId;
3014     VldbEntry->flags = VlEntry->flags;
3015 }
3016
3017
3018 /* Convert from the internal (compacted) vldb entry to the external
3019  * representation used by the interface. */
3020 static void
3021 vlentry_to_nvldbentry(struct vl_ctx *ctx, struct nvlentry *VlEntry,
3022                       struct nvldbentry *VldbEntry)
3023 {
3024     int i, j;
3025
3026     memset(VldbEntry, 0, sizeof(struct vldbentry));
3027     strncpy(VldbEntry->name, VlEntry->name, sizeof(VldbEntry->name));
3028     for (i = 0; i < NMAXNSERVERS; i++) {
3029         if (VlEntry->serverNumber[i] == BADSERVERID)
3030             break;
3031         if ((ctx->hostaddress[j = VlEntry->serverNumber[i]] & 0xff000000) ==
3032             0xff000000) {
3033             struct extentaddr *exp;
3034             int base, index;
3035
3036             base = (ctx->hostaddress[j] >> 16) & 0xff;
3037             index = ctx->hostaddress[j] & 0x0000ffff;
3038             exp = &ctx->ex_addr[base][index];
3039             /* For now return the first ip address back */
3040             for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
3041                 if (exp->ex_addrs[j]) {
3042                     VldbEntry->serverNumber[i] = ntohl(exp->ex_addrs[j]);
3043                     break;
3044                 }
3045             }
3046         } else
3047             VldbEntry->serverNumber[i] =
3048                 ctx->hostaddress[VlEntry->serverNumber[i]];
3049         VldbEntry->serverPartition[i] = VlEntry->serverPartition[i];
3050         VldbEntry->serverFlags[i] = VlEntry->serverFlags[i];
3051     }
3052     VldbEntry->nServers = i;
3053     for (i = 0; i < MAXTYPES; i++)
3054         VldbEntry->volumeId[i] = VlEntry->volumeId[i];
3055     VldbEntry->cloneId = VlEntry->cloneId;
3056     VldbEntry->flags = VlEntry->flags;
3057 }
3058
3059 static void
3060 vlentry_to_uvldbentry(struct vl_ctx *ctx, struct nvlentry *VlEntry,
3061                       struct uvldbentry *VldbEntry)
3062 {
3063     int i, j;
3064
3065     memset(VldbEntry, 0, sizeof(struct vldbentry));
3066     strncpy(VldbEntry->name, VlEntry->name, sizeof(VldbEntry->name));
3067     for (i = 0; i < NMAXNSERVERS; i++) {
3068         if (VlEntry->serverNumber[i] == BADSERVERID)
3069             break;
3070         VldbEntry->serverFlags[i] = VlEntry->serverFlags[i];
3071         VldbEntry->serverUnique[i] = 0;
3072         if ((ctx->hostaddress[j = VlEntry->serverNumber[i]] & 0xff000000) ==
3073             0xff000000) {
3074             struct extentaddr *exp;
3075             int base, index;
3076             afsUUID tuuid;
3077
3078             base = (ctx->hostaddress[j] >> 16) & 0xff;
3079             index = ctx->hostaddress[j] & 0x0000ffff;
3080             exp = &ctx->ex_addr[base][index];
3081             tuuid = exp->ex_hostuuid;
3082             afs_ntohuuid(&tuuid);
3083             VldbEntry->serverFlags[i] |= VLSERVER_FLAG_UUID;
3084             VldbEntry->serverNumber[i] = tuuid;
3085             VldbEntry->serverUnique[i] = ntohl(exp->ex_uniquifier);
3086         } else {
3087             VldbEntry->serverNumber[i].time_low =
3088                 ctx->hostaddress[VlEntry->serverNumber[i]];
3089         }
3090         VldbEntry->serverPartition[i] = VlEntry->serverPartition[i];
3091
3092     }
3093     VldbEntry->nServers = i;
3094     for (i = 0; i < MAXTYPES; i++)
3095         VldbEntry->volumeId[i] = VlEntry->volumeId[i];
3096     VldbEntry->cloneId = VlEntry->cloneId;
3097     VldbEntry->flags = VlEntry->flags;
3098 }
3099
3100 #define LEGALCHARS ".ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
3101
3102
3103 /* Verify that the volname is a valid volume name. */
3104 static int
3105 InvalidVolname(char *volname)
3106 {
3107     char *map;
3108     int slen;
3109
3110     map = LEGALCHARS;
3111     slen = strlen(volname);
3112     if (slen >= VL_MAXNAMELEN)
3113         return 1;
3114     return (slen != strspn(volname, map));
3115 }
3116
3117
3118 /* Verify that the given volume type is valid. */
3119 static int
3120 InvalidVoltype(afs_int32 voltype)
3121 {
3122     if (voltype != RWVOL && voltype != ROVOL && voltype != BACKVOL)
3123         return 1;
3124     return 0;
3125 }
3126
3127
3128 static int
3129 InvalidOperation(afs_int32 voloper)
3130 {
3131     if (voloper != VLOP_MOVE && voloper != VLOP_RELEASE
3132         && voloper != VLOP_BACKUP && voloper != VLOP_DELETE
3133         && voloper != VLOP_DUMP)
3134         return 1;
3135     return 0;
3136 }
3137
3138 static int
3139 InvalidReleasetype(afs_int32 releasetype)
3140 {
3141     if ((releasetype & LOCKREL_TIMESTAMP) || (releasetype & LOCKREL_OPCODE)
3142         || (releasetype & LOCKREL_AFSID))
3143         return 0;
3144     return 1;
3145 }
3146
3147 static int
3148 IpAddrToRelAddr(struct vl_ctx *ctx, afs_uint32 ipaddr, int create)
3149 {
3150     int i, j;
3151     afs_int32 code, base, index;
3152     struct extentaddr *exp;
3153
3154     for (i = 0; i <= MAXSERVERID; i++) {
3155         if (ctx->hostaddress[i] == ipaddr)
3156             return i;
3157         if ((ctx->hostaddress[i] & 0xff000000) == 0xff000000) {
3158             base = (ctx->hostaddress[i] >> 16) & 0xff;
3159             index = ctx->hostaddress[i] & 0x0000ffff;
3160             if (base >= VL_MAX_ADDREXTBLKS) {
3161                 VLog(0,
3162                      ("Internal error: Multihome extent base is too large. Base %d index %d\n",
3163                       base, index));
3164                 return -1;      /* EINVAL */
3165             }
3166             if (index >= VL_MHSRV_PERBLK) {
3167                 VLog(0,
3168                      ("Internal error: Multihome extent index is too large. Base %d index %d\n",
3169                       base, index));
3170                 return -1;      /* EINVAL */
3171             }
3172             if (!ctx->ex_addr[base]) {
3173                 VLog(0,
3174                      ("Internal error: Multihome extent does not exist. Base %d\n",
3175                       base));
3176                 return -1;      /* EINVAL */
3177             }
3178             exp = &ctx->ex_addr[base][index];
3179             for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
3180                 if (exp->ex_addrs[j] && (ntohl(exp->ex_addrs[j]) == ipaddr)) {
3181                     return i;
3182                 }
3183             }
3184         }
3185     }
3186
3187     /* allocate the new server a server id pronto */
3188     if (create) {
3189         for (i = 0; i <= MAXSERVERID; i++) {
3190             if (ctx->cheader->IpMappedAddr[i] == 0) {
3191                 ctx->cheader->IpMappedAddr[i] = htonl(ipaddr);
3192                 code =
3193                     vlwrite(ctx->trans,
3194                             DOFFSET(0, ctx->cheader, &ctx->cheader->IpMappedAddr[i]),
3195                             (char *)&ctx->cheader->IpMappedAddr[i],
3196                             sizeof(afs_int32));
3197                 ctx->hostaddress[i] = ipaddr;
3198                 if (code)
3199                     return -1;
3200                 return i;
3201             }
3202         }
3203     }
3204     return -1;
3205 }
3206
3207 static int
3208 ChangeIPAddr(struct vl_ctx *ctx, afs_uint32 ipaddr1, afs_uint32 ipaddr2)
3209 {
3210     int i, j;
3211     afs_int32 code;
3212     struct extentaddr *exp = NULL;
3213     int base = 0;
3214     int index, mhidx;
3215     afsUUID tuuid;
3216     afs_int32 blockindex, count;
3217     int pollcount = 0;
3218     struct nvlentry tentry;
3219     int ipaddr1_id = -1, ipaddr2_id = -1;
3220
3221     /* Don't let addr change to 256.*.*.* : Causes internal error below */
3222     if ((ipaddr2 & 0xff000000) == 0xff000000)
3223         return (VL_BADSERVER);
3224
3225     /* If we are removing an address, ip1 will be -1 and ip2 will be
3226      * the original address. This prevents an older revision vlserver
3227      * from removing the IP address (won't find server 0xfffffff in
3228      * the VLDB). An older revision vlserver does not have the check
3229      * to see if any volumes exist on the server being removed.
3230      */
3231     if (ipaddr1 == 0xffffffff) {
3232         ipaddr1 = ipaddr2;
3233         ipaddr2 = 0;
3234     }
3235
3236     for (i = 0; i <= MAXSERVERID; i++) {
3237         if ((ctx->hostaddress[i] & 0xff000000) == 0xff000000) {
3238             base = (ctx->hostaddress[i] >> 16) & 0xff;
3239             index = ctx->hostaddress[i] & 0x0000ffff;
3240             if ((base >= VL_MAX_ADDREXTBLKS) || (index >= VL_MHSRV_PERBLK)) {
3241                 VLog(0,
3242                      ("Internal error: Multihome extent addr is too large. Base %d index %d\n",
3243                       base, index));
3244                 return -1;      /* EINVAL */
3245             }
3246
3247             exp = &ctx->ex_addr[base][index];
3248             for (mhidx = 0; mhidx < VL_MAXIPADDRS_PERMH; mhidx++) {
3249                 if (!exp->ex_addrs[mhidx])
3250                     continue;
3251                 if (ntohl(exp->ex_addrs[mhidx]) == ipaddr1) {
3252                     ipaddr1_id = i;
3253                 }
3254                 if (ipaddr2 != 0 && ntohl(exp->ex_addrs[mhidx]) == ipaddr2) {
3255                     ipaddr2_id = i;
3256                 }
3257             }
3258         } else {
3259             if (ctx->hostaddress[i] == ipaddr1) {
3260                 exp = NULL;
3261                 ipaddr1_id = i;
3262             }
3263             if (ipaddr2 != 0 && ctx->hostaddress[i] == ipaddr2) {
3264                 ipaddr2_id = i;
3265             }
3266         }
3267
3268         if (ipaddr1_id >= 0 && (ipaddr2 == 0 || ipaddr2_id >= 0)) {
3269             /* we've either found both IPs already in the VLDB, or we found
3270              * ipaddr1, and we're not going to find ipaddr2 because it's 0 */
3271             break;
3272         }
3273     }
3274
3275     if (ipaddr1_id < 0) {
3276         return VL_NOENT;        /* not found */
3277     }
3278
3279     if (ipaddr2_id >= 0 && ipaddr2_id != ipaddr1_id) {
3280         char buf1[16], buf2[16];
3281         VLog(0, ("Cannot change IP address from %s to %s because the latter "
3282                  "is in use by server id %d\n",
3283                  afs_inet_ntoa_r(htonl(ipaddr1), buf1),
3284                  afs_inet_ntoa_r(htonl(ipaddr2), buf2),
3285                  ipaddr2_id));
3286         return VL_MULTIPADDR;
3287     }
3288
3289     /* If we are removing a server entry, a volume cannot
3290      * exist on the server. If one does, don't remove the
3291      * server entry: return error "volume entry exists".
3292      */
3293     if (ipaddr2 == 0) {
3294         for (blockindex = NextEntry(ctx, 0, &tentry, &count); blockindex;
3295              blockindex = NextEntry(ctx, blockindex, &tentry, &count)) {
3296             if (++pollcount > 50) {
3297 #ifndef AFS_PTHREAD_ENV
3298                 IOMGR_Poll();
3299 #endif
3300                 pollcount = 0;
3301             }
3302             for (j = 0; j < NMAXNSERVERS; j++) {
3303                 if (tentry.serverNumber[j] == BADSERVERID)
3304                     break;
3305                 if (tentry.serverNumber[j] == ipaddr1_id) {
3306                     return VL_IDEXIST;
3307                 }
3308             }
3309         }
3310     }
3311
3312     /* Log a message saying we are changing/removing an IP address */
3313     VLog(0,
3314          ("The following IP address is being %s:\n",
3315           (ipaddr2 ? "changed" : "removed")));
3316     VLog(0, ("      entry %d: ", i));
3317     if (exp) {
3318         VLog(0, ("["));
3319         for (mhidx = 0; mhidx < VL_MAXIPADDRS_PERMH; mhidx++) {
3320             if (!exp->ex_addrs[mhidx])
3321                 continue;
3322             if (mhidx > 0)
3323                 VLog(0, (" "));
3324             PADDR(ntohl(exp->ex_addrs[mhidx]));
3325         }
3326         VLog(0, ("]"));
3327     } else {
3328         PADDR(ipaddr1);
3329     }
3330     if (ipaddr2) {
3331         VLog(0, (" -> "));
3332         PADDR(ipaddr2);
3333     }
3334     VLog(0, ("\n"));
3335
3336     /* Change the registered uuuid addresses */
3337     if (exp) {
3338         memset(&tuuid, 0, sizeof(afsUUID));
3339         afs_htonuuid(&tuuid);
3340         exp->ex_hostuuid = tuuid;
3341         code =
3342             vlwrite(ctx->trans,
3343                     DOFFSET(ntohl(ctx->ex_addr[0]->ex_contaddrs[base]),
3344                             (char *)ctx->ex_addr[base], (char *)exp),
3345                     (char *)&tuuid, sizeof(tuuid));
3346         if (code)
3347             return VL_IO;
3348     }
3349
3350     /* Now change the host address entry */
3351     ctx->cheader->IpMappedAddr[ipaddr1_id] = htonl(ipaddr2);
3352     code =
3353         vlwrite(ctx->trans, DOFFSET(0, ctx->cheader, &ctx->cheader->IpMappedAddr[ipaddr1_id]),
3354                 (char *)
3355                 &ctx->cheader->IpMappedAddr[ipaddr1_id], sizeof(afs_int32));
3356     ctx->hostaddress[ipaddr1_id] = ipaddr2;
3357     if (code)
3358         return VL_IO;
3359
3360     return 0;
3361 }
3362
3363 /* see if the vlserver is back yet */
3364 afs_int32
3365 SVL_ProbeServer(struct rx_call *rxcall)
3366 {
3367     return 0;
3368 }