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