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