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