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