dbservers: Don't cast returns from malloc()
[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 #define PADDR(addr) VLog(0,("%d.%d.%d.%d", (addr>>24)&0xff, (addr>>16)&0xff, (addr>>8) &0xff, addr&0xff));
2135
2136 afs_int32
2137 SVL_RegisterAddrs(struct rx_call *rxcall, afsUUID *uuidp, afs_int32 spare1,
2138                   bulkaddrs *addrsp)
2139 {
2140     int this_op = VLREGADDR;
2141     afs_int32 code;
2142     struct vl_ctx ctx;
2143     int cnt, h, i, j, k, m;
2144     struct extentaddr *exp = 0, *tex;
2145     afsUUID tuuid;
2146     afs_uint32 addrs[VL_MAXIPADDRS_PERMH];
2147     int base;
2148     int count, willChangeEntry, foundUuidEntry, willReplaceCnt;
2149     int WillReplaceEntry, WillChange[MAXSERVERID + 1];
2150     int FoundUuid = 0;
2151     int ReplaceEntry = 0;
2152     int srvidx, mhidx;
2153
2154     countRequest(this_op);
2155     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL))
2156         return (VL_PERM);
2157     if ((code = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
2158         return code;
2159
2160     /* Eliminate duplicates from IP address list */
2161     for (k = 0, cnt = 0; k < addrsp->bulkaddrs_len; k++) {
2162         if (addrsp->bulkaddrs_val[k] == 0)
2163             continue;
2164         for (m = 0; m < cnt; m++) {
2165             if (addrs[m] == addrsp->bulkaddrs_val[k])
2166                 break;
2167         }
2168         if (m == cnt) {
2169             if (m == VL_MAXIPADDRS_PERMH) {
2170                 VLog(0,
2171                      ("Number of addresses exceeds %d. Cannot register IP addr 0x%x in VLDB\n",
2172                       VL_MAXIPADDRS_PERMH, addrsp->bulkaddrs_val[k]));
2173             } else {
2174                 addrs[m] = addrsp->bulkaddrs_val[k];
2175                 cnt++;
2176             }
2177         }
2178     }
2179     if (cnt <= 0) {
2180         code = VL_INDEXERANGE;
2181         goto abort;
2182     }
2183
2184     count = 0;
2185     willReplaceCnt = 0;
2186     foundUuidEntry = 0;
2187     /* For each server registered within the VLDB */
2188     for (srvidx = 0; srvidx <= MAXSERVERID; srvidx++) {
2189         willChangeEntry = 0;
2190         WillReplaceEntry = 1;
2191         code = multiHomedExtent(&ctx, srvidx, &exp);
2192         if (code)
2193              continue;
2194
2195         if (exp) {
2196             /* See if the addresses to register will change this server entry */
2197             tuuid = exp->ex_hostuuid;
2198             afs_ntohuuid(&tuuid);
2199             if (afs_uuid_equal(uuidp, &tuuid)) {
2200                 foundUuidEntry = 1;
2201                 FoundUuid = srvidx;
2202             } else {
2203                 for (mhidx = 0; mhidx < VL_MAXIPADDRS_PERMH; mhidx++) {
2204                     if (!exp->ex_addrs[mhidx])
2205                         continue;
2206                     for (k = 0; k < cnt; k++) {
2207                         if (ntohl(exp->ex_addrs[mhidx]) == addrs[k]) {
2208                             willChangeEntry = 1;
2209                             WillChange[count] = srvidx;
2210                             break;
2211                         }
2212                     }
2213                     if (k >= cnt)
2214                         WillReplaceEntry = 0;
2215                 }
2216             }
2217         } else {
2218             /* The server is not registered as a multihomed.
2219              * See if the addresses to register will replace this server entry.
2220              */
2221             for (k = 0; k < cnt; k++) {
2222                 if (ctx.hostaddress[srvidx] == addrs[k]) {
2223                     willChangeEntry = 1;
2224                     WillChange[count] = srvidx;
2225                     WillReplaceEntry = 1;
2226                     break;
2227                 }
2228             }
2229         }
2230         if (willChangeEntry) {
2231             if (WillReplaceEntry) {
2232                 willReplaceCnt++;
2233                 ReplaceEntry = srvidx;
2234             }
2235             count++;
2236         }
2237     }
2238
2239     /* If we found the uuid in the VLDB and if we are replacing another
2240      * entire entry, then complain and fail. Also, if we did not find
2241      * the uuid in the VLDB and the IP addresses being registered was
2242      * found in more than one other entry, then we don't know which one
2243      * to replace and will complain and fail.
2244      */
2245     if ((foundUuidEntry && (willReplaceCnt > 0))
2246         || (!foundUuidEntry && (count > 1))) {
2247         VLog(0,
2248              ("The following fileserver is being registered in the VLDB:\n"));
2249         VLog(0, ("      ["));
2250         for (k = 0; k < cnt; k++) {
2251             if (k > 0)
2252                 VLog(0,(" "));
2253             PADDR(addrs[k]);
2254         }
2255         VLog(0,("]\n"));
2256
2257         if (foundUuidEntry) {
2258             code = multiHomedExtent(&ctx, FoundUuid, &exp);
2259             if (code == 0) {
2260                 VLog(0, ("   It would have replaced the existing VLDB server "
2261                          "entry:\n"));
2262                 VLog(0, ("      entry %d: [", FoundUuid));
2263                 for (mhidx = 0; mhidx < VL_MAXIPADDRS_PERMH; mhidx++) {
2264                     if (!exp->ex_addrs[mhidx])
2265                         continue;
2266                     if (mhidx > 0)
2267                         VLog(0,(" "));
2268                     PADDR(ntohl(exp->ex_addrs[mhidx]));
2269                 }
2270                 VLog(0, ("]\n"));
2271             }
2272         }
2273
2274         if (count == 1)
2275             VLog(0, ("   Yet another VLDB server entry exists:\n"));
2276         else
2277             VLog(0, ("   Yet other VLDB server entries exist:\n"));
2278         for (j = 0; j < count; j++) {
2279             srvidx = WillChange[j];
2280             VLog(0, ("      entry %d: ", srvidx));
2281
2282             code = multiHomedExtent(&ctx, srvidx, &exp);
2283             if (code)
2284                 goto abort;
2285
2286             if (exp) {
2287                 VLog(0, ("["));
2288                 for (mhidx = 0; mhidx < VL_MAXIPADDRS_PERMH; mhidx++) {
2289                     if (!exp->ex_addrs[mhidx])
2290                         continue;
2291                     if (mhidx > 0)
2292                         VLog(0, (" "));
2293                     PADDR(ntohl(exp->ex_addrs[mhidx]));
2294                 }
2295                 VLog(0, ("]"));
2296             } else {
2297                 PADDR(ctx.hostaddress[srvidx]);
2298             }
2299             VLog(0, ("\n"));
2300         }
2301
2302         if (count == 1)
2303             VLog(0, ("   You must 'vos changeaddr' this other server entry\n"));
2304         else
2305             VLog(0,
2306                 ("   You must 'vos changeaddr' these other server entries\n"));
2307         if (foundUuidEntry)
2308             VLog(0,
2309                 ("   and/or remove the sysid file from the registering fileserver\n"));
2310         VLog(0, ("   before the fileserver can be registered in the VLDB.\n"));
2311
2312         code = VL_MULTIPADDR;
2313         goto abort;
2314     }
2315
2316     /* Passed the checks. Now find and update the existing mh entry, or create
2317      * a new mh entry.
2318      */
2319     if (foundUuidEntry) {
2320         /* Found the entry with same uuid. See if we need to change it */
2321         int change = 0;
2322
2323         code = multiHomedExtentBase(&ctx, FoundUuid, &exp, &base);
2324         if (code)
2325             goto abort;
2326
2327         /* Determine if the entry has changed */
2328         for (k = 0; ((k < cnt) && !change); k++) {
2329             if (ntohl(exp->ex_addrs[k]) != addrs[k])
2330                 change = 1;
2331         }
2332         for (; ((k < VL_MAXIPADDRS_PERMH) && !change); k++) {
2333             if (exp->ex_addrs[k] != 0)
2334                 change = 1;
2335         }
2336         if (!change) {
2337             return (ubik_EndTrans(ctx.trans));
2338         }
2339     }
2340
2341     VLog(0, ("The following fileserver is being registered in the VLDB:\n"));
2342     VLog(0, ("      ["));
2343     for (k = 0; k < cnt; k++) {
2344         if (k > 0)
2345             VLog(0, (" "));
2346         PADDR(addrs[k]);
2347     }
2348     VLog(0, ("]\n"));
2349
2350     if (foundUuidEntry) {
2351         VLog(0,
2352             ("   It will replace the following existing entry in the VLDB (same uuid):\n"));
2353         VLog(0, ("      entry %d: [", FoundUuid));
2354         for (k = 0; k < VL_MAXIPADDRS_PERMH; k++) {
2355             if (exp->ex_addrs[k] == 0)
2356                 continue;
2357             if (k > 0)
2358                 VLog(0, (" "));
2359             PADDR(ntohl(exp->ex_addrs[k]));
2360         }
2361         VLog(0, ("]\n"));
2362     } else if (willReplaceCnt || (count == 1)) {
2363         /* If we are not replacing an entry and there is only one entry to change,
2364          * then we will replace that entry.
2365          */
2366         if (!willReplaceCnt) {
2367             ReplaceEntry = WillChange[0];
2368             willReplaceCnt++;
2369         }
2370
2371         /* Have an entry that needs to be replaced */
2372         code = multiHomedExtentBase(&ctx, ReplaceEntry, &exp, &base);
2373         if (code)
2374             goto abort;
2375
2376         if (exp) {
2377             VLog(0,
2378                 ("   It will replace the following existing entry in the VLDB (new uuid):\n"));
2379             VLog(0, ("      entry %d: [", ReplaceEntry));
2380             for (k = 0; k < VL_MAXIPADDRS_PERMH; k++) {
2381                 if (exp->ex_addrs[k] == 0)
2382                     continue;
2383                 if (k > 0)
2384                     VLog(0, (" "));
2385                 PADDR(ntohl(exp->ex_addrs[k]));
2386             }
2387             VLog(0, ("]\n"));
2388         } else {
2389             /* Not a mh entry. So we have to create a new mh entry and
2390              * put it on the ReplaceEntry slot of the ctx.hostaddress array.
2391              */
2392             VLog(0, ("   It will replace existing entry %d, ", ReplaceEntry));
2393             PADDR(ctx.hostaddress[ReplaceEntry]);
2394             VLog(0,(", in the VLDB (new uuid):\n"));
2395
2396             code =
2397                 FindExtentBlock(&ctx, uuidp, 1, ReplaceEntry, &exp, &base);
2398             if (code || !exp) {
2399                 if (!code)
2400                     code = VL_IO;
2401                 goto abort;
2402             }
2403         }
2404     } else {
2405         /* There is no entry for this server, must create a new mh entry as
2406          * well as use a new slot of the ctx.hostaddress array.
2407          */
2408         VLog(0, ("   It will create a new entry in the VLDB.\n"));
2409         code = FindExtentBlock(&ctx, uuidp, 1, -1, &exp, &base);
2410         if (code || !exp) {
2411             if (!code)
2412                 code = VL_IO;
2413             goto abort;
2414         }
2415     }
2416
2417     /* Now we have a mh entry to fill in. Update the uuid, bump the
2418      * uniquifier, and fill in its IP addresses.
2419      */
2420     tuuid = *uuidp;
2421     afs_htonuuid(&tuuid);
2422     exp->ex_hostuuid = tuuid;
2423     exp->ex_uniquifier = htonl(ntohl(exp->ex_uniquifier) + 1);
2424     for (k = 0; k < cnt; k++) {
2425         exp->ex_addrs[k] = htonl(addrs[k]);
2426     }
2427     for (; k < VL_MAXIPADDRS_PERMH; k++) {
2428         exp->ex_addrs[k] = 0;
2429     }
2430
2431     /* Write the new mh entry out */
2432     if (vlwrite
2433         (ctx.trans,
2434          DOFFSET(ntohl(ctx.ex_addr[0]->ex_contaddrs[base]),
2435                  (char *)ctx.ex_addr[base], (char *)exp), (char *)exp,
2436          sizeof(*exp))) {
2437         code = VL_IO;
2438         goto abort;
2439     }
2440
2441     /* Remove any common addresses from other mh entres. We know these entries
2442      * are being changed and not replaced so they are mh entries.
2443      */
2444     m = 0;
2445     for (i = 0; i < count; i++) {
2446         afs_int32 doff;
2447
2448         /* Skip the entry we replaced */
2449         if (willReplaceCnt && (WillChange[i] == ReplaceEntry))
2450             continue;
2451
2452         code = multiHomedExtentBase(&ctx, WillChange[i], &tex, &base);
2453         if (code)
2454             goto abort;
2455
2456         if (++m == 1)
2457             VLog(0,
2458                 ("   The following existing entries in the VLDB will be updated:\n"));
2459
2460         VLog(0, ("      entry %d: [", WillChange[i]));
2461         for (h = j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
2462             if (tex->ex_addrs[j]) {
2463                 if (j > 0)
2464                     printf(" ");
2465                 PADDR(ntohl(tex->ex_addrs[j]));
2466             }
2467
2468             for (k = 0; k < cnt; k++) {
2469                 if (ntohl(tex->ex_addrs[j]) == addrs[k])
2470                     break;
2471             }
2472             if (k >= cnt) {
2473                 /* Not found, so we keep it */
2474                 tex->ex_addrs[h] = tex->ex_addrs[j];
2475                 h++;
2476             }
2477         }
2478         for (j = h; j < VL_MAXIPADDRS_PERMH; j++) {
2479             tex->ex_addrs[j] = 0;       /* zero rest of mh entry */
2480         }
2481         VLog(0, ("]\n"));
2482
2483         /* Write out the modified mh entry */
2484         tex->ex_uniquifier = htonl(ntohl(tex->ex_uniquifier) + 1);
2485         doff =
2486             DOFFSET(ntohl(ctx.ex_addr[0]->ex_contaddrs[base]),
2487                     (char *)ctx.ex_addr[base], (char *)tex);
2488         if (vlwrite(ctx.trans, doff, (char *)tex, sizeof(*tex))) {
2489             code = VL_IO;
2490             goto abort;
2491         }
2492     }
2493
2494     return (ubik_EndTrans(ctx.trans));
2495
2496 abort:
2497     countAbort(this_op);
2498     ubik_AbortTrans(ctx.trans);
2499     return code;
2500 }
2501
2502 afs_int32
2503 SVL_GetAddrsU(struct rx_call *rxcall,
2504               struct ListAddrByAttributes *attributes,
2505               afsUUID *uuidpo,
2506               afs_int32 *uniquifier,
2507               afs_int32 *nentries,
2508               bulkaddrs *addrsp)
2509 {
2510     int this_op = VLGETADDRSU;
2511     afs_int32 code, index = -1, offset;
2512     struct vl_ctx ctx;
2513     int nservers, i, j, base = 0;
2514     struct extentaddr *exp = 0;
2515     afsUUID tuuid;
2516     afs_uint32 *taddrp, taddr;
2517     char rxstr[AFS_RXINFO_LEN];
2518
2519     countRequest(this_op);
2520     addrsp->bulkaddrs_len = *nentries = 0;
2521     addrsp->bulkaddrs_val = 0;
2522     VLog(5, ("GetAddrsU %s\n", rxinfo(rxstr, rxcall)));
2523     if ((code = Init_VLdbase(&ctx, LOCKREAD, this_op)))
2524         return code;
2525
2526     if (attributes->Mask & VLADDR_IPADDR) {
2527         if (attributes->Mask & (VLADDR_INDEX | VLADDR_UUID)) {
2528             code = VL_BADMASK;
2529             goto abort;
2530         }
2531         for (base = 0; base < VL_MAX_ADDREXTBLKS; base++) {
2532             if (!ctx.ex_addr[base])
2533                 break;
2534             for (i = 1; i < VL_MHSRV_PERBLK; i++) {
2535                 exp = &ctx.ex_addr[base][i];
2536                 tuuid = exp->ex_hostuuid;
2537                 afs_ntohuuid(&tuuid);
2538                 if (afs_uuid_is_nil(&tuuid))
2539                     continue;
2540                 for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
2541                     if (exp->ex_addrs[j]
2542                         && (ntohl(exp->ex_addrs[j]) == attributes->ipaddr)) {
2543                         break;
2544                     }
2545                 }
2546                 if (j < VL_MAXIPADDRS_PERMH)
2547                     break;
2548             }
2549             if (i < VL_MHSRV_PERBLK)
2550                 break;
2551         }
2552         if (base >= VL_MAX_ADDREXTBLKS) {
2553             code = VL_NOENT;
2554             goto abort;
2555         }
2556     } else if (attributes->Mask & VLADDR_INDEX) {
2557         if (attributes->Mask & (VLADDR_IPADDR | VLADDR_UUID)) {
2558             code = VL_BADMASK;
2559             goto abort;
2560         }
2561         index = attributes->index;
2562         if (index < 1 || index >= (VL_MAX_ADDREXTBLKS * VL_MHSRV_PERBLK)) {
2563             code = VL_INDEXERANGE;
2564             goto abort;
2565         }
2566         base = index / VL_MHSRV_PERBLK;
2567         offset = index % VL_MHSRV_PERBLK;
2568         if (offset == 0) {
2569             code = VL_NOENT;
2570             goto abort;
2571         }
2572         if (!ctx.ex_addr[base]) {
2573             code = VL_INDEXERANGE;
2574             goto abort;
2575         }
2576         exp = &ctx.ex_addr[base][offset];
2577     } else if (attributes->Mask & VLADDR_UUID) {
2578         if (attributes->Mask & (VLADDR_IPADDR | VLADDR_INDEX)) {
2579             code = VL_BADMASK;
2580             goto abort;
2581         }
2582         if (!ctx.ex_addr[0]) {  /* mh servers probably aren't setup on this vldb */
2583             code = VL_NOENT;
2584             goto abort;
2585         }
2586         code = FindExtentBlock(&ctx, &attributes->uuid, 0, -1, &exp, &base);
2587         if (code)
2588             goto abort;
2589     } else {
2590         code = VL_BADMASK;
2591         goto abort;
2592     }
2593
2594     if (exp == NULL) {
2595         code = VL_NOENT;
2596         goto abort;
2597     }
2598     addrsp->bulkaddrs_val = taddrp =
2599         malloc(sizeof(afs_int32) * (MAXSERVERID + 1));
2600     nservers = *nentries = addrsp->bulkaddrs_len = 0;
2601     if (!taddrp) {
2602         code = VL_NOMEM;
2603         goto abort;
2604     }
2605     tuuid = exp->ex_hostuuid;
2606     afs_ntohuuid(&tuuid);
2607     if (afs_uuid_is_nil(&tuuid)) {
2608         code = VL_NOENT;
2609         goto abort;
2610     }
2611     if (uuidpo)
2612         *uuidpo = tuuid;
2613     if (uniquifier)
2614         *uniquifier = ntohl(exp->ex_uniquifier);
2615     for (i = 0; i < VL_MAXIPADDRS_PERMH; i++) {
2616         if (exp->ex_addrs[i]) {
2617             taddr = ntohl(exp->ex_addrs[i]);
2618             /* Weed out duplicates */
2619             for (j = 0; j < nservers; j++) {
2620                 if (taddrp[j] == taddr)
2621                     break;
2622             }
2623             if ((j == nservers) && (j <= MAXSERVERID)) {
2624                 taddrp[nservers] = taddr;
2625                 nservers++;
2626             }
2627         }
2628     }
2629     addrsp->bulkaddrs_len = *nentries = nservers;
2630     return (ubik_EndTrans(ctx.trans));
2631
2632 abort:
2633     countAbort(this_op);
2634     ubik_AbortTrans(ctx.trans);
2635     return code;
2636 }
2637
2638 /* ============> End of Exported vldb RPC functions <============= */
2639
2640
2641 /* Routine that copies the given vldb entry to the output buffer, vldbentries. */
2642 static int
2643 put_attributeentry(struct vl_ctx *ctx,
2644                    struct vldbentry **Vldbentry,
2645                    struct vldbentry **VldbentryFirst,
2646                    struct vldbentry **VldbentryLast,
2647                    bulkentries *vldbentries,
2648                    struct nvlentry *entry,
2649                    afs_int32 *nentries,
2650                    afs_int32 *alloccnt)
2651 {
2652     vldbentry *reall;
2653     afs_int32 allo;
2654     int code;
2655
2656     if (*Vldbentry == *VldbentryLast) {
2657         if (smallMem)
2658             return VL_SIZEEXCEEDED;     /* no growing if smallMem defined */
2659
2660         /* Allocate another set of memory; each time allocate twice as
2661          * many blocks as the last time. When we reach VLDBALLOCLIMIT,
2662          * then grow in increments of VLDBALLOCINCR.
2663          */
2664         allo = (*alloccnt > VLDBALLOCLIMIT) ? VLDBALLOCINCR : *alloccnt;
2665         reall = realloc(*VldbentryFirst,
2666                         (*alloccnt + allo) * sizeof(vldbentry));
2667         if (reall == NULL)
2668             return VL_NOMEM;
2669
2670         *VldbentryFirst = vldbentries->bulkentries_val = reall;
2671         *Vldbentry = *VldbentryFirst + *alloccnt;
2672         *VldbentryLast = *Vldbentry + allo;
2673         *alloccnt += allo;
2674     }
2675
2676     code = vlentry_to_vldbentry(ctx, entry, *Vldbentry);
2677     if (code)
2678         return code;
2679
2680     (*Vldbentry)++;
2681     (*nentries)++;
2682     vldbentries->bulkentries_len++;
2683     return 0;
2684 }
2685
2686 static int
2687 put_nattributeentry(struct vl_ctx *ctx,
2688                     struct nvldbentry **Vldbentry,
2689                     struct nvldbentry **VldbentryFirst,
2690                     struct nvldbentry **VldbentryLast,
2691                     nbulkentries *vldbentries,
2692                     struct nvlentry *entry,
2693                     afs_int32 matchtype,
2694                     afs_int32 matchindex,
2695                     afs_int32 *nentries,
2696                     afs_int32 *alloccnt)
2697 {
2698     nvldbentry *reall;
2699     afs_int32 allo;
2700     int code;
2701
2702     if (*Vldbentry == *VldbentryLast) {
2703         if (smallMem)
2704             return VL_SIZEEXCEEDED;     /* no growing if smallMem defined */
2705
2706         /* Allocate another set of memory; each time allocate twice as
2707          * many blocks as the last time. When we reach VLDBALLOCLIMIT,
2708          * then grow in increments of VLDBALLOCINCR.
2709          */
2710         allo = (*alloccnt > VLDBALLOCLIMIT) ? VLDBALLOCINCR : *alloccnt;
2711         reall = realloc(*VldbentryFirst,
2712                         (*alloccnt + allo) * sizeof(nvldbentry));
2713         if (reall == NULL)
2714             return VL_NOMEM;
2715
2716         *VldbentryFirst = vldbentries->nbulkentries_val = reall;
2717         *Vldbentry = *VldbentryFirst + *alloccnt;
2718         *VldbentryLast = *Vldbentry + allo;
2719         *alloccnt += allo;
2720     }
2721     code = vlentry_to_nvldbentry(ctx, entry, *Vldbentry);
2722     if (code)
2723         return code;
2724
2725     (*Vldbentry)->matchindex = (matchtype << 16) + matchindex;
2726     (*Vldbentry)++;
2727     (*nentries)++;
2728     vldbentries->nbulkentries_len++;
2729     return 0;
2730 }
2731
2732
2733 /* Common code to actually remove a vldb entry from the database. */
2734 static int
2735 RemoveEntry(struct vl_ctx *ctx, afs_int32 entryptr,
2736             struct nvlentry *tentry)
2737 {
2738     int code;
2739
2740     if ((code = UnthreadVLentry(ctx, entryptr, tentry)))
2741         return code;
2742     if ((code = FreeBlock(ctx, entryptr)))
2743         return code;
2744     return 0;
2745 }
2746
2747 static void
2748 ReleaseEntry(struct nvlentry *tentry, afs_int32 releasetype)
2749 {
2750     if (releasetype & LOCKREL_TIMESTAMP)
2751         tentry->LockTimestamp = 0;
2752     if (releasetype & LOCKREL_OPCODE)
2753         tentry->flags &= ~VLOP_ALLOPERS;
2754     if (releasetype & LOCKREL_AFSID)
2755         tentry->LockAfsId = 0;
2756 }
2757
2758
2759 /* Verify that the incoming vldb entry is valid; multi type of error codes
2760  * are returned. */
2761 static int
2762 check_vldbentry(struct vldbentry *aentry)
2763 {
2764     afs_int32 i;
2765
2766     if (InvalidVolname(aentry->name))
2767         return VL_BADNAME;
2768     if (aentry->nServers <= 0 || aentry->nServers > OMAXNSERVERS)
2769         return VL_BADSERVER;
2770     for (i = 0; i < aentry->nServers; i++) {
2771 /*      if (aentry->serverNumber[i] < 0 || aentry->serverNumber[i] > MAXSERVERID)
2772             return VL_BADSERVER;        */
2773         if (aentry->serverPartition[i] < 0
2774             || aentry->serverPartition[i] > MAXPARTITIONID)
2775             return VL_BADPARTITION;
2776         if (aentry->serverFlags[i] < 0
2777             || aentry->serverFlags[i] > MAXSERVERFLAG)
2778             return VL_BADSERVERFLAG;
2779     }
2780     return 0;
2781 }
2782
2783 static int
2784 check_nvldbentry(struct nvldbentry *aentry)
2785 {
2786     afs_int32 i;
2787
2788     if (InvalidVolname(aentry->name))
2789         return VL_BADNAME;
2790     if (aentry->nServers <= 0 || aentry->nServers > NMAXNSERVERS)
2791         return VL_BADSERVER;
2792     for (i = 0; i < aentry->nServers; i++) {
2793 /*      if (aentry->serverNumber[i] < 0 || aentry->serverNumber[i] > MAXSERVERID)
2794             return VL_BADSERVER;        */
2795         if (aentry->serverPartition[i] < 0
2796             || aentry->serverPartition[i] > MAXPARTITIONID)
2797             return VL_BADPARTITION;
2798         if (aentry->serverFlags[i] < 0
2799             || aentry->serverFlags[i] > MAXSERVERFLAG)
2800             return VL_BADSERVERFLAG;
2801     }
2802     return 0;
2803 }
2804
2805
2806 /* Convert from the external vldb entry representation to its internal
2807    (more compact) form.  This call should not change the hash chains! */
2808 static int
2809 vldbentry_to_vlentry(struct vl_ctx *ctx,
2810                      struct vldbentry *VldbEntry,
2811                      struct nvlentry *VlEntry)
2812 {
2813     int i, serverindex;
2814
2815     if (strcmp(VlEntry->name, VldbEntry->name))
2816         strncpy(VlEntry->name, VldbEntry->name, sizeof(VlEntry->name));
2817     for (i = 0; i < VldbEntry->nServers; i++) {
2818         serverindex = IpAddrToRelAddr(ctx, VldbEntry->serverNumber[i], 1);
2819         if (serverindex == -1)
2820             return VL_BADSERVER;
2821         VlEntry->serverNumber[i] = serverindex;
2822         VlEntry->serverPartition[i] = VldbEntry->serverPartition[i];
2823         VlEntry->serverFlags[i] = VldbEntry->serverFlags[i];
2824     }
2825     for (; i < OMAXNSERVERS; i++)
2826         VlEntry->serverNumber[i] = VlEntry->serverPartition[i] =
2827             VlEntry->serverFlags[i] = BADSERVERID;
2828     for (i = 0; i < MAXTYPES; i++)
2829         VlEntry->volumeId[i] = VldbEntry->volumeId[i];
2830     VlEntry->cloneId = VldbEntry->cloneId;
2831     VlEntry->flags = VldbEntry->flags;
2832     return 0;
2833 }
2834
2835 static int
2836 nvldbentry_to_vlentry(struct vl_ctx *ctx,
2837                       struct nvldbentry *VldbEntry,
2838                       struct nvlentry *VlEntry)
2839 {
2840     int i, serverindex;
2841
2842     if (strcmp(VlEntry->name, VldbEntry->name))
2843         strncpy(VlEntry->name, VldbEntry->name, sizeof(VlEntry->name));
2844     for (i = 0; i < VldbEntry->nServers; i++) {
2845         serverindex = IpAddrToRelAddr(ctx, VldbEntry->serverNumber[i], 1);
2846         if (serverindex == -1)
2847             return VL_BADSERVER;
2848         VlEntry->serverNumber[i] = serverindex;
2849         VlEntry->serverPartition[i] = VldbEntry->serverPartition[i];
2850         VlEntry->serverFlags[i] = VldbEntry->serverFlags[i];
2851     }
2852     for (; i < NMAXNSERVERS; i++)
2853         VlEntry->serverNumber[i] = VlEntry->serverPartition[i] =
2854             VlEntry->serverFlags[i] = BADSERVERID;
2855     for (i = 0; i < MAXTYPES; i++)
2856         VlEntry->volumeId[i] = VldbEntry->volumeId[i];
2857     VlEntry->cloneId = VldbEntry->cloneId;
2858     VlEntry->flags = VldbEntry->flags;
2859     return 0;
2860 }
2861
2862
2863 /* Update the vldb entry with the new fields as indicated by the value of
2864  * the Mask entry in the updateentry structure. All necessary validation
2865  * checks are performed.
2866  */
2867 static int
2868 get_vldbupdateentry(struct vl_ctx *ctx,
2869                     afs_int32 blockindex,
2870                     struct VldbUpdateEntry *updateentry,
2871                     struct nvlentry *VlEntry)
2872 {
2873     int i, j, code, serverindex;
2874     afs_uint32 checkids[MAXTYPES];
2875
2876     /* check if any specified new IDs are already present in the db. Do
2877      * this check before doing anything else, so we don't get a half-
2878      * updated entry. */
2879     memset(&checkids, 0, sizeof(checkids));
2880     if (updateentry->Mask & VLUPDATE_RWID) {
2881         checkids[RWVOL] = updateentry->spares3; /* rw id */
2882     }
2883     if (updateentry->Mask & VLUPDATE_READONLYID) {
2884         checkids[ROVOL] = updateentry->ReadOnlyId;
2885     }
2886     if (updateentry->Mask & VLUPDATE_BACKUPID) {
2887         checkids[BACKVOL] = updateentry->BackupId;
2888     }
2889
2890     if (EntryIDExists(ctx, checkids, MAXTYPES, &code)) {
2891         return VL_IDEXIST;
2892     } else if (code) {
2893         return code;
2894     }
2895
2896     if (updateentry->Mask & VLUPDATE_VOLUMENAME) {
2897         struct nvlentry tentry;
2898
2899         if (InvalidVolname(updateentry->name))
2900             return VL_BADNAME;
2901
2902         if (FindByName(ctx, updateentry->name, &tentry, &code)) {
2903             return VL_NAMEEXIST;
2904         } else if (code) {
2905             return code;
2906         }
2907
2908         if ((code = UnhashVolname(ctx, blockindex, VlEntry)))
2909             return code;
2910         strncpy(VlEntry->name, updateentry->name, sizeof(VlEntry->name));
2911         HashVolname(ctx, blockindex, VlEntry);
2912     }
2913
2914     if (updateentry->Mask & VLUPDATE_VOLNAMEHASH) {
2915         if ((code = UnhashVolname(ctx, blockindex, VlEntry))) {
2916             if (code != VL_NOENT)
2917                 return code;
2918         }
2919         HashVolname(ctx, blockindex, VlEntry);
2920     }
2921
2922     if (updateentry->Mask & VLUPDATE_FLAGS) {
2923         VlEntry->flags = updateentry->flags;
2924     }
2925     if (updateentry->Mask & VLUPDATE_CLONEID) {
2926         VlEntry->cloneId = updateentry->cloneId;
2927     }
2928     if (updateentry->Mask & VLUPDATE_RWID) {
2929         if ((code = UnhashVolid(ctx, RWVOL, blockindex, VlEntry))) {
2930             if (code != VL_NOENT)
2931                 return code;
2932         }
2933         VlEntry->volumeId[RWVOL] = updateentry->spares3;        /* rw id */
2934         if ((code = HashVolid(ctx, RWVOL, blockindex, VlEntry)))
2935             return code;
2936     }
2937     if (updateentry->Mask & VLUPDATE_READONLYID) {
2938         if ((code = UnhashVolid(ctx, ROVOL, blockindex, VlEntry))) {
2939             if (code != VL_NOENT)
2940                 return code;
2941         }
2942         VlEntry->volumeId[ROVOL] = updateentry->ReadOnlyId;
2943         if ((code = HashVolid(ctx, ROVOL, blockindex, VlEntry)))
2944             return code;
2945     }
2946     if (updateentry->Mask & VLUPDATE_BACKUPID) {
2947         if ((code = UnhashVolid(ctx, BACKVOL, blockindex, VlEntry))) {
2948             if (code != VL_NOENT)
2949                 return code;
2950         }
2951         VlEntry->volumeId[BACKVOL] = updateentry->BackupId;
2952         if ((code = HashVolid(ctx, BACKVOL, blockindex, VlEntry)))
2953             return code;
2954     }
2955     if (updateentry->Mask & VLUPDATE_REPSITES) {
2956         if (updateentry->nModifiedRepsites <= 0
2957             || updateentry->nModifiedRepsites > OMAXNSERVERS)
2958             return VL_BADSERVER;
2959         for (i = 0; i < updateentry->nModifiedRepsites; i++) {
2960 /*          if (updateentry->RepsitesTargetServer[i] < 0 || updateentry->RepsitesTargetServer[i] > MAXSERVERID)
2961                 return VL_BADSERVER;    */
2962             if (updateentry->RepsitesTargetPart[i] < 0
2963                 || updateentry->RepsitesTargetPart[i] > MAXPARTITIONID)
2964                 return VL_BADPARTITION;
2965             if (updateentry->RepsitesMask[i] & VLUPDATE_REPS_DELETE) {
2966                 if ((j =
2967                      repsite_exists(VlEntry,
2968                                     IpAddrToRelAddr(ctx, updateentry->
2969                                                     RepsitesTargetServer[i],
2970                                                     1),
2971                                     updateentry->RepsitesTargetPart[i])) !=
2972                     -1)
2973                     repsite_compress(VlEntry, j);
2974                 else
2975                     return VL_NOREPSERVER;
2976             }
2977             if (updateentry->RepsitesMask[i] & VLUPDATE_REPS_ADD) {
2978 /*              if (updateentry->RepsitesNewServer[i] < 0 || updateentry->RepsitesNewServer[i] > MAXSERVERID)
2979                     return VL_BADSERVER;                */
2980                 if (updateentry->RepsitesNewPart[i] < 0
2981                     || updateentry->RepsitesNewPart[i] > MAXPARTITIONID)
2982                     return VL_BADPARTITION;
2983                 if (repsite_exists
2984                     (VlEntry,
2985                      IpAddrToRelAddr(ctx, updateentry->RepsitesNewServer[i], 1),
2986                      updateentry->RepsitesNewPart[i]) != -1)
2987                     return VL_DUPREPSERVER;
2988                 for (j = 0;
2989                      VlEntry->serverNumber[j] != BADSERVERID
2990                      && j < OMAXNSERVERS; j++);
2991                 if (j >= OMAXNSERVERS)
2992                     return VL_REPSFULL;
2993                 if ((serverindex =
2994                      IpAddrToRelAddr(ctx, updateentry->RepsitesNewServer[i],
2995                                      1)) == -1)
2996                     return VL_BADSERVER;
2997                 VlEntry->serverNumber[j] = serverindex;
2998                 VlEntry->serverPartition[j] = updateentry->RepsitesNewPart[i];
2999                 if (updateentry->RepsitesNewFlags[i] < 0
3000                     || updateentry->RepsitesNewFlags[i] > MAXSERVERFLAG)
3001                     return VL_BADSERVERFLAG;
3002                 VlEntry->serverFlags[j] = updateentry->RepsitesNewFlags[i];
3003             }
3004             if (updateentry->RepsitesMask[i] & VLUPDATE_REPS_MODSERV) {
3005 /*n             if (updateentry->RepsitesNewServer[i] < 0 || updateentry->RepsitesNewServer[i] > MAXSERVERID)
3006                     return VL_BADSERVER;            */
3007                 if ((j =
3008                      repsite_exists(VlEntry,
3009                                     IpAddrToRelAddr(ctx, updateentry->
3010                                                     RepsitesTargetServer[i],
3011                                                     1),
3012                                     updateentry->RepsitesTargetPart[i])) !=
3013                     -1) {
3014                     VlEntry->serverNumber[j] =
3015                         IpAddrToRelAddr(ctx, updateentry->RepsitesNewServer[i],
3016                                         1);
3017                 } else
3018                     return VL_NOREPSERVER;
3019             }
3020             if (updateentry->RepsitesMask[i] & VLUPDATE_REPS_MODPART) {
3021                 if (updateentry->RepsitesNewPart[i] < 0
3022                     || updateentry->RepsitesNewPart[i] > MAXPARTITIONID)
3023                     return VL_BADPARTITION;
3024                 if ((j =
3025                      repsite_exists(VlEntry,
3026                                     IpAddrToRelAddr(ctx, updateentry->
3027                                                     RepsitesTargetServer[i],
3028                                                     1),
3029                                     updateentry->RepsitesTargetPart[i])) !=
3030                     -1)
3031                     VlEntry->serverPartition[j] =
3032                         updateentry->RepsitesNewPart[i];
3033                 else
3034                     return VL_NOREPSERVER;
3035             }
3036             if (updateentry->RepsitesMask[i] & VLUPDATE_REPS_MODFLAG) {
3037                 if ((j =
3038                      repsite_exists(VlEntry,
3039                                     IpAddrToRelAddr(ctx, updateentry->
3040                                                     RepsitesTargetServer[i],
3041                                                     1),
3042                                     updateentry->RepsitesTargetPart[i])) !=
3043                     -1) {
3044                     if (updateentry->RepsitesNewFlags[i] < 0
3045                         || updateentry->RepsitesNewFlags[i] > MAXSERVERFLAG)
3046                         return VL_BADSERVERFLAG;
3047                     VlEntry->serverFlags[j] =
3048                         updateentry->RepsitesNewFlags[i];
3049                 } else
3050                     return VL_NOREPSERVER;
3051             }
3052         }
3053     }
3054     return 0;
3055 }
3056
3057
3058 /* Check if the specified [server,partition] entry is found in the vldb
3059  * entry's repsite table; it's offset in the table is returned, if it's
3060  * present there. */
3061 static int
3062 repsite_exists(struct nvlentry *VlEntry, int server, int partition)
3063 {
3064     int i;
3065
3066     for (i = 0; VlEntry->serverNumber[i] != BADSERVERID && i < OMAXNSERVERS;
3067          i++) {
3068         if ((VlEntry->serverNumber[i] == server)
3069             && (VlEntry->serverPartition[i] == partition))
3070             return i;
3071     }
3072     return -1;
3073 }
3074
3075
3076
3077 /* Repsite table compression: used when deleting a repsite entry so that
3078  * all active repsite entries are on the top of the table. */
3079 static void
3080 repsite_compress(struct nvlentry *VlEntry, int offset)
3081 {
3082     int repsite_offset = offset;
3083     for (;
3084          VlEntry->serverNumber[repsite_offset] != BADSERVERID
3085          && repsite_offset < OMAXNSERVERS - 1; repsite_offset++) {
3086         VlEntry->serverNumber[repsite_offset] =
3087             VlEntry->serverNumber[repsite_offset + 1];
3088         VlEntry->serverPartition[repsite_offset] =
3089             VlEntry->serverPartition[repsite_offset + 1];
3090         VlEntry->serverFlags[repsite_offset] =
3091             VlEntry->serverFlags[repsite_offset + 1];
3092     }
3093     VlEntry->serverNumber[repsite_offset] = BADSERVERID;
3094 }
3095
3096
3097 /* Convert from the internal (compacted) vldb entry to the external
3098  * representation used by the interface. */
3099 static int
3100 vlentry_to_vldbentry(struct vl_ctx *ctx, struct nvlentry *VlEntry,
3101                      struct vldbentry *VldbEntry)
3102 {
3103     int i, j, code;
3104     struct extentaddr *exp;
3105
3106     memset(VldbEntry, 0, sizeof(struct vldbentry));
3107     strncpy(VldbEntry->name, VlEntry->name, sizeof(VldbEntry->name));
3108     for (i = 0; i < OMAXNSERVERS; i++) {
3109         if (VlEntry->serverNumber[i] == BADSERVERID)
3110             break;
3111         j = VlEntry->serverNumber[i];
3112         code = multiHomedExtent(ctx, VlEntry->serverNumber[i], &exp);
3113         if (code)
3114             return code;
3115         if (exp) {
3116             /* For now return the first ip address back */
3117             for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
3118                 if (exp->ex_addrs[j]) {
3119                     VldbEntry->serverNumber[i] = ntohl(exp->ex_addrs[j]);
3120                     break;
3121                 }
3122             }
3123         } else
3124             VldbEntry->serverNumber[i] =
3125                 ctx->hostaddress[VlEntry->serverNumber[i]];
3126         VldbEntry->serverPartition[i] = VlEntry->serverPartition[i];
3127         VldbEntry->serverFlags[i] = VlEntry->serverFlags[i];
3128     }
3129     VldbEntry->nServers = i;
3130     for (i = 0; i < MAXTYPES; i++)
3131         VldbEntry->volumeId[i] = VlEntry->volumeId[i];
3132     VldbEntry->cloneId = VlEntry->cloneId;
3133     VldbEntry->flags = VlEntry->flags;
3134
3135     return 0;
3136 }
3137
3138
3139 /* Convert from the internal (compacted) vldb entry to the external
3140  * representation used by the interface. */
3141 static int
3142 vlentry_to_nvldbentry(struct vl_ctx *ctx, struct nvlentry *VlEntry,
3143                       struct nvldbentry *VldbEntry)
3144 {
3145     int i, j, code;
3146     struct extentaddr *exp;
3147
3148     memset(VldbEntry, 0, sizeof(struct nvldbentry));
3149     strncpy(VldbEntry->name, VlEntry->name, sizeof(VldbEntry->name));
3150     for (i = 0; i < NMAXNSERVERS; i++) {
3151         if (VlEntry->serverNumber[i] == BADSERVERID)
3152             break;
3153         code = multiHomedExtent(ctx, VlEntry->serverNumber[i], &exp);
3154         if (code)
3155             return code;
3156
3157         if (exp) {
3158             /* For now return the first ip address back */
3159             for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
3160                 if (exp->ex_addrs[j]) {
3161                     VldbEntry->serverNumber[i] = ntohl(exp->ex_addrs[j]);
3162                     break;
3163                 }
3164             }
3165         } else
3166             VldbEntry->serverNumber[i] =
3167                 ctx->hostaddress[VlEntry->serverNumber[i]];
3168         VldbEntry->serverPartition[i] = VlEntry->serverPartition[i];
3169         VldbEntry->serverFlags[i] = VlEntry->serverFlags[i];
3170     }
3171     VldbEntry->nServers = i;
3172     for (i = 0; i < MAXTYPES; i++)
3173         VldbEntry->volumeId[i] = VlEntry->volumeId[i];
3174     VldbEntry->cloneId = VlEntry->cloneId;
3175     VldbEntry->flags = VlEntry->flags;
3176
3177     return 0;
3178 }
3179
3180 static int
3181 vlentry_to_uvldbentry(struct vl_ctx *ctx, struct nvlentry *VlEntry,
3182                       struct uvldbentry *VldbEntry)
3183 {
3184     int i, code;
3185     struct extentaddr *exp;
3186
3187     memset(VldbEntry, 0, sizeof(struct uvldbentry));
3188     strncpy(VldbEntry->name, VlEntry->name, sizeof(VldbEntry->name));
3189     for (i = 0; i < NMAXNSERVERS; i++) {
3190         if (VlEntry->serverNumber[i] == BADSERVERID)
3191             break;
3192         VldbEntry->serverFlags[i] = VlEntry->serverFlags[i];
3193         VldbEntry->serverUnique[i] = 0;
3194         code = multiHomedExtent(ctx, VlEntry->serverNumber[i], &exp);
3195         if (code)
3196             return code;
3197
3198         if (exp) {
3199             afsUUID tuuid;
3200
3201             tuuid = exp->ex_hostuuid;
3202             afs_ntohuuid(&tuuid);
3203             VldbEntry->serverFlags[i] |= VLSF_UUID;
3204             VldbEntry->serverNumber[i] = tuuid;
3205             VldbEntry->serverUnique[i] = ntohl(exp->ex_uniquifier);
3206         } else {
3207             VldbEntry->serverNumber[i].time_low =
3208                 ctx->hostaddress[VlEntry->serverNumber[i]];
3209         }
3210         VldbEntry->serverPartition[i] = VlEntry->serverPartition[i];
3211
3212     }
3213     VldbEntry->nServers = i;
3214     for (i = 0; i < MAXTYPES; i++)
3215         VldbEntry->volumeId[i] = VlEntry->volumeId[i];
3216     VldbEntry->cloneId = VlEntry->cloneId;
3217     VldbEntry->flags = VlEntry->flags;
3218
3219     return 0;
3220 }
3221
3222 #define LEGALCHARS ".ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
3223
3224
3225 /* Verify that the volname is a valid volume name. */
3226 static int
3227 InvalidVolname(char *volname)
3228 {
3229     char *map;
3230     int slen;
3231
3232     map = LEGALCHARS;
3233     slen = strlen(volname);
3234     if (slen >= VL_MAXNAMELEN)
3235         return 1;
3236     return (slen != strspn(volname, map));
3237 }
3238
3239
3240 /* Verify that the given volume type is valid. */
3241 static int
3242 InvalidVoltype(afs_int32 voltype)
3243 {
3244     if (voltype != RWVOL && voltype != ROVOL && voltype != BACKVOL)
3245         return 1;
3246     return 0;
3247 }
3248
3249
3250 static int
3251 InvalidOperation(afs_int32 voloper)
3252 {
3253     if (voloper != VLOP_MOVE && voloper != VLOP_RELEASE
3254         && voloper != VLOP_BACKUP && voloper != VLOP_DELETE
3255         && voloper != VLOP_DUMP)
3256         return 1;
3257     return 0;
3258 }
3259
3260 static int
3261 InvalidReleasetype(afs_int32 releasetype)
3262 {
3263     if ((releasetype & LOCKREL_TIMESTAMP) || (releasetype & LOCKREL_OPCODE)
3264         || (releasetype & LOCKREL_AFSID))
3265         return 0;
3266     return 1;
3267 }
3268
3269 static int
3270 IpAddrToRelAddr(struct vl_ctx *ctx, afs_uint32 ipaddr, int create)
3271 {
3272     int i, j;
3273     afs_int32 code;
3274     struct extentaddr *exp;
3275
3276     for (i = 0; i <= MAXSERVERID; i++) {
3277         if (ctx->hostaddress[i] == ipaddr)
3278             return i;
3279         code = multiHomedExtent(ctx, i, &exp);
3280         if (code)
3281             return -1;
3282         if (exp) {
3283             for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
3284                 if (exp->ex_addrs[j] && (ntohl(exp->ex_addrs[j]) == ipaddr)) {
3285                     return i;
3286                 }
3287             }
3288         }
3289     }
3290
3291     /* allocate the new server a server id pronto */
3292     if (create) {
3293         for (i = 0; i <= MAXSERVERID; i++) {
3294             if (ctx->cheader->IpMappedAddr[i] == 0) {
3295                 ctx->cheader->IpMappedAddr[i] = htonl(ipaddr);
3296                 code =
3297                     vlwrite(ctx->trans,
3298                             DOFFSET(0, ctx->cheader, &ctx->cheader->IpMappedAddr[i]),
3299                             (char *)&ctx->cheader->IpMappedAddr[i],
3300                             sizeof(afs_int32));
3301                 ctx->hostaddress[i] = ipaddr;
3302                 if (code)
3303                     return -1;
3304                 return i;
3305             }
3306         }
3307     }
3308     return -1;
3309 }
3310
3311 static int
3312 ChangeIPAddr(struct vl_ctx *ctx, afs_uint32 ipaddr1, afs_uint32 ipaddr2)
3313 {
3314     int i, j;
3315     afs_int32 code;
3316     struct extentaddr *exp = NULL;
3317     int base;
3318     int mhidx;
3319     afsUUID tuuid;
3320     afs_int32 blockindex, count;
3321     int pollcount = 0;
3322     struct nvlentry tentry;
3323     int ipaddr1_id = -1, ipaddr2_id = -1;
3324
3325     /* Don't let addr change to 256.*.*.* : Causes internal error below */
3326     if ((ipaddr2 & 0xff000000) == 0xff000000)
3327         return (VL_BADSERVER);
3328
3329     /* If we are removing an address, ip1 will be -1 and ip2 will be
3330      * the original address. This prevents an older revision vlserver
3331      * from removing the IP address (won't find server 0xfffffff in
3332      * the VLDB). An older revision vlserver does not have the check
3333      * to see if any volumes exist on the server being removed.
3334      */
3335     if (ipaddr1 == 0xffffffff) {
3336         ipaddr1 = ipaddr2;
3337         ipaddr2 = 0;
3338     }
3339
3340     for (i = 0; i <= MAXSERVERID; i++) {
3341         code = multiHomedExtentBase(ctx, i, &exp, &base);
3342         if (code)
3343             return code;
3344
3345         if (exp) {
3346             for (mhidx = 0; mhidx < VL_MAXIPADDRS_PERMH; mhidx++) {
3347                 if (!exp->ex_addrs[mhidx])
3348                     continue;
3349                 if (ntohl(exp->ex_addrs[mhidx]) == ipaddr1) {
3350                     ipaddr1_id = i;
3351                 }
3352                 if (ipaddr2 != 0 && ntohl(exp->ex_addrs[mhidx]) == ipaddr2) {
3353                     ipaddr2_id = i;
3354                 }
3355             }
3356         } else {
3357             if (ctx->hostaddress[i] == ipaddr1) {
3358                 exp = NULL;
3359                 ipaddr1_id = i;
3360             }
3361             if (ipaddr2 != 0 && ctx->hostaddress[i] == ipaddr2) {
3362                 ipaddr2_id = i;
3363             }
3364         }
3365
3366         if (ipaddr1_id >= 0 && (ipaddr2 == 0 || ipaddr2_id >= 0)) {
3367             /* we've either found both IPs already in the VLDB, or we found
3368              * ipaddr1, and we're not going to find ipaddr2 because it's 0 */
3369             break;
3370         }
3371     }
3372
3373     if (ipaddr1_id < 0) {
3374         return VL_NOENT;        /* not found */
3375     }
3376
3377     if (ipaddr2_id >= 0 && ipaddr2_id != ipaddr1_id) {
3378         char buf1[16], buf2[16];
3379         VLog(0, ("Cannot change IP address from %s to %s because the latter "
3380                  "is in use by server id %d\n",
3381                  afs_inet_ntoa_r(htonl(ipaddr1), buf1),
3382                  afs_inet_ntoa_r(htonl(ipaddr2), buf2),
3383                  ipaddr2_id));
3384         return VL_MULTIPADDR;
3385     }
3386
3387     /* If we are removing a server entry, a volume cannot
3388      * exist on the server. If one does, don't remove the
3389      * server entry: return error "volume entry exists".
3390      */
3391     if (ipaddr2 == 0) {
3392         for (blockindex = NextEntry(ctx, 0, &tentry, &count); blockindex;
3393              blockindex = NextEntry(ctx, blockindex, &tentry, &count)) {
3394             if (++pollcount > 50) {
3395 #ifndef AFS_PTHREAD_ENV
3396                 IOMGR_Poll();
3397 #endif
3398                 pollcount = 0;
3399             }
3400             for (j = 0; j < NMAXNSERVERS; j++) {
3401                 if (tentry.serverNumber[j] == BADSERVERID)
3402                     break;
3403                 if (tentry.serverNumber[j] == ipaddr1_id) {
3404                     return VL_IDEXIST;
3405                 }
3406             }
3407         }
3408     }
3409
3410     /* Log a message saying we are changing/removing an IP address */
3411     VLog(0,
3412          ("The following IP address is being %s:\n",
3413           (ipaddr2 ? "changed" : "removed")));
3414     VLog(0, ("      entry %d: ", i));
3415     if (exp) {
3416         VLog(0, ("["));
3417         for (mhidx = 0; mhidx < VL_MAXIPADDRS_PERMH; mhidx++) {
3418             if (!exp->ex_addrs[mhidx])
3419                 continue;
3420             if (mhidx > 0)
3421                 VLog(0, (" "));
3422             PADDR(ntohl(exp->ex_addrs[mhidx]));
3423         }
3424         VLog(0, ("]"));
3425     } else {
3426         PADDR(ipaddr1);
3427     }
3428     if (ipaddr2) {
3429         VLog(0, (" -> "));
3430         PADDR(ipaddr2);
3431     }
3432     VLog(0, ("\n"));
3433
3434     /* Change the registered uuuid addresses */
3435     if (exp) {
3436         memset(&tuuid, 0, sizeof(afsUUID));
3437         afs_htonuuid(&tuuid);
3438         exp->ex_hostuuid = tuuid;
3439         code =
3440             vlwrite(ctx->trans,
3441                     DOFFSET(ntohl(ctx->ex_addr[0]->ex_contaddrs[base]),
3442                             (char *)ctx->ex_addr[base], (char *)exp),
3443                     (char *)&tuuid, sizeof(tuuid));
3444         if (code)
3445             return VL_IO;
3446     }
3447
3448     /* Now change the host address entry */
3449     ctx->cheader->IpMappedAddr[ipaddr1_id] = htonl(ipaddr2);
3450     code =
3451         vlwrite(ctx->trans, DOFFSET(0, ctx->cheader, &ctx->cheader->IpMappedAddr[ipaddr1_id]),
3452                 (char *)
3453                 &ctx->cheader->IpMappedAddr[ipaddr1_id], sizeof(afs_int32));
3454     ctx->hostaddress[ipaddr1_id] = ipaddr2;
3455     if (code)
3456         return VL_IO;
3457
3458     return 0;
3459 }
3460
3461 /* see if the vlserver is back yet */
3462 afs_int32
3463 SVL_ProbeServer(struct rx_call *rxcall)
3464 {
3465     return 0;
3466 }