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