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