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