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