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