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