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