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