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