libadmin: Don't overflow volume name
[openafs.git] / src / libadmin / vos / vsprocs.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 /*
11  * This file is a reimplementation of volser/vsproc.s.  Every attempt
12  * has been made to keep it as similar as possible to aid comprehension
13  * of the code.  For most functions, two parameters have been added
14  * the cell handle, and a status variable.  For those functions that
15  * require one, a server handle may also be added.
16  *
17  * Other changes were made to provide thread safe functions and
18  * eliminate the practice of reporting errors to STDOUT.
19  */
20
21 #include <afsconfig.h>
22 #include <afs/param.h>
23
24 #include <roken.h>
25
26 #include <afs/afs_AdminErrors.h>
27
28 #include "vsprocs.h"
29 #include "vosutils.h"
30 #include "lockprocs.h"
31 #include "../adminutil/afs_AdminInternal.h"
32 #include "afs_vosAdmin.h"
33
34 static afs_int32 GroupEntries(struct rx_connection *server, volintInfo * pntr, afs_int32 count,
35              struct qHead *myQueue, afs_int32 apart);
36
37 struct release {
38     afs_int32 time;
39     afs_int32 vldbEntryIndex;
40 };
41
42 static struct rx_connection *
43 UV_Bind(afs_cell_handle_p cellHandle, afs_int32 aserver, afs_int32 port)
44 {
45     return rx_GetCachedConnection(htonl(aserver), htons(port), VOLSERVICE_ID,
46                                   cellHandle->tokens->afs_sc[cellHandle->
47                                                              tokens->
48                                                              sc_index],
49                                   cellHandle->tokens->sc_index);
50 }
51
52
53 /* if <okvol> is allright(indicated by beibg able to
54  * start a transaction, delete the <delvol> */
55 static afs_int32
56 CheckAndDeleteVolume(struct rx_connection *aconn, afs_int32 apart,
57                      afs_uint32 okvol, afs_uint32 delvol)
58 {
59     afs_int32 error, code, tid, rcode;
60
61     error = 0;
62
63     if (okvol == 0) {
64         code = AFSVolTransCreate(aconn, delvol, apart, ITOffline, &tid);
65         if (!error && code)
66             error = code;
67         code = AFSVolDeleteVolume(aconn, tid);
68         if (!error && code)
69             error = code;
70         code = AFSVolEndTrans(aconn, tid, &rcode);
71         if (!code)
72             code = rcode;
73         if (!error && code)
74             error = code;
75         return error;
76     } else {
77         code = AFSVolTransCreate(aconn, okvol, apart, ITOffline, &tid);
78         if (!code) {
79             code = AFSVolEndTrans(aconn, tid, &rcode);
80             if (!code)
81                 code = rcode;
82             if (!error && code)
83                 error = code;
84             code = AFSVolTransCreate(aconn, delvol, apart, ITOffline, &tid);
85             if (!error && code)
86                 error = code;
87             code = AFSVolDeleteVolume(aconn, tid);
88             if (!error && code)
89                 error = code;
90             code = AFSVolEndTrans(aconn, tid, &rcode);
91             if (!code)
92                 code = rcode;
93             if (!error && code)
94                 error = code;
95         } else
96             error = code;
97         return error;
98     }
99 }
100
101 /* forcibly remove a volume.  Very dangerous call */
102 int
103 UV_NukeVolume(afs_cell_handle_p cellHandle, struct rx_connection *server,
104               unsigned int partition, afs_uint32 volumeId, afs_status_p st)
105 {
106     int rc = 0;
107     afs_status_t tst = 0;
108
109     tst = AFSVolNukeVolume(server, partition, volumeId);
110
111     if (!tst) {
112         rc = 1;
113     }
114
115     if (st != NULL) {
116         *st = tst;
117     }
118     return rc;
119 }
120
121 /* create a volume, given a server, partition number, volume name --> sends
122 * back new vol id in <anewid>*/
123 int
124 UV_CreateVolume(afs_cell_handle_p cellHandle, struct rx_connection *server,
125                 unsigned int partition, char *volumeName,
126                 unsigned int quota, afs_uint32 *volumeId, afs_status_p st)
127 {
128     int rc = 0;
129     afs_status_t tst = 0;
130     afs_int32 tid = 0;
131     afs_int32 rcode;
132     struct nvldbentry entry;
133     struct volintInfo tstatus;
134
135     memset(&tstatus, 0, sizeof(tstatus));
136     tstatus.dayUse = -1;
137     tstatus.maxquota = quota;
138
139     /* next the next 3 available ids from the VLDB */
140     tst = ubik_VL_GetNewVolumeId(cellHandle->vos, 0, 3, volumeId);
141     if (tst) {
142         goto fail_UV_CreateVolume;
143     }
144
145     tst =
146         AFSVolCreateVolume(server, partition, volumeName, volser_RW, 0,
147                            volumeId, &tid);
148     if (tst) {
149         goto fail_UV_CreateVolume;
150     }
151
152     AFSVolSetInfo(server, tid, &tstatus);
153
154     tst = AFSVolSetFlags(server, tid, 0);
155     if (tst) {
156         goto fail_UV_CreateVolume;
157     }
158
159     /* set up the vldb entry for this volume */
160     strncpy(entry.name, volumeName, VOLSER_OLDMAXVOLNAME);
161     entry.nServers = 1;
162     entry.serverNumber[0] = ntohl(rx_HostOf(rx_PeerOf(server)));
163     entry.serverPartition[0] = partition;
164     entry.flags = RW_EXISTS;
165     entry.serverFlags[0] = ITSRWVOL;
166     entry.volumeId[RWVOL] = *volumeId;
167     entry.volumeId[ROVOL] = *volumeId + 1;
168     entry.volumeId[BACKVOL] = *volumeId + 2;
169     entry.cloneId = 0;
170
171     if (!VLDB_CreateEntry(cellHandle, &entry, &tst)) {
172         AFSVolDeleteVolume(server, tid);
173         goto fail_UV_CreateVolume;
174     }
175
176     tst = AFSVolEndTrans(server, tid, &rcode);
177     tid = 0;
178     if (tst) {
179         goto fail_UV_CreateVolume;
180     }
181     rc = 1;
182
183   fail_UV_CreateVolume:
184
185     if (tid != 0) {
186         AFSVolEndTrans(server, tid, &rcode);
187     }
188
189     if (st != NULL) {
190         *st = tst;
191     }
192     return rc;
193 }
194
195
196 /* Delete the volume <volid>on <aserver> <apart>
197  * the physical entry gets removed from the vldb only if the ref count 
198  * becomes zero
199  */
200 int
201 UV_DeleteVolume(afs_cell_handle_p cellHandle, struct rx_connection *server,
202                 unsigned int partition, afs_uint32 volumeId,
203                 afs_status_p st)
204 {
205     int rc = 0;
206     afs_status_t tst = 0;
207     afs_status_t temp = 0;
208     int serverAddr = ntohl(rx_HostOf(rx_PeerOf(server)));
209
210     afs_int32 ttid = 0;
211     afs_int32 rcode;
212     struct nvldbentry entry;
213     int islocked = 0;
214     afs_int32 avoltype = -1, vtype;
215     int notondisk = 0, notinvldb = 0;
216
217     /* Find and read the VLDB entry for this volume */
218     tst =
219         ubik_VL_SetLock(cellHandle->vos, 0, volumeId, avoltype,
220                   VLOP_DELETE);
221     if (tst) {
222         if (tst != VL_NOENT) {
223             goto fail_UV_DeleteVolume;
224         }
225         notinvldb = 1;
226     } else {
227         islocked = 1;
228
229         if (!aVLDB_GetEntryByID(cellHandle, volumeId, avoltype, &entry, &tst)) {
230             goto fail_UV_DeleteVolume;
231         }
232
233     }
234
235     /* Whether volume is in the VLDB or not. Delete the volume on disk */
236     tst = AFSVolTransCreate(server, volumeId, partition, ITOffline, &ttid);
237     if (tst) {
238         if (tst == VNOVOL) {
239             notondisk = 1;
240         } else {
241             goto fail_UV_DeleteVolume;
242         }
243     } else {
244         tst = AFSVolDeleteVolume(server, ttid);
245         if (tst) {
246             goto fail_UV_DeleteVolume;
247         }
248         tst = AFSVolEndTrans(server, ttid, &rcode);
249         tst = (tst ? tst : rcode);
250         ttid = 0;
251         if (tst) {
252             goto fail_UV_DeleteVolume;
253         }
254     }
255
256     if (notinvldb) {
257         goto fail_UV_DeleteVolume;
258     }
259
260     if (volumeId == entry.volumeId[BACKVOL]) {
261         if (!(entry.flags & BACK_EXISTS)
262             || !Lp_Match(cellHandle, &entry, serverAddr, partition, &tst)) {
263             notinvldb = 2;
264             goto fail_UV_DeleteVolume;
265         }
266
267         entry.flags &= ~BACK_EXISTS;
268         vtype = BACKVOL;
269     }
270
271     else if (volumeId == entry.volumeId[ROVOL]) {
272         if (!Lp_ROMatch(cellHandle, &entry, serverAddr, partition, &tst)) {
273             notinvldb = 2;
274             goto fail_UV_DeleteVolume;
275         }
276
277         Lp_SetROValue(cellHandle, &entry, serverAddr, partition, 0, 0);
278         entry.nServers--;
279         if (!Lp_ROMatch(cellHandle, &entry, 0, 0, &tst)) {
280             entry.flags &= ~RO_EXISTS;
281         }
282         vtype = ROVOL;
283     }
284
285     else if (volumeId == entry.volumeId[RWVOL]) {
286         if (!(entry.flags & RW_EXISTS)
287             || !Lp_Match(cellHandle, &entry, serverAddr, partition, &tst)) {
288             notinvldb = 2;
289             goto fail_UV_DeleteVolume;
290         }
291
292         /* Delete backup if it exists */
293         tst =
294             AFSVolTransCreate(server, entry.volumeId[BACKVOL], partition,
295                               ITOffline, &ttid);
296         if (!tst) {
297             tst = AFSVolDeleteVolume(server, ttid);
298             if (tst) {
299                 goto fail_UV_DeleteVolume;
300             }
301             tst = AFSVolEndTrans(server, ttid, &rcode);
302             ttid = 0;
303             tst = (tst ? tst : rcode);
304             if (tst) {
305                 goto fail_UV_DeleteVolume;
306             }
307         }
308
309         Lp_SetRWValue(cellHandle, &entry, serverAddr, partition, 0L, 0L);
310         entry.nServers--;
311         entry.flags &= ~(BACK_EXISTS | RW_EXISTS);
312         vtype = RWVOL;
313
314     }
315
316     else {
317         notinvldb = 2;          /* Not found on this server and partition */
318         goto fail_UV_DeleteVolume;
319     }
320
321     if ((entry.nServers <= 0) || !(entry.flags & (RO_EXISTS | RW_EXISTS))) {
322         tst = ubik_VL_DeleteEntry(cellHandle->vos, 0, volumeId, vtype);
323         if (tst) {
324             goto fail_UV_DeleteVolume;
325         }
326     } else {
327         if (!VLDB_ReplaceEntry
328             (cellHandle, volumeId, vtype, &entry,
329              (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP), &tst)) {
330             goto fail_UV_DeleteVolume;
331         }
332     }
333     islocked = 0;
334     rc = 1;
335
336   fail_UV_DeleteVolume:
337
338     if (notondisk && notinvldb) {
339         if (!tst)
340             tst = ADMVOSVOLUMENOEXIST;
341     }
342
343     if (ttid) {
344         temp = AFSVolEndTrans(server, ttid, &rcode);
345         temp = (temp ? temp : rcode);
346         if (temp) {
347             if (!tst)
348                 tst = temp;
349         }
350     }
351
352     if (islocked) {
353         temp =
354             ubik_VL_ReleaseLock(cellHandle->vos, 0, volumeId, -1,
355                       (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP));
356         if (temp) {
357             if (!tst)
358                 tst = temp;
359         }
360     }
361
362     if (st != NULL) {
363         *st = tst;
364     }
365     return rc;
366 }
367
368 #define ONERR(ec, es, ep) if (ec) { fprintf(STDERR, (es), (ep)); error = (ec); goto mfail; }
369
370 /* Move volume <afromvol> on <afromserver> <afrompart> to <atoserver>
371  * <atopart>. The operation is almost idempotent 
372  */
373
374 int
375 UV_MoveVolume(afs_cell_handle_p cellHandle, afs_uint32 afromvol,
376               afs_int32 afromserver, afs_int32 afrompart, afs_int32 atoserver,
377               afs_int32 atopart, afs_status_p st)
378 {
379     int rc = 0;
380     afs_status_t tst = 0;
381     afs_status_t etst = 0;
382     struct rx_connection *toconn, *fromconn;
383     afs_int32 fromtid, totid, clonetid;
384     char vname[64];
385     char *volName = 0;
386     char tmpName[VOLSER_MAXVOLNAME + 1];
387     afs_int32 rcode;
388     afs_int32 fromDate;
389     struct restoreCookie cookie;
390     afs_uint32 newVol, volid, backupId;
391     struct volser_status tstatus;
392     struct destServer destination;
393
394     struct nvldbentry entry;
395     int islocked;
396     int same;
397     afs_int32 store_flags;
398
399 #ifdef  ENABLE_BUGFIX_1165
400     volEntries volumeInfo;
401     struct volintInfo *infop = 0;
402 #endif
403
404     islocked = 0;
405     fromconn = (struct rx_connection *)0;
406     toconn = (struct rx_connection *)0;
407     fromtid = 0;
408     totid = 0;
409     clonetid = 0;
410     volid = 0;
411     backupId = 0;
412     newVol = 0;
413
414     if (!aVLDB_GetEntryByID(cellHandle, afromvol, -1, &entry, &tst)) {
415         goto fail_UV_MoveVolume;
416     }
417
418     if (entry.volumeId[RWVOL] != afromvol) {
419         tst = ADMVOSVOLUMEMOVERWONLY;
420         goto fail_UV_MoveVolume;
421     }
422
423     tst =
424         ubik_VL_SetLock(cellHandle->vos, 0, afromvol, RWVOL, VLOP_MOVE);
425     if (tst) {
426         goto fail_UV_MoveVolume;
427     }
428     islocked = 1;
429
430     if (!aVLDB_GetEntryByID(cellHandle, afromvol, RWVOL, &entry, &tst)) {
431         goto fail_UV_MoveVolume;
432     }
433
434     backupId = entry.volumeId[BACKVOL];
435
436     if (!Lp_Match(cellHandle, &entry, afromserver, afrompart, &tst)) {
437         /* the from server and partition do not exist in the vldb entry corresponding to volid */
438         if (!Lp_Match(cellHandle, &entry, atoserver, atopart, &tst)) {
439             /* the to server and partition do not exist in the vldb entry corresponding to volid */
440             tst =
441                 ubik_VL_ReleaseLock(cellHandle->vos, 0, afromvol, -1,
442                           (LOCKREL_OPCODE | LOCKREL_AFSID |
443                            LOCKREL_TIMESTAMP));
444             if (tst) {
445                 goto fail_UV_MoveVolume;
446             }
447             tst = VOLSERVOLMOVED;
448             goto fail_UV_MoveVolume;
449         }
450
451         /* delete the volume afromvol on src_server */
452         /* from-info does not exist but to-info does =>
453          * we have already done the move, but the volume
454          * may still be existing physically on from fileserver
455          */
456         fromconn = UV_Bind(cellHandle, afromserver, AFSCONF_VOLUMEPORT);
457         fromtid = 0;
458
459         tst =
460             AFSVolTransCreate(fromconn, afromvol, afrompart, ITOffline,
461                               &fromtid);
462         if (!tst) {             /* volume exists - delete it */
463             tst =
464                 AFSVolSetFlags(fromconn, fromtid,
465                                VTDeleteOnSalvage | VTOutOfService);
466             if (tst) {
467                 goto fail_UV_MoveVolume;
468             }
469
470             tst = AFSVolDeleteVolume(fromconn, fromtid);
471             if (tst) {
472                 goto fail_UV_MoveVolume;
473             }
474
475             tst = AFSVolEndTrans(fromconn, fromtid, &rcode);
476             fromtid = 0;
477             if (!tst)
478                 tst = rcode;
479             if (tst) {
480                 goto fail_UV_MoveVolume;
481             }
482         }
483
484         /*delete the backup volume now */
485         fromtid = 0;
486         tst =
487             AFSVolTransCreate(fromconn, backupId, afrompart, ITOffline,
488                               &fromtid);
489         if (!tst) {             /* backup volume exists - delete it */
490             tst =
491                 AFSVolSetFlags(fromconn, fromtid,
492                                VTDeleteOnSalvage | VTOutOfService);
493             if (tst) {
494                 goto fail_UV_MoveVolume;
495             }
496
497             tst = AFSVolDeleteVolume(fromconn, fromtid);
498             if (tst) {
499                 goto fail_UV_MoveVolume;
500             }
501
502             tst = AFSVolEndTrans(fromconn, fromtid, &rcode);
503             fromtid = 0;
504             if (!tst)
505                 tst = rcode;
506             if (tst) {
507                 goto fail_UV_MoveVolume;
508             }
509         }
510
511         fromtid = 0;
512         goto fail_UV_MoveVolume;
513     }
514
515     /* From-info matches the vldb info about volid,
516      * its ok start the move operation, the backup volume 
517      * on the old site is deleted in the process 
518      */
519     if (afrompart == atopart) {
520         if (!VLDB_IsSameAddrs
521             (cellHandle, afromserver, atoserver, &same, &tst)) {
522             goto fail_UV_MoveVolume;
523         }
524         if (same) {
525             tst = VOLSERVOLMOVED;
526             goto fail_UV_MoveVolume;
527         }
528     }
529
530     toconn = UV_Bind(cellHandle, atoserver, AFSCONF_VOLUMEPORT);        /* get connections to the servers */
531     fromconn = UV_Bind(cellHandle, afromserver, AFSCONF_VOLUMEPORT);
532     fromtid = totid = 0;        /* initialize to uncreated */
533
534     /* ***
535      * clone the read/write volume locally.
536      * ***/
537
538     tst = AFSVolTransCreate(fromconn, afromvol, afrompart, ITBusy, &fromtid);
539     if (tst) {
540         goto fail_UV_MoveVolume;
541     }
542
543     /* Get a clone id */
544     newVol = 0;
545     tst = ubik_VL_GetNewVolumeId(cellHandle->vos, 0, 1, &newVol);
546     if (tst) {
547         goto fail_UV_MoveVolume;
548     }
549
550     /* Do the clone. Default flags on clone are set to delete on salvage and out of service */
551     strcpy(vname, "move-clone-temp");
552     tst = AFSVolClone(fromconn, fromtid, 0, readonlyVolume, vname, &newVol);
553     if (tst) {
554         goto fail_UV_MoveVolume;
555     }
556
557     /* lookup the name of the volume we just cloned */
558     volid = afromvol;
559     tst = AFSVolGetName(fromconn, fromtid, &volName);
560     if (tst) {
561         goto fail_UV_MoveVolume;
562     }
563
564     rcode = 0;
565     tst = AFSVolEndTrans(fromconn, fromtid, &rcode);
566     fromtid = 0;
567     if (!tst)
568         tst = rcode;
569     if (tst) {
570         goto fail_UV_MoveVolume;
571     }
572
573     /* ***
574      * Create the destination volume
575      * ***/
576
577     tst =
578         AFSVolTransCreate(fromconn, newVol, afrompart, ITOffline, &clonetid);
579     if (tst) {
580         goto fail_UV_MoveVolume;
581     }
582     tst = AFSVolSetFlags(fromconn, clonetid, VTDeleteOnSalvage | VTOutOfService);       /*redundant */
583     if (tst) {
584         goto fail_UV_MoveVolume;
585     }
586
587     /* remember time from which we've dumped the volume */
588     tst = AFSVolGetStatus(fromconn, clonetid, &tstatus);
589     if (tst) {
590         goto fail_UV_MoveVolume;
591     }
592
593     fromDate = tstatus.creationDate - CLOCKSKEW;
594
595 #ifdef  ENABLE_BUGFIX_1165
596     /*
597      * Get the internal volume state from the source volume. We'll use such info (i.e. dayUse)
598      * to copy it to the new volume (via AFSSetInfo later on) so that when we move volumes we
599      * don't use this information...
600      */
601     volumeInfo.volEntries_val = (volintInfo *) 0;       /*this hints the stub to allocate space */
602     volumeInfo.volEntries_len = 0;
603     tst = AFSVolListOneVolume(fromconn, afrompart, afromvol, &volumeInfo);
604     if (tst) {
605         goto fail_UV_MoveVolume;
606     }
607
608     infop = (volintInfo *) volumeInfo.volEntries_val;
609     infop->maxquota = -1;       /* Else it will replace the default quota */
610 #endif
611
612     /* create a volume on the target machine */
613     volid = afromvol;
614     tst = AFSVolTransCreate(toconn, volid, atopart, ITOffline, &totid);
615     if (!tst) {                 /*delete the existing volume */
616
617         tst = AFSVolDeleteVolume(toconn, totid);
618         if (tst) {
619             goto fail_UV_MoveVolume;
620         }
621
622         tst = AFSVolEndTrans(toconn, totid, &rcode);
623         totid = 0;
624         if (!tst)
625             tst = rcode;
626         if (tst) {
627             goto fail_UV_MoveVolume;
628         }
629
630     }
631
632     tst =
633         AFSVolCreateVolume(toconn, atopart, volName, volser_RW, volid, &volid,
634                            &totid);
635     if (tst) {
636         goto fail_UV_MoveVolume;
637     }
638
639     strncpy(tmpName, volName, VOLSER_OLDMAXVOLNAME);
640     free(volName);
641     volName = NULL;
642
643     tst = AFSVolSetFlags(toconn, totid, (VTDeleteOnSalvage | VTOutOfService));
644     if (tst) {
645         goto fail_UV_MoveVolume;
646     }
647
648     /***
649      * Now dump the clone to the new volume
650      ***/
651
652     destination.destHost = atoserver;
653     destination.destPort = AFSCONF_VOLUMEPORT;
654     destination.destSSID = 1;
655
656     /* Copy the clone to the new volume */
657     strncpy(cookie.name, tmpName, VOLSER_OLDMAXVOLNAME);
658     cookie.type = RWVOL;
659     cookie.parent = entry.volumeId[RWVOL];
660     cookie.clone = 0;
661     tst = AFSVolForward(fromconn, clonetid, 0, &destination, totid, &cookie);
662     if (tst) {
663         goto fail_UV_MoveVolume;
664     }
665
666     tst = AFSVolEndTrans(fromconn, clonetid, &rcode);
667     if (!tst)
668         tst = rcode;
669     clonetid = 0;
670     if (tst) {
671         goto fail_UV_MoveVolume;
672     }
673
674     /* ***
675      * reattach to the main-line volume, and incrementally dump it.
676      * ***/
677
678     tst = AFSVolTransCreate(fromconn, afromvol, afrompart, ITBusy, &fromtid);
679     if (tst) {
680         goto fail_UV_MoveVolume;
681     }
682
683     /* now do the incremental */
684     tst =
685         AFSVolForward(fromconn, fromtid, fromDate, &destination, totid,
686                       &cookie);
687     if (tst) {
688         goto fail_UV_MoveVolume;
689     }
690
691     /* now adjust the flags so that the new volume becomes official */
692     tst = AFSVolSetFlags(fromconn, fromtid, VTOutOfService);
693     if (tst) {
694         goto fail_UV_MoveVolume;
695     }
696
697     tst = AFSVolSetFlags(toconn, totid, 0);
698     if (tst) {
699         goto fail_UV_MoveVolume;
700     }
701 #ifdef  ENABLE_BUGFIX_1165
702     tst = AFSVolSetInfo(toconn, totid, infop);
703     if (tst) {
704         goto fail_UV_MoveVolume;
705     }
706 #endif
707
708     /* put new volume online */
709     tst = AFSVolEndTrans(toconn, totid, &rcode);
710     totid = 0;
711     if (!tst)
712         tst = rcode;
713     if (tst) {
714         goto fail_UV_MoveVolume;
715     }
716
717     Lp_SetRWValue(cellHandle, &entry, afromserver, afrompart, atoserver,
718                   atopart);
719     store_flags = entry.flags;
720     entry.flags &= ~BACK_EXISTS;
721
722     if (!VLDB_ReplaceEntry
723         (cellHandle, afromvol, -1, &entry,
724          (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP), &tst)) {
725         goto fail_UV_MoveVolume;
726     }
727     entry.flags = store_flags;
728     islocked = 0;
729
730     if (atoserver != afromserver) {
731         /* set forwarding pointer for moved volumes */
732         tst = AFSVolSetForwarding(fromconn, fromtid, htonl(atoserver));
733         if (tst) {
734             goto fail_UV_MoveVolume;
735         }
736     }
737
738     tst = AFSVolDeleteVolume(fromconn, fromtid);        /* zap original volume */
739     if (tst) {
740         goto fail_UV_MoveVolume;
741     }
742
743     tst = AFSVolEndTrans(fromconn, fromtid, &rcode);
744     fromtid = 0;
745     if (!tst)
746         tst = rcode;
747     if (tst) {
748         goto fail_UV_MoveVolume;
749     }
750
751     /* Delete the backup volume on the original site */
752     tst =
753         AFSVolTransCreate(fromconn, backupId, afrompart, ITOffline, &fromtid);
754     if (!tst) {
755         tst =
756             AFSVolSetFlags(fromconn, fromtid,
757                            VTDeleteOnSalvage | VTOutOfService);
758         if (tst) {
759             goto fail_UV_MoveVolume;
760         }
761
762         tst = AFSVolDeleteVolume(fromconn, fromtid);
763         if (tst) {
764             goto fail_UV_MoveVolume;
765         }
766
767         tst = AFSVolEndTrans(fromconn, fromtid, &rcode);
768         fromtid = 0;
769         if (!tst)
770             tst = rcode;
771         if (tst) {
772             goto fail_UV_MoveVolume;
773         }
774
775     } else
776         tst = 0;                /* no backup volume? that's okay */
777
778     fromtid = 0;
779
780     tst =
781         AFSVolTransCreate(fromconn, newVol, afrompart, ITOffline, &clonetid);
782     if (tst) {
783         goto fail_UV_MoveVolume;
784     }
785
786     /* now delete the clone */
787
788     tst = AFSVolDeleteVolume(fromconn, clonetid);
789     if (tst) {
790         goto fail_UV_MoveVolume;
791     }
792
793     tst = AFSVolEndTrans(fromconn, clonetid, &rcode);
794     if (!tst)
795         tst = rcode;
796     clonetid = 0;
797     if (tst) {
798         goto fail_UV_MoveVolume;
799     }
800
801     /* fall through */
802     /* END OF MOVE */
803
804     /* normal cleanup code */
805
806     if (islocked) {
807         etst =
808             ubik_VL_ReleaseLock(cellHandle->vos, 0, afromvol, -1,
809                       (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP));
810         if (etst) {
811             if (!tst)
812                 tst = etst;
813         }
814     }
815
816     if (fromtid) {
817         etst = AFSVolEndTrans(fromconn, fromtid, &rcode);
818         if (etst || rcode) {
819             if (!tst)
820                 tst = (etst ? etst : rcode);
821         }
822     }
823
824     if (clonetid) {
825         etst = AFSVolEndTrans(fromconn, clonetid, &rcode);
826         if (etst || rcode) {
827             if (!tst)
828                 tst = (etst ? etst : rcode);
829         }
830     }
831
832     if (totid) {
833         etst = AFSVolEndTrans(toconn, totid, &rcode);
834         if (etst) {
835             if (!tst)
836                 tst = (etst ? etst : rcode);
837         }
838     }
839     if (volName)
840         free(volName);
841 #ifdef  ENABLE_BUGFIX_1165
842     if (infop)
843         free(infop);
844 #endif
845     if (fromconn)
846         rx_ReleaseCachedConnection(fromconn);
847     if (toconn)
848         rx_ReleaseCachedConnection(toconn);
849
850     rc = 1;
851     if (st != NULL) {
852         *st = tst;
853     }
854     return rc;
855
856     /* come here only when the sky falls */
857
858   fail_UV_MoveVolume:
859
860     /* unlock VLDB entry */
861     if (islocked)
862         ubik_VL_ReleaseLock(cellHandle->vos, 0, afromvol, -1,
863                   (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP));
864
865     if (clonetid)
866         AFSVolEndTrans(fromconn, clonetid, &rcode);
867     if (totid)
868         AFSVolEndTrans(toconn, totid, &rcode);
869     if (fromtid) {              /* put it on-line */
870         AFSVolSetFlags(fromconn, fromtid, 0);
871         AFSVolEndTrans(fromconn, fromtid, &rcode);
872     }
873
874     if (!aVLDB_GetEntryByID(cellHandle, afromvol, -1, &entry, &tst)) {
875         goto done;
876     }
877
878     /* Delete either the volume on the source location or the target location. 
879      * If the vldb entry still points to the source location, then we know the
880      * volume move didn't finish so we remove the volume from the target 
881      * location. Otherwise, we remove the volume from the source location.
882      */
883     if (Lp_Match(cellHandle, &entry, afromserver, afrompart, &tst)) {   /* didn't move - delete target volume */
884
885         if (volid && toconn) {
886             tst =
887                 AFSVolTransCreate(toconn, volid, atopart, ITOffline, &totid);
888             if (!tst) {
889                 AFSVolSetFlags(toconn, totid,
890                                VTDeleteOnSalvage | VTOutOfService);
891                 AFSVolDeleteVolume(toconn, totid);
892                 AFSVolEndTrans(toconn, totid, &rcode);
893             }
894         }
895
896         /* put source volume on-line */
897         if (fromconn) {
898             tst =
899                 AFSVolTransCreate(fromconn, afromvol, afrompart, ITBusy,
900                                   &fromtid);
901             if (!tst) {
902                 AFSVolSetFlags(fromconn, fromtid, 0);
903                 AFSVolEndTrans(fromconn, fromtid, &rcode);
904             }
905         }
906     } else {                    /* yep, move complete */
907         /* delete backup volume */
908         if (fromconn) {
909             tst =
910                 AFSVolTransCreate(fromconn, backupId, afrompart, ITOffline,
911                                   &fromtid);
912             if (!tst) {
913                 AFSVolSetFlags(fromconn, fromtid,
914                                VTDeleteOnSalvage | VTOutOfService);
915                 AFSVolDeleteVolume(fromconn, fromtid);
916                 AFSVolEndTrans(fromconn, fromtid, &rcode);
917             }
918
919             /* delete source volume */
920             tst =
921                 AFSVolTransCreate(fromconn, afromvol, afrompart, ITBusy,
922                                   &fromtid);
923             if (!tst) {
924                 AFSVolSetFlags(fromconn, fromtid,
925                                VTDeleteOnSalvage | VTOutOfService);
926                 if (atoserver != afromserver)
927                     AFSVolSetForwarding(fromconn, fromtid, htonl(atoserver));
928                 AFSVolDeleteVolume(fromconn, fromtid);
929                 AFSVolEndTrans(fromconn, fromtid, &rcode);
930             }
931         }
932     }
933
934     /* common cleanup - delete local clone */
935     if (newVol) {
936         tst =
937             AFSVolTransCreate(fromconn, newVol, afrompart, ITOffline,
938                               &clonetid);
939         if (!tst) {
940             AFSVolDeleteVolume(fromconn, clonetid);
941             AFSVolEndTrans(fromconn, clonetid, &rcode);
942         }
943     }
944
945     /* unlock VLDB entry */
946     ubik_VL_ReleaseLock(cellHandle->vos, 0, afromvol, -1,
947               (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP));
948
949   done:                 /* routine cleanup */
950     if (volName)
951         free(volName);
952 #ifdef  ENABLE_BUGFIX_1165
953     if (infop)
954         free(infop);
955 #endif
956     if (fromconn)
957         rx_ReleaseCachedConnection(fromconn);
958     if (toconn)
959         rx_ReleaseCachedConnection(toconn);
960
961     if (st != NULL) {
962         *st = tst;
963     }
964     return rc;
965 }
966
967 /* Make a new backup of volume <avolid> on <aserver> and <apart> 
968  * if one already exists, update it 
969  */
970
971 int
972 UV_BackupVolume(afs_cell_handle_p cellHandle, afs_int32 aserver,
973                 afs_int32 apart, afs_uint32 avolid, afs_status_p st)
974 {
975     int rc = 0;
976     afs_status_t tst = 0, temp = 0;
977     afs_int32 ttid = 0, btid = 0;
978     afs_uint32 backupID;
979     afs_int32 rcode = 0;
980     char vname[VOLSER_MAXVOLNAME + 1];
981     struct nvldbentry entry;
982     int vldblocked = 0, vldbmod = 0, backexists = 1;
983     struct rx_connection *aconn = UV_Bind(cellHandle, aserver,
984                                           AFSCONF_VOLUMEPORT);
985
986
987     /* the calls to VLDB will succeed only if avolid is a RW volume,
988      * since we are following the RW hash chain for searching */
989     if (!aVLDB_GetEntryByID(cellHandle, avolid, RWVOL, &entry, &tst)) {
990         goto fail_UV_BackupVolume;
991     }
992
993     /* These operations require the VLDB be locked since it means the VLDB
994      * will change or the vldb is already locked.
995      */
996     if (!(entry.flags & BACK_EXISTS) || /* backup volume doesnt exist */
997         (entry.flags & VLOP_ALLOPERS) ||        /* vldb lock already held */
998         (entry.volumeId[BACKVOL] == INVALID_BID)) {
999         /* no assigned backup volume id */
1000
1001         tst =
1002             ubik_VL_SetLock(cellHandle->vos, 0, avolid, RWVOL,
1003                       VLOP_BACKUP);
1004         if (tst) {
1005             goto fail_UV_BackupVolume;
1006         }
1007         vldblocked = 1;
1008
1009         /* Reread the vldb entry */
1010         if (!aVLDB_GetEntryByID(cellHandle, avolid, RWVOL, &entry, &tst)) {
1011             goto fail_UV_BackupVolume;
1012         }
1013     }
1014
1015     if (!ISNAMEVALID(entry.name)) {
1016         tst = VOLSERBADNAME;
1017         goto fail_UV_BackupVolume;
1018     }
1019
1020     backupID = entry.volumeId[BACKVOL];
1021     if (backupID == INVALID_BID) {
1022         /* Get a backup volume id from the VLDB and update the vldb
1023          * entry with it. 
1024          */
1025         tst = ubik_VL_GetNewVolumeId(cellHandle->vos, 0, 1, &backupID);
1026         if (tst) {
1027             goto fail_UV_BackupVolume;
1028         }
1029         entry.volumeId[BACKVOL] = backupID;
1030         vldbmod = 1;
1031     }
1032
1033     /* Test to see if the backup volume exists by trying to create
1034      * a transaction on the backup volume. We've assumed the backup exists.
1035      */
1036     tst = AFSVolTransCreate(aconn, backupID, apart, ITOffline, &btid);
1037     if (tst) {
1038         if (tst != VNOVOL) {
1039             goto fail_UV_BackupVolume;
1040         }
1041         backexists = 0;         /* backup volume does not exist */
1042     }
1043     if (btid) {
1044         tst = AFSVolEndTrans(aconn, btid, &rcode);
1045         btid = 0;
1046         if (tst || rcode) {
1047             tst = (tst ? tst : rcode);
1048             goto fail_UV_BackupVolume;
1049         }
1050     }
1051
1052     /* Now go ahead and try to clone the RW volume.
1053      * First start a transaction on the RW volume 
1054      */
1055     tst = AFSVolTransCreate(aconn, avolid, apart, ITBusy, &ttid);
1056     if (tst) {
1057         goto fail_UV_BackupVolume;
1058     }
1059
1060     /* Clone or reclone the volume, depending on whether the backup 
1061      * volume exists or not
1062      */
1063     if (backexists) {
1064         tst = AFSVolReClone(aconn, ttid, backupID);
1065         if (tst) {
1066             goto fail_UV_BackupVolume;
1067         }
1068     } else {
1069         strcpy(vname, entry.name);
1070         strcat(vname, ".backup");
1071
1072         tst = AFSVolClone(aconn, ttid, 0, backupVolume, vname, &backupID);
1073         if (tst) {
1074             goto fail_UV_BackupVolume;
1075         }
1076     }
1077
1078     /* End transaction on the RW volume */
1079     tst = AFSVolEndTrans(aconn, ttid, &rcode);
1080     ttid = 0;
1081     if (tst || rcode) {
1082         tst = (tst ? tst : rcode);
1083         goto fail_UV_BackupVolume;
1084     }
1085
1086     /* Mork vldb as backup exists */
1087     if (!(entry.flags & BACK_EXISTS)) {
1088         entry.flags |= BACK_EXISTS;
1089         vldbmod = 1;
1090     }
1091
1092     /* Now go back to the backup volume and bring it on line */
1093     tst = AFSVolTransCreate(aconn, backupID, apart, ITOffline, &btid);
1094     if (tst) {
1095         goto fail_UV_BackupVolume;
1096     }
1097
1098     tst = AFSVolSetFlags(aconn, btid, 0);
1099     if (tst) {
1100         goto fail_UV_BackupVolume;
1101     }
1102
1103     tst = AFSVolEndTrans(aconn, btid, &rcode);
1104     btid = 0;
1105     if (tst || rcode) {
1106         tst = (tst ? tst : rcode);
1107         goto fail_UV_BackupVolume;
1108     }
1109     rc = 1;
1110
1111     /* Will update the vldb below */
1112
1113   fail_UV_BackupVolume:
1114
1115     if (ttid) {
1116         temp = AFSVolEndTrans(aconn, ttid, &rcode);
1117         if (temp || rcode) {
1118             if (!tst)
1119                 tst = (temp ? temp : rcode);
1120         }
1121     }
1122
1123     if (btid) {
1124         temp = AFSVolEndTrans(aconn, btid, &rcode);
1125         if (temp || rcode) {
1126             if (!tst)
1127                 tst = (temp ? temp : rcode);
1128         }
1129     }
1130
1131     /* Now update the vldb - if modified */
1132     if (vldblocked) {
1133         if (vldbmod) {
1134             if (!VLDB_ReplaceEntry
1135                 (cellHandle, avolid, RWVOL, &entry,
1136                  (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP),
1137                  &temp)) {
1138                 if (!tst) {
1139                     tst = temp;
1140                 }
1141             }
1142         } else {
1143             temp =
1144                 ubik_VL_ReleaseLock(cellHandle->vos, 0, avolid, RWVOL,
1145                           (LOCKREL_OPCODE | LOCKREL_AFSID |
1146                            LOCKREL_TIMESTAMP));
1147             if (temp) {
1148                 if (!tst) {
1149                     tst = temp;
1150                 }
1151             }
1152         }
1153     }
1154
1155     if (aconn) {
1156         rx_ReleaseCachedConnection(aconn);
1157     }
1158
1159     if (st != NULL) {
1160         *st = tst;
1161     }
1162     return rc;
1163 }
1164
1165 static int
1166 DelVol(struct rx_connection *conn, afs_uint32 vid, afs_int32 part,
1167        afs_int32 flags)
1168 {
1169     afs_int32 acode, rcode, tid;
1170     rcode = tid = 0;
1171
1172     acode = AFSVolTransCreate(conn, vid, part, flags, &tid);
1173     if (!acode) {               /* It really was there */
1174         acode = AFSVolDeleteVolume(conn, tid);
1175         AFSVolEndTrans(conn, tid, &rcode);
1176     }
1177
1178     return acode;
1179 }
1180
1181 #define ONERROR(ec, ep, es) if (ec) { fprintf(STDERR, (es), (ep)); error = (ec); goto rfail; }
1182 #define ERROREXIT(ec) { error = (ec); goto rfail; }
1183
1184 #if 0                           /* doesn't appear to be used, why compile it */
1185 static int
1186 CloneVol(afs_cell_handle_p cellHandle, struct rx_connection *conn,
1187          afs_uint32 rwvid, afs_int32 part, afs_uint32 * rovidp, int nottemp,
1188          struct nvldbentry *entry, afs_int32 * vidCreateDate, afs_status_p st)
1189 {
1190     int rc = 0;
1191     afs_status_t tst = 0, etst = 0;
1192     afs_int32 rcode = 0, tid = 0;
1193     struct volser_status volstatus;
1194     char vname[64];
1195
1196     /* Begin transaction on RW volume marking it busy (clients will wait) */
1197     tst = AFSVolTransCreate(conn, rwvid, part, ITBusy, &tid);
1198     if (tst) {
1199         goto fail_CloneVol;
1200     }
1201
1202     /* Get the RO volume id. Allocate a new one if need to */
1203     *rovidp = entry->volumeId[ROVOL];
1204     if (*rovidp == INVALID_BID) {
1205         tst = ubik_VL_GetNewVolumeId(cellHandle->vos, 0, 1, rovidp);
1206         if (tst) {
1207             goto fail_CloneVol;
1208         }
1209
1210         entry->volumeId[ROVOL] = *rovidp;
1211     }
1212
1213     /* If we are creating the ro clone, what are we calling it.
1214      * Depends on whether its a temporary clone or not.
1215      */
1216     if (nottemp) {
1217         strcpy(vname, entry->name);
1218         strcat(vname, ".readonly");
1219     } else {
1220         strcpy(vname, "readonly-clone-temp");   /* Should be unique? */
1221     }
1222
1223     /* Create the new clone. If it exists, then reclone it */
1224     tst = AFSVolClone(conn, tid, 0, readonlyVolume, vname, rovidp);
1225     if (tst == VVOLEXISTS) {
1226         tst = AFSVolReClone(conn, tid, *rovidp);
1227         if (tst) {
1228             goto fail_CloneVol;
1229         }
1230     }
1231     if (tst) {
1232         goto fail_CloneVol;
1233     }
1234
1235     /* Bring the volume back on-line as soon as possible */
1236     if (nottemp) {
1237         afs_int32 fromtid = 0;
1238
1239         /* Now bring the RO clone on-line */
1240         tst = AFSVolTransCreate(conn, *rovidp, part, ITOffline, &fromtid);
1241         if (tst) {
1242             goto fail_CloneVol;
1243         }
1244
1245         tst = AFSVolSetFlags(conn, fromtid, 0);
1246         if (tst) {
1247             goto fail_CloneVol;
1248         }
1249
1250         tst = AFSVolEndTrans(conn, fromtid, &rcode);
1251         fromtid = 0;
1252         if (!tst)
1253             tst = rcode;
1254         if (tst) {
1255             goto fail_CloneVol;
1256         }
1257     }
1258
1259     /* Get the time the RW was created for return information */
1260     tst = AFSVolGetStatus(conn, tid, &volstatus);
1261     if (tst) {
1262         goto fail_CloneVol;
1263     }
1264     *vidCreateDate = volstatus.creationDate;
1265     rc = 1;
1266
1267   fail_CloneVol:
1268
1269     if (tid) {
1270         tst = AFSVolEndTrans(conn, tid, &rcode);
1271         tid = 0;
1272         if (!tst)
1273             tst = rcode;
1274         if (tst) {
1275             rc = 0;
1276             goto fail_CloneVol;
1277         }
1278     }
1279
1280     if (st != NULL) {
1281         *st = tst;
1282     }
1283     return rc;
1284 }
1285 #endif
1286
1287 /* Get a "transaction" on this replica.  Create the volume 
1288  * if necessary.  Return the time from which a dump should
1289  * be made (0 if it's a new volume)
1290  */
1291 static int
1292 GetTrans(afs_cell_handle_p cellHandle, struct nvldbentry *vldbEntryPtr,
1293          afs_int32 index, struct rx_connection **connPtr,
1294          afs_int32 * transPtr, afs_int32 * timePtr, afs_status_p st)
1295 {
1296     int rc = 0;
1297     afs_status_t tst = 0;
1298     afs_uint32 volid;
1299     struct volser_status tstatus;
1300     int rcode;
1301
1302     *connPtr = (struct rx_connection *)0;
1303     *timePtr = 0;
1304     *transPtr = 0;
1305
1306     /* get connection to the replication site */
1307     *connPtr =
1308         UV_Bind(cellHandle, vldbEntryPtr->serverNumber[index],
1309                 AFSCONF_VOLUMEPORT);
1310     if (!*connPtr) {
1311         /* server is down */
1312         tst = -1;
1313         goto fail_GetTrans;
1314     }
1315
1316     volid = vldbEntryPtr->volumeId[ROVOL];
1317     if (volid) {
1318         tst =
1319             AFSVolTransCreate(*connPtr, volid,
1320                               vldbEntryPtr->serverPartition[index], ITOffline,
1321                               transPtr);
1322     }
1323
1324     /* If the volume does not exist, create it */
1325     if (!volid || tst) {
1326         char volname[VL_MAXNAMELEN];
1327
1328         if (volid && (tst != VNOVOL)) {
1329             goto fail_GetTrans;
1330         }
1331
1332         strlcpy(volname, vldbEntryPtr->name, sizeof(volname));
1333         if (strlcat(volname, ".readonly", sizeof(volname))
1334                 >= sizeof(volname)) {
1335             tst = ENOMEM;
1336             goto fail_GetTrans;
1337         }
1338
1339         tst =
1340             AFSVolCreateVolume(*connPtr, vldbEntryPtr->serverPartition[index],
1341                                volname, volser_RO,
1342                                vldbEntryPtr->volumeId[RWVOL], &volid,
1343                                transPtr);
1344         if (tst) {
1345             goto fail_GetTrans;
1346         }
1347         vldbEntryPtr->volumeId[ROVOL] = volid;
1348
1349         /* The following is a bit redundant, since create sets these flags by default */
1350         tst =
1351             AFSVolSetFlags(*connPtr, *transPtr,
1352                            VTDeleteOnSalvage | VTOutOfService);
1353         if (tst) {
1354             goto fail_GetTrans;
1355         }
1356     }
1357
1358     /* Otherwise, the transaction did succeed, so get the creation date of the
1359      * latest RO volume on the replication site 
1360      */
1361     else {
1362         tst = AFSVolGetStatus(*connPtr, *transPtr, &tstatus);
1363         if (tst) {
1364             goto fail_GetTrans;
1365         }
1366         *timePtr = tstatus.creationDate - CLOCKSKEW;
1367     }
1368     rc = 1;
1369
1370   fail_GetTrans:
1371
1372     if ((rc == 0) && (*transPtr)) {
1373         AFSVolEndTrans(*connPtr, *transPtr, &rcode);
1374         *transPtr = 0;
1375     }
1376
1377     if (st != NULL) {
1378         *st = tst;
1379     }
1380     return rc;
1381 }
1382
1383 static int
1384 SimulateForwardMultiple(struct rx_connection *fromconn, afs_int32 fromtid,
1385                         afs_int32 fromdate, manyDests * tr, afs_int32 flags,
1386                         void *cookie, manyResults * results)
1387 {
1388     int i;
1389
1390     for (i = 0; i < tr->manyDests_len; i++) {
1391         results->manyResults_val[i] =
1392             AFSVolForward(fromconn, fromtid, fromdate,
1393                           &(tr->manyDests_val[i].server),
1394                           tr->manyDests_val[i].trans, cookie);
1395     }
1396     return 0;
1397 }
1398
1399
1400 /* VolumeExists()
1401  *      Determine if a volume exists on a server and partition.
1402  *      Try creating a transaction on the volume. If we can,
1403  *      the volume exists, if not, then return the error code.
1404  *      Some error codes mean the volume is unavailable but
1405  *      still exists - so we catch these error codes.
1406  */
1407 static afs_int32
1408 VolumeExists(afs_cell_handle_p cellHandle, afs_int32 server,
1409              afs_int32 partition, afs_int32 volumeid, afs_status_p st)
1410 {
1411     int rc = 0;
1412     afs_status_t tst = 0;
1413     struct rx_connection *conn = (struct rx_connection *)0;
1414     volEntries volumeInfo;
1415
1416     conn = UV_Bind(cellHandle, server, AFSCONF_VOLUMEPORT);
1417     if (conn) {
1418         volumeInfo.volEntries_val = (volintInfo *) 0;
1419         volumeInfo.volEntries_len = 0;
1420         tst = AFSVolListOneVolume(conn, partition, volumeid, &volumeInfo);
1421         if (volumeInfo.volEntries_val)
1422             free(volumeInfo.volEntries_val);
1423         if (tst == VOLSERILLEGAL_PARTITION) {
1424             tst = ENODEV;
1425         }
1426         rx_ReleaseCachedConnection(conn);
1427     }
1428     rc = 1;
1429
1430     if (st != NULL) {
1431         *st = tst;
1432     }
1433     return rc;
1434 }
1435
1436 /* release volume <afromvol> on <afromserver> <afrompart> to all the
1437  * sites if forceflag is 1.If its 0 complete the release if the previous
1438  * release aborted else start a new release */
1439 int
1440 UV_ReleaseVolume(afs_cell_handle_p cellHandle, afs_uint32 afromvol,
1441                  afs_int32 afromserver, afs_int32 afrompart, int forceflag,
1442                  afs_status_p st)
1443 {
1444     int rc = 0;
1445     afs_status_t tst = 0, etst = 0;
1446
1447     char vname[64];
1448     afs_int32 rcode;
1449     afs_uint32 cloneVolId, roVolId;
1450     struct replica *replicas = 0;
1451     struct nvldbentry entry;
1452     int i, volcount, m, fullrelease, vldbindex;
1453     int failure;
1454     struct restoreCookie cookie;
1455     struct rx_connection **toconns = 0;
1456     struct release *times = 0;
1457     int nservers = 0;
1458     struct rx_connection *fromconn = (struct rx_connection *)0;
1459     int islocked = 0;
1460     afs_int32 clonetid = 0, onlinetid;
1461     afs_int32 fromtid = 0;
1462     afs_uint32 fromdate = 0, thisdate;
1463     int s;
1464     manyDests tr;
1465     manyResults results;
1466     int rwindex, roindex, roclone, roexists;
1467     afs_int32 rwcrdate = 0;
1468     struct rtime {
1469         int validtime;
1470         afs_uint32 time;
1471     } remembertime[NMAXNSERVERS];
1472     int releasecount = 0;
1473     struct volser_status volstatus;
1474
1475     memset(remembertime, 0, sizeof(remembertime));
1476     memset(&results, 0, sizeof(results));
1477
1478     tst =
1479         ubik_VL_SetLock(cellHandle->vos, 0, afromvol, RWVOL,
1480                   VLOP_RELEASE);
1481     if ((tst) && (tst != VL_RERELEASE)) {
1482         goto fail_UV_ReleaseVolume;
1483     }
1484     islocked = 1;
1485
1486     /* Get the vldb entry in readable format */
1487     if (!aVLDB_GetEntryByID(cellHandle, afromvol, RWVOL, &entry, &tst)) {
1488         goto fail_UV_ReleaseVolume;
1489     }
1490
1491     if (!ISNAMEVALID(entry.name)) {
1492         tst = VOLSERBADNAME;
1493         goto fail_UV_ReleaseVolume;
1494     }
1495
1496     if (entry.volumeId[RWVOL] != afromvol) {
1497         tst = ADMVOSVOLUMERELEASERWONLY;
1498         goto fail_UV_ReleaseVolume;
1499     }
1500
1501     if (entry.nServers <= 1) {
1502         tst = ADMVOSVOLUMENOREPLICAS;
1503         goto fail_UV_ReleaseVolume;
1504     }
1505
1506     if (strlen(entry.name) > (VOLSER_OLDMAXVOLNAME - 10)) {
1507         tst = VOLSERBADNAME;
1508         goto fail_UV_ReleaseVolume;
1509     }
1510
1511     /* roclone is true if one of the RO volumes is on the same
1512      * partition as the RW volume. In this case, we make the RO volume
1513      * on the same partition a clone instead of a complete copy.
1514      */
1515
1516     roindex =
1517         Lp_ROMatch(cellHandle, &entry, afromserver, afrompart, &tst) - 1;
1518     roclone = ((roindex == -1) ? 0 : 1);
1519     rwindex = Lp_GetRwIndex(cellHandle, &entry, 0);
1520     if (rwindex < 0) {
1521         tst = VOLSERNOVOL;
1522         goto fail_UV_ReleaseVolume;
1523     }
1524
1525     /* Make sure we have a RO volume id to work with */
1526     if (entry.volumeId[ROVOL] == INVALID_BID) {
1527         /* need to get a new RO volume id */
1528         tst = ubik_VL_GetNewVolumeId(cellHandle->vos, 0, 1, &roVolId);
1529         if (tst) {
1530             goto fail_UV_ReleaseVolume;
1531         }
1532
1533         entry.volumeId[ROVOL] = roVolId;
1534         if (!VLDB_ReplaceEntry(cellHandle, afromvol, RWVOL, &entry, 0, &tst)) {
1535             goto fail_UV_ReleaseVolume;
1536         }
1537     }
1538
1539     /* Will we be completing a previously unfinished release. -force overrides */
1540     for (fullrelease = 1, i = 0; (fullrelease && (i < entry.nServers)); i++) {
1541         if (entry.serverFlags[i] & NEW_REPSITE)
1542             fullrelease = 0;
1543     }
1544     if (forceflag && !fullrelease)
1545         fullrelease = 1;
1546
1547     /* Determine which volume id to use and see if it exists */
1548     cloneVolId =
1549         ((fullrelease
1550           || (entry.cloneId == 0)) ? entry.volumeId[ROVOL] : entry.cloneId);
1551     VolumeExists(cellHandle, afromserver, afrompart, cloneVolId, &tst);
1552     roexists = ((tst == ENODEV) ? 0 : 1);
1553     if (!roexists && !fullrelease)
1554         fullrelease = 1;        /* Do a full release if RO clone does not exist */
1555
1556     fromconn = UV_Bind(cellHandle, afromserver, AFSCONF_VOLUMEPORT);
1557     if (!fromconn) {
1558         tst = -1;
1559         goto fail_UV_ReleaseVolume;
1560     }
1561
1562     if (fullrelease) {
1563         /* If the RO clone exists, then if the clone is a temporary
1564          * clone, delete it. Or if the RO clone is marked RO_DONTUSE
1565          * (it was recently added), then also delete it. We do not
1566          * want to "reclone" a temporary RO clone.
1567          */
1568         if (roexists
1569             && (!roclone || (entry.serverFlags[roindex] & RO_DONTUSE))) {
1570             tst = DelVol(fromconn, cloneVolId, afrompart, ITOffline);
1571             if (tst && (tst != VNOVOL)) {
1572                 goto fail_UV_ReleaseVolume;
1573             }
1574             roexists = 0;
1575         }
1576
1577         /* Mark all the ROs in the VLDB entry as RO_DONTUSE. We don't
1578          * write this entry out to the vlserver until after the first
1579          * RO volume is released (temp RO clones don't count).
1580          */
1581         for (i = 0; i < entry.nServers; i++) {
1582             entry.serverFlags[i] &= ~NEW_REPSITE;
1583             entry.serverFlags[i] |= RO_DONTUSE;
1584         }
1585         entry.serverFlags[rwindex] |= NEW_REPSITE;
1586         entry.serverFlags[rwindex] &= ~RO_DONTUSE;
1587
1588         /* Begin transaction on RW and mark it busy while we clone it */
1589         tst =
1590             AFSVolTransCreate(fromconn, afromvol, afrompart, ITBusy,
1591                               &clonetid);
1592         if (tst) {
1593             goto fail_UV_ReleaseVolume;
1594         }
1595
1596         /* Clone or reclone the volume */
1597         if (roexists) {
1598             tst = AFSVolReClone(fromconn, clonetid, cloneVolId);
1599             if (tst) {
1600                 goto fail_UV_ReleaseVolume;
1601             }
1602         } else {
1603             if (roclone) {
1604                 strcpy(vname, entry.name);
1605                 strcat(vname, ".readonly");
1606             } else {
1607                 strcpy(vname, "readonly-clone-temp");
1608             }
1609             tst =
1610                 AFSVolClone(fromconn, clonetid, 0, readonlyVolume, vname,
1611                             &cloneVolId);
1612             if (tst) {
1613                 goto fail_UV_ReleaseVolume;
1614             }
1615         }
1616
1617         /* Get the time the RW was created for future information */
1618         tst = AFSVolGetStatus(fromconn, clonetid, &volstatus);
1619         if (tst) {
1620             goto fail_UV_ReleaseVolume;
1621         }
1622         rwcrdate = volstatus.creationDate;
1623
1624         /* End the transaction on the RW volume */
1625         tst = AFSVolEndTrans(fromconn, clonetid, &rcode);
1626         clonetid = 0;
1627         tst = (tst ? tst : rcode);
1628         if (tst) {
1629             goto fail_UV_ReleaseVolume;
1630         }
1631
1632         /* Remember clone volume ID in case we fail or are interrupted */
1633         entry.cloneId = cloneVolId;
1634
1635         if (roclone) {
1636             /* Bring the RO clone online - though not if it's a temporary clone */
1637             tst =
1638                 AFSVolTransCreate(fromconn, cloneVolId, afrompart, ITOffline,
1639                                   &onlinetid);
1640             if (tst) {
1641                 goto fail_UV_ReleaseVolume;
1642             }
1643
1644             etst = AFSVolSetFlags(fromconn, onlinetid, 0);
1645
1646             tst = AFSVolEndTrans(fromconn, onlinetid, &rcode);
1647             tst = (tst ? tst : rcode);
1648             if (tst) {
1649                 goto fail_UV_ReleaseVolume;
1650             }
1651             if (etst) {
1652                 tst = etst;
1653                 goto fail_UV_ReleaseVolume;
1654             }
1655
1656             /* Sleep so that a client searching for an online volume won't
1657              * find the clone offline and then the next RO offline while the 
1658              * release brings the clone online and the next RO offline (race).
1659              * There is a fix in the 3.4 client that does not need this sleep
1660              * anymore, but we don't know what clients we have.
1661              */
1662             if (entry.nServers > 2)
1663                 sleep(5);
1664
1665             /* Mark the RO clone in the VLDB as a good site (already released) */
1666             entry.serverFlags[roindex] |= NEW_REPSITE;
1667             entry.serverFlags[roindex] &= ~RO_DONTUSE;
1668             entry.flags |= RO_EXISTS;
1669
1670             releasecount++;
1671
1672             /* Write out the VLDB entry only if the clone is not a temporary
1673              * clone. If we did this to a temporary clone then we would end
1674              * up marking all the ROs as "old release" making the ROs
1675              * temporarily unavailable.
1676              */
1677             if (!VLDB_ReplaceEntry
1678                 (cellHandle, afromvol, RWVOL, &entry, 0, &tst)) {
1679                 goto fail_UV_ReleaseVolume;
1680             }
1681         }
1682     }
1683
1684     /* Now we will release from the clone to the remaining RO replicas.
1685      * The first 2 ROs (counting the non-temporary RO clone) are released
1686      * individually: releasecount. This is to reduce the race condition
1687      * of clients trying to find an on-line RO volume. The remaining ROs
1688      * are released in parallel but no more than half the number of ROs
1689      * (rounded up) at a time: nservers.
1690      */
1691
1692     strcpy(vname, entry.name);
1693     strcat(vname, ".readonly");
1694     memset(&cookie, 0, sizeof(cookie));
1695     strncpy(cookie.name, vname, VOLSER_OLDMAXVOLNAME);
1696     cookie.type = ROVOL;
1697     cookie.parent = entry.volumeId[RWVOL];
1698     cookie.clone = 0;
1699
1700     nservers = entry.nServers / 2;      /* how many to do at once, excluding clone */
1701     replicas = calloc(nservers + 1, sizeof(struct replica));
1702     times = calloc(nservers + 1, sizeof(struct release));
1703     toconns = calloc(nservers + 1, sizeof(struct rx_connection *));
1704     results.manyResults_val = calloc(nservers + 1, sizeof(afs_int32));
1705     if (!replicas || !times || !!!results.manyResults_val || !toconns) {
1706         tst = ADMNOMEM;
1707         goto fail_UV_ReleaseVolume;
1708     }
1709
1710     /* Create a transaction on the cloned volume */
1711     tst =
1712         AFSVolTransCreate(fromconn, cloneVolId, afrompart, ITBusy, &fromtid);
1713     if (tst) {
1714         goto fail_UV_ReleaseVolume;
1715     }
1716
1717     /* For each index in the VLDB */
1718     for (vldbindex = 0; vldbindex < entry.nServers;) {
1719
1720         /* Get a transaction on the replicas. Pick replacas which have an old release. */
1721         for (volcount = 0;
1722              ((volcount < nservers) && (vldbindex < entry.nServers));
1723              vldbindex++) {
1724             /* The first two RO volumes will be released individually.
1725              * The rest are then released in parallel. This is a hack
1726              * for clients not recognizing right away when a RO volume
1727              * comes back on-line.
1728              */
1729             if ((volcount == 1) && (releasecount < 2))
1730                 break;
1731
1732             if (vldbindex == roindex)
1733                 continue;       /* the clone    */
1734             if ((entry.serverFlags[vldbindex] & NEW_REPSITE)
1735                 && !(entry.serverFlags[vldbindex] & RO_DONTUSE))
1736                 continue;
1737             if (!(entry.serverFlags[vldbindex] & ITSROVOL))
1738                 continue;       /* not a RO vol */
1739
1740
1741             /* Get a Transaction on this replica. Get a new connection if
1742              * necessary.  Create the volume if necessary.  Return the
1743              * time from which the dump should be made (0 if it's a new
1744              * volume).  Each volume might have a different time. 
1745              */
1746             replicas[volcount].server.destHost =
1747                 entry.serverNumber[vldbindex];
1748             replicas[volcount].server.destPort = AFSCONF_VOLUMEPORT;
1749             replicas[volcount].server.destSSID = 1;
1750             times[volcount].vldbEntryIndex = vldbindex;
1751
1752             if (!GetTrans
1753                 (cellHandle, &entry, vldbindex, &(toconns[volcount]),
1754                  &(replicas[volcount].trans), &(times[volcount].time),
1755                  &tst)) {
1756                 continue;
1757             }
1758
1759             /* Thisdate is the date from which we want to pick up all changes */
1760             if (forceflag || !fullrelease
1761                 || (rwcrdate > times[volcount].time)) {
1762                 /* If the forceflag is set, then we want to do a full dump.
1763                  * If it's not a full release, we can't be sure that the creation
1764                  *  date is good (so we also do a full dump).
1765                  * If the RW volume was replaced (its creation date is newer than
1766                  *  the last release), then we can't be sure what has changed (so
1767                  *  we do a full dump).
1768                  */
1769                 thisdate = 0;
1770             } else if (remembertime[vldbindex].validtime) {
1771                 /* Trans was prev ended. Use the time from the prev trans
1772                  * because, prev trans may have created the volume. In which
1773                  * case time[volcount].time would be now instead of 0.
1774                  */
1775                 thisdate =
1776                     (remembertime[vldbindex].time <
1777                      times[volcount].time) ? remembertime[vldbindex].
1778                     time : times[volcount].time;
1779             } else {
1780                 thisdate = times[volcount].time;
1781             }
1782             remembertime[vldbindex].validtime = 1;
1783             remembertime[vldbindex].time = thisdate;
1784
1785             if (volcount == 0) {
1786                 fromdate = thisdate;
1787             } else {
1788                 /* Include this volume if it is within 15 minutes of the earliest */
1789                 if (((fromdate >
1790                       thisdate) ? (fromdate - thisdate) : (thisdate -
1791                                                            fromdate)) > 900) {
1792                     AFSVolEndTrans(toconns[volcount],
1793                                    replicas[volcount].trans, &rcode);
1794                     replicas[volcount].trans = 0;
1795                     break;
1796                 }
1797                 if (thisdate < fromdate)
1798                     fromdate = thisdate;
1799             }
1800             volcount++;
1801         }
1802         if (!volcount)
1803             continue;
1804
1805         /* Release the ones we have collected */
1806         tr.manyDests_val = &(replicas[0]);
1807         tr.manyDests_len = results.manyResults_len = volcount;
1808         tst =
1809             AFSVolForwardMultiple(fromconn, fromtid, fromdate, &tr,
1810                                   0 /*spare */ , &cookie, &results);
1811         if (tst == RXGEN_OPCODE) {      /* RPC Interface Mismatch */
1812             tst =
1813                 SimulateForwardMultiple(fromconn, fromtid, fromdate, &tr,
1814                                         0 /*spare */ , &cookie, &results);
1815             nservers = 1;
1816         }
1817
1818         if (tst) {
1819             goto fail_UV_ReleaseVolume;
1820         } else {
1821             for (m = 0; m < volcount; m++) {
1822                 if (results.manyResults_val[m]) {
1823                     continue;
1824                 }
1825
1826                 tst =
1827                     AFSVolSetIdsTypes(toconns[m], replicas[m].trans, vname,
1828                                       ROVOL, entry.volumeId[RWVOL], 0, 0);
1829                 if (tst) {
1830                     continue;
1831                 }
1832
1833                 /* have to clear dest. flags to ensure new vol goes online:
1834                  * because the restore (forwarded) operation copied
1835                  * the V_inService(=0) flag over to the destination. 
1836                  */
1837                 tst = AFSVolSetFlags(toconns[m], replicas[m].trans, 0);
1838                 if (tst) {
1839                     continue;
1840                 }
1841
1842                 entry.serverFlags[times[m].vldbEntryIndex] |= NEW_REPSITE;
1843                 entry.serverFlags[times[m].vldbEntryIndex] &= ~RO_DONTUSE;
1844                 entry.flags |= RO_EXISTS;
1845                 releasecount++;
1846             }
1847         }
1848
1849         /* End the transactions and destroy the connections */
1850         for (s = 0; s < volcount; s++) {
1851             if (replicas[s].trans)
1852                 tst = AFSVolEndTrans(toconns[s], replicas[s].trans, &rcode);
1853             replicas[s].trans = 0;
1854             if (!tst)
1855                 tst = rcode;
1856             if (tst) {
1857                 if ((s == 0) || (tst != ENOENT)) {
1858                 } else {
1859                     if (times[s].vldbEntryIndex < vldbindex)
1860                         vldbindex = times[s].vldbEntryIndex;
1861                 }
1862             }
1863
1864             if (toconns[s])
1865                 rx_ReleaseCachedConnection(toconns[s]);
1866             toconns[s] = 0;
1867         }
1868
1869         if (!VLDB_ReplaceEntry(cellHandle, afromvol, RWVOL, &entry, 0, &tst)) {
1870             goto fail_UV_ReleaseVolume;
1871         }
1872     }                           /* for each index in the vldb */
1873
1874     /* End the transaction on the cloned volume */
1875     tst = AFSVolEndTrans(fromconn, fromtid, &rcode);
1876     fromtid = 0;
1877
1878     /* Figure out if any volume were not released and say so */
1879     for (failure = 0, i = 0; i < entry.nServers; i++) {
1880         if (!(entry.serverFlags[i] & NEW_REPSITE))
1881             failure++;
1882     }
1883     if (failure) {
1884         if (!VLDB_ReplaceEntry
1885             (cellHandle, afromvol, RWVOL, &entry, LOCKREL_TIMESTAMP, &tst)) {
1886             goto fail_UV_ReleaseVolume;
1887         }
1888
1889         tst = VOLSERBADRELEASE;
1890         goto fail_UV_ReleaseVolume;
1891     }
1892
1893     /* All the ROs were release successfully. Remove the temporary clone */
1894     if (!roclone) {
1895         tst = DelVol(fromconn, cloneVolId, afrompart, ITOffline);
1896         if (tst) {
1897             goto fail_UV_ReleaseVolume;
1898         }
1899     }
1900     entry.cloneId = 0;
1901
1902     for (i = 0; i < entry.nServers; i++)
1903         entry.serverFlags[i] &= ~NEW_REPSITE;
1904
1905     /* Update the VLDB */
1906     if (!VLDB_ReplaceEntry
1907         (cellHandle, afromvol, RWVOL, &entry,
1908          LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP, &tst)) {
1909         goto fail_UV_ReleaseVolume;
1910     }
1911     rc = 1;
1912
1913   fail_UV_ReleaseVolume:
1914
1915     if (clonetid) {
1916         tst = AFSVolEndTrans(fromconn, clonetid, &rcode);
1917         clonetid = 0;
1918         if (tst) {
1919             rc = 0;
1920         }
1921     }
1922     if (fromtid) {
1923         tst = AFSVolEndTrans(fromconn, fromtid, &rcode);
1924         fromtid = 0;
1925         if (tst) {
1926             rc = 0;
1927         }
1928     }
1929     for (i = 0; i < nservers; i++) {
1930         if (replicas && replicas[i].trans) {
1931             tst = AFSVolEndTrans(toconns[i], replicas[i].trans, &rcode);
1932             replicas[i].trans = 0;
1933             if (tst) {
1934                 rc = 0;
1935             }
1936         }
1937         if (toconns && toconns[i]) {
1938             rx_ReleaseCachedConnection(toconns[i]);
1939             toconns[i] = 0;
1940         }
1941     }
1942     if (islocked) {
1943         tst =
1944             ubik_VL_ReleaseLock(cellHandle->vos, 0, afromvol, RWVOL,
1945                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
1946         if (tst) {
1947             rc = 0;
1948         }
1949     }
1950
1951     if (fromconn)
1952         rx_ReleaseCachedConnection(fromconn);
1953     if (results.manyResults_val)
1954         free(results.manyResults_val);
1955     if (replicas)
1956         free(replicas);
1957     if (toconns)
1958         free(toconns);
1959     if (times)
1960         free(times);
1961
1962     if (st != NULL) {
1963         *st = tst;
1964     }
1965     return rc;
1966 }
1967
1968 static int
1969 ReceiveFile(int fd, struct rx_call *call,
1970             struct stat *status)
1971 {
1972     char *buffer = (char *)0;
1973     int blockSize;
1974     afs_int32 bytesread, nbytes, bytesleft, w;
1975     fd_set out;
1976     afs_int32 error = 0;
1977
1978 #ifdef AFS_NT40_ENV
1979     blockSize = 4096;
1980 #else
1981     if (fd != 1) {
1982 #ifdef  AFS_AIX_ENV
1983         struct statfs tstatfs;
1984
1985 /* Unfortunately in AIX valuable fields such as st_blksize are gone from the sta
1986 t structure!! */
1987         fstatfs(fd, &tstatfs);
1988         blockSize = tstatfs.f_bsize;
1989 #else
1990         blockSize = status->st_blksize;
1991 #endif
1992     } else {
1993         blockSize = 4096;
1994     }
1995 #endif
1996     nbytes = blockSize;
1997     buffer = malloc(blockSize);
1998     if (!buffer) {
1999         return ADMNOMEM;
2000     }
2001     bytesread = 1;
2002     while (!error && (bytesread > 0)) {
2003         bytesread = rx_Read(call, buffer, nbytes);
2004         bytesleft = bytesread;
2005         while (!error && (bytesleft > 0)) {
2006             FD_ZERO(&out);
2007             FD_SET(fd, &out);
2008 #ifndef AFS_NT40_ENV            /* NT csn't select on non-socket fd's */
2009             select(fd + 1, 0, &out, 0, 0);      /* don't timeout if write bl
2010                                                  * ocks */
2011 #endif
2012             w = write(fd, &buffer[bytesread - bytesleft], bytesleft);
2013             if (w < 0) {
2014                 error = ADMVOSDUMPFILEWRITEFAIL;
2015             } else {
2016                 bytesleft -= w;
2017             }
2018         }
2019     }
2020     if (buffer)
2021         free(buffer);
2022     if (fd != 1)
2023         if (!error)
2024             fstat(fd, status);
2025     return error;
2026 }
2027
2028
2029 static afs_int32
2030 DumpFunction(struct rx_call *call, const char *filename)
2031 {
2032     int fd;
2033     struct stat status;
2034     afs_int32 error, code;
2035
2036     error = 0;
2037
2038     fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0666);
2039     if (fd < 0 || fstat(fd, &status) < 0) {
2040         error = VOLSERBADOP;
2041         goto dffail;
2042     }
2043     code = ReceiveFile(fd, call, &status);
2044     if (code) {
2045         error = code;
2046         goto dffail;
2047     }
2048   dffail:
2049     if (fd >= 0)
2050         code = close(fd);
2051     else
2052         code = 0;
2053     if (code) {
2054         if (!error)
2055             error = code;
2056     }
2057     return error;
2058 }
2059
2060
2061 /*dump the volume <afromvol> on <afromserver> and
2062 * <afrompart> to <afilename> starting from <fromdate>.
2063 * DumpFunction does the real work behind the scenes after
2064 * extracting parameters from the rock  */
2065 int
2066 UV_DumpVolume(afs_cell_handle_p cellHandle, afs_uint32 afromvol,
2067               afs_int32 afromserver, afs_int32 afrompart, afs_int32 fromdate,
2068               const char *filename, afs_status_p st)
2069 {
2070     int rc = 0;
2071     afs_status_t tst = 0;
2072     afs_status_t etst = 0;
2073     struct rx_connection *fromconn;
2074     struct rx_call *fromcall;
2075     afs_int32 fromtid;
2076     afs_int32 rxError;
2077     afs_int32 rcode;
2078
2079     struct nvldbentry entry;
2080     int islocked;
2081
2082     islocked = 0;
2083     rxError = 0;
2084     fromconn = (struct rx_connection *)0;
2085     fromtid = 0;
2086     fromcall = (struct rx_call *)0;
2087
2088     if (!aVLDB_GetEntryByID(cellHandle, afromvol, -1, &entry, &tst)) {
2089         goto fail_UV_DumpVolume;
2090     }
2091
2092     /* get connections to the servers */
2093     fromconn = UV_Bind(cellHandle, afromserver, AFSCONF_VOLUMEPORT);
2094     tst = AFSVolTransCreate(fromconn, afromvol, afrompart, ITBusy, &fromtid);
2095     if (tst) {
2096         goto fail_UV_DumpVolume;
2097     }
2098     fromcall = rx_NewCall(fromconn);
2099     tst = StartAFSVolDump(fromcall, fromtid, fromdate);
2100     if (tst) {
2101         goto fail_UV_DumpVolume;
2102     }
2103     if ((tst = DumpFunction(fromcall, filename))) {
2104         goto fail_UV_DumpVolume;
2105     }
2106     tst = rx_EndCall(fromcall, rxError);
2107     fromcall = (struct rx_call *)0;
2108     if (tst) {
2109         goto fail_UV_DumpVolume;
2110     }
2111     tst = AFSVolEndTrans(fromconn, fromtid, &rcode);
2112     fromtid = 0;
2113     if (!tst)
2114         tst = rcode;
2115     if (tst) {
2116         goto fail_UV_DumpVolume;
2117     }
2118     rc = 1;
2119
2120   fail_UV_DumpVolume:
2121
2122     if (islocked) {
2123         etst =
2124             ubik_VL_ReleaseLock(cellHandle->vos, 0, afromvol, -1,
2125                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
2126         if (etst) {
2127             if (!tst)
2128                 tst = etst;
2129         }
2130     }
2131
2132     if (fromcall) {
2133         etst = rx_EndCall(fromcall, rxError);
2134         if (etst) {
2135             if (!tst)
2136                 tst = etst;
2137         }
2138     }
2139
2140     if (fromtid) {
2141         etst = AFSVolEndTrans(fromconn, fromtid, &rcode);
2142         if (!tst)
2143             tst = etst;
2144         if (rcode) {
2145             if (!tst)
2146                 tst = rcode;
2147         }
2148     }
2149
2150     if (fromconn) {
2151         rx_ReleaseCachedConnection(fromconn);
2152     }
2153
2154     if (st != NULL) {
2155         *st = tst;
2156     }
2157     return rc;
2158 }
2159
2160 int
2161 SendFile(int fd, struct rx_call *call,
2162          struct stat *status)
2163 {
2164     char *buffer = (char *)0;
2165     int blockSize;
2166     fd_set in;
2167     afs_int32 error = 0;
2168     int nbytes;
2169
2170 #ifdef AFS_NT40_ENV
2171     blockSize = 4096;
2172 #else
2173     if (fd != 0) {
2174 #ifdef  AFS_AIX_ENV
2175         struct statfs tstatfs;
2176
2177 /* Unfortunately in AIX valuable fields such as st_blksize are gone from the sta
2178 t structure!! */
2179         fstatfs(fd, &tstatfs);
2180         blockSize = tstatfs.f_bsize;
2181 #else
2182         blockSize = status->st_blksize;
2183 #endif
2184     } else {
2185         blockSize = 4096;
2186     }
2187 #endif
2188     buffer = malloc(blockSize);
2189     if (!buffer) {
2190         return ADMNOMEM;
2191     }
2192
2193     while (!error) {
2194         FD_ZERO(&in);
2195         FD_SET(fd, &in);
2196 #ifndef AFS_NT40_ENV            /* NT csn't select on non-socket fd's */
2197         select(fd + 1, &in, 0, 0, 0);   /* don't timeout if read blocks */
2198 #endif
2199         nbytes = read(fd, buffer, blockSize);
2200         if (nbytes < 0) {
2201             error = ADMVOSRESTOREFILEREADFAIL;
2202             break;
2203         }
2204
2205         if (nbytes == 0)
2206             break;
2207
2208         if (rx_Write(call, buffer, nbytes) != nbytes) {
2209             error = ADMVOSRESTOREFILEWRITEFAIL;
2210             break;
2211         }
2212     }
2213     if (buffer)
2214         free(buffer);
2215     return error;
2216 }
2217
2218 static afs_int32
2219 WriteData(struct rx_call *call, const char *filename)
2220 {
2221     int fd;
2222     struct stat status;
2223     afs_int32 error, code;
2224
2225     error = 0;
2226
2227     fd = open(filename, 0);
2228     if (fd < 0 || fstat(fd, &status) < 0) {
2229         fprintf(STDERR, "Could access file '%s'\n", filename);
2230         error = ADMVOSRESTOREFILEOPENFAIL;
2231         goto fail_WriteData;
2232     }
2233     code = SendFile(fd, call, &status);
2234     if (code) {
2235         error = code;
2236         goto fail_WriteData;
2237     }
2238
2239   fail_WriteData:
2240
2241     if (fd >= 0)
2242         code = close(fd);
2243     else
2244         code = 0;
2245     if (code) {
2246         if (!error)
2247             error = ADMVOSRESTOREFILECLOSEFAIL;
2248     }
2249     return error;
2250 }
2251
2252 /*
2253  * Restore a volume <tovolid> <tovolname> on <toserver> <topart> from
2254  * the dump file <afilename>. WriteData does all the real work
2255  * after extracting params from the rock 
2256  */
2257 int
2258 UV_RestoreVolume(afs_cell_handle_p cellHandle, afs_int32 toserver,
2259                  afs_int32 topart, afs_uint32 tovolid, char *tovolname,
2260                  int flags, const char *dumpFile, afs_status_p st)
2261 {
2262     int rc = 0;
2263     afs_status_t tst = 0;
2264     afs_status_t etst = 0;
2265     struct rx_connection *toconn, *tempconn;
2266     struct rx_call *tocall;
2267     afs_int32 totid, rcode;
2268     afs_int32 rxError = 0;
2269     struct volser_status tstatus;
2270     char partName[10];
2271     afs_uint32 pvolid;
2272     afs_int32 temptid;
2273     int success;
2274     struct nvldbentry entry;
2275     int islocked;
2276     struct restoreCookie cookie;
2277     int reuseID;
2278     afs_int32 newDate, volflag;
2279     int index, same;
2280
2281
2282     memset(&cookie, 0, sizeof(cookie));
2283     islocked = 0;
2284     reuseID = 1;
2285     tocall = (struct rx_call *)0;
2286     tempconn = (struct rx_connection *)0;
2287     totid = 0;
2288     temptid = 0;
2289
2290     pvolid = tovolid;
2291     toconn = UV_Bind(cellHandle, toserver, AFSCONF_VOLUMEPORT);
2292     if (pvolid == 0) {          /*alot a new id if needed */
2293         aVLDB_GetEntryByName(cellHandle, tovolname, &entry, &tst);
2294         if (tst == VL_NOENT) {
2295             tst =
2296                 ubik_VL_GetNewVolumeId(cellHandle->vos, 0, 1, &pvolid);
2297             if (tst) {
2298                 goto fail_UV_RestoreVolume;
2299             }
2300             reuseID = 0;
2301         } else {
2302             pvolid = entry.volumeId[RWVOL];
2303         }
2304     }
2305
2306     /* 
2307      * at this point we have a volume id to use/reuse for the
2308      * volume to be restored
2309      */
2310     if (strlen(tovolname) > (VOLSER_OLDMAXVOLNAME - 1)) {
2311         tst = ADMVOSRESTOREVOLUMENAMETOOBIG;
2312         goto fail_UV_RestoreVolume;
2313     }
2314
2315     if (!vos_PartitionIdToName(topart, partName, &tst)) {
2316         goto fail_UV_RestoreVolume;
2317     }
2318     /*what should the volume be restored as ? rw or ro or bk ?
2319      * right now the default is rw always */
2320     tst =
2321         AFSVolCreateVolume(toconn, topart, tovolname, volser_RW, 0, &pvolid,
2322                            &totid);
2323     if (tst) {
2324         if (flags & RV_FULLRST) {       /* full restore: delete then create anew */
2325             tst =
2326                 AFSVolTransCreate(toconn, pvolid, topart, ITOffline, &totid);
2327             if (tst) {
2328                 goto fail_UV_RestoreVolume;
2329             }
2330             tst =
2331                 AFSVolSetFlags(toconn, totid,
2332                                VTDeleteOnSalvage | VTOutOfService);
2333             if (tst) {
2334                 goto fail_UV_RestoreVolume;
2335             }
2336             tst = AFSVolDeleteVolume(toconn, totid);
2337             if (tst) {
2338                 goto fail_UV_RestoreVolume;
2339             }
2340             tst = AFSVolEndTrans(toconn, totid, &rcode);
2341             totid = 0;
2342             if (!tst)
2343                 tst = rcode;
2344             if (tst) {
2345                 goto fail_UV_RestoreVolume;
2346             }
2347             tst =
2348                 AFSVolCreateVolume(toconn, topart, tovolname, volser_RW, 0,
2349                                    &pvolid, &totid);
2350             if (tst) {
2351                 goto fail_UV_RestoreVolume;
2352             }
2353         } else {
2354             tst =
2355                 AFSVolTransCreate(toconn, pvolid, topart, ITOffline, &totid);
2356             if (tst) {
2357                 goto fail_UV_RestoreVolume;
2358             }
2359         }
2360     }
2361     cookie.parent = pvolid;
2362     cookie.type = RWVOL;
2363     cookie.clone = 0;
2364     strncpy(cookie.name, tovolname, VOLSER_OLDMAXVOLNAME);
2365
2366     tocall = rx_NewCall(toconn);
2367     tst = StartAFSVolRestore(tocall, totid, 1, &cookie);
2368     if (tst) {
2369         goto fail_UV_RestoreVolume;
2370     }
2371     tst = WriteData(tocall, dumpFile);
2372     if (tst) {
2373         goto fail_UV_RestoreVolume;
2374     }
2375     tst = rx_EndCall(tocall, rxError);
2376     tocall = (struct rx_call *)0;
2377     if (tst) {
2378         goto fail_UV_RestoreVolume;
2379     }
2380     tst = AFSVolGetStatus(toconn, totid, &tstatus);
2381     if (tst) {
2382         goto fail_UV_RestoreVolume;
2383     }
2384     tst = AFSVolSetIdsTypes(toconn, totid, tovolname, RWVOL, pvolid, 0, 0);
2385     if (tst) {
2386         goto fail_UV_RestoreVolume;
2387     }
2388     newDate = time(0);
2389     tst = AFSVolSetDate(toconn, totid, newDate);
2390     if (tst) {
2391         goto fail_UV_RestoreVolume;
2392     }
2393
2394     volflag = ((flags & RV_OFFLINE) ? VTOutOfService : 0);      /* off or on-line */
2395     tst = AFSVolSetFlags(toconn, totid, volflag);
2396     if (tst) {
2397         goto fail_UV_RestoreVolume;
2398     }
2399
2400 /* It isn't handled right in fail_UV_RestoreVolume */
2401     tst = AFSVolEndTrans(toconn, totid, &rcode);
2402     totid = 0;
2403     if (!tst)
2404         tst = rcode;
2405     if (tst) {
2406         goto fail_UV_RestoreVolume;
2407     }
2408
2409     success = 1;
2410     if (success && (!reuseID || (flags & RV_FULLRST))) {
2411         /* Volume was restored on the file server, update the 
2412          * VLDB to reflect the change.
2413          */
2414         aVLDB_GetEntryByID(cellHandle, pvolid, RWVOL, &entry, &tst);
2415         if (tst && tst != VL_NOENT && tst != VL_ENTDELETED) {
2416             goto fail_UV_RestoreVolume;
2417         }
2418         if (tst == VL_NOENT) {  /* it doesnot exist already */
2419             /*make the vldb return this indication specifically */
2420             strcpy(entry.name, tovolname);
2421             entry.nServers = 1;
2422             entry.serverNumber[0] = toserver;   /*should be indirect */
2423             entry.serverPartition[0] = topart;
2424             entry.serverFlags[0] = ITSRWVOL;
2425             entry.flags = RW_EXISTS;
2426             if (tstatus.cloneID != 0) {
2427                 entry.volumeId[ROVOL] = tstatus.cloneID;        /*this should come from status info on the volume if non zero */
2428             } else
2429                 entry.volumeId[ROVOL] = INVALID_BID;
2430             entry.volumeId[RWVOL] = pvolid;
2431             entry.cloneId = 0;
2432             if (tstatus.backupID != 0) {
2433                 entry.volumeId[BACKVOL] = tstatus.backupID;
2434                 /*this should come from status info on the volume if non zero */
2435             } else
2436                 entry.volumeId[BACKVOL] = INVALID_BID;
2437             if (!VLDB_CreateEntry(cellHandle, &entry, &tst)) {
2438                 goto fail_UV_RestoreVolume;
2439             }
2440             islocked = 0;
2441         } else {                /*update the existing entry */
2442             tst =
2443                 ubik_VL_SetLock(cellHandle->vos, 0, pvolid, RWVOL,
2444                           VLOP_RESTORE);
2445             if (tst) {
2446                 goto fail_UV_RestoreVolume;
2447             }
2448             islocked = 1;
2449             strcpy(entry.name, tovolname);
2450
2451             /* Update the vlentry with the new information */
2452             index = Lp_GetRwIndex(cellHandle, &entry, 0);
2453             if (index == -1) {
2454                 /* Add the rw site for the volume being restored */
2455                 entry.serverNumber[entry.nServers] = toserver;
2456                 entry.serverPartition[entry.nServers] = topart;
2457                 entry.serverFlags[entry.nServers] = ITSRWVOL;
2458                 entry.nServers++;
2459             } else {
2460                 /* This volume should be deleted on the old site
2461                  * if its different from new site.
2462                  */
2463                 VLDB_IsSameAddrs(cellHandle, toserver,
2464                                  entry.serverNumber[index], &same, &tst);
2465                 if ((!tst && !same)
2466                     || (entry.serverPartition[index] != topart)) {
2467                     tempconn =
2468                         UV_Bind(cellHandle, entry.serverNumber[index],
2469                                 AFSCONF_VOLUMEPORT);
2470                     tst =
2471                         AFSVolTransCreate(tempconn, pvolid,
2472                                           entry.serverPartition[index],
2473                                           ITOffline, &temptid);
2474                     if (!tst) {
2475                         tst =
2476                             AFSVolSetFlags(tempconn, temptid,
2477                                            VTDeleteOnSalvage |
2478                                            VTOutOfService);
2479                         if (tst) {
2480                             goto fail_UV_RestoreVolume;
2481                         }
2482                         tst = AFSVolDeleteVolume(tempconn, temptid);
2483                         if (tst) {
2484                             goto fail_UV_RestoreVolume;
2485                         }
2486                         tst = AFSVolEndTrans(tempconn, temptid, &rcode);
2487                         temptid = 0;
2488                         if (!tst)
2489                             tst = rcode;
2490                         if (tst) {
2491                             goto fail_UV_RestoreVolume;
2492                         }
2493                         vos_PartitionIdToName(entry.serverPartition[index],
2494                                               partName, &tst);
2495                     }
2496                 }
2497                 entry.serverNumber[index] = toserver;
2498                 entry.serverPartition[index] = topart;
2499             }
2500
2501             entry.flags |= RW_EXISTS;
2502             if (!VLDB_ReplaceEntry
2503                 (cellHandle, pvolid, RWVOL, &entry,
2504                  LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP, &tst)) {
2505                 goto fail_UV_RestoreVolume;
2506             }
2507             islocked = 0;
2508         }
2509     }
2510     rc = 1;
2511
2512   fail_UV_RestoreVolume:
2513
2514     if (tocall) {
2515         etst = rx_EndCall(tocall, rxError);
2516         if (!tst)
2517             tst = etst;
2518     }
2519     if (islocked) {
2520         etst =
2521             ubik_VL_ReleaseLock(cellHandle->vos, 0, pvolid, RWVOL,
2522                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
2523         if (etst) {
2524             if (!tst)
2525                 tst = etst;
2526         }
2527     }
2528     if (totid) {
2529         etst = AFSVolEndTrans(toconn, totid, &rcode);
2530         if (!etst)
2531             etst = rcode;
2532         if (etst) {
2533             if (!tst)
2534                 tst = etst;
2535         }
2536     }
2537     if (temptid) {
2538         etst = AFSVolEndTrans(toconn, temptid, &rcode);
2539         if (!etst)
2540             etst = rcode;
2541         if (etst) {
2542             if (!tst)
2543                 tst = etst;
2544         }
2545     }
2546
2547     if (tempconn)
2548         rx_ReleaseCachedConnection(tempconn);
2549     if (toconn)
2550         rx_ReleaseCachedConnection(toconn);
2551
2552     if (st != NULL) {
2553         *st = tst;
2554     }
2555     return rc;
2556 }
2557
2558 /*adds <server> and <part> as a readonly replication site for <volid>
2559 *in vldb */
2560 int
2561 UV_AddSite(afs_cell_handle_p cellHandle, afs_int32 server, afs_int32 part,
2562            afs_uint32 volid, afs_status_p st)
2563 {
2564     int rc = 0;
2565     afs_status_t tst = 0;
2566     int j, nro = 0, islocked = 0;
2567     struct nvldbentry entry;
2568     int same = 0;
2569
2570     tst =
2571         ubik_VL_SetLock(cellHandle->vos, 0, volid, RWVOL, VLOP_ADDSITE);
2572     if (tst) {
2573         goto fail_UV_AddSite;
2574     }
2575     islocked = 1;
2576
2577     if (!aVLDB_GetEntryByID(cellHandle, volid, RWVOL, &entry, &tst)) {
2578         goto fail_UV_AddSite;
2579     }
2580     if (!ISNAMEVALID(entry.name)) {
2581         tst = VOLSERBADOP;
2582         goto fail_UV_AddSite;
2583     }
2584
2585     /* See if it's too many entries */
2586     if (entry.nServers >= NMAXNSERVERS) {
2587         tst = VOLSERBADOP;
2588         goto fail_UV_AddSite;
2589     }
2590
2591     /* See if it's on the same server */
2592     for (j = 0; j < entry.nServers; j++) {
2593         if (entry.serverFlags[j] & ITSROVOL) {
2594             nro++;
2595             if (!VLDB_IsSameAddrs
2596                 (cellHandle, server, entry.serverNumber[j], &same, &tst)) {
2597                 goto fail_UV_AddSite;
2598             }
2599             if (same) {
2600                 tst = VOLSERBADOP;
2601                 goto fail_UV_AddSite;
2602             }
2603         }
2604     }
2605
2606     /* See if it's too many RO sites - leave one for the RW */
2607     if (nro >= NMAXNSERVERS - 1) {
2608         tst = VOLSERBADOP;
2609         goto fail_UV_AddSite;
2610     }
2611
2612     entry.serverNumber[entry.nServers] = server;
2613     entry.serverPartition[entry.nServers] = part;
2614     entry.serverFlags[entry.nServers] = (ITSROVOL | RO_DONTUSE);
2615     entry.nServers++;
2616
2617     if (!VLDB_ReplaceEntry
2618         (cellHandle, volid, RWVOL, &entry,
2619          LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP, &tst)) {
2620         goto fail_UV_AddSite;
2621     }
2622     islocked = 0;
2623     rc = 1;
2624
2625   fail_UV_AddSite:
2626
2627     if (islocked) {
2628         tst =
2629             ubik_VL_ReleaseLock(cellHandle->vos, 0, volid, RWVOL,
2630                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
2631     }
2632
2633     if (st != NULL) {
2634         *st = tst;
2635     }
2636     return rc;
2637 }
2638
2639 /*removes <server> <part> as read only site for <volid> from the vldb */
2640 int
2641 UV_RemoveSite(afs_cell_handle_p cellHandle, afs_int32 server, afs_int32 part,
2642               afs_uint32 volid, afs_status_p st)
2643 {
2644     int rc = 0;
2645     afs_status_t tst = 0;
2646     struct nvldbentry entry;
2647     int islocked = 0;
2648
2649     tst =
2650         ubik_VL_SetLock(cellHandle->vos, 0, volid, RWVOL, VLOP_ADDSITE);
2651     if (tst) {
2652         goto fail_UV_RemoveSite;
2653     }
2654     islocked = 1;
2655
2656     if (!aVLDB_GetEntryByID(cellHandle, volid, RWVOL, &entry, &tst)) {
2657         goto fail_UV_RemoveSite;
2658     }
2659     if (!Lp_ROMatch(cellHandle, &entry, server, part, &tst)) {
2660         /*this site doesnot exist  */
2661         goto fail_UV_RemoveSite;
2662     } else {                    /*remove the rep site */
2663         Lp_SetROValue(cellHandle, &entry, server, part, 0, 0);
2664         entry.nServers--;
2665         if ((entry.nServers == 1) && (entry.flags & RW_EXISTS))
2666             entry.flags &= ~RO_EXISTS;
2667         if (entry.nServers < 1) {       /*this is the last ref */
2668             tst = ubik_VL_DeleteEntry(cellHandle->vos, 0, volid, ROVOL);
2669             if (tst) {
2670                 goto fail_UV_RemoveSite;
2671             }
2672         }
2673         if (!VLDB_ReplaceEntry
2674             (cellHandle, volid, RWVOL, &entry,
2675              (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP), &tst)) {
2676             goto fail_UV_RemoveSite;
2677         }
2678     }
2679     rc = 1;
2680
2681   fail_UV_RemoveSite:
2682
2683     if (islocked) {
2684         afs_status_t t;
2685         t = ubik_VL_ReleaseLock(cellHandle->vos, 0, volid, RWVOL,
2686                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
2687         if (tst == 0) {
2688             tst = t;
2689         }
2690     }
2691
2692     if (st != NULL) {
2693         *st = tst;
2694     }
2695     return rc;
2696 }
2697
2698 /*list all the partitions on <aserver> */
2699 int
2700 UV_ListPartitions(struct rx_connection *server, struct partList *ptrPartList,
2701                   afs_int32 * cntp, afs_status_p st)
2702 {
2703     int rc = 0;
2704     afs_status_t tst = 0;
2705     struct pIDs partIds;
2706     struct partEntries partEnts;
2707     int i, j = 0;
2708
2709     *cntp = 0;
2710
2711     partEnts.partEntries_len = 0;
2712     partEnts.partEntries_val = NULL;
2713     /* this is available only on new servers */
2714     tst = AFSVolXListPartitions(server, &partEnts);
2715
2716     /* next, try old interface */
2717     if (tst == RXGEN_OPCODE) {
2718         for (i = 0; i < 26; i++)
2719             partIds.partIds[i] = -1;
2720         tst = AFSVolListPartitions(server, &partIds);
2721         if (!tst) {
2722             for (i = 0; i < 26; i++) {
2723                 if ((partIds.partIds[i]) != -1) {
2724                     ptrPartList->partId[j] = partIds.partIds[i];
2725                     ptrPartList->partFlags[j] = PARTVALID;
2726                     j++;
2727                 } else
2728                     ptrPartList->partFlags[i] = 0;
2729             }
2730             *cntp = j;
2731         } else {
2732             goto fail_UV_ListPartitions;
2733         }
2734     } else if (!tst) {
2735         *cntp = partEnts.partEntries_len;
2736         if (*cntp > VOLMAXPARTS) {
2737             *cntp = VOLMAXPARTS;
2738         }
2739         for (i = 0; i < *cntp; i++) {
2740             ptrPartList->partId[i] = partEnts.partEntries_val[i];
2741             ptrPartList->partFlags[i] = PARTVALID;
2742         }
2743         free(partEnts.partEntries_val);
2744     } else {
2745         goto fail_UV_ListPartitions;
2746     }
2747     rc = 1;
2748
2749   fail_UV_ListPartitions:
2750
2751     if (st != NULL) {
2752         *st = tst;
2753     }
2754     return rc;
2755 }
2756
2757 /*------------------------------------------------------------------------
2758  * EXPORTED UV_XListVolumes
2759  *
2760  * Description:
2761  *      List the extended information for all the volumes on a particular
2762  *      File Server and partition.  We may either return the volume's ID
2763  *      or all of its extended information.
2764  *
2765  * Arguments:
2766  *      a_serverID         : Address of the File Server for which we want
2767  *                              extended volume info.
2768  *      a_partID           : Partition for which we want the extended
2769  *                              volume info.
2770  *      a_all              : If non-zero, fetch ALL the volume info,
2771  *                              otherwise just the volume ID.
2772  *      a_resultPP         : Ptr to the address of the area containing
2773  *                              the returned volume info.
2774  *      a_numEntsInResultP : Ptr for the value we set for the number of
2775  *                              entries returned.
2776  *
2777  * Returns:
2778  *      0 on success,
2779  *      Otherise, the return value of AFSVolXListVolumes.
2780  *
2781  * Environment:
2782  *      This routine is closely related to UV_ListVolumes, which returns
2783  *      only the standard level of detail on AFS volumes. It is a
2784  *      heavyweight operation, zipping through all the volume entries for
2785  *      a given server/partition.
2786  *
2787  * Side Effects:
2788  *      As advertised.
2789  *------------------------------------------------------------------------*/
2790
2791 int
2792 UV_XListVolumes(struct rx_connection *server, afs_int32 a_partID, int a_all,
2793                 struct volintXInfo **a_resultPP,
2794                 afs_int32 * a_numEntsInResultP, afs_status_p st)
2795 {
2796     int rc = 0;
2797     afs_status_t tst = 0;
2798
2799     volXEntries volumeXInfo;    /*Area for returned extended vol info */
2800
2801     /*
2802      * Set up our error code and the area for returned extended volume info.
2803      * We set the val field to a null pointer as a hint for the stub to
2804      * allocate space.
2805      */
2806     *a_numEntsInResultP = 0;
2807     *a_resultPP = (volintXInfo *) 0;
2808     volumeXInfo.volXEntries_val = (volintXInfo *) 0;
2809     volumeXInfo.volXEntries_len = 0;
2810
2811     /*
2812      * Bind to the Volume Server port on the File Server machine in question,
2813      * then go for it.
2814      */
2815     tst = AFSVolXListVolumes(server, a_partID, a_all, &volumeXInfo);
2816     if (tst) {
2817         goto fail_UV_XListVolumes;
2818     } else {
2819         /*
2820          * We got the info; pull out the pointer to where the results lie
2821          * and how many entries are there.
2822          */
2823         *a_resultPP = volumeXInfo.volXEntries_val;
2824         *a_numEntsInResultP = volumeXInfo.volXEntries_len;
2825     }
2826     rc = 1;
2827
2828   fail_UV_XListVolumes:
2829
2830     if (st != NULL) {
2831         *st = tst;
2832     }
2833     return rc;
2834 }
2835
2836 /*------------------------------------------------------------------------
2837  * EXPORTED UV_XListOneVolume
2838  *
2839  * Description:
2840  *      List the extended information for a volume on a particular File
2841  *      Server and partition.
2842  *
2843  * Arguments:
2844  *      server     : a handle to the server where the volume resides.
2845  *      a_partID           : Partition for which we want the extended
2846  *                              volume info.
2847  *      a_volID            : Volume ID for which we want the info.
2848  *      a_resultPP         : Ptr to the address of the area containing
2849  *                              the returned volume info.
2850  *
2851  * Returns:
2852  *      0 on success,
2853  *      Otherise, the return value of AFSVolXListOneVolume.
2854  *
2855  * Environment:
2856  *      This routine is closely related to UV_ListOneVolume, which returns
2857  *      only the standard level of detail on the chosen AFS volume.
2858  *
2859  * Side Effects:
2860  *      As advertised.
2861  *------------------------------------------------------------------------*/
2862
2863 int
2864 UV_XListOneVolume(struct rx_connection *server, afs_int32 a_partID,
2865                   afs_uint32 a_volID, struct volintXInfo **a_resultPP,
2866                   afs_status_p st)
2867 {
2868     int rc = 0;
2869     afs_status_t tst = 0;
2870     volXEntries volumeXInfo;    /*Area for returned info */
2871
2872     /*
2873      * Set the area we're in which we are returning
2874      * the info.  Setting the val field to a null pointer tells the stub
2875      * to allocate space for us.
2876      */
2877     *a_resultPP = (volintXInfo *) 0;
2878     volumeXInfo.volXEntries_val = (volintXInfo *) 0;
2879     volumeXInfo.volXEntries_len = 0;
2880
2881     tst = AFSVolXListOneVolume(server, a_partID, a_volID, &volumeXInfo);
2882
2883     if (tst) {
2884         goto fail_UV_XListOneVolume;
2885     } else {
2886         /*
2887          * We got the info; pull out the pointer to where the results lie.
2888          */
2889         *a_resultPP = volumeXInfo.volXEntries_val;
2890     }
2891     rc = 1;
2892
2893   fail_UV_XListOneVolume:
2894
2895     if (st != NULL) {
2896         *st = tst;
2897     }
2898     return rc;
2899
2900 }                               /*UV_XListOneVolume */
2901
2902 /*------------------------------------------------------------------------
2903  * EXPORTED UV_ListOneVolume
2904  *
2905  * Description:
2906  *      List the volume information for a volume on a particular File
2907  *      Server and partition.
2908  *
2909  * Arguments:
2910  *      server     : a handle to the server where the volume resides.
2911  *      a_partID           : Partition for which we want the extended
2912  *                              volume info.
2913  *      a_volID            : Volume ID for which we want the info.
2914  *      a_resultPP         : Ptr to the address of the area containing
2915  *                              the returned volume info.
2916  *
2917  * Returns:
2918  *      0 on success,
2919  *      Otherise, the return value of AFSVolXListOneVolume.
2920  *
2921  * Side Effects:
2922  *      As advertised.
2923  *------------------------------------------------------------------------*/
2924
2925 int UV_ListOneVolume(struct rx_connection *server, afs_int32 a_partID,
2926                   afs_uint32 a_volID, struct volintInfo **a_resultPP,
2927                   afs_status_p st)
2928 {
2929     int rc = 0;
2930     afs_status_t tst = 0;
2931     volEntries volumeInfo;      /*Area for returned info */
2932
2933     /*
2934      * Set the area we're in which we are returning
2935      * the info.  Setting the val field to a null pointer tells the stub
2936      * to allocate space for us.
2937      */
2938     *a_resultPP = (volintInfo *) 0;
2939     volumeInfo.volEntries_val = (volintInfo *) 0;
2940     volumeInfo.volEntries_len = 0;
2941
2942     tst = AFSVolListOneVolume(server, a_partID, a_volID, &volumeInfo);
2943
2944     if (tst) {
2945         goto fail_UV_ListOneVolume;
2946     } else {
2947         /*
2948          * We got the info; pull out the pointer to where the results lie.
2949          */
2950         *a_resultPP = volumeInfo.volEntries_val;
2951     }
2952     rc = 1;
2953
2954   fail_UV_ListOneVolume:
2955
2956     if (st != NULL) {
2957         *st = tst;
2958     }
2959     return rc;
2960 }/*UV_ListOneVolume*/
2961
2962 /*sync vldb with all the entries on <myQueue> on <aserver> and <apart>*/
2963 static afs_int32
2964 ProcessEntries(afs_cell_handle_p cellHandle, struct qHead *myQueue,
2965                struct rx_connection *server, afs_int32 apart, afs_int32 force)
2966 {
2967     struct aqueue elem;
2968     int success, temp;
2969     afs_uint32 temp2;
2970     afs_int32 vcode;
2971     afs_uint32 maxVolid = 0;
2972     struct nvldbentry entry;
2973     int noError = 1, error, same;
2974     int totalC, totalU, totalCE, totalUE, totalG;
2975     int counter;
2976     int aserver = ntohl(rx_HostOf(rx_PeerOf(server)));
2977     afs_status_t tst;
2978
2979     totalC = totalU = totalCE = totalUE = totalG = 0;
2980     counter = 0;
2981
2982     /* get the next  available id's from the vldb server */
2983     vcode = ubik_VL_GetNewVolumeId(cellHandle->vos, 0, 0, &maxVolid);
2984     if (vcode) {
2985         return (vcode);
2986     }
2987     totalG = myQueue->count;
2988     if (totalG == 0)
2989         return 0;
2990     while (1) {
2991         Lp_QEnumerate(myQueue, &success, &elem, 0);
2992         if (!success)
2993             break;
2994         counter++;
2995
2996         if (!elem.isValid[RWVOL] && !elem.isValid[ROVOL] && !elem.isValid[BACKVOL]) {   /*something is wrong with elem */
2997             noError = 0;
2998             continue;
2999         }
3000         if (maxVolid <= elem.ids[RWVOL]) {
3001             temp2 = elem.ids[RWVOL] - maxVolid + 1;
3002             maxVolid = 0;
3003             vcode = ubik_VL_GetNewVolumeId(cellHandle->vos, 0, temp2,
3004                                            &maxVolid);
3005             if (vcode)
3006                 return vcode;
3007
3008             maxVolid += temp2;
3009         }
3010         if (maxVolid <= elem.ids[ROVOL]) {
3011             temp2 = elem.ids[ROVOL] - maxVolid + 1;
3012             maxVolid = 0;
3013             vcode = ubik_VL_GetNewVolumeId(cellHandle->vos, 0, temp2,
3014                                            &maxVolid);
3015             if (vcode)
3016                 return vcode;
3017
3018             maxVolid += temp2;
3019         }
3020         if (maxVolid <= elem.ids[BACKVOL]) {
3021             temp2 = elem.ids[BACKVOL] - maxVolid + 1;
3022             maxVolid = 0;
3023             vcode = ubik_VL_GetNewVolumeId(cellHandle->vos, 0, temp2,
3024                                            &maxVolid);
3025             if (vcode)
3026                 return vcode;
3027
3028             maxVolid += temp2;
3029         }
3030         aVLDB_GetEntryByID(cellHandle, elem.ids[RWVOL], RWVOL, &entry, &tst);
3031         if (tst && (tst != VL_NOENT)) {
3032             noError = 0;
3033             totalCE++;
3034         } else if (tst && (tst == VL_NOENT)) {  /*entry doesnot exist */
3035             /*set up a vldb entry for elem */
3036             memset(&entry, 0, sizeof(entry));
3037             strncpy(entry.name, elem.name, VOLSER_OLDMAXVOLNAME);
3038             if (elem.isValid[RWVOL]) {  /*rw exists */
3039                 entry.flags |= RW_EXISTS;
3040                 entry.serverFlags[entry.nServers] = ITSRWVOL;
3041                 entry.serverNumber[entry.nServers] = aserver;
3042                 entry.serverPartition[entry.nServers] = apart;
3043                 entry.nServers += 1;
3044                 entry.volumeId[RWVOL] = elem.ids[RWVOL];
3045                 entry.volumeId[ROVOL] = elem.ids[ROVOL];
3046                 entry.volumeId[BACKVOL] = elem.ids[BACKVOL];
3047             }
3048             if (elem.isValid[ROVOL]) {  /*ro volume exists */
3049                 entry.flags |= RO_EXISTS;
3050                 entry.serverFlags[entry.nServers] = ITSROVOL;
3051                 entry.serverNumber[entry.nServers] = aserver;
3052                 entry.serverPartition[entry.nServers] = apart;
3053                 entry.nServers += 1;
3054                 entry.volumeId[RWVOL] = elem.ids[RWVOL];
3055                 entry.volumeId[ROVOL] = elem.ids[ROVOL];
3056
3057             }
3058             if (elem.isValid[BACKVOL]) {        /*backup volume exists */
3059                 entry.flags |= BACK_EXISTS;
3060                 if (!(entry.flags & RW_EXISTS)) {       /*this helps to check for a stray backup if parent moves */
3061                     entry.serverFlags[entry.nServers] = ITSRWVOL;
3062                     entry.serverNumber[entry.nServers] = aserver;
3063                     entry.serverPartition[entry.nServers] = apart;
3064                     entry.nServers += 1;
3065                 }
3066
3067                 entry.volumeId[RWVOL] = elem.ids[RWVOL];
3068                 entry.volumeId[BACKVOL] = elem.ids[BACKVOL];
3069
3070             }
3071             VLDB_CreateEntry(cellHandle, &entry, &tst);
3072             if (tst) {
3073                 noError = 0;
3074                 totalCE++;
3075             } else
3076                 totalC++;
3077         } else {                /* Update the existing entry */
3078             strncpy(entry.name, elem.name, VOLSER_OLDMAXVOLNAME);       /*the name Could have changed */
3079
3080             if (elem.isValid[RWVOL]) {  /* A RW volume */
3081                 temp = Lp_GetRwIndex(cellHandle, &entry, 0);
3082                 if (temp == -1) {
3083                     /* A RW index is not found in the VLDB entry - will add it */
3084
3085                     entry.flags |= RW_EXISTS;
3086                     entry.serverNumber[entry.nServers] = aserver;
3087                     entry.serverPartition[entry.nServers] = apart;
3088                     entry.serverFlags[entry.nServers] = ITSRWVOL;
3089                     entry.nServers++;
3090                 } else {
3091                     /* A RW index is found in the VLDB entry.
3092                      * Verify that the volume location matches the VLDB location.
3093                      * Fix the VLDB entry if it is not correct.
3094                      */
3095
3096                     error =
3097                         VLDB_IsSameAddrs(cellHandle, aserver,
3098                                          entry.serverNumber[temp], &same,
3099                                          &tst);
3100                     if (!error) {
3101                         continue;
3102                     }
3103                     if (!same || (apart != entry.serverPartition[temp])) {
3104                         /* VLDB says volume is in another place. Fix the VLDB entry */
3105                         entry.serverNumber[temp] = aserver;
3106                         entry.serverPartition[temp] = apart;
3107
3108                     }
3109                     entry.flags |= RW_EXISTS;
3110                 }
3111                 if ((elem.ids[BACKVOL] != 0) && elem.isValid[BACKVOL])
3112                     entry.volumeId[BACKVOL] = elem.ids[BACKVOL];
3113                 if ((elem.ids[ROVOL] != 0) && elem.isValid[ROVOL])
3114                     entry.volumeId[ROVOL] = elem.ids[ROVOL];
3115             }
3116
3117             if (elem.isValid[ROVOL]) {
3118                 /*tackle a ro volume */
3119
3120                 if (!Lp_ROMatch(cellHandle, &entry, aserver, apart, 0)) {
3121                     /*add this site */
3122                     if (elem.ids[ROVOL] > entry.volumeId[ROVOL]) {
3123                         /*there is a conflict of ids, keep the later volume */
3124                         /*delete all the ro volumes listed in vldb entry since they 
3125                          * are older */
3126
3127                         int j, count, rwsite;
3128
3129
3130                         count = entry.nServers;
3131                         rwsite = -1;
3132                         for (j = 0; j < count; j++) {
3133                             if (entry.serverFlags[j] & ITSROVOL) {
3134
3135                                 /*delete the site */
3136                                 entry.serverNumber[j] = 0;
3137                                 entry.serverPartition[j] = 0;
3138                                 entry.serverFlags[j] = 0;
3139
3140                             } else if (entry.serverFlags[j] & ITSRWVOL)
3141                                 rwsite = j;
3142                         }
3143                         entry.nServers = 0;
3144                         if (rwsite != -1) {
3145                             entry.serverNumber[entry.nServers] =
3146                                 entry.serverNumber[rwsite];
3147                             entry.serverPartition[entry.nServers] =
3148                                 entry.serverPartition[rwsite];
3149                             entry.serverFlags[entry.nServers] =
3150                                 entry.serverFlags[rwsite];
3151                             entry.nServers++;
3152                         }
3153                         entry.serverNumber[entry.nServers] = aserver;
3154                         entry.serverPartition[entry.nServers] = apart;
3155                         entry.serverFlags[entry.nServers] = ITSROVOL;
3156                         entry.nServers++;
3157                         entry.volumeId[ROVOL] = elem.ids[ROVOL];
3158                         entry.flags |= RO_EXISTS;
3159
3160                     } else if (elem.ids[ROVOL] < entry.volumeId[ROVOL]) {
3161                         if (!(entry.flags & RO_EXISTS)) {
3162                             entry.volumeId[ROVOL] = elem.ids[ROVOL];
3163                             entry.serverNumber[entry.nServers] = aserver;
3164                             entry.serverPartition[entry.nServers] = apart;
3165                             entry.serverFlags[entry.nServers] = ITSROVOL;
3166                             entry.nServers++;
3167                             entry.flags |= RO_EXISTS;
3168                         }
3169
3170                     }
3171
3172                     else if (elem.ids[ROVOL] == entry.volumeId[ROVOL]) {
3173                         entry.serverNumber[entry.nServers] = aserver;
3174                         entry.serverPartition[entry.nServers] = apart;
3175                         entry.serverFlags[entry.nServers] = ITSROVOL;
3176                         entry.nServers++;
3177                         entry.flags |= RO_EXISTS;
3178                         entry.volumeId[ROVOL] = elem.ids[ROVOL];
3179                     }
3180                 }
3181                 if (entry.volumeId[ROVOL] == INVALID_BID)
3182                     entry.volumeId[ROVOL] = elem.ids[ROVOL];
3183             }
3184
3185             if (elem.isValid[BACKVOL]) {
3186                 temp = Lp_GetRwIndex(cellHandle, &entry, 0);
3187                 if (temp != -1) {       /*check if existing backup site matches with the given arguments */
3188                     error =
3189                         VLDB_IsSameAddrs(cellHandle, aserver,
3190                                          entry.serverNumber[temp], &same,
3191                                          &tst);
3192                     if (!error) {
3193                         continue;
3194                     }
3195                 } else {
3196                     /*tackle the backup volume */
3197                     entry.volumeId[BACKVOL] = elem.ids[BACKVOL];
3198                     entry.flags |= BACK_EXISTS;
3199                 }
3200                 if (entry.volumeId[BACKVOL] == INVALID_BID)
3201                     entry.volumeId[BACKVOL] = elem.ids[BACKVOL];
3202             }
3203
3204             VLDB_ReplaceEntry(cellHandle, elem.ids[RWVOL], RWVOL, &entry,
3205                               LOCKREL_OPCODE | LOCKREL_AFSID |
3206                               LOCKREL_TIMESTAMP, &tst);
3207             if (tst) {
3208                 noError = 0;
3209                 totalUE++;
3210
3211                 vcode =
3212                     ubik_VL_ReleaseLock(cellHandle->vos, 0,
3213                               elem.ids[RWVOL], RWVOL,
3214                               LOCKREL_OPCODE | LOCKREL_AFSID |
3215                               LOCKREL_TIMESTAMP);
3216                 if (vcode) {
3217                     noError = 0;
3218                 }
3219             }
3220         }                       /* else update the existing entry */
3221
3222     }                           /* End of while(1) */
3223
3224     if (noError)
3225         return 0;
3226     else
3227         return VOLSERBADOP;
3228 }
3229
3230 /*synchronise vldb with the file server <aserver> and <apart>(if flags=1).
3231 *else synchronise with all the valid partitions on <aserver>
3232 */
3233 int
3234 UV_SyncVldb(afs_cell_handle_p cellHandle, struct rx_connection *server,
3235             afs_int32 apart, int flags, int force, afs_status_p st)
3236 {
3237     int rc = 0;
3238     afs_status_t tst = 0;
3239     afs_int32 count;
3240     int i;
3241     volEntries volumeInfo;
3242     volintInfo *pntr;
3243     struct qHead myQueue;
3244     struct partList PartList;
3245     int noError = 1;
3246     afs_int32 cnt;
3247     char pname[10];
3248
3249     /*this hints the stub to allocate space */
3250     volumeInfo.volEntries_val = (volintInfo *) 0;
3251     volumeInfo.volEntries_len = 0;
3252
3253     if (!flags) {               /*generate all the valid partitions */
3254         UV_ListPartitions(server, &PartList, &cnt, &tst);
3255         if (tst) {
3256             goto fail_UV_SyncVldb;
3257         }
3258     } else {
3259         PartList.partId[0] = apart;
3260         cnt = 1;
3261     }
3262
3263     for (i = 0; i < cnt; i++) {
3264         apart = PartList.partId[i];
3265         /*this hints the stub to allocate space */
3266         volumeInfo.volEntries_val = (volintInfo *) 0;
3267         volumeInfo.volEntries_len = 0;
3268         tst = AFSVolListVolumes(server, apart, 1, &volumeInfo);
3269         if (tst) {
3270             goto fail_UV_SyncVldb;
3271         }
3272         count = volumeInfo.volEntries_len;
3273         pntr = volumeInfo.volEntries_val;
3274
3275         if (!vos_PartitionIdToName(apart, pname, &tst)) {
3276             goto fail_UV_SyncVldb;
3277         }
3278         /*collect all vol entries by their parentid */
3279         tst = GroupEntries(server, pntr, count, &myQueue, apart);
3280         if (tst) {
3281             noError = 0;
3282             if (volumeInfo.volEntries_val) {
3283                 /*free the space allocated by the stub */
3284                 free(volumeInfo.volEntries_val);
3285                 volumeInfo.volEntries_val = 0;
3286             }
3287             continue;
3288         }
3289         tst = ProcessEntries(cellHandle, &myQueue, server, apart, force);
3290         if (tst) {
3291             tst = VOLSERFAILEDOP;
3292             if (volumeInfo.volEntries_val) {
3293                 /*free the space allocated by the stub */
3294                 free(volumeInfo.volEntries_val);
3295                 volumeInfo.volEntries_val = 0;
3296             }
3297             continue;
3298         }
3299         if (noError)
3300             tst = 0;
3301         else
3302             tst = VOLSERFAILEDOP;
3303     }                           /* thru all partitions */
3304     rc = 1;
3305
3306   fail_UV_SyncVldb:
3307
3308     if (volumeInfo.volEntries_val)
3309         free(volumeInfo.volEntries_val);
3310
3311     if (tst != 0) {
3312         rc = 0;
3313     }
3314
3315     if (st != NULL) {
3316         *st = tst;
3317     }
3318     return rc;
3319 }
3320
3321 static afs_int32
3322 CheckVldbRWBK(afs_cell_handle_p cellHandle, struct nvldbentry *entry,
3323               afs_int32 * modified, afs_status_p st)
3324 {
3325     int rc = 0;
3326     afs_status_t tst = 0;
3327     int modentry = 0;
3328     int idx;
3329
3330     if (modified)
3331         *modified = 0;
3332     idx = Lp_GetRwIndex(cellHandle, entry, 0);
3333
3334     /* Check to see if the RW volume exists and set the RW_EXISTS
3335      * flag accordingly.
3336      */
3337     if (idx == -1) {            /* Did not find a RW entry */
3338         if (entry->flags & RW_EXISTS) { /* ... yet entry says RW exists */
3339             entry->flags &= ~RW_EXISTS; /* ... so say RW does not exist */
3340             modentry++;
3341         }
3342     } else {
3343         if (VolumeExists
3344             (cellHandle, entry->serverNumber[idx],
3345              entry->serverPartition[idx], entry->volumeId[RWVOL], &tst)) {
3346             if (!(entry->flags & RW_EXISTS)) {  /* ... yet entry says RW does no
3347                                                  * t exist */
3348                 entry->flags |= RW_EXISTS;      /* ... so say RW does exist */
3349                 modentry++;
3350             }
3351         } else if (tst == ENODEV) {     /* RW volume does not exist */
3352             if (entry->flags & RW_EXISTS) {     /* ... yet entry says RW exists
3353                                                  */
3354                 entry->flags &= ~RW_EXISTS;     /* ... so say RW does not exist
3355                                                  */
3356                 modentry++;
3357             }
3358         } else {
3359             /* If VLDB says it didn't exist, then ignore error */
3360             if (entry->flags & RW_EXISTS) {
3361                 goto fail_CheckVldbRWBK;
3362             }
3363         }
3364     }
3365
3366     /* Check to see if the BK volume exists and set the BACK_EXISTS
3367      * flag accordingly. idx already ponts to the RW entry.
3368      */
3369     if (idx == -1) {            /* Did not find a RW entry */
3370         if (entry->flags & BACK_EXISTS) {       /* ... yet entry says BK exists */
3371             entry->flags &= ~BACK_EXISTS;       /* ... so say BK does not exist */
3372             modentry++;
3373         }
3374     } else {                    /* Found a RW entry */
3375         if (VolumeExists
3376             (cellHandle, entry->serverNumber[idx],
3377              entry->serverPartition[idx], entry->volumeId[BACKVOL], &tst)) {
3378             if (!(entry->flags & BACK_EXISTS)) {        /* ... yet entry says BK does n
3379                                                          * ot exist */
3380                 entry->flags |= BACK_EXISTS;    /* ... so say BK does exist */
3381                 modentry++;
3382             }
3383         } else if (tst == ENODEV) {     /* BK volume does not exist */
3384             if (entry->flags & BACK_EXISTS) {   /* ... yet entry says BK exists
3385                                                  */
3386                 entry->flags &= ~BACK_EXISTS;   /* ... so say BK does not exist
3387                                                  */
3388                 modentry++;
3389             }
3390         } else {
3391             /* If VLDB says it didn't exist, then ignore error */
3392             if (entry->flags & BACK_EXISTS) {
3393                 goto fail_CheckVldbRWBK;
3394             }
3395         }
3396     }
3397
3398     /* If there is an idx but the BK and RW volumes no
3399      * longer exist, then remove the RW entry.
3400      */
3401     if ((idx != -1) && !(entry->flags & RW_EXISTS)
3402         && !(entry->flags & BACK_EXISTS)) {
3403         Lp_SetRWValue(cellHandle, entry, entry->serverNumber[idx],
3404                       entry->serverPartition[idx], 0L, 0L);
3405         entry->nServers--;
3406         modentry++;
3407     }
3408     rc = 1;
3409
3410   fail_CheckVldbRWBK:
3411
3412     if (modified)
3413         *modified = modentry;
3414
3415     if (st != NULL) {
3416         *st = tst;
3417     }
3418     return rc;
3419 }
3420
3421
3422 static int
3423 CheckVldbRO(afs_cell_handle_p cellHandle, struct nvldbentry *entry,
3424             afs_int32 * modified, afs_status_p st)
3425 {
3426     int rc = 0;
3427     afs_status_t tst = 0;
3428     int idx;
3429     int foundro = 0, modentry = 0;
3430
3431     if (modified)
3432         *modified = 0;
3433
3434     /* Check to see if the RO volumes exist and set the RO_EXISTS
3435      * flag accordingly.
3436      */
3437     for (idx = 0; idx < entry->nServers; idx++) {
3438         if (!(entry->serverFlags[idx] & ITSROVOL)) {
3439             continue;           /* not a RO */
3440         }
3441
3442         if (VolumeExists
3443             (cellHandle, entry->serverNumber[idx],
3444              entry->serverPartition[idx], entry->volumeId[ROVOL], &tst)) {
3445             foundro++;
3446         } else if (tst == ENODEV) {     /* RW volume does not exist */
3447             Lp_SetROValue(cellHandle, entry, entry->serverNumber[idx],
3448                           entry->serverPartition[idx], 0L, 0L);
3449             entry->nServers--;
3450             idx--;
3451             modentry++;
3452         } else {
3453             goto fail_CheckVldbRO;
3454         }
3455     }
3456
3457     if (foundro) {              /* A RO volume exists */
3458         if (!(entry->flags & RO_EXISTS)) {      /* ... yet entry says RW does not e
3459                                                  * xist */
3460             entry->flags |= RO_EXISTS;  /* ... so say RW does exist */
3461             modentry++;
3462         }
3463     } else {                    /* A RO volume does not exist */
3464         if (entry->flags & RO_EXISTS) { /* ... yet entry says RO exists */
3465             entry->flags &= ~RO_EXISTS; /* ... so say RO does not exist */
3466             modentry++;
3467         }
3468     }
3469     rc = 1;
3470
3471   fail_CheckVldbRO:
3472
3473     if (modified)
3474         *modified = modentry;
3475
3476     if (st != NULL) {
3477         *st = tst;
3478     }
3479     return rc;
3480 }
3481
3482 /*ensure that <entry> matches with the info on file servers */
3483 int
3484 CheckVldb(afs_cell_handle_p cellHandle, struct nvldbentry *entry,
3485           afs_int32 * modified, afs_status_p st)
3486 {
3487     int rc = 0;
3488     afs_status_t tst = 0;
3489     afs_int32 vcode;
3490     int islocked = 0;
3491     int pass = 0;
3492     afs_int32 modentry = 0;
3493
3494     if (modified) {
3495         *modified = 0;
3496     }
3497
3498     if (strlen(entry->name) > (VOLSER_OLDMAXVOLNAME - 10)) {
3499         tst = VOLSERBADOP;
3500         goto fail_CheckVldb;
3501     }
3502
3503   retry:
3504
3505     /* Check to see if the VLDB is ok without locking it (pass 1).
3506      * If it will change, then lock the VLDB entry, read it again,
3507      * then make the changes to it (pass 2).
3508      */
3509     if (++pass == 2) {
3510         tst =
3511             ubik_VL_SetLock(cellHandle->vos, 0, entry->volumeId[RWVOL],
3512                       RWVOL, VLOP_DELETE);
3513         if (tst) {
3514             goto fail_CheckVldb;
3515         }
3516         islocked = 1;
3517
3518         if (!aVLDB_GetEntryByID
3519             (cellHandle, entry->volumeId[RWVOL], RWVOL, entry, &tst)) {
3520             goto fail_CheckVldb;
3521         }
3522     }
3523
3524     modentry = 0;
3525
3526     /* Check if the RW and BK entries are ok */
3527     if (!CheckVldbRWBK(cellHandle, entry, &modentry, &tst)) {
3528         goto fail_CheckVldb;
3529     }
3530     if (modentry && (pass == 1))
3531         goto retry;
3532
3533     /* Check if the RO volumes entries are ok */
3534     if (!CheckVldbRO(cellHandle, entry, &modentry, &tst)) {
3535         goto fail_CheckVldb;
3536     }
3537     if (modentry && (pass == 1))
3538         goto retry;