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