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