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