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