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