6868edba12cdba15c638e72c4f3069e4fe28e6b9
[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         (vldbentry *) 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             (vldbentry *) realloc(vldbentries->bulkentries_val,
1352                                   vldbentries->bulkentries_len *
1353                                   sizeof(vldbentry));
1354         if (vldbentries->bulkentries_val == NULL) {
1355             code = VL_NOMEM;
1356             goto abort;
1357         }
1358     }
1359     VLog(5,
1360          ("ListAttrs nentries=%d %s\n", vldbentries->bulkentries_len,
1361           rxinfo(rxstr, rxcall)));
1362     return (ubik_EndTrans(ctx.trans));
1363
1364 abort:
1365     if (vldbentries->bulkentries_val)
1366         free(vldbentries->bulkentries_val);
1367     vldbentries->bulkentries_val = 0;
1368     vldbentries->bulkentries_len = 0;
1369
1370     countAbort(this_op);
1371     ubik_AbortTrans(ctx.trans);
1372
1373     return code;
1374 }
1375
1376 afs_int32
1377 SVL_ListAttributesN(struct rx_call *rxcall,
1378                     struct VldbListByAttributes *attributes,
1379                     afs_int32 *nentries,
1380                     nbulkentries *vldbentries)
1381 {
1382     int this_op = VLLISTATTRIBUTESN;
1383     int code, allocCount = 0;
1384     struct vl_ctx ctx;
1385     struct nvlentry tentry;
1386     struct nvldbentry *Vldbentry = 0, *VldbentryFirst = 0, *VldbentryLast = 0;
1387     int pollcount = 0;
1388     char rxstr[AFS_RXINFO_LEN];
1389
1390     countRequest(this_op);
1391     vldbentries->nbulkentries_val = 0;
1392     vldbentries->nbulkentries_len = *nentries = 0;
1393     if ((code = Init_VLdbase(&ctx, LOCKREAD, this_op)))
1394         return code;
1395     allocCount = VLDBALLOCCOUNT;
1396     Vldbentry = VldbentryFirst = vldbentries->nbulkentries_val =
1397         (nvldbentry *) malloc(allocCount * sizeof(nvldbentry));
1398     if (Vldbentry == NULL) {
1399         code = VL_NOMEM;
1400         goto abort;
1401     }
1402     VldbentryLast = VldbentryFirst + allocCount;
1403     /* Handle the attribute by volume id totally separate of the rest
1404      * (thus additional Mask values are ignored if VLLIST_VOLUMEID is set!) */
1405     if (attributes->Mask & VLLIST_VOLUMEID) {
1406         afs_int32 blockindex;
1407
1408         blockindex =
1409             FindByID(&ctx, attributes->volumeid, -1, &tentry, &code);
1410         if (blockindex == 0) {
1411             if (!code)
1412                 code = VL_NOENT;
1413             goto abort;
1414         }
1415
1416         code = put_nattributeentry(&ctx, &Vldbentry, &VldbentryFirst,
1417                                    &VldbentryLast, vldbentries, &tentry,
1418                                    0, 0, nentries, &allocCount);
1419         if (code)
1420             goto abort;
1421     } else {
1422         afs_int32 nextblockindex = 0, count = 0, k = 0, match = 0;
1423         while ((nextblockindex =
1424                NextEntry(&ctx, nextblockindex, &tentry, &count))) {
1425             if (++pollcount > 50) {
1426 #ifndef AFS_PTHREAD_ENV
1427                 IOMGR_Poll();
1428 #endif
1429                 pollcount = 0;
1430             }
1431
1432             match = 0;
1433             if (attributes->Mask & VLLIST_SERVER) {
1434                 int serverindex;
1435                 if ((serverindex =
1436                      IpAddrToRelAddr(&ctx, attributes->server, 0)) == -1)
1437                     continue;
1438                 for (k = 0; k < NMAXNSERVERS; k++) {
1439                     if (tentry.serverNumber[k] == BADSERVERID)
1440                         break;
1441                     if (tentry.serverNumber[k] == serverindex) {
1442                         match = 1;
1443                         break;
1444                     }
1445                 }
1446                 if (!match)
1447                     continue;
1448             }
1449             if (attributes->Mask & VLLIST_PARTITION) {
1450                 if (match) {
1451                     if (tentry.serverPartition[k] != attributes->partition)
1452                         continue;
1453                 } else {
1454                     for (k = 0; k < NMAXNSERVERS; k++) {
1455                         if (tentry.serverNumber[k] == BADSERVERID)
1456                             break;
1457                         if (tentry.serverPartition[k] ==
1458                             attributes->partition) {
1459                             match = 1;
1460                             break;
1461                         }
1462                     }
1463                     if (!match)
1464                         continue;
1465                 }
1466             }
1467
1468             if (attributes->Mask & VLLIST_FLAG) {
1469                 if (!(tentry.flags & attributes->flag))
1470                     continue;
1471             }
1472             code = put_nattributeentry(&ctx, &Vldbentry, &VldbentryFirst,
1473                                        &VldbentryLast, vldbentries,
1474                                        &tentry, 0, 0, nentries, &allocCount);
1475             if (code)
1476                 goto abort;
1477         }
1478     }
1479     if (vldbentries->nbulkentries_len
1480         && (allocCount > vldbentries->nbulkentries_len)) {
1481
1482         vldbentries->nbulkentries_val =
1483             (nvldbentry *) realloc(vldbentries->nbulkentries_val,
1484                                    vldbentries->nbulkentries_len *
1485                                    sizeof(nvldbentry));
1486         if (vldbentries->nbulkentries_val == NULL) {
1487             code = VL_NOMEM;
1488             goto abort;
1489         }
1490     }
1491     VLog(5,
1492          ("NListAttrs nentries=%d %s\n", vldbentries->nbulkentries_len,
1493           rxinfo(rxstr, rxcall)));
1494     return (ubik_EndTrans(ctx.trans));
1495
1496 abort:
1497     countAbort(this_op);
1498     ubik_AbortTrans(ctx.trans);
1499     if (vldbentries->nbulkentries_val)
1500         free(vldbentries->nbulkentries_val);
1501     vldbentries->nbulkentries_val = 0;
1502     vldbentries->nbulkentries_len = 0;
1503     return code;
1504 }
1505
1506
1507 afs_int32
1508 SVL_ListAttributesN2(struct rx_call *rxcall,
1509                      struct VldbListByAttributes *attributes,
1510                      char *name,                /* Wildcarded volume name */
1511                      afs_int32 startindex,
1512                      afs_int32 *nentries,
1513                      nbulkentries *vldbentries,
1514                      afs_int32 *nextstartindex)
1515 {
1516     int this_op = VLLISTATTRIBUTESN2;
1517     int code = 0, maxCount = VLDBALLOCCOUNT;
1518     struct vl_ctx ctx;
1519     struct nvlentry tentry;
1520     struct nvldbentry *Vldbentry = 0, *VldbentryFirst = 0, *VldbentryLast = 0;
1521     afs_int32 blockindex = 0, count = 0, k, match;
1522     afs_int32 matchindex = 0;
1523     int serverindex = -1;       /* no server found */
1524     int findserver = 0, findpartition = 0, findflag = 0, findname = 0;
1525     int pollcount = 0;
1526     int namematchRWBK, namematchRO, thismatch;
1527     int matchtype = 0;
1528     char volumename[VL_MAXNAMELEN+2]; /* regex anchors */
1529     char rxstr[AFS_RXINFO_LEN];
1530 #ifdef HAVE_POSIX_REGEX
1531     regex_t re;
1532     int need_regfree = 0;
1533 #else
1534     char *t;
1535 #endif
1536
1537     countRequest(this_op);
1538     vldbentries->nbulkentries_val = 0;
1539     vldbentries->nbulkentries_len = 0;
1540     *nentries = 0;
1541     *nextstartindex = -1;
1542
1543     code = Init_VLdbase(&ctx, LOCKREAD, this_op);
1544     if (code)
1545         return code;
1546
1547     Vldbentry = VldbentryFirst = vldbentries->nbulkentries_val =
1548         (nvldbentry *) malloc(maxCount * sizeof(nvldbentry));
1549     if (Vldbentry == NULL) {
1550         countAbort(this_op);
1551         ubik_AbortTrans(ctx.trans);
1552         return VL_NOMEM;
1553     }
1554
1555     VldbentryLast = VldbentryFirst + maxCount;
1556
1557     /* Handle the attribute by volume id totally separate of the rest
1558      * (thus additional Mask values are ignored if VLLIST_VOLUMEID is set!)
1559      */
1560     if (attributes->Mask & VLLIST_VOLUMEID) {
1561         blockindex =
1562             FindByID(&ctx, attributes->volumeid, -1, &tentry, &code);
1563         if (blockindex == 0) {
1564             if (!code)
1565                 code = VL_NOENT;
1566         } else {
1567             code =
1568                 put_nattributeentry(&ctx, &Vldbentry, &VldbentryFirst,
1569                                     &VldbentryLast, vldbentries, &tentry, 0,
1570                                     0, nentries, &maxCount);
1571             if (code)
1572                 goto done;
1573         }
1574     }
1575
1576     /* Search each entry in the database and return all entries
1577      * that match the request. It checks volumename (with
1578      * wildcarding), entry flags, server, and partition.
1579      */
1580     else {
1581         /* Get the server index for matching server address */
1582         if (attributes->Mask & VLLIST_SERVER) {
1583             serverindex =
1584                 IpAddrToRelAddr(&ctx, attributes->server, 0);
1585             if (serverindex == -1)
1586                 goto done;
1587             findserver = 1;
1588         }
1589         findpartition = ((attributes->Mask & VLLIST_PARTITION) ? 1 : 0);
1590         findflag = ((attributes->Mask & VLLIST_FLAG) ? 1 : 0);
1591         if (name && (strcmp(name, ".*") != 0) && (strcmp(name, "") != 0)) {
1592             sprintf(volumename, "^%s$", name);
1593 #ifdef HAVE_POSIX_REGEX
1594             if (regcomp(&re, volumename, REG_NOSUB) != 0) {
1595                 code = VL_BADNAME;
1596                 goto done;
1597             }
1598             need_regfree = 1;
1599 #else
1600             t = (char *)re_comp(volumename);
1601             if (t) {
1602                 code = VL_BADNAME;
1603                 goto done;
1604             }
1605 #endif
1606             findname = 1;
1607         }
1608
1609         /* Read each entry and see if it is the one we want */
1610         blockindex = startindex;
1611         while ((blockindex = NextEntry(&ctx, blockindex, &tentry, &count))) {
1612             if (++pollcount > 50) {
1613 #ifndef AFS_PTHREAD_ENV
1614                 IOMGR_Poll();
1615 #endif
1616                 pollcount = 0;
1617             }
1618
1619             /* Step through each server index searching for a match.
1620              * Match to an existing RW, BK, or RO volume name (preference
1621              * is in this order). Remember which index we matched against.
1622              */
1623             namematchRWBK = namematchRO = 0;    /* 0->notTried; 1->match; 2->noMatch */
1624             match = 0;
1625             for (k = 0;
1626                  (k < NMAXNSERVERS
1627                   && (tentry.serverNumber[k] != BADSERVERID)); k++) {
1628                 thismatch = 0;  /* does this index match */
1629
1630                 /* Match against the RW or BK volume name. Remember
1631                  * results in namematchRWBK. Prefer RW over BK.
1632                  */
1633                 if (tentry.serverFlags[k] & VLSF_RWVOL) {
1634                     /* Does the name match the RW name */
1635                     if (tentry.flags & VLF_RWEXISTS) {
1636                         if (findname) {
1637                             sprintf(volumename, "%s", tentry.name);
1638 #ifdef HAVE_POSIX_REGEX
1639                             if (regexec(&re, volumename, 0, NULL, 0) == 0) {
1640                                 thismatch = VLSF_RWVOL;
1641                             }
1642 #else
1643                             if (re_exec(volumename)) {
1644                                 thismatch = VLSF_RWVOL;
1645                             }
1646 #endif
1647                         } else {
1648                             thismatch = VLSF_RWVOL;
1649                         }
1650                     }
1651
1652                     /* Does the name match the BK name */
1653                     if (!thismatch && (tentry.flags & VLF_BACKEXISTS)) {
1654                         if (findname) {
1655                             sprintf(volumename, "%s.backup", tentry.name);
1656 #ifdef HAVE_POSIX_REGEX
1657                             if (regexec(&re, volumename, 0, NULL, 0) == 0) {
1658                                 thismatch = VLSF_BACKVOL;
1659                             }
1660 #else
1661                             if (re_exec(volumename)) {
1662                                 thismatch = VLSF_BACKVOL;
1663                             }
1664 #endif
1665                         } else {
1666                             thismatch = VLSF_BACKVOL;
1667                         }
1668                     }
1669
1670                     namematchRWBK = (thismatch ? 1 : 2);
1671                 }
1672
1673                 /* Match with the RO volume name. Compare once and
1674                  * remember results in namematchRO. Note that this will
1675                  * pick up entries marked NEWREPSITEs and DONTUSE.
1676                  */
1677                 else {
1678                     if (tentry.flags & VLF_ROEXISTS) {
1679                         if (findname) {
1680                             if (namematchRO) {
1681                                 thismatch =
1682                                     ((namematchRO == 1) ? VLSF_ROVOL : 0);
1683                             } else {
1684                                 sprintf(volumename, "%s.readonly",
1685                                         tentry.name);
1686 #ifdef HAVE_POSIX_REGEX
1687                             if (regexec(&re, volumename, 0, NULL, 0) == 0) {
1688                                 thismatch = VLSF_ROVOL;
1689                             }
1690 #else
1691                                 if (re_exec(volumename))
1692                                     thismatch = VLSF_ROVOL;
1693 #endif
1694                             }
1695                         } else {
1696                             thismatch = VLSF_ROVOL;
1697                         }
1698                     }
1699                     namematchRO = (thismatch ? 1 : 2);
1700                 }
1701
1702                 /* Is there a server match */
1703                 if (thismatch && findserver
1704                     && (tentry.serverNumber[k] != serverindex))
1705                     thismatch = 0;
1706
1707                 /* Is there a partition match */
1708                 if (thismatch && findpartition
1709                     && (tentry.serverPartition[k] != attributes->partition))
1710                     thismatch = 0;
1711
1712                 /* Is there a flag match */
1713                 if (thismatch && findflag
1714                     && !(tentry.flags & attributes->flag))
1715                     thismatch = 0;
1716
1717                 /* We found a match. Remember the index, and type */
1718                 if (thismatch) {
1719                     match = 1;
1720                     matchindex = k;
1721                     matchtype = thismatch;
1722                 }
1723
1724                 /* Since we prefer RW and BK volume matches over RO matches,
1725                  * if we have already checked the RWBK name, then we already
1726                  * found the best match and so end the search.
1727                  *
1728                  * If we tried matching against the RW, BK, and RO volume names
1729                  * and both failed, then we end the search (none will match).
1730                  */
1731                 if ((match && namematchRWBK)
1732                     || ((namematchRWBK == 2) && (namematchRO == 2)))
1733                     break;
1734             }
1735
1736             /* Passed all the tests. Take it */
1737             if (match) {
1738                 code =
1739                     put_nattributeentry(&ctx, &Vldbentry, &VldbentryFirst,
1740                                         &VldbentryLast, vldbentries, &tentry,
1741                                         matchtype, matchindex, nentries,
1742                                         &maxCount);
1743                 if (code)
1744                     goto done;
1745
1746                 if (*nentries >= maxCount)
1747                     break;      /* collected the max */
1748             }
1749         }
1750         *nextstartindex = (blockindex ? blockindex : -1);
1751     }
1752
1753   done:
1754 #ifdef HAVE_POSIX_REGEX
1755     if (need_regfree)
1756         regfree(&re);
1757 #endif
1758
1759     if (code) {
1760         countAbort(this_op);
1761         ubik_AbortTrans(ctx.trans);
1762         if (vldbentries->nbulkentries_val)
1763             free((char *)vldbentries->nbulkentries_val);
1764         vldbentries->nbulkentries_val = 0;
1765         vldbentries->nbulkentries_len = 0;
1766         *nextstartindex = -1;
1767         return code;
1768     } else {
1769         VLog(5,
1770              ("N2ListAttrs nentries=%d %s\n", vldbentries->nbulkentries_len,
1771               rxinfo(rxstr, rxcall)));
1772         return (ubik_EndTrans(ctx.trans));
1773     }
1774 }
1775
1776
1777 /* Retrieves in vldbentries all vldb entries that match the specified
1778  * attributes (by server number, partition, volume type, and flag); if
1779  * volume id is specified then the associated list for that entry is
1780  * returned. CAUTION: This could be a very expensive call since in most
1781  * cases sequential search of all vldb entries is performed.
1782  */
1783 afs_int32
1784 SVL_LinkedList(struct rx_call *rxcall,
1785                struct VldbListByAttributes *attributes,
1786                afs_int32 *nentries,
1787                vldb_list *vldbentries)
1788 {
1789     int this_op = VLLINKEDLIST;
1790     int code;
1791     struct vl_ctx ctx;
1792     struct nvlentry tentry;
1793     vldblist vllist, *vllistptr;
1794     afs_int32 blockindex, count, match;
1795     afs_int32 k = 0;
1796     int serverindex;
1797     int pollcount = 0;
1798
1799     countRequest(this_op);
1800     if ((code = Init_VLdbase(&ctx, LOCKREAD, this_op)))
1801         return code;
1802
1803     *nentries = 0;
1804     vldbentries->node = NULL;
1805     vllistptr = &vldbentries->node;
1806
1807     /* List by volumeid */
1808     if (attributes->Mask & VLLIST_VOLUMEID) {
1809         blockindex =
1810             FindByID(&ctx, attributes->volumeid, -1, &tentry, &code);
1811         if (!blockindex) {
1812             if (!code)
1813                 code = VL_NOENT;
1814             goto abort;
1815         }
1816
1817         vllist = (single_vldbentry *) malloc(sizeof(single_vldbentry));
1818         if (vllist == NULL) {
1819             code = VL_NOMEM;
1820             goto abort;
1821         }
1822         code = vlentry_to_vldbentry(&ctx, &tentry, &vllist->VldbEntry);
1823         if (code)
1824             goto abort;
1825
1826         vllist->next_vldb = NULL;
1827
1828         *vllistptr = vllist;    /* Thread onto list */
1829         vllistptr = &vllist->next_vldb;
1830         (*nentries)++;
1831     }
1832
1833     /* Search by server, partition, and flags */
1834     else {
1835         for (blockindex = NextEntry(&ctx, 0, &tentry, &count); blockindex;
1836              blockindex = NextEntry(&ctx, blockindex, &tentry, &count)) {
1837             match = 0;
1838
1839             if (++pollcount > 50) {
1840 #ifndef AFS_PTHREAD_ENV
1841                 IOMGR_Poll();
1842 #endif
1843                 pollcount = 0;
1844             }
1845
1846             /* Does this volume exist on the desired server */
1847             if (attributes->Mask & VLLIST_SERVER) {
1848                 serverindex =
1849                     IpAddrToRelAddr(&ctx, attributes->server, 0);
1850                 if (serverindex == -1)
1851                     continue;
1852                 for (k = 0; k < OMAXNSERVERS; k++) {
1853                     if (tentry.serverNumber[k] == BADSERVERID)
1854                         break;
1855                     if (tentry.serverNumber[k] == serverindex) {
1856                         match = 1;
1857                         break;
1858                     }
1859                 }
1860                 if (!match)
1861                     continue;
1862             }
1863
1864             /* Does this volume exist on the desired partition */
1865             if (attributes->Mask & VLLIST_PARTITION) {
1866                 if (match) {
1867                     if (tentry.serverPartition[k] != attributes->partition)
1868                         match = 0;
1869                 } else {
1870                     for (k = 0; k < OMAXNSERVERS; k++) {
1871                         if (tentry.serverNumber[k] == BADSERVERID)
1872                             break;
1873                         if (tentry.serverPartition[k] ==
1874                             attributes->partition) {
1875                             match = 1;
1876                             break;
1877                         }
1878                     }
1879                 }
1880                 if (!match)
1881                     continue;
1882             }
1883
1884             /* Does this volume have the desired flags */
1885             if (attributes->Mask & VLLIST_FLAG) {
1886                 if (!(tentry.flags & attributes->flag))
1887                     continue;
1888             }
1889
1890             vllist = (single_vldbentry *) malloc(sizeof(single_vldbentry));
1891             if (vllist == NULL) {
1892                 code = VL_NOMEM;
1893                 goto abort;
1894             }
1895             code = vlentry_to_vldbentry(&ctx, &tentry, &vllist->VldbEntry);
1896             if (code)
1897                 goto abort;
1898
1899             vllist->next_vldb = NULL;
1900
1901             *vllistptr = vllist;        /* Thread onto list */
1902             vllistptr = &vllist->next_vldb;
1903             (*nentries)++;
1904             if (smallMem && (*nentries >= VLDBALLOCCOUNT)) {
1905                 code = VL_SIZEEXCEEDED;
1906                 goto abort;
1907             }
1908         }
1909     }
1910     *vllistptr = NULL;
1911     return (ubik_EndTrans(ctx.trans));
1912
1913 abort:
1914     countAbort(this_op);
1915     ubik_AbortTrans(ctx.trans);
1916     return code;
1917 }
1918
1919 afs_int32
1920 SVL_LinkedListN(struct rx_call *rxcall,
1921                 struct VldbListByAttributes *attributes,
1922                 afs_int32 *nentries,
1923                 nvldb_list *vldbentries)
1924 {
1925     int this_op = VLLINKEDLISTN;
1926     int code;
1927     struct vl_ctx ctx;
1928     struct nvlentry tentry;
1929     nvldblist vllist, *vllistptr;
1930     afs_int32 blockindex, count, match;
1931     afs_int32 k = 0;
1932     int serverindex;
1933     int pollcount = 0;
1934
1935     countRequest(this_op);
1936     if ((code = Init_VLdbase(&ctx, LOCKREAD, this_op)))
1937         return code;
1938
1939     *nentries = 0;
1940     vldbentries->node = NULL;
1941     vllistptr = &vldbentries->node;
1942
1943     /* List by volumeid */
1944     if (attributes->Mask & VLLIST_VOLUMEID) {
1945         blockindex =
1946             FindByID(&ctx, attributes->volumeid, -1, &tentry, &code);
1947         if (!blockindex) {
1948             if (!code)
1949                 code = VL_NOENT;
1950             goto abort;
1951         }
1952
1953         vllist = (single_nvldbentry *) malloc(sizeof(single_nvldbentry));
1954         if (vllist == NULL) {
1955             code = VL_NOMEM;
1956             goto abort;
1957         }
1958         code = vlentry_to_nvldbentry(&ctx, &tentry, &vllist->VldbEntry);
1959         if (code)
1960             goto abort;
1961
1962         vllist->next_vldb = NULL;
1963
1964         *vllistptr = vllist;    /* Thread onto list */
1965         vllistptr = &vllist->next_vldb;
1966         (*nentries)++;
1967     }
1968
1969     /* Search by server, partition, and flags */
1970     else {
1971         for (blockindex = NextEntry(&ctx, 0, &tentry, &count); blockindex;
1972              blockindex = NextEntry(&ctx, blockindex, &tentry, &count)) {
1973             match = 0;
1974
1975             if (++pollcount > 50) {
1976 #ifndef AFS_PTHREAD_ENV
1977                 IOMGR_Poll();
1978 #endif
1979                 pollcount = 0;
1980             }
1981
1982             /* Does this volume exist on the desired server */
1983             if (attributes->Mask & VLLIST_SERVER) {
1984                 serverindex =
1985                     IpAddrToRelAddr(&ctx, attributes->server, 0);
1986                 if (serverindex == -1)
1987                     continue;
1988                 for (k = 0; k < NMAXNSERVERS; k++) {
1989                     if (tentry.serverNumber[k] == BADSERVERID)
1990                         break;
1991                     if (tentry.serverNumber[k] == serverindex) {
1992                         match = 1;
1993                         break;
1994                     }
1995                 }
1996                 if (!match)
1997                     continue;
1998             }
1999
2000             /* Does this volume exist on the desired partition */
2001             if (attributes->Mask & VLLIST_PARTITION) {
2002                 if (match) {
2003                     if (tentry.serverPartition[k] != attributes->partition)
2004                         match = 0;
2005                 } else {
2006                     for (k = 0; k < NMAXNSERVERS; k++) {
2007                         if (tentry.serverNumber[k] == BADSERVERID)
2008                             break;
2009                         if (tentry.serverPartition[k] ==
2010                             attributes->partition) {
2011                             match = 1;
2012                             break;
2013                         }
2014                     }
2015                 }
2016                 if (!match)
2017                     continue;
2018             }
2019
2020             /* Does this volume have the desired flags */
2021             if (attributes->Mask & VLLIST_FLAG) {
2022                 if (!(tentry.flags & attributes->flag))
2023                     continue;
2024             }
2025
2026             vllist = (single_nvldbentry *) malloc(sizeof(single_nvldbentry));
2027             if (vllist == NULL) {
2028                 code = VL_NOMEM;
2029                 goto abort;
2030             }
2031             code = vlentry_to_nvldbentry(&ctx, &tentry, &vllist->VldbEntry);
2032             if (code)
2033                 goto abort;
2034
2035             vllist->next_vldb = NULL;
2036
2037             *vllistptr = vllist;        /* Thread onto list */
2038             vllistptr = &vllist->next_vldb;
2039             (*nentries)++;
2040             if (smallMem && (*nentries >= VLDBALLOCCOUNT)) {
2041                 code = VL_SIZEEXCEEDED;
2042                 goto abort;
2043             }
2044         }
2045     }
2046     *vllistptr = NULL;
2047     return (ubik_EndTrans(ctx.trans));
2048
2049 abort:
2050     countAbort(this_op);
2051     ubik_AbortTrans(ctx.trans);
2052     return code;
2053 }
2054
2055 /* Get back vldb header statistics (allocs, frees, maxvolumeid,
2056  * totalentries, etc) and dynamic statistics (number of requests and/or
2057  * aborts per remote procedure call, etc)
2058  */
2059 afs_int32
2060 SVL_GetStats(struct rx_call *rxcall,
2061              vldstats *stats,
2062              vital_vlheader *vital_header)
2063 {
2064     int this_op = VLGETSTATS;
2065     afs_int32 code;
2066     struct vl_ctx ctx;
2067     char rxstr[AFS_RXINFO_LEN];
2068
2069     countRequest(this_op);
2070 #ifdef  notdef
2071     /* Allow users to get statistics freely */
2072     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL)) /* Must be in 'UserList' to use */
2073         return VL_PERM;
2074 #endif
2075     if ((code = Init_VLdbase(&ctx, LOCKREAD, this_op)))
2076         return code;
2077     VLog(5, ("GetStats %s\n", rxinfo(rxstr, rxcall)));
2078     memcpy((char *)vital_header, (char *)&ctx.cheader->vital_header,
2079            sizeof(vital_vlheader));
2080     memcpy((char *)stats, (char *)&dynamic_statistics, sizeof(vldstats));
2081     return (ubik_EndTrans(ctx.trans));
2082 }
2083
2084 /* Get the list of file server addresses from the VLDB.  Currently it's pretty
2085  * easy to do.  In the future, it might require a little bit of grunging
2086  * through the VLDB, but that's life.
2087  */
2088 afs_int32
2089 SVL_GetAddrs(struct rx_call *rxcall,
2090              afs_int32 Handle,
2091              afs_int32 spare2,
2092              struct VLCallBack *spare3,
2093              afs_int32 *nentries,
2094              bulkaddrs *addrsp)
2095 {
2096     int this_op = VLGETADDRS;
2097     afs_int32 code;
2098     struct vl_ctx ctx;
2099     int nservers, i;
2100     afs_uint32 *taddrp;
2101
2102     countRequest(this_op);
2103     addrsp->bulkaddrs_len = *nentries = 0;
2104     addrsp->bulkaddrs_val = 0;
2105     memset(spare3, 0, sizeof(struct VLCallBack));
2106
2107     if ((code = Init_VLdbase(&ctx, LOCKREAD, this_op)))
2108         return code;
2109
2110     VLog(5, ("GetAddrs\n"));
2111     addrsp->bulkaddrs_val = taddrp =
2112         (afs_uint32 *) malloc(sizeof(afs_int32) * (MAXSERVERID + 1));
2113     nservers = *nentries = addrsp->bulkaddrs_len = 0;
2114
2115     if (!taddrp) {
2116         code = VL_NOMEM;
2117         goto abort;
2118     }
2119
2120     for (i = 0; i <= MAXSERVERID; i++) {
2121         if ((*taddrp = ntohl(ctx.cheader->IpMappedAddr[i]))) {
2122             taddrp++;
2123             nservers++;
2124         }
2125     }
2126
2127     addrsp->bulkaddrs_len = *nentries = nservers;
2128     return (ubik_EndTrans(ctx.trans));
2129
2130 abort:
2131     countAbort(this_op);
2132     ubik_AbortTrans(ctx.trans);
2133     return code;
2134 }
2135
2136 #define PADDR(addr) VLog(0,("%d.%d.%d.%d", (addr>>24)&0xff, (addr>>16)&0xff, (addr>>8) &0xff, addr&0xff));
2137
2138 afs_int32
2139 SVL_RegisterAddrs(struct rx_call *rxcall, afsUUID *uuidp, afs_int32 spare1,
2140                   bulkaddrs *addrsp)
2141 {
2142     int this_op = VLREGADDR;
2143     afs_int32 code;
2144     struct vl_ctx ctx;
2145     int cnt, h, i, j, k, m;
2146     struct extentaddr *exp = 0, *tex;
2147     afsUUID tuuid;
2148     afs_uint32 addrs[VL_MAXIPADDRS_PERMH];
2149     int base;
2150     int count, willChangeEntry, foundUuidEntry, willReplaceCnt;
2151     int WillReplaceEntry, WillChange[MAXSERVERID + 1];
2152     int FoundUuid = 0;
2153     int ReplaceEntry = 0;
2154     int srvidx, mhidx;
2155
2156     countRequest(this_op);
2157     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL))
2158         return (VL_PERM);
2159     if ((code = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
2160         return code;
2161
2162     /* Eliminate duplicates from IP address list */
2163     for (k = 0, cnt = 0; k < addrsp->bulkaddrs_len; k++) {
2164         if (addrsp->bulkaddrs_val[k] == 0)
2165             continue;
2166         for (m = 0; m < cnt; m++) {
2167             if (addrs[m] == addrsp->bulkaddrs_val[k])
2168                 break;
2169         }
2170         if (m == cnt) {
2171             if (m == VL_MAXIPADDRS_PERMH) {
2172                 VLog(0,
2173                      ("Number of addresses exceeds %d. Cannot register IP addr 0x%x in VLDB\n",
2174                       VL_MAXIPADDRS_PERMH, addrsp->bulkaddrs_val[k]));
2175             } else {
2176                 addrs[m] = addrsp->bulkaddrs_val[k];
2177                 cnt++;
2178             }
2179         }
2180     }
2181     if (cnt <= 0) {
2182         code = VL_INDEXERANGE;
2183         goto abort;
2184     }
2185
2186     count = 0;
2187     willReplaceCnt = 0;
2188     foundUuidEntry = 0;
2189     /* For each server registered within the VLDB */
2190     for (srvidx = 0; srvidx <= MAXSERVERID; srvidx++) {
2191         willChangeEntry = 0;
2192         WillReplaceEntry = 1;
2193         code = multiHomedExtent(&ctx, srvidx, &exp);
2194         if (code)
2195              continue;
2196
2197         if (exp) {
2198             /* See if the addresses to register will change this server entry */
2199             tuuid = exp->ex_hostuuid;
2200             afs_ntohuuid(&tuuid);
2201             if (afs_uuid_equal(uuidp, &tuuid)) {
2202                 foundUuidEntry = 1;
2203                 FoundUuid = srvidx;
2204             } else {
2205                 for (mhidx = 0; mhidx < VL_MAXIPADDRS_PERMH; mhidx++) {
2206                     if (!exp->ex_addrs[mhidx])
2207                         continue;
2208                     for (k = 0; k < cnt; k++) {
2209                         if (ntohl(exp->ex_addrs[mhidx]) == addrs[k]) {
2210                             willChangeEntry = 1;
2211                             WillChange[count] = srvidx;
2212                             break;
2213                         }
2214                     }
2215                     if (k >= cnt)
2216                         WillReplaceEntry = 0;
2217                 }
2218             }
2219         } else {
2220             /* The server is not registered as a multihomed.
2221              * See if the addresses to register will replace this server entry.
2222              */
2223             for (k = 0; k < cnt; k++) {
2224                 if (ctx.hostaddress[srvidx] == addrs[k]) {
2225                     willChangeEntry = 1;
2226                     WillChange[count] = srvidx;
2227                     WillReplaceEntry = 1;
2228                     break;
2229                 }
2230             }
2231         }
2232         if (willChangeEntry) {
2233             if (WillReplaceEntry) {
2234                 willReplaceCnt++;
2235                 ReplaceEntry = srvidx;
2236             }
2237             count++;
2238         }
2239     }
2240
2241     /* If we found the uuid in the VLDB and if we are replacing another
2242      * entire entry, then complain and fail. Also, if we did not find
2243      * the uuid in the VLDB and the IP addresses being registered was
2244      * found in more than one other entry, then we don't know which one
2245      * to replace and will complain and fail.
2246      */
2247     if ((foundUuidEntry && (willReplaceCnt > 0))
2248         || (!foundUuidEntry && (count > 1))) {
2249         VLog(0,
2250              ("The following fileserver is being registered in the VLDB:\n"));
2251         VLog(0, ("      ["));
2252         for (k = 0; k < cnt; k++) {
2253             if (k > 0)
2254                 VLog(0,(" "));
2255             PADDR(addrs[k]);
2256         }
2257         VLog(0,("]\n"));
2258
2259         if (foundUuidEntry) {
2260             code = multiHomedExtent(&ctx, FoundUuid, &exp);
2261             if (code == 0) {
2262                 VLog(0, ("   It would have replaced the existing VLDB server "
2263                          "entry:\n"));
2264                 VLog(0, ("      entry %d: [", FoundUuid));
2265                 for (mhidx = 0; mhidx < VL_MAXIPADDRS_PERMH; mhidx++) {
2266                     if (!exp->ex_addrs[mhidx])
2267                         continue;
2268                     if (mhidx > 0)
2269                         VLog(0,(" "));
2270                     PADDR(ntohl(exp->ex_addrs[mhidx]));
2271                 }
2272                 VLog(0, ("]\n"));
2273             }
2274         }
2275
2276         if (count == 1)
2277             VLog(0, ("   Yet another VLDB server entry exists:\n"));
2278         else
2279             VLog(0, ("   Yet other VLDB server entries exist:\n"));
2280         for (j = 0; j < count; j++) {
2281             srvidx = WillChange[j];
2282             VLog(0, ("      entry %d: ", srvidx));
2283
2284             code = multiHomedExtent(&ctx, srvidx, &exp);
2285             if (code)
2286                 goto abort;
2287
2288             if (exp) {
2289                 VLog(0, ("["));
2290                 for (mhidx = 0; mhidx < VL_MAXIPADDRS_PERMH; mhidx++) {
2291                     if (!exp->ex_addrs[mhidx])
2292                         continue;
2293                     if (mhidx > 0)
2294                         VLog(0, (" "));
2295                     PADDR(ntohl(exp->ex_addrs[mhidx]));
2296                 }
2297                 VLog(0, ("]"));
2298             } else {
2299                 PADDR(ctx.hostaddress[srvidx]);
2300             }
2301             VLog(0, ("\n"));
2302         }
2303
2304         if (count == 1)
2305             VLog(0, ("   You must 'vos changeaddr' this other server entry\n"));
2306         else
2307             VLog(0,
2308                 ("   You must 'vos changeaddr' these other server entries\n"));
2309         if (foundUuidEntry)
2310             VLog(0,
2311                 ("   and/or remove the sysid file from the registering fileserver\n"));
2312         VLog(0, ("   before the fileserver can be registered in the VLDB.\n"));
2313
2314         code = VL_MULTIPADDR;
2315         goto abort;
2316     }
2317
2318     /* Passed the checks. Now find and update the existing mh entry, or create
2319      * a new mh entry.
2320      */
2321     if (foundUuidEntry) {
2322         /* Found the entry with same uuid. See if we need to change it */
2323         int change = 0;
2324
2325         code = multiHomedExtentBase(&ctx, FoundUuid, &exp, &base);
2326         if (code)
2327             goto abort;
2328
2329         /* Determine if the entry has changed */
2330         for (k = 0; ((k < cnt) && !change); k++) {
2331             if (ntohl(exp->ex_addrs[k]) != addrs[k])
2332                 change = 1;
2333         }
2334         for (; ((k < VL_MAXIPADDRS_PERMH) && !change); k++) {
2335             if (exp->ex_addrs[k] != 0)
2336                 change = 1;
2337         }
2338         if (!change) {
2339             return (ubik_EndTrans(ctx.trans));
2340         }
2341     }
2342
2343     VLog(0, ("The following fileserver is being registered in the VLDB:\n"));
2344     VLog(0, ("      ["));
2345     for (k = 0; k < cnt; k++) {
2346         if (k > 0)
2347             VLog(0, (" "));
2348         PADDR(addrs[k]);
2349     }
2350     VLog(0, ("]\n"));
2351
2352     if (foundUuidEntry) {
2353         VLog(0,
2354             ("   It will replace the following existing entry in the VLDB (same uuid):\n"));
2355         VLog(0, ("      entry %d: [", FoundUuid));
2356         for (k = 0; k < VL_MAXIPADDRS_PERMH; k++) {
2357             if (exp->ex_addrs[k] == 0)
2358                 continue;
2359             if (k > 0)
2360                 VLog(0, (" "));
2361             PADDR(ntohl(exp->ex_addrs[k]));
2362         }
2363         VLog(0, ("]\n"));
2364     } else if (willReplaceCnt || (count == 1)) {
2365         /* If we are not replacing an entry and there is only one entry to change,
2366          * then we will replace that entry.
2367          */
2368         if (!willReplaceCnt) {
2369             ReplaceEntry = WillChange[0];
2370             willReplaceCnt++;
2371         }
2372
2373         /* Have an entry that needs to be replaced */
2374         code = multiHomedExtentBase(&ctx, ReplaceEntry, &exp, &base);
2375         if (code)
2376             goto abort;
2377
2378         if (exp) {
2379             VLog(0,
2380                 ("   It will replace the following existing entry in the VLDB (new uuid):\n"));
2381             VLog(0, ("      entry %d: [", ReplaceEntry));
2382             for (k = 0; k < VL_MAXIPADDRS_PERMH; k++) {
2383                 if (exp->ex_addrs[k] == 0)
2384                     continue;
2385                 if (k > 0)
2386                     VLog(0, (" "));
2387                 PADDR(ntohl(exp->ex_addrs[k]));
2388             }
2389             VLog(0, ("]\n"));
2390         } else {
2391             /* Not a mh entry. So we have to create a new mh entry and
2392              * put it on the ReplaceEntry slot of the ctx.hostaddress array.
2393              */
2394             VLog(0, ("   It will replace existing entry %d, ", ReplaceEntry));
2395             PADDR(ctx.hostaddress[ReplaceEntry]);
2396             VLog(0,(", in the VLDB (new uuid):\n"));
2397
2398             code =
2399                 FindExtentBlock(&ctx, uuidp, 1, ReplaceEntry, &exp, &base);
2400             if (code || !exp) {
2401                 if (!code)
2402                     code = VL_IO;
2403                 goto abort;
2404             }
2405         }
2406     } else {
2407         /* There is no entry for this server, must create a new mh entry as
2408          * well as use a new slot of the ctx.hostaddress array.
2409          */
2410         VLog(0, ("   It will create a new entry in the VLDB.\n"));
2411         code = FindExtentBlock(&ctx, uuidp, 1, -1, &exp, &base);
2412         if (code || !exp) {
2413             if (!code)
2414                 code = VL_IO;
2415             goto abort;
2416         }
2417     }
2418
2419     /* Now we have a mh entry to fill in. Update the uuid, bump the
2420      * uniquifier, and fill in its IP addresses.
2421      */
2422     tuuid = *uuidp;
2423     afs_htonuuid(&tuuid);
2424     exp->ex_hostuuid = tuuid;
2425     exp->ex_uniquifier = htonl(ntohl(exp->ex_uniquifier) + 1);
2426     for (k = 0; k < cnt; k++) {
2427         exp->ex_addrs[k] = htonl(addrs[k]);
2428     }
2429     for (; k < VL_MAXIPADDRS_PERMH; k++) {
2430         exp->ex_addrs[k] = 0;
2431     }
2432
2433     /* Write the new mh entry out */
2434     if (vlwrite
2435         (ctx.trans,
2436          DOFFSET(ntohl(ctx.ex_addr[0]->ex_contaddrs[base]),
2437                  (char *)ctx.ex_addr[base], (char *)exp), (char *)exp,
2438          sizeof(*exp))) {
2439         code = VL_IO;
2440         goto abort;
2441     }
2442
2443     /* Remove any common addresses from other mh entres. We know these entries
2444      * are being changed and not replaced so they are mh entries.
2445      */
2446     m = 0;
2447     for (i = 0; i < count; i++) {
2448         afs_int32 doff;
2449
2450         /* Skip the entry we replaced */
2451         if (willReplaceCnt && (WillChange[i] == ReplaceEntry))
2452             continue;
2453
2454         code = multiHomedExtentBase(&ctx, WillChange[i], &tex, &base);
2455         if (code)
2456             goto abort;
2457
2458         if (++m == 1)
2459             VLog(0,
2460                 ("   The following existing entries in the VLDB will be updated:\n"));
2461
2462         VLog(0, ("      entry %d: [", WillChange[i]));
2463         for (h = j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
2464             if (tex->ex_addrs[j]) {
2465                 if (j > 0)
2466                     printf(" ");
2467                 PADDR(ntohl(tex->ex_addrs[j]));
2468             }
2469
2470             for (k = 0; k < cnt; k++) {
2471                 if (ntohl(tex->ex_addrs[j]) == addrs[k])
2472                     break;
2473             }
2474             if (k >= cnt) {
2475                 /* Not found, so we keep it */
2476                 tex->ex_addrs[h] = tex->ex_addrs[j];
2477                 h++;
2478             }
2479         }
2480         for (j = h; j < VL_MAXIPADDRS_PERMH; j++) {
2481             tex->ex_addrs[j] = 0;       /* zero rest of mh entry */
2482         }
2483         VLog(0, ("]\n"));
2484
2485         /* Write out the modified mh entry */
2486         tex->ex_uniquifier = htonl(ntohl(tex->ex_uniquifier) + 1);
2487         doff =
2488             DOFFSET(ntohl(ctx.ex_addr[0]->ex_contaddrs[base]),
2489                     (char *)ctx.ex_addr[base], (char *)tex);
2490         if (vlwrite(ctx.trans, doff, (char *)tex, sizeof(*tex))) {
2491             code = VL_IO;
2492             goto abort;
2493         }
2494     }
2495
2496     return (ubik_EndTrans(ctx.trans));
2497
2498 abort:
2499     countAbort(this_op);
2500     ubik_AbortTrans(ctx.trans);
2501     return code;
2502 }
2503
2504 afs_int32
2505 SVL_GetAddrsU(struct rx_call *rxcall,
2506               struct ListAddrByAttributes *attributes,
2507               afsUUID *uuidpo,
2508               afs_int32 *uniquifier,
2509               afs_int32 *nentries,
2510               bulkaddrs *addrsp)
2511 {
2512     int this_op = VLGETADDRSU;
2513     afs_int32 code, index = -1, offset;
2514     struct vl_ctx ctx;
2515     int nservers, i, j, base = 0;
2516     struct extentaddr *exp = 0;
2517     afsUUID tuuid;
2518     afs_uint32 *taddrp, taddr;
2519     char rxstr[AFS_RXINFO_LEN];
2520
2521     countRequest(this_op);
2522     addrsp->bulkaddrs_len = *nentries = 0;
2523     addrsp->bulkaddrs_val = 0;
2524     VLog(5, ("GetAddrsU %s\n", rxinfo(rxstr, rxcall)));
2525     if ((code = Init_VLdbase(&ctx, LOCKREAD, this_op)))
2526         return code;
2527
2528     if (attributes->Mask & VLADDR_IPADDR) {
2529         if (attributes->Mask & (VLADDR_INDEX | VLADDR_UUID)) {
2530             code = VL_BADMASK;
2531             goto abort;
2532         }
2533         for (base = 0; base < VL_MAX_ADDREXTBLKS; base++) {
2534             if (!ctx.ex_addr[base])
2535                 break;
2536             for (i = 1; i < VL_MHSRV_PERBLK; i++) {
2537                 exp = &ctx.ex_addr[base][i];
2538                 tuuid = exp->ex_hostuuid;
2539                 afs_ntohuuid(&tuuid);
2540                 if (afs_uuid_is_nil(&tuuid))
2541                     continue;
2542                 for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
2543                     if (exp->ex_addrs[j]
2544                         && (ntohl(exp->ex_addrs[j]) == attributes->ipaddr)) {
2545                         break;
2546                     }
2547                 }
2548                 if (j < VL_MAXIPADDRS_PERMH)
2549                     break;
2550             }
2551             if (i < VL_MHSRV_PERBLK)
2552                 break;
2553         }
2554         if (base >= VL_MAX_ADDREXTBLKS) {
2555             code = VL_NOENT;
2556             goto abort;
2557         }
2558     } else if (attributes->Mask & VLADDR_INDEX) {
2559         if (attributes->Mask & (VLADDR_IPADDR | VLADDR_UUID)) {
2560             code = VL_BADMASK;
2561             goto abort;
2562         }
2563         index = attributes->index;
2564         if (index < 1 || index >= (VL_MAX_ADDREXTBLKS * VL_MHSRV_PERBLK)) {
2565             code = VL_INDEXERANGE;
2566             goto abort;
2567         }
2568         base = index / VL_MHSRV_PERBLK;
2569         offset = index % VL_MHSRV_PERBLK;
2570         if (offset == 0) {
2571             code = VL_NOENT;
2572             goto abort;
2573         }
2574         if (!ctx.ex_addr[base]) {
2575             code = VL_INDEXERANGE;
2576             goto abort;
2577         }
2578         exp = &ctx.ex_addr[base][offset];
2579     } else if (attributes->Mask & VLADDR_UUID) {
2580         if (attributes->Mask & (VLADDR_IPADDR | VLADDR_INDEX)) {
2581             code = VL_BADMASK;
2582             goto abort;
2583         }
2584         if (!ctx.ex_addr[0]) {  /* mh servers probably aren't setup on this vldb */
2585             code = VL_NOENT;
2586             goto abort;
2587         }
2588         code = FindExtentBlock(&ctx, &attributes->uuid, 0, -1, &exp, &base);
2589         if (code)
2590             goto abort;
2591     } else {
2592         code = VL_BADMASK;
2593         goto abort;
2594     }
2595
2596     if (exp == NULL) {
2597         code = VL_NOENT;
2598         goto abort;
2599     }
2600     addrsp->bulkaddrs_val = taddrp =
2601         (afs_uint32 *) malloc(sizeof(afs_int32) * (MAXSERVERID + 1));
2602     nservers = *nentries = addrsp->bulkaddrs_len = 0;
2603     if (!taddrp) {
2604         code = VL_NOMEM;
2605         goto abort;
2606     }
2607     tuuid = exp->ex_hostuuid;
2608     afs_ntohuuid(&tuuid);
2609     if (afs_uuid_is_nil(&tuuid)) {
2610         code = VL_NOENT;
2611         goto abort;
2612     }
2613     if (uuidpo)
2614         *uuidpo = tuuid;
2615     if (uniquifier)
2616         *uniquifier = ntohl(exp->ex_uniquifier);
2617     for (i = 0; i < VL_MAXIPADDRS_PERMH; i++) {
2618         if (exp->ex_addrs[i]) {
2619             taddr = ntohl(exp->ex_addrs[i]);
2620             /* Weed out duplicates */
2621             for (j = 0; j < nservers; j++) {
2622                 if (taddrp[j] == taddr)
2623                     break;
2624             }
2625             if ((j == nservers) && (j <= MAXSERVERID)) {
2626                 taddrp[nservers] = taddr;
2627                 nservers++;
2628             }
2629         }
2630     }
2631     addrsp->bulkaddrs_len = *nentries = nservers;
2632     return (ubik_EndTrans(ctx.trans));
2633
2634 abort:
2635     countAbort(this_op);
2636     ubik_AbortTrans(ctx.trans);
2637     return code;
2638 }
2639
2640 /* ============> End of Exported vldb RPC functions <============= */
2641
2642
2643 /* Routine that copies the given vldb entry to the output buffer, vldbentries. */
2644 static int
2645 put_attributeentry(struct vl_ctx *ctx,
2646                    struct vldbentry **Vldbentry,
2647                    struct vldbentry **VldbentryFirst,
2648                    struct vldbentry **VldbentryLast,
2649                    bulkentries *vldbentries,
2650                    struct nvlentry *entry,
2651                    afs_int32 *nentries,
2652                    afs_int32 *alloccnt)
2653 {
2654     vldbentry *reall;
2655     afs_int32 allo;
2656     int code;
2657
2658     if (*Vldbentry == *VldbentryLast) {
2659         if (smallMem)
2660             return VL_SIZEEXCEEDED;     /* no growing if smallMem defined */
2661
2662         /* Allocate another set of memory; each time allocate twice as
2663          * many blocks as the last time. When we reach VLDBALLOCLIMIT,
2664          * then grow in increments of VLDBALLOCINCR.
2665          */
2666         allo = (*alloccnt > VLDBALLOCLIMIT) ? VLDBALLOCINCR : *alloccnt;
2667         reall =
2668             (vldbentry *) realloc(*VldbentryFirst,
2669                                   (*alloccnt + allo) * sizeof(vldbentry));
2670         if (reall == NULL)
2671             return VL_NOMEM;
2672
2673         *VldbentryFirst = vldbentries->bulkentries_val = reall;
2674         *Vldbentry = *VldbentryFirst + *alloccnt;
2675         *VldbentryLast = *Vldbentry + allo;
2676         *alloccnt += allo;
2677     }
2678
2679     code = vlentry_to_vldbentry(ctx, entry, *Vldbentry);
2680     if (code)
2681         return code;
2682
2683     (*Vldbentry)++;
2684     (*nentries)++;
2685     vldbentries->bulkentries_len++;
2686     return 0;
2687 }
2688
2689 static int
2690 put_nattributeentry(struct vl_ctx *ctx,
2691                     struct nvldbentry **Vldbentry,
2692                     struct nvldbentry **VldbentryFirst,
2693                     struct nvldbentry **VldbentryLast,
2694                     nbulkentries *vldbentries,
2695                     struct nvlentry *entry,
2696                     afs_int32 matchtype,
2697                     afs_int32 matchindex,
2698                     afs_int32 *nentries,
2699                     afs_int32 *alloccnt)
2700 {
2701     nvldbentry *reall;
2702     afs_int32 allo;
2703     int code;
2704
2705     if (*Vldbentry == *VldbentryLast) {
2706         if (smallMem)
2707             return VL_SIZEEXCEEDED;     /* no growing if smallMem defined */
2708
2709         /* Allocate another set of memory; each time allocate twice as
2710          * many blocks as the last time. When we reach VLDBALLOCLIMIT,
2711          * then grow in increments of VLDBALLOCINCR.
2712          */
2713         allo = (*alloccnt > VLDBALLOCLIMIT) ? VLDBALLOCINCR : *alloccnt;
2714         reall =
2715             (nvldbentry *) realloc(*VldbentryFirst,
2716                                    (*alloccnt + allo) * sizeof(nvldbentry));
2717         if (reall == NULL)
2718             return VL_NOMEM;
2719
2720         *VldbentryFirst = vldbentries->nbulkentries_val = reall;
2721         *Vldbentry = *VldbentryFirst + *alloccnt;
2722         *VldbentryLast = *Vldbentry + allo;
2723         *alloccnt += allo;
2724     }
2725     code = vlentry_to_nvldbentry(ctx, entry, *Vldbentry);
2726     if (code)
2727         return code;
2728
2729     (*Vldbentry)->matchindex = (matchtype << 16) + matchindex;
2730     (*Vldbentry)++;
2731     (*nentries)++;
2732     vldbentries->nbulkentries_len++;
2733     return 0;
2734 }
2735
2736
2737 /* Common code to actually remove a vldb entry from the database. */
2738 static int
2739 RemoveEntry(struct vl_ctx *ctx, afs_int32 entryptr,
2740             struct nvlentry *tentry)
2741 {
2742     int code;
2743
2744     if ((code = UnthreadVLentry(ctx, entryptr, tentry)))
2745         return code;
2746     if ((code = FreeBlock(ctx, entryptr)))
2747         return code;
2748     return 0;
2749 }
2750
2751 static void
2752 ReleaseEntry(struct nvlentry *tentry, afs_int32 releasetype)
2753 {
2754     if (releasetype & LOCKREL_TIMESTAMP)
2755         tentry->LockTimestamp = 0;
2756     if (releasetype & LOCKREL_OPCODE)
2757         tentry->flags &= ~VLOP_ALLOPERS;
2758     if (releasetype & LOCKREL_AFSID)
2759         tentry->LockAfsId = 0;
2760 }
2761
2762
2763 /* Verify that the incoming vldb entry is valid; multi type of error codes
2764  * are returned. */
2765 static int
2766 check_vldbentry(struct vldbentry *aentry)
2767 {
2768     afs_int32 i;
2769
2770     if (InvalidVolname(aentry->name))
2771         return VL_BADNAME;
2772     if (aentry->nServers <= 0 || aentry->nServers > OMAXNSERVERS)
2773         return VL_BADSERVER;
2774     for (i = 0; i < aentry->nServers; i++) {
2775 /*      if (aentry->serverNumber[i] < 0 || aentry->serverNumber[i] > MAXSERVERID)
2776             return VL_BADSERVER;        */
2777         if (aentry->serverPartition[i] < 0
2778             || aentry->serverPartition[i] > MAXPARTITIONID)
2779             return VL_BADPARTITION;
2780         if (aentry->serverFlags[i] < 0
2781             || aentry->serverFlags[i] > MAXSERVERFLAG)
2782             return VL_BADSERVERFLAG;
2783     }
2784     return 0;
2785 }
2786
2787 static int
2788 check_nvldbentry(struct nvldbentry *aentry)
2789 {
2790     afs_int32 i;
2791
2792     if (InvalidVolname(aentry->name))
2793         return VL_BADNAME;
2794     if (aentry->nServers <= 0 || aentry->nServers > NMAXNSERVERS)
2795         return VL_BADSERVER;
2796     for (i = 0; i < aentry->nServers; i++) {
2797 /*      if (aentry->serverNumber[i] < 0 || aentry->serverNumber[i] > MAXSERVERID)
2798             return VL_BADSERVER;        */
2799         if (aentry->serverPartition[i] < 0
2800             || aentry->serverPartition[i] > MAXPARTITIONID)
2801             return VL_BADPARTITION;
2802         if (aentry->serverFlags[i] < 0
2803             || aentry->serverFlags[i] > MAXSERVERFLAG)
2804             return VL_BADSERVERFLAG;
2805     }
2806     return 0;
2807 }
2808
2809
2810 /* Convert from the external vldb entry representation to its internal
2811    (more compact) form.  This call should not change the hash chains! */
2812 static int
2813 vldbentry_to_vlentry(struct vl_ctx *ctx,
2814                      struct vldbentry *VldbEntry,
2815                      struct nvlentry *VlEntry)
2816 {
2817     int i, serverindex;
2818
2819     if (strcmp(VlEntry->name, VldbEntry->name))
2820         strncpy(VlEntry->name, VldbEntry->name, sizeof(VlEntry->name));
2821     for (i = 0; i < VldbEntry->nServers; i++) {
2822         serverindex = IpAddrToRelAddr(ctx, VldbEntry->serverNumber[i], 1);
2823         if (serverindex == -1)
2824             return VL_BADSERVER;
2825         VlEntry->serverNumber[i] = serverindex;
2826         VlEntry->serverPartition[i] = VldbEntry->serverPartition[i];
2827         VlEntry->serverFlags[i] = VldbEntry->serverFlags[i];
2828     }
2829     for (; i < OMAXNSERVERS; i++)
2830         VlEntry->serverNumber[i] = VlEntry->serverPartition[i] =
2831             VlEntry->serverFlags[i] = BADSERVERID;
2832     for (i = 0; i < MAXTYPES; i++)
2833         VlEntry->volumeId[i] = VldbEntry->volumeId[i];
2834     VlEntry->cloneId = VldbEntry->cloneId;
2835     VlEntry->flags = VldbEntry->flags;
2836     return 0;
2837 }
2838
2839 static int
2840 nvldbentry_to_vlentry(struct vl_ctx *ctx,
2841                       struct nvldbentry *VldbEntry,
2842                       struct nvlentry *VlEntry)
2843 {
2844     int i, serverindex;
2845
2846     if (strcmp(VlEntry->name, VldbEntry->name))
2847         strncpy(VlEntry->name, VldbEntry->name, sizeof(VlEntry->name));
2848     for (i = 0; i < VldbEntry->nServers; i++) {
2849         serverindex = IpAddrToRelAddr(ctx, VldbEntry->serverNumber[i], 1);
2850         if (serverindex == -1)
2851             return VL_BADSERVER;
2852         VlEntry->serverNumber[i] = serverindex;
2853         VlEntry->serverPartition[i] = VldbEntry->serverPartition[i];
2854         VlEntry->serverFlags[i] = VldbEntry->serverFlags[i];
2855     }
2856     for (; i < NMAXNSERVERS; i++)
2857         VlEntry->serverNumber[i] = VlEntry->serverPartition[i] =
2858             VlEntry->serverFlags[i] = BADSERVERID;
2859     for (i = 0; i < MAXTYPES; i++)
2860         VlEntry->volumeId[i] = VldbEntry->volumeId[i];
2861     VlEntry->cloneId = VldbEntry->cloneId;
2862     VlEntry->flags = VldbEntry->flags;
2863     return 0;
2864 }
2865
2866
2867 /* Update the vldb entry with the new fields as indicated by the value of
2868  * the Mask entry in the updateentry structure. All necessary validation
2869  * checks are performed.
2870  */
2871 static int
2872 get_vldbupdateentry(struct vl_ctx *ctx,
2873                     afs_int32 blockindex,
2874                     struct VldbUpdateEntry *updateentry,
2875                     struct nvlentry *VlEntry)
2876 {
2877     int i, j, code, serverindex;
2878     afs_uint32 checkids[MAXTYPES];
2879
2880     /* check if any specified new IDs are already present in the db. Do
2881      * this check before doing anything else, so we don't get a half-
2882      * updated entry. */
2883     memset(&checkids, 0, sizeof(checkids));
2884     if (updateentry->Mask & VLUPDATE_RWID) {
2885         checkids[RWVOL] = updateentry->spares3; /* rw id */
2886     }
2887     if (updateentry->Mask & VLUPDATE_READONLYID) {
2888         checkids[ROVOL] = updateentry->ReadOnlyId;
2889     }
2890     if (updateentry->Mask & VLUPDATE_BACKUPID) {
2891         checkids[BACKVOL] = updateentry->BackupId;
2892     }
2893
2894     if (EntryIDExists(ctx, checkids, MAXTYPES, &code)) {
2895         return VL_IDEXIST;
2896     } else if (code) {
2897         return code;
2898     }
2899
2900     if (updateentry->Mask & VLUPDATE_VOLUMENAME) {
2901         struct nvlentry tentry;
2902
2903         if (InvalidVolname(updateentry->name))
2904             return VL_BADNAME;
2905
2906         if (FindByName(ctx, updateentry->name, &tentry, &code)) {
2907             return VL_NAMEEXIST;
2908         } else if (code) {
2909             return code;
2910         }
2911
2912         if ((code = UnhashVolname(ctx, blockindex, VlEntry)))
2913             return code;
2914         strncpy(VlEntry->name, updateentry->name, sizeof(VlEntry->name));
2915         HashVolname(ctx, blockindex, VlEntry);
2916     }
2917
2918     if (updateentry->Mask & VLUPDATE_VOLNAMEHASH) {
2919         if ((code = UnhashVolname(ctx, blockindex, VlEntry))) {
2920             if (code != VL_NOENT)
2921                 return code;
2922         }
2923         HashVolname(ctx, blockindex, VlEntry);
2924     }
2925
2926     if (updateentry->Mask & VLUPDATE_FLAGS) {
2927         VlEntry->flags = updateentry->flags;
2928     }
2929     if (updateentry->Mask & VLUPDATE_CLONEID) {
2930         VlEntry->cloneId = updateentry->cloneId;
2931     }
2932     if (updateentry->Mask & VLUPDATE_RWID) {
2933         if ((code = UnhashVolid(ctx, RWVOL, blockindex, VlEntry))) {
2934             if (code != VL_NOENT)
2935                 return code;
2936         }
2937         VlEntry->volumeId[RWVOL] = updateentry->spares3;        /* rw id */
2938         if ((code = HashVolid(ctx, RWVOL, blockindex, VlEntry)))
2939             return code;
2940     }
2941     if (updateentry->Mask & VLUPDATE_READONLYID) {
2942         if ((code = UnhashVolid(ctx, ROVOL, blockindex, VlEntry))) {
2943             if (code != VL_NOENT)
2944                 return code;
2945         }
2946         VlEntry->volumeId[ROVOL] = updateentry->ReadOnlyId;
2947         if ((code = HashVolid(ctx, ROVOL, blockindex, VlEntry)))
2948             return code;
2949     }
2950     if (updateentry->Mask & VLUPDATE_BACKUPID) {
2951         if ((code = UnhashVolid(ctx, BACKVOL, blockindex, VlEntry))) {
2952             if (code != VL_NOENT)
2953                 return code;
2954         }
2955         VlEntry->volumeId[BACKVOL] = updateentry->BackupId;
2956         if ((code = HashVolid(ctx, BACKVOL, blockindex, VlEntry)))
2957             return code;
2958     }
2959     if (updateentry->Mask & VLUPDATE_REPSITES) {
2960         if (updateentry->nModifiedRepsites <= 0
2961             || updateentry->nModifiedRepsites > OMAXNSERVERS)
2962             return VL_BADSERVER;
2963         for (i = 0; i < updateentry->nModifiedRepsites; i++) {
2964 /*          if (updateentry->RepsitesTargetServer[i] < 0 || updateentry->RepsitesTargetServer[i] > MAXSERVERID)
2965                 return VL_BADSERVER;    */
2966             if (updateentry->RepsitesTargetPart[i] < 0
2967                 || updateentry->RepsitesTargetPart[i] > MAXPARTITIONID)
2968                 return VL_BADPARTITION;
2969             if (updateentry->RepsitesMask[i] & VLUPDATE_REPS_DELETE) {
2970                 if ((j =
2971                      repsite_exists(VlEntry,
2972                                     IpAddrToRelAddr(ctx, updateentry->
2973                                                     RepsitesTargetServer[i],
2974                                                     1),
2975                                     updateentry->RepsitesTargetPart[i])) !=
2976                     -1)
2977                     repsite_compress(VlEntry, j);
2978                 else
2979                     return VL_NOREPSERVER;
2980             }
2981             if (updateentry->RepsitesMask[i] & VLUPDATE_REPS_ADD) {
2982 /*              if (updateentry->RepsitesNewServer[i] < 0 || updateentry->RepsitesNewServer[i] > MAXSERVERID)
2983                     return VL_BADSERVER;                */
2984                 if (updateentry->RepsitesNewPart[i] < 0
2985                     || updateentry->RepsitesNewPart[i] > MAXPARTITIONID)
2986                     return VL_BADPARTITION;
2987                 if (repsite_exists
2988                     (VlEntry,
2989                      IpAddrToRelAddr(ctx, updateentry->RepsitesNewServer[i], 1),
2990                      updateentry->RepsitesNewPart[i]) != -1)
2991                     return VL_DUPREPSERVER;
2992                 for (j = 0;
2993                      VlEntry->serverNumber[j] != BADSERVERID
2994                      && j < OMAXNSERVERS; j++);
2995                 if (j >= OMAXNSERVERS)
2996                     return VL_REPSFULL;
2997                 if ((serverindex =
2998                      IpAddrToRelAddr(ctx, updateentry->RepsitesNewServer[i],
2999                                      1)) == -1)
3000                     return VL_BADSERVER;
3001                 VlEntry->serverNumber[j] = serverindex;
3002                 VlEntry->serverPartition[j] = updateentry->RepsitesNewPart[i];
3003                 if (updateentry->RepsitesNewFlags[i] < 0
3004                     || updateentry->RepsitesNewFlags[i] > MAXSERVERFLAG)
3005                     return VL_BADSERVERFLAG;
3006                 VlEntry->serverFlags[j] = updateentry->RepsitesNewFlags[i];
3007             }
3008             if (updateentry->RepsitesMask[i] & VLUPDATE_REPS_MODSERV) {
3009 /*n             if (updateentry->RepsitesNewServer[i] < 0 || updateentry->RepsitesNewServer[i] > MAXSERVERID)
3010                     return VL_BADSERVER;            */
3011                 if ((j =
3012                      repsite_exists(VlEntry,
3013                                     IpAddrToRelAddr(ctx, updateentry->
3014                                                     RepsitesTargetServer[i],
3015                                                     1),
3016                                     updateentry->RepsitesTargetPart[i])) !=
3017                     -1) {
3018                     VlEntry->serverNumber[j] =
3019                         IpAddrToRelAddr(ctx, updateentry->RepsitesNewServer[i],
3020                                         1);
3021                 } else
3022                     return VL_NOREPSERVER;
3023             }
3024             if (updateentry->RepsitesMask[i] & VLUPDATE_REPS_MODPART) {
3025                 if (updateentry->RepsitesNewPart[i] < 0
3026                     || updateentry->RepsitesNewPart[i] > MAXPARTITIONID)
3027                     return VL_BADPARTITION;
3028                 if ((j =
3029                      repsite_exists(VlEntry,
3030                                     IpAddrToRelAddr(ctx, updateentry->
3031                                                     RepsitesTargetServer[i],
3032                                                     1),
3033                                     updateentry->RepsitesTargetPart[i])) !=
3034                     -1)
3035                     VlEntry->serverPartition[j] =
3036                         updateentry->RepsitesNewPart[i];
3037                 else
3038                     return VL_NOREPSERVER;
3039             }
3040             if (updateentry->RepsitesMask[i] & VLUPDATE_REPS_MODFLAG) {
3041                 if ((j =
3042                      repsite_exists(VlEntry,
3043                                     IpAddrToRelAddr(ctx, updateentry->
3044                                                     RepsitesTargetServer[i],
3045                                                     1),
3046                                     updateentry->RepsitesTargetPart[i])) !=
3047                     -1) {
3048                     if (updateentry->RepsitesNewFlags[i] < 0
3049                         || updateentry->RepsitesNewFlags[i] > MAXSERVERFLAG)
3050                         return VL_BADSERVERFLAG;
3051                     VlEntry->serverFlags[j] =
3052                         updateentry->RepsitesNewFlags[i];
3053                 } else
3054                     return VL_NOREPSERVER;
3055             }
3056         }
3057     }
3058     return 0;
3059 }
3060
3061
3062 /* Check if the specified [server,partition] entry is found in the vldb
3063  * entry's repsite table; it's offset in the table is returned, if it's
3064  * present there. */
3065 static int
3066 repsite_exists(struct nvlentry *VlEntry, int server, int partition)
3067 {
3068     int i;
3069
3070     for (i = 0; VlEntry->serverNumber[i] != BADSERVERID && i < OMAXNSERVERS;
3071          i++) {
3072         if ((VlEntry->serverNumber[i] == server)
3073             && (VlEntry->serverPartition[i] == partition))
3074             return i;
3075     }
3076     return -1;
3077 }
3078
3079
3080
3081 /* Repsite table compression: used when deleting a repsite entry so that
3082  * all active repsite entries are on the top of the table. */
3083 static void
3084 repsite_compress(struct nvlentry *VlEntry, int offset)
3085 {
3086     int repsite_offset = offset;
3087     for (;
3088          VlEntry->serverNumber[repsite_offset] != BADSERVERID
3089          && repsite_offset < OMAXNSERVERS - 1; repsite_offset++) {
3090         VlEntry->serverNumber[repsite_offset] =
3091             VlEntry->serverNumber[repsite_offset + 1];
3092         VlEntry->serverPartition[repsite_offset] =
3093             VlEntry->serverPartition[repsite_offset + 1];
3094         VlEntry->serverFlags[repsite_offset] =
3095             VlEntry->serverFlags[repsite_offset + 1];
3096     }
3097     VlEntry->serverNumber[repsite_offset] = BADSERVERID;
3098 }
3099
3100
3101 /* Convert from the internal (compacted) vldb entry to the external
3102  * representation used by the interface. */
3103 static int
3104 vlentry_to_vldbentry(struct vl_ctx *ctx, struct nvlentry *VlEntry,
3105                      struct vldbentry *VldbEntry)
3106 {
3107     int i, j, code;
3108     struct extentaddr *exp;
3109
3110     memset(VldbEntry, 0, sizeof(struct vldbentry));
3111     strncpy(VldbEntry->name, VlEntry->name, sizeof(VldbEntry->name));
3112     for (i = 0; i < OMAXNSERVERS; i++) {
3113         if (VlEntry->serverNumber[i] == BADSERVERID)
3114             break;
3115         j = VlEntry->serverNumber[i];
3116         code = multiHomedExtent(ctx, VlEntry->serverNumber[i], &exp);
3117         if (code)
3118             return code;
3119         if (exp) {
3120             /* For now return the first ip address back */
3121             for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
3122                 if (exp->ex_addrs[j]) {
3123                     VldbEntry->serverNumber[i] = ntohl(exp->ex_addrs[j]);
3124                     break;
3125                 }
3126             }
3127         } else
3128             VldbEntry->serverNumber[i] =
3129                 ctx->hostaddress[VlEntry->serverNumber[i]];
3130         VldbEntry->serverPartition[i] = VlEntry->serverPartition[i];
3131         VldbEntry->serverFlags[i] = VlEntry->serverFlags[i];
3132     }
3133     VldbEntry->nServers = i;
3134     for (i = 0; i < MAXTYPES; i++)
3135         VldbEntry->volumeId[i] = VlEntry->volumeId[i];
3136     VldbEntry->cloneId = VlEntry->cloneId;
3137     VldbEntry->flags = VlEntry->flags;
3138
3139     return 0;
3140 }
3141
3142
3143 /* Convert from the internal (compacted) vldb entry to the external
3144  * representation used by the interface. */
3145 static int
3146 vlentry_to_nvldbentry(struct vl_ctx *ctx, struct nvlentry *VlEntry,
3147                       struct nvldbentry *VldbEntry)
3148 {
3149     int i, j, code;
3150     struct extentaddr *exp;
3151
3152     memset(VldbEntry, 0, sizeof(struct nvldbentry));
3153     strncpy(VldbEntry->name, VlEntry->name, sizeof(VldbEntry->name));
3154     for (i = 0; i < NMAXNSERVERS; i++) {
3155         if (VlEntry->serverNumber[i] == BADSERVERID)
3156             break;
3157         code = multiHomedExtent(ctx, VlEntry->serverNumber[i], &exp);
3158         if (code)
3159             return code;
3160
3161         if (exp) {
3162             /* For now return the first ip address back */
3163             for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
3164                 if (exp->ex_addrs[j]) {
3165                     VldbEntry->serverNumber[i] = ntohl(exp->ex_addrs[j]);
3166                     break;
3167                 }
3168             }
3169         } else
3170             VldbEntry->serverNumber[i] =
3171                 ctx->hostaddress[VlEntry->serverNumber[i]];
3172         VldbEntry->serverPartition[i] = VlEntry->serverPartition[i];
3173         VldbEntry->serverFlags[i] = VlEntry->serverFlags[i];
3174     }
3175     VldbEntry->nServers = i;
3176     for (i = 0; i < MAXTYPES; i++)
3177         VldbEntry->volumeId[i] = VlEntry->volumeId[i];
3178     VldbEntry->cloneId = VlEntry->cloneId;
3179     VldbEntry->flags = VlEntry->flags;
3180
3181     return 0;
3182 }
3183
3184 static int
3185 vlentry_to_uvldbentry(struct vl_ctx *ctx, struct nvlentry *VlEntry,
3186                       struct uvldbentry *VldbEntry)
3187 {
3188     int i, code;
3189     struct extentaddr *exp;
3190
3191     memset(VldbEntry, 0, sizeof(struct uvldbentry));
3192     strncpy(VldbEntry->name, VlEntry->name, sizeof(VldbEntry->name));
3193     for (i = 0; i < NMAXNSERVERS; i++) {
3194         if (VlEntry->serverNumber[i] == BADSERVERID)
3195             break;
3196         VldbEntry->serverFlags[i] = VlEntry->serverFlags[i];
3197         VldbEntry->serverUnique[i] = 0;
3198         code = multiHomedExtent(ctx, VlEntry->serverNumber[i], &exp);
3199         if (code)
3200             return code;
3201
3202         if (exp) {
3203             afsUUID tuuid;
3204
3205             tuuid = exp->ex_hostuuid;
3206             afs_ntohuuid(&tuuid);
3207             VldbEntry->serverFlags[i] |= VLSF_UUID;
3208             VldbEntry->serverNumber[i] = tuuid;
3209             VldbEntry->serverUnique[i] = ntohl(exp->ex_uniquifier);
3210         } else {
3211             VldbEntry->serverNumber[i].time_low =
3212                 ctx->hostaddress[VlEntry->serverNumber[i]];
3213         }
3214         VldbEntry->serverPartition[i] = VlEntry->serverPartition[i];
3215
3216     }
3217     VldbEntry->nServers = i;
3218     for (i = 0; i < MAXTYPES; i++)
3219         VldbEntry->volumeId[i] = VlEntry->volumeId[i];
3220     VldbEntry->cloneId = VlEntry->cloneId;
3221     VldbEntry->flags = VlEntry->flags;
3222
3223     return 0;
3224 }
3225
3226 #define LEGALCHARS ".ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
3227
3228
3229 /* Verify that the volname is a valid volume name. */
3230 static int
3231 InvalidVolname(char *volname)
3232 {
3233     char *map;
3234     int slen;
3235
3236     map = LEGALCHARS;
3237     slen = strlen(volname);
3238     if (slen >= VL_MAXNAMELEN)
3239         return 1;
3240     return (slen != strspn(volname, map));
3241 }
3242
3243
3244 /* Verify that the given volume type is valid. */
3245 static int
3246 InvalidVoltype(afs_int32 voltype)
3247 {
3248     if (voltype != RWVOL && voltype != ROVOL && voltype != BACKVOL)
3249         return 1;
3250     return 0;
3251 }
3252
3253
3254 static int
3255 InvalidOperation(afs_int32 voloper)
3256 {
3257     if (voloper != VLOP_MOVE && voloper != VLOP_RELEASE
3258         && voloper != VLOP_BACKUP && voloper != VLOP_DELETE
3259         && voloper != VLOP_DUMP)
3260         return 1;
3261     return 0;
3262 }
3263
3264 static int
3265 InvalidReleasetype(afs_int32 releasetype)
3266 {
3267     if ((releasetype & LOCKREL_TIMESTAMP) || (releasetype & LOCKREL_OPCODE)
3268         || (releasetype & LOCKREL_AFSID))
3269         return 0;
3270     return 1;
3271 }
3272
3273 static int
3274 IpAddrToRelAddr(struct vl_ctx *ctx, afs_uint32 ipaddr, int create)
3275 {
3276     int i, j;
3277     afs_int32 code;
3278     struct extentaddr *exp;
3279
3280     for (i = 0; i <= MAXSERVERID; i++) {
3281         if (ctx->hostaddress[i] == ipaddr)
3282             return i;
3283         code = multiHomedExtent(ctx, i, &exp);
3284         if (code)
3285             return -1;
3286         if (exp) {
3287             for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
3288                 if (exp->ex_addrs[j] && (ntohl(exp->ex_addrs[j]) == ipaddr)) {
3289                     return i;
3290                 }
3291             }
3292         }
3293     }
3294
3295     /* allocate the new server a server id pronto */
3296     if (create) {
3297         for (i = 0; i <= MAXSERVERID; i++) {
3298             if (ctx->cheader->IpMappedAddr[i] == 0) {
3299                 ctx->cheader->IpMappedAddr[i] = htonl(ipaddr);
3300                 code =
3301                     vlwrite(ctx->trans,
3302                             DOFFSET(0, ctx->cheader, &ctx->cheader->IpMappedAddr[i]),
3303                             (char *)&ctx->cheader->IpMappedAddr[i],
3304                             sizeof(afs_int32));
3305                 ctx->hostaddress[i] = ipaddr;
3306                 if (code)
3307                     return -1;
3308                 return i;
3309             }
3310         }
3311     }
3312     return -1;
3313 }
3314
3315 static int
3316 ChangeIPAddr(struct vl_ctx *ctx, afs_uint32 ipaddr1, afs_uint32 ipaddr2)
3317 {
3318     int i, j;
3319     afs_int32 code;
3320     struct extentaddr *exp = NULL;
3321     int base;
3322     int mhidx;
3323     afsUUID tuuid;
3324     afs_int32 blockindex, count;
3325     int pollcount = 0;
3326     struct nvlentry tentry;
3327     int ipaddr1_id = -1, ipaddr2_id = -1;
3328
3329     /* Don't let addr change to 256.*.*.* : Causes internal error below */
3330     if ((ipaddr2 & 0xff000000) == 0xff000000)
3331         return (VL_BADSERVER);
3332
3333     /* If we are removing an address, ip1 will be -1 and ip2 will be
3334      * the original address. This prevents an older revision vlserver
3335      * from removing the IP address (won't find server 0xfffffff in
3336      * the VLDB). An older revision vlserver does not have the check
3337      * to see if any volumes exist on the server being removed.
3338      */
3339     if (ipaddr1 == 0xffffffff) {
3340         ipaddr1 = ipaddr2;
3341         ipaddr2 = 0;
3342     }
3343
3344     for (i = 0; i <= MAXSERVERID; i++) {
3345         code = multiHomedExtentBase(ctx, i, &exp, &base);
3346         if (code)
3347             return code;
3348
3349         if (exp) {
3350             for (mhidx = 0; mhidx < VL_MAXIPADDRS_PERMH; mhidx++) {
3351                 if (!exp->ex_addrs[mhidx])
3352                     continue;
3353                 if (ntohl(exp->ex_addrs[mhidx]) == ipaddr1) {
3354                     ipaddr1_id = i;
3355                 }
3356                 if (ipaddr2 != 0 && ntohl(exp->ex_addrs[mhidx]) == ipaddr2) {
3357                     ipaddr2_id = i;
3358                 }
3359             }
3360         } else {
3361             if (ctx->hostaddress[i] == ipaddr1) {
3362                 exp = NULL;
3363                 ipaddr1_id = i;
3364             }
3365             if (ipaddr2 != 0 && ctx->hostaddress[i] == ipaddr2) {
3366                 ipaddr2_id = i;
3367             }
3368         }
3369
3370         if (ipaddr1_id >= 0 && (ipaddr2 == 0 || ipaddr2_id >= 0)) {
3371             /* we've either found both IPs already in the VLDB, or we found
3372              * ipaddr1, and we're not going to find ipaddr2 because it's 0 */
3373             break;
3374         }
3375     }
3376
3377     if (ipaddr1_id < 0) {
3378         return VL_NOENT;        /* not found */
3379     }
3380
3381     if (ipaddr2_id >= 0 && ipaddr2_id != ipaddr1_id) {
3382         char buf1[16], buf2[16];
3383         VLog(0, ("Cannot change IP address from %s to %s because the latter "
3384                  "is in use by server id %d\n",
3385                  afs_inet_ntoa_r(htonl(ipaddr1), buf1),
3386                  afs_inet_ntoa_r(htonl(ipaddr2), buf2),
3387                  ipaddr2_id));
3388         return VL_MULTIPADDR;
3389     }
3390
3391     /* If we are removing a server entry, a volume cannot
3392      * exist on the server. If one does, don't remove the
3393      * server entry: return error "volume entry exists".
3394      */
3395     if (ipaddr2 == 0) {
3396         for (blockindex = NextEntry(ctx, 0, &tentry, &count); blockindex;
3397              blockindex = NextEntry(ctx, blockindex, &tentry, &count)) {
3398             if (++pollcount > 50) {
3399 #ifndef AFS_PTHREAD_ENV
3400                 IOMGR_Poll();
3401 #endif
3402                 pollcount = 0;
3403             }
3404             for (j = 0; j < NMAXNSERVERS; j++) {
3405                 if (tentry.serverNumber[j] == BADSERVERID)
3406                     break;
3407                 if (tentry.serverNumber[j] == ipaddr1_id) {
3408                     return VL_IDEXIST;
3409                 }
3410             }
3411         }
3412     }
3413
3414     /* Log a message saying we are changing/removing an IP address */
3415     VLog(0,
3416          ("The following IP address is being %s:\n",
3417           (ipaddr2 ? "changed" : "removed")));
3418     VLog(0, ("      entry %d: ", i));
3419     if (exp) {
3420         VLog(0, ("["));
3421         for (mhidx = 0; mhidx < VL_MAXIPADDRS_PERMH; mhidx++) {
3422             if (!exp->ex_addrs[mhidx])
3423                 continue;
3424             if (mhidx > 0)
3425                 VLog(0, (" "));
3426             PADDR(ntohl(exp->ex_addrs[mhidx]));
3427         }
3428         VLog(0, ("]"));
3429     } else {
3430         PADDR(ipaddr1);
3431     }
3432     if (ipaddr2) {
3433         VLog(0, (" -> "));
3434         PADDR(ipaddr2);
3435     }
3436     VLog(0, ("\n"));
3437
3438     /* Change the registered uuuid addresses */
3439     if (exp) {
3440         memset(&tuuid, 0, sizeof(afsUUID));
3441         afs_htonuuid(&tuuid);
3442         exp->ex_hostuuid = tuuid;
3443         code =
3444             vlwrite(ctx->trans,
3445                     DOFFSET(ntohl(ctx->ex_addr[0]->ex_contaddrs[base]),
3446                             (char *)ctx->ex_addr[base], (char *)exp),
3447                     (char *)&tuuid, sizeof(tuuid));
3448         if (code)
3449             return VL_IO;
3450     }
3451
3452     /* Now change the host address entry */
3453     ctx->cheader->IpMappedAddr[ipaddr1_id] = htonl(ipaddr2);
3454     code =
3455         vlwrite(ctx->trans, DOFFSET(0, ctx->cheader, &ctx->cheader->IpMappedAddr[ipaddr1_id]),
3456                 (char *)
3457                 &ctx->cheader->IpMappedAddr[ipaddr1_id], sizeof(afs_int32));
3458     ctx->hostaddress[ipaddr1_id] = ipaddr2;
3459     if (code)
3460         return VL_IO;
3461
3462     return 0;
3463 }
3464
3465 /* see if the vlserver is back yet */
3466 afs_int32
3467 SVL_ProbeServer(struct rx_call *rxcall)
3468 {
3469     return 0;
3470 }