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