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