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