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