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