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