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