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