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