03ba43ca4c97311b2fad15419e3bbd6227a925ac
[openafs.git] / src / volser / 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 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 RCSID
14     ("$Header$");
15
16 #include <stdio.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <string.h>
20 #ifdef  AFS_AIX_ENV
21 #include <sys/statfs.h>
22 #endif
23 #ifdef AFS_NT40_ENV
24 #include <fcntl.h>
25 #include <winsock2.h>
26 #else
27 #include <sys/file.h>
28 #include <netinet/in.h>
29 #endif
30
31 #include <lock.h>
32 #include <afs/voldefs.h>
33 #include <rx/xdr.h>
34 #include <rx/rx.h>
35 #include <afs/vlserver.h>
36 #include <afs/nfs.h>
37 #include <afs/cellconfig.h>
38 #include <afs/keys.h>
39 #include <ubik.h>
40 #include <afs/afsint.h>
41 #include "volser.h"
42 #include "volint.h"
43 #include "lockdata.h"
44 #include <afs/com_err.h>
45 #include <rx/rxkad.h>
46 #include <afs/kautils.h>
47 #include <afs/cmd.h>
48 #include <errno.h>
49 #define ERRCODE_RANGE 8         /* from error_table.h */
50 #define CLOCKSKEW   2           /* not really skew, but resolution */
51 #define CLOCKADJ(x) (((x) < CLOCKSKEW) ? 0 : (x) - CLOCKSKEW)
52
53 /* for UV_MoveVolume() recovery */
54
55 #include <afs/procmgmt.h>       /* signal(), kill(), wait(), etc. */
56 #include <setjmp.h>
57
58 #include "volser_prototypes.h"
59 #include "vsutils_prototypes.h"
60 #include "lockprocs_prototypes.h"
61
62 struct ubik_client *cstruct;
63 int verbose = 0, noresolve = 0;
64
65 struct release {
66     afs_uint32 crtime;
67     afs_uint32 uptime;
68     afs_int32 vldbEntryIndex;
69 };
70
71 /* Utility macros used by rest of this source file */
72 #define EPRINT(ec, es) \
73 do { \
74         fprintf(STDERR, "\n"); \
75         fprintf(STDERR, (es)); \
76         PrintError("   ",ec); \
77 } while (0)
78
79 #define EPRINT1(ec, es, ep1) \
80 do { \
81         fprintf(STDERR, "\n"); \
82         fprintf(STDERR, (es), (ep1)); \
83         PrintError("   ",ec); \
84 } while (0)
85
86 #define EPRINT2(ec, es, ep1, ep2) \
87 do { \
88         fprintf(STDERR, "\n"); \
89         fprintf(STDERR, (es), (ep1), (ep2)); \
90         PrintError("   ",ec); \
91 } while (0)
92
93 #define EPRINT3(ec, es, ep1, ep2, ep3) \
94 do { \
95         fprintf(STDERR, "\n"); \
96         fprintf(STDERR, (es), (ep1), (ep2), (ep3)); \
97         PrintError("   ",ec); \
98 } while (0)
99
100 #define EGOTO(where, ec, es) \
101 do { \
102         if (ec) { \
103                 EPRINT((ec),(es)); \
104                 error = (ec); \
105                 goto where; \
106         } \
107 } while (0)
108
109 #define EGOTO1(where, ec, es, ep1) \
110 do { \
111         if (ec) { \
112                 EPRINT1((ec),(es),(ep1)); \
113                 error = (ec); \
114                 goto where; \
115         } \
116 } while (0)
117
118 #define EGOTO2(where, ec, es, ep1, ep2) \
119 do { \
120         if (ec) { \
121                 EPRINT2((ec),(es),(ep1),(ep2)); \
122                 error = (ec); \
123                 goto where; \
124         } \
125 } while (0)
126
127 #define EGOTO3(where, ec, es, ep1, ep2, ep3) \
128 do { \
129         if (ec) { \
130                 EPRINT3((ec),(es),(ep1),(ep2),(ep3)); \
131                 error = (ec); \
132                 goto where; \
133         } \
134 } while (0)
135
136 #define VPRINT(es) \
137         { if (verbose) { fprintf(STDOUT, (es)); fflush(STDOUT); } }
138 #define VPRINT1(es, p) \
139         { if (verbose) { fprintf(STDOUT, (es), (p)); fflush(STDOUT); } }
140 #define VPRINT2(es, p1, p2) \
141         { if (verbose) { fprintf(STDOUT, (es), (p1), (p2)); fflush(STDOUT); } }
142 #define VPRINT3(es, p1, p2, p3) \
143         { if (verbose) { fprintf(STDOUT, (es), (p1), (p2), (p3)); fflush(STDOUT); } }
144 #define VDONE \
145         { if (verbose) { fprintf(STDOUT, " done\n"); fflush(STDOUT); } }
146 #define VEPRINT(es) \
147         { if (verbose) { fprintf(STDERR, (es)); fflush(STDERR); } }
148 #define VEPRINT1(es, p) \
149         { if (verbose) { fprintf(STDERR, (es), (p)); fflush(STDERR); } }
150 #define VEPRINT2(es, p1, p2) \
151         { if (verbose) { fprintf(STDERR, (es), (p1), (p2)); fflush(STDERR); } }
152 #define VEPRINT3(es, p1, p2, p3) \
153         { if (verbose) { fprintf(STDERR, (es), (p1), (p2), (p3)); fflush(STDERR); } }
154 #define VEDONE \
155         { if (verbose) { fprintf(STDERR, " done\n"); fflush(STDERR); } }
156
157
158
159 /* getting rid of this */
160 #define ERROR_EXIT(code) {error=(code); goto error_exit;}
161
162
163 /* Protos for static routines */
164 static afs_int32 CheckAndDeleteVolume(struct rx_connection *aconn,
165                                       afs_int32 apart, afs_uint32 okvol,
166                                       afs_uint32 delvol);
167 static int DelVol(struct rx_connection *conn, afs_uint32 vid, afs_int32 part,
168                   afs_int32 flags);
169 static int GetTrans(struct nvldbentry *vldbEntryPtr, afs_int32 index,
170                     struct rx_connection **connPtr, afs_int32 * transPtr,
171                     afs_int32 * crtimePtr, afs_int32 * uptimePtr);
172 static int SimulateForwardMultiple(struct rx_connection *fromconn,
173                                    afs_int32 fromtid, afs_int32 fromdate,
174                                    manyDests * tr, afs_int32 flags,
175                                    void *cookie, manyResults * results);
176 static afs_int32 CheckVolume(volintInfo * volumeinfo, afs_int32 aserver,
177                              afs_int32 apart, afs_int32 * modentry,
178                              afs_uint32 * maxvolid);
179
180
181 /*map the partition <partId> into partition name <partName>*/
182 void
183 MapPartIdIntoName(afs_int32 partId, char *partName)
184 {
185     if (partId < 26) {          /* what if partId > = 26 ? */
186         strcpy(partName, "/vicep");
187         partName[6] = partId + 'a';
188         partName[7] = '\0';
189         return;
190     } else if (partId < VOLMAXPARTS) {
191         strcpy(partName, "/vicep");
192         partId -= 26;
193         partName[6] = 'a' + (partId / 26);
194         partName[7] = 'a' + (partId % 26);
195         partName[8] = '\0';
196         return;
197     }
198 }
199
200 int
201 yesprompt(char *str)
202 {
203     int response, c;
204     int code;
205
206     fprintf(STDERR, "Do you want to %s? [yn](n): ", str);
207     response = c = getchar();
208     while (!(c == EOF || c == '\n'))
209         c = getchar();          /*skip to end of line */
210     code = (response == 'y' || response == 'Y');
211     return code;
212 }
213
214
215 int
216 PrintError(char *msg, afs_int32 errcode)
217 {
218     fprintf(STDERR, msg);
219     /*replace by a big switch statement */
220     switch (errcode) {
221     case 0:
222         break;
223     case -1:
224         fprintf(STDERR, "Possible communication failure\n");
225         break;
226     case VSALVAGE:
227         fprintf(STDERR, "Volume needs to be salvaged\n");
228         break;
229     case VNOVNODE:
230         fprintf(STDERR, "Bad vnode number quoted\n");
231         break;
232     case VNOVOL:
233         fprintf(STDERR,
234                 "Volume not attached, does not exist, or not on line\n");
235         break;
236     case VVOLEXISTS:
237         fprintf(STDERR, "Volume already exists\n");
238         break;
239     case VNOSERVICE:
240         fprintf(STDERR, "Volume is not in service\n");
241         break;
242     case VOFFLINE:
243         fprintf(STDERR, "Volume is off line\n");
244         break;
245     case VONLINE:
246         fprintf(STDERR, "Volume is already on line\n");
247         break;
248     case VDISKFULL:
249         fprintf(STDERR, "Partition is full\n");
250         break;
251     case VOVERQUOTA:
252         fprintf(STDERR, "Volume max quota exceeded\n");
253         break;
254     case VBUSY:
255         fprintf(STDERR, "Volume temporarily unavailable\n");
256         break;
257     case VMOVED:
258         fprintf(STDERR, "Volume has moved to another server\n");
259         break;
260     case VL_IDEXIST:
261         fprintf(STDERR, "VLDB: volume Id exists in the vldb\n");
262         break;
263     case VL_IO:
264         fprintf(STDERR, "VLDB: a read terminated too early\n");
265         break;
266     case VL_NAMEEXIST:
267         fprintf(STDERR, "VLDB: volume entry exists in the vldb\n");
268         break;
269     case VL_CREATEFAIL:
270         fprintf(STDERR, "VLDB: internal creation failure\n");
271         break;
272     case VL_NOENT:
273         fprintf(STDERR, "VLDB: no such entry\n");
274         break;
275     case VL_EMPTY:
276         fprintf(STDERR, "VLDB: vldb database is empty\n");
277         break;
278     case VL_ENTDELETED:
279         fprintf(STDERR, "VLDB: entry is deleted (soft delete)\n");
280         break;
281     case VL_BADNAME:
282         fprintf(STDERR, "VLDB: volume name is illegal\n");
283         break;
284     case VL_BADINDEX:
285         fprintf(STDERR, "VLDB: index was out of range\n");
286         break;
287     case VL_BADVOLTYPE:
288         fprintf(STDERR, "VLDB: bad volume type\n");
289         break;
290     case VL_BADSERVER:
291         fprintf(STDERR, "VLDB: illegal server number (not within limits)\n");
292         break;
293     case VL_BADPARTITION:
294         fprintf(STDERR, "VLDB: bad partition number\n");
295         break;
296     case VL_REPSFULL:
297         fprintf(STDERR, "VLDB: run out of space for replication sites\n");
298         break;
299     case VL_NOREPSERVER:
300         fprintf(STDERR, "VLDB: no such repsite server exists\n");
301         break;
302     case VL_DUPREPSERVER:
303         fprintf(STDERR, "VLDB: replication site server already exists\n");
304         break;
305     case VL_RWNOTFOUND:
306         fprintf(STDERR, "VLDB: parent r/w entry not found\n");
307         break;
308     case VL_BADREFCOUNT:
309         fprintf(STDERR, "VLDB: illegal reference count number\n");
310         break;
311     case VL_SIZEEXCEEDED:
312         fprintf(STDERR, "VLDB: vldb size for attributes exceeded\n");
313         break;
314     case VL_BADENTRY:
315         fprintf(STDERR, "VLDB: bad incoming vldb entry\n");
316         break;
317     case VL_BADVOLIDBUMP:
318         fprintf(STDERR, "VLDB: illegal max volid increment\n");
319         break;
320     case VL_IDALREADYHASHED:
321         fprintf(STDERR, "VLDB: (RO/BACK) Id already hashed\n");
322         break;
323     case VL_ENTRYLOCKED:
324         fprintf(STDERR, "VLDB: vldb entry is already locked\n");
325         break;
326     case VL_BADVOLOPER:
327         fprintf(STDERR, "VLDB: bad volume operation code\n");
328         break;
329     case VL_BADRELLOCKTYPE:
330         fprintf(STDERR, "VLDB: bad release lock type\n");
331         break;
332     case VL_RERELEASE:
333         fprintf(STDERR, "VLDB: status report: last release was aborted\n");
334         break;
335     case VL_BADSERVERFLAG:
336         fprintf(STDERR, "VLDB: invalid replication site server flag\n");
337         break;
338     case VL_PERM:
339         fprintf(STDERR, "VLDB: no permission access for call\n");
340         break;
341     case VOLSERREAD_DUMPERROR:
342         fprintf(STDERR,
343                 "VOLSER:  Problems encountered in reading the dump file !\n");
344         break;
345     case VOLSERDUMPERROR:
346         fprintf(STDERR, "VOLSER: Problems encountered in doing the dump !\n");
347         break;
348     case VOLSERATTACH_ERROR:
349         fprintf(STDERR, "VOLSER: Could not attach the volume\n");
350         break;
351     case VOLSERDETACH_ERROR:
352         fprintf(STDERR, "VOLSER: Could not detach the volume\n");
353         break;
354     case VOLSERILLEGAL_PARTITION:
355         fprintf(STDERR, "VOLSER: encountered illegal partition number\n");
356         break;
357     case VOLSERBAD_ACCESS:
358         fprintf(STDERR, "VOLSER: permission denied, not a super user\n");
359         break;
360     case VOLSERVLDB_ERROR:
361         fprintf(STDERR, "VOLSER: error detected in the VLDB\n");
362         break;
363     case VOLSERBADNAME:
364         fprintf(STDERR, "VOLSER: error in volume name\n");
365         break;
366     case VOLSERVOLMOVED:
367         fprintf(STDERR, "VOLSER: volume has moved\n");
368         break;
369     case VOLSERBADOP:
370         fprintf(STDERR, "VOLSER: illegal operation\n");
371         break;
372     case VOLSERBADRELEASE:
373         fprintf(STDERR, "VOLSER: release could not be completed\n");
374         break;
375     case VOLSERVOLBUSY:
376         fprintf(STDERR, "VOLSER: volume is busy\n");
377         break;
378     case VOLSERNO_MEMORY:
379         fprintf(STDERR, "VOLSER: volume server is out of memory\n");
380         break;
381     case VOLSERNOVOL:
382         fprintf(STDERR,
383                 "VOLSER: no such volume - location specified incorrectly or volume does not exist\n");
384         break;
385     case VOLSERMULTIRWVOL:
386         fprintf(STDERR,
387                 "VOLSER: multiple RW volumes with same ID, one of which should be deleted\n");
388         break;
389     case VOLSERFAILEDOP:
390         fprintf(STDERR,
391                 "VOLSER: not all entries were successfully processed\n");
392         break;
393     default:
394         {
395
396             afs_int32 offset;
397
398             initialize_KA_error_table();
399             initialize_RXK_error_table();
400             initialize_KTC_error_table();
401             initialize_ACFG_error_table();
402             initialize_CMD_error_table();
403             initialize_VL_error_table();
404
405             offset = errcode & ((1 << ERRCODE_RANGE) - 1);
406             fprintf(STDERR, "%s: %s\n", afs_error_table_name(errcode),
407                     afs_error_message(errcode));
408             break;
409         }
410     }
411     return 0;
412 }
413
414 void init_volintInfo(struct volintInfo *vinfo) {
415     memset(vinfo, 0, sizeof(struct volintInfo));
416
417     vinfo->maxquota = -1;
418     vinfo->dayUse = -1;
419     vinfo->creationDate = -1;
420     vinfo->updateDate = -1;
421     vinfo->flags = -1;
422     vinfo->spare0 = -1;
423     vinfo->spare1 = -1;
424     vinfo->spare2 = -1;
425     vinfo->spare3 = -1;
426 }
427
428 static struct rx_securityClass *uvclass = 0;
429 static int uvindex = -1;
430 /* called by VLDBClient_Init to set the security module to be used in the RPC */
431 int
432 UV_SetSecurity(register struct rx_securityClass *as, afs_int32 aindex)
433 {
434     uvindex = aindex;
435     uvclass = as;
436     return 0;
437 }
438
439 /* bind to volser on <port> <aserver> */
440 /* takes server address in network order, port in host order.  dumb */
441 struct rx_connection *
442 UV_Bind(afs_int32 aserver, afs_int32 port)
443 {
444     register struct rx_connection *tc;
445
446     tc = rx_NewConnection(aserver, htons(port), VOLSERVICE_ID, uvclass,
447                           uvindex);
448     return tc;
449 }
450
451 static int 
452 AFSVolCreateVolume_retry(struct rx_connection *z_conn,
453                        afs_int32 partition, char *name, afs_int32 type,
454                        afs_int32 parent, afs_int32 *volid, afs_int32 *trans)
455 {
456     afs_int32 code;
457     int retries = 3;
458     while (retries) {
459         code = AFSVolCreateVolume(z_conn, partition, name, type, parent,
460                                   volid, trans);
461         if (code != VOLSERVOLBUSY)
462             break;
463         retries--;
464 #ifdef AFS_PTHREAD_ENV
465         sleep(3-retries);
466 #else
467         IOMGR_Sleep(3-retries);
468 #endif
469     }
470     return code;
471 }
472
473 static int 
474 AFSVolTransCreate_retry(struct rx_connection *z_conn,
475                         afs_int32 volume, afs_int32 partition, 
476                         afs_int32 flags, afs_int32 * trans) 
477 {
478     afs_int32 code;
479     int retries = 3;
480     while (retries) {
481         code = AFSVolTransCreate(z_conn, volume, partition, flags, trans);
482         if (code != VOLSERVOLBUSY)
483             break;
484         retries--;
485 #ifdef AFS_PTHREAD_ENV
486         sleep(3-retries);
487 #else
488         IOMGR_Sleep(3-retries);
489 #endif
490     }
491     return code;
492 }
493
494 /* if <okvol> is allright(indicated by beibg able to
495  * start a transaction, delete the <delvol> */
496 static afs_int32
497 CheckAndDeleteVolume(struct rx_connection *aconn, afs_int32 apart,
498                      afs_uint32 okvol, afs_uint32 delvol)
499 {
500     afs_int32 error, code, tid, rcode;
501     error = 0;
502     code = 0;
503
504     if (okvol == 0) {
505         code = AFSVolTransCreate_retry(aconn, delvol, apart, ITOffline, &tid);
506         if (!error && code)
507             error = code;
508         code = AFSVolDeleteVolume(aconn, tid);
509         if (!error && code)
510             error = code;
511         code = AFSVolEndTrans(aconn, tid, &rcode);
512         if (!code)
513             code = rcode;
514         if (!error && code)
515             error = code;
516         return error;
517     } else {
518         code = AFSVolTransCreate_retry(aconn, okvol, apart, ITOffline, &tid);
519         if (!code) {
520             code = AFSVolEndTrans(aconn, tid, &rcode);
521             if (!code)
522                 code = rcode;
523             if (!error && code)
524                 error = code;
525             code = AFSVolTransCreate_retry(aconn, delvol, apart, ITOffline, &tid);
526             if (!error && code)
527                 error = code;
528             code = AFSVolDeleteVolume(aconn, tid);
529             if (!error && code)
530                 error = code;
531             code = AFSVolEndTrans(aconn, tid, &rcode);
532             if (!code)
533                 code = rcode;
534             if (!error && code)
535                 error = code;
536         } else
537             error = code;
538         return error;
539     }
540 }
541
542 /* called by EmuerateEntry, show vldb entry in a reasonable format */
543 void
544 SubEnumerateEntry(struct nvldbentry *entry)
545 {
546     int i;
547     char pname[10];
548     int isMixed = 0;
549     char hoststr[16];
550
551 #ifdef notdef
552     fprintf(STDOUT, "   readWriteID %-10u ", entry->volumeId[RWVOL]);
553     if (entry->flags & RW_EXISTS)
554         fprintf(STDOUT, " valid \n");
555     else
556         fprintf(STDOUT, " invalid \n");
557     fprintf(STDOUT, "   readOnlyID  %-10u ", entry->volumeId[ROVOL]);
558     if (entry->flags & RO_EXISTS)
559         fprintf(STDOUT, " valid \n");
560     else
561         fprintf(STDOUT, " invalid \n");
562     fprintf(STDOUT, "   backUpID    %-10u ", entry->volumeId[BACKVOL]);
563     if (entry->flags & BACK_EXISTS)
564         fprintf(STDOUT, " valid \n");
565     else
566         fprintf(STDOUT, " invalid \n");
567     if ((entry->cloneId != 0) && (entry->flags & RO_EXISTS))
568         fprintf(STDOUT, "    releaseClone %-10u \n", entry->cloneId);
569 #else
570     if (entry->flags & RW_EXISTS)
571         fprintf(STDOUT, "    RWrite: %-10u", entry->volumeId[RWVOL]);
572     if (entry->flags & RO_EXISTS)
573         fprintf(STDOUT, "    ROnly: %-10u", entry->volumeId[ROVOL]);
574     if (entry->flags & BACK_EXISTS)
575         fprintf(STDOUT, "    Backup: %-10u", entry->volumeId[BACKVOL]);
576     if ((entry->cloneId != 0) && (entry->flags & RO_EXISTS))
577         fprintf(STDOUT, "    RClone: %-10lu", (unsigned long)entry->cloneId);
578     fprintf(STDOUT, "\n");
579 #endif
580     fprintf(STDOUT, "    number of sites -> %lu\n",
581             (unsigned long)entry->nServers);
582     for (i = 0; i < entry->nServers; i++) {
583         if (entry->serverFlags[i] & NEW_REPSITE)
584             isMixed = 1;
585     }
586     for (i = 0; i < entry->nServers; i++) {
587         MapPartIdIntoName(entry->serverPartition[i], pname);
588         fprintf(STDOUT, "       server %s partition %s ",
589                 noresolve ? afs_inet_ntoa_r(entry->serverNumber[i], hoststr) : 
590                 hostutil_GetNameByINet(entry->serverNumber[i]), pname);
591         if (entry->serverFlags[i] & ITSRWVOL)
592             fprintf(STDOUT, "RW Site ");
593         else
594             fprintf(STDOUT, "RO Site ");
595         if (isMixed) {
596             if (entry->serverFlags[i] & NEW_REPSITE)
597                 fprintf(STDOUT," -- New release");
598             else
599                 if (!(entry->serverFlags[i] & ITSRWVOL))
600                     fprintf(STDOUT," -- Old release");
601         } else {
602             if (entry->serverFlags[i] & RO_DONTUSE)
603                 fprintf(STDOUT, " -- Not released");
604         }
605         fprintf(STDOUT, "\n");
606     }
607
608     return;
609
610 }
611
612 /*enumerate the vldb entry corresponding to <entry> */
613 void
614 EnumerateEntry(struct nvldbentry *entry)
615 {
616
617     fprintf(STDOUT, "\n");
618     fprintf(STDOUT, "%s \n", entry->name);
619     SubEnumerateEntry(entry);
620     return;
621 }
622
623 /* forcibly remove a volume.  Very dangerous call */
624 int
625 UV_NukeVolume(afs_int32 server, afs_int32 partid, afs_uint32 volid)
626 {
627     register struct rx_connection *tconn;
628     register afs_int32 code;
629
630     tconn = UV_Bind(server, AFSCONF_VOLUMEPORT);
631     if (tconn) {
632         code = AFSVolNukeVolume(tconn, partid, volid);
633         rx_DestroyConnection(tconn);
634     } else
635         code = 0;
636     return code;
637 }
638
639 /* like df. Return usage of <pname> on <server> in <partition> */
640 int
641 UV_PartitionInfo64(afs_int32 server, char *pname,
642                    struct diskPartition64 *partition)
643 {
644     register struct rx_connection *aconn;
645     afs_int32 code = 0;
646
647     aconn = (struct rx_connection *)0;
648     aconn = UV_Bind(server, AFSCONF_VOLUMEPORT);
649     code = AFSVolPartitionInfo64(aconn, pname, partition);
650     if (code == RXGEN_OPCODE) {
651         struct diskPartition *dpp = 
652             (struct diskPartition *)malloc(sizeof(struct diskPartition));
653         code = AFSVolPartitionInfo(aconn, pname, dpp);
654         if (!code) {
655             strncpy(partition->name, dpp->name, 32);
656             strncpy(partition->devName, dpp->devName, 32);
657             partition->lock_fd = dpp->lock_fd;
658             partition->free = dpp->free;
659             partition->minFree = dpp->minFree;
660         }
661         free(dpp);
662     } 
663     if (code) {
664         fprintf(STDERR, "Could not get information on partition %s\n", pname);
665         PrintError("", code);
666     }
667     if (aconn)
668         rx_DestroyConnection(aconn);
669     return code;
670 }
671
672 /* old interface to create volume */
673 int
674 UV_CreateVolume(afs_int32 aserver, afs_int32 apart, char *aname,
675                 afs_uint32 * anewid)
676 {
677     afs_int32 code;
678     code = UV_CreateVolume2(aserver, apart, aname, 5000, 0, 0, 0, 0, anewid);
679     return code;
680 }
681
682 /* create a volume, given a server, partition number, volume name --> sends
683 * back new vol id in <anewid>*/
684 int
685 UV_CreateVolume2(afs_int32 aserver, afs_int32 apart, char *aname,
686                  afs_int32 aquota, afs_int32 aspare1, afs_int32 aspare2,
687                  afs_int32 aspare3, afs_int32 aspare4, afs_uint32 * anewid)
688 {
689     register struct rx_connection *aconn;
690     afs_int32 tid;
691     register afs_int32 code;
692     afs_int32 error;
693     afs_int32 rcode, vcode;
694     struct nvldbentry entry, storeEntry;        /*the new vldb entry */
695     struct volintInfo tstatus;
696
697     tid = 0;
698     aconn = (struct rx_connection *)0;
699     error = 0;
700
701     init_volintInfo(&tstatus);
702     tstatus.maxquota = aquota;
703
704     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
705     /* next the next 3 available ids from the VLDB */
706     vcode = ubik_VL_GetNewVolumeId(cstruct, 0, 3, anewid);
707     EGOTO1(cfail, vcode, "Could not get an Id for volume %s\n", aname);
708     code =
709       AFSVolCreateVolume_retry(aconn, apart, aname, volser_RW, 0, anewid, &tid);
710     EGOTO2(cfail, code, "Failed to create the volume %s %u \n", aname,
711            *anewid);
712
713     code = AFSVolSetInfo(aconn, tid, &tstatus);
714     if (code)
715         EPRINT(code, "Could not change quota, continuing...\n");
716
717     code = AFSVolSetFlags(aconn, tid, 0);       /* bring it online (mark it InService */
718     EGOTO2(cfail, vcode, "Could not bring the volume %s %u online \n", aname,
719            *anewid);
720
721     VPRINT2("Volume %s %u created and brought online\n", aname, *anewid);
722
723     /* set up the vldb entry for this volume */
724     strncpy(entry.name, aname, VOLSER_OLDMAXVOLNAME);
725     entry.nServers = 1;
726     entry.serverNumber[0] = aserver;    /* this should have another 
727                                          * level of indirection later */
728     entry.serverPartition[0] = apart;   /* this should also have 
729                                          * another indirection level */
730     entry.flags = RW_EXISTS;    /* this records that rw volume exists */
731     entry.serverFlags[0] = ITSRWVOL;    /*this rep site has rw  vol */
732     entry.volumeId[RWVOL] = *anewid;
733     entry.volumeId[ROVOL] = *anewid + 1;        /* rw,ro, bk id are related in the default case */
734     entry.volumeId[BACKVOL] = *anewid + 2;
735     entry.cloneId = 0;
736     /*map into right byte order, before passing to xdr, the stuff has to be in host
737      * byte order. Xdr converts it into network order */
738     MapNetworkToHost(&entry, &storeEntry);
739     /* create the vldb entry */
740     vcode = VLDB_CreateEntry(&storeEntry);
741     if (vcode) {
742         fprintf(STDERR,
743                 "Could not create a VLDB entry for the volume %s %lu\n",
744                 aname, (unsigned long)*anewid);
745         /*destroy the created volume */
746         VPRINT1("Deleting the newly created volume %u\n", *anewid);
747         AFSVolDeleteVolume(aconn, tid);
748         error = vcode;
749         goto cfail;
750     }
751     VPRINT2("Created the VLDB entry for the volume %s %u\n", aname, *anewid);
752     /* volume created, now terminate the transaction and release the connection */
753     code = AFSVolEndTrans(aconn, tid, &rcode);  /*if it crashes before this
754                                                  * the volume will come online anyway when transaction timesout , so if
755                                                  * vldb entry exists then the volume is guaranteed to exist too wrt create */
756     tid = 0;
757     if (code) {
758         fprintf(STDERR,
759                 "Failed to end the transaction on the volume %s %lu\n", aname,
760                 (unsigned long)*anewid);
761         error = code;
762         goto cfail;
763     }
764
765   cfail:
766     if (tid) {
767         code = AFSVolEndTrans(aconn, tid, &rcode);
768         if (code)
769             fprintf(STDERR, "WARNING: could not end transaction\n");
770     }
771     if (aconn)
772         rx_DestroyConnection(aconn);
773     PrintError("", error);
774     return error;
775 }
776
777 /* create a volume, given a server, partition number, volume name --> sends
778 * back new vol id in <anewid>*/
779 int
780 UV_AddVLDBEntry(afs_int32 aserver, afs_int32 apart, char *aname,
781                 afs_uint32 aid)
782 {
783     register struct rx_connection *aconn;
784     afs_int32 error;
785     afs_int32 vcode;
786     struct nvldbentry entry, storeEntry;        /*the new vldb entry */
787
788     aconn = (struct rx_connection *)0;
789     error = 0;
790
791     /* set up the vldb entry for this volume */
792     strncpy(entry.name, aname, VOLSER_OLDMAXVOLNAME);
793     entry.nServers = 1;
794     entry.serverNumber[0] = aserver;    /* this should have another 
795                                          * level of indirection later */
796     entry.serverPartition[0] = apart;   /* this should also have 
797                                          * another indirection level */
798     entry.flags = RW_EXISTS;    /* this records that rw volume exists */
799     entry.serverFlags[0] = ITSRWVOL;    /*this rep site has rw  vol */
800     entry.volumeId[RWVOL] = aid;
801 #ifdef notdef
802     entry.volumeId[ROVOL] = anewid + 1; /* rw,ro, bk id are related in the default case */
803     entry.volumeId[BACKVOL] = *anewid + 2;
804 #else
805     entry.volumeId[ROVOL] = 0;
806     entry.volumeId[BACKVOL] = 0;
807 #endif
808     entry.cloneId = 0;
809     /*map into right byte order, before passing to xdr, the stuff has to be in host
810      * byte order. Xdr converts it into network order */
811     MapNetworkToHost(&entry, &storeEntry);
812     /* create the vldb entry */
813     vcode = VLDB_CreateEntry(&storeEntry);
814     if (vcode) {
815         fprintf(STDERR,
816                 "Could not create a VLDB entry for the  volume %s %lu\n",
817                 aname, (unsigned long)aid);
818         error = vcode;
819         goto cfail;
820     }
821     VPRINT2("Created the VLDB entry for the volume %s %u\n", aname, aid);
822
823   cfail:
824     if (aconn)
825         rx_DestroyConnection(aconn);
826     PrintError("", error);
827     return error;
828 }
829
830 /* Delete the volume <volid>on <aserver> <apart>
831  * the physical entry gets removed from the vldb only if the ref count 
832  * becomes zero
833  */
834 int
835 UV_DeleteVolume(afs_int32 aserver, afs_int32 apart, afs_uint32 avolid)
836 {
837     struct rx_connection *aconn = (struct rx_connection *)0;
838     afs_int32 ttid = 0;
839     afs_int32 code, rcode;
840     afs_int32 error = 0;
841     struct nvldbentry entry, storeEntry;
842     int islocked = 0;
843     afs_int32 avoltype = -1, vtype;
844     int notondisk = 0, notinvldb = 0;
845
846     /* Find and read bhe VLDB entry for this volume */
847     code = ubik_VL_SetLock(cstruct, 0, avolid, avoltype, VLOP_DELETE);
848     if (code) {
849         if (code != VL_NOENT) {
850             EGOTO1(error_exit, code,
851                    "Could not lock VLDB entry for the volume %u\n", avolid);
852         }
853         notinvldb = 1;
854     } else {
855         islocked = 1;
856
857         code = VLDB_GetEntryByID(avolid, avoltype, &entry);
858         EGOTO1(error_exit, code, "Could not fetch VLDB entry for volume %u\n",
859                avolid);
860         MapHostToNetwork(&entry);
861
862         if (verbose)
863             EnumerateEntry(&entry);
864     }
865
866     /* Whether volume is in the VLDB or not. Delete the volume on disk */
867     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
868     code = AFSVolTransCreate_retry(aconn, avolid, apart, ITOffline, &ttid);
869     if (code) {
870         if (code == VNOVOL) {
871             notondisk = 1;
872         } else {
873             EGOTO1(error_exit, code, "Transaction on volume %u failed\n",
874                    avolid);
875         }
876     } else {
877         VPRINT1("Trying to delete the volume %u ...", avolid);
878
879         code = AFSVolDeleteVolume(aconn, ttid);
880         EGOTO1(error_exit, code, "Could not delete the volume %u \n", avolid);
881
882         code = AFSVolEndTrans(aconn, ttid, &rcode);
883         code = (code ? code : rcode);
884         ttid = 0;
885         EGOTO1(error_exit, code,
886                "Could not end the transaction for the volume %u \n", avolid);
887         VDONE;
888     }
889
890     /* Now update the VLDB entry.
891      * But first, verify we have a VLDB entry.
892      * Whether volume is on disk or not. Delete the volume in VLDB.
893      */
894     if (notinvldb)
895         ERROR_EXIT(0);
896
897     if (avolid == entry.volumeId[BACKVOL]) {
898         /* Its a backup volume, modify the VLDB entry. Check that the
899          * backup volume is on the server/partition we asked to delete.
900          */
901         if (!(entry.flags & BACK_EXISTS) || !Lp_Match(aserver, apart, &entry)) {
902             notinvldb = 2;      /* Not on this server and partition */
903             ERROR_EXIT(0);
904         }
905
906         VPRINT1("Marking the backup volume %u deleted in the VLDB\n", avolid);
907
908         entry.flags &= ~BACK_EXISTS;
909         vtype = BACKVOL;
910     }
911
912     else if (avolid == entry.volumeId[ROVOL]) {
913         /* Its a read-only volume, modify the VLDB entry. Check that the
914          * readonly volume is on the server/partition we asked to delete.
915          * If flags does not have RO_EIXSTS set, then this may mean the RO 
916          * hasn't been released (and could exist in VLDB).
917          */
918         if (!Lp_ROMatch(aserver, apart, &entry)) {
919             notinvldb = 2;      /* Not found on this server and partition */
920             ERROR_EXIT(0);
921         }
922
923         if (verbose)
924             fprintf(STDOUT,
925                     "Marking the readonly volume %lu deleted in the VLDB\n",
926                     (unsigned long)avolid);
927
928         Lp_SetROValue(&entry, aserver, apart, 0, 0);    /* delete the site */
929         entry.nServers--;
930         if (!Lp_ROMatch(0, 0, &entry))
931             entry.flags &= ~RO_EXISTS;  /* This was the last ro volume */
932         vtype = ROVOL;
933     }
934
935     else if (avolid == entry.volumeId[RWVOL]) {
936         /* It's a rw volume, delete the backup volume, modify the VLDB entry.
937          * Check that the readwrite volumes is on the server/partition we
938          * asked to delete.
939          */
940         if (!(entry.flags & RW_EXISTS) || !Lp_Match(aserver, apart, &entry)) {
941             notinvldb = 2;      /* Not found on this server and partition */
942             ERROR_EXIT(0);
943         }
944
945         /* Delete backup if it exists */
946         code =
947             AFSVolTransCreate_retry(aconn, entry.volumeId[BACKVOL], apart,
948                                     ITOffline, &ttid);
949
950         if (!code) {
951             if (verbose) {
952                 fprintf(STDOUT, "Trying to delete the backup volume %u ...",
953                         entry.volumeId[BACKVOL]);
954                 fflush(STDOUT);
955             }
956             code = AFSVolDeleteVolume(aconn, ttid);
957             EGOTO1(error_exit, code, "Could not delete the volume %u \n",
958                    entry.volumeId[BACKVOL]);
959
960             code = AFSVolEndTrans(aconn, ttid, &rcode);
961             ttid = 0;
962             code = (code ? code : rcode);
963             EGOTO1(error_exit, code,
964                    "Could not end the transaction for the volume %u \n",
965                    entry.volumeId[BACKVOL]);
966             if (verbose)
967                 fprintf(STDOUT, " done\n");
968         }
969
970         if (verbose)
971             fprintf(STDOUT,
972                     "Marking the readwrite volume %lu%s deleted in the VLDB\n",
973                     (unsigned long)avolid,
974                     ((entry.
975                       flags & BACK_EXISTS) ? ", and its backup volume," :
976                      ""));
977
978         Lp_SetRWValue(&entry, aserver, apart, 0L, 0L);
979         entry.nServers--;
980         entry.flags &= ~(BACK_EXISTS | RW_EXISTS);
981         vtype = RWVOL;
982
983         if (entry.flags & RO_EXISTS)
984             fprintf(STDERR, "WARNING: ReadOnly copy(s) may still exist\n");
985     }
986
987     else {
988         notinvldb = 2;          /* Not found on this server and partition */
989         ERROR_EXIT(0);
990     }
991
992     /* Either delete or replace the VLDB entry */
993     if ((entry.nServers <= 0) || !(entry.flags & (RO_EXISTS | RW_EXISTS))) {
994         if (verbose)
995             fprintf(STDOUT,
996                     "Last reference to the VLDB entry for %lu - deleting entry\n",
997                     (unsigned long)avolid);
998         code = ubik_VL_DeleteEntry(cstruct, 0, avolid, vtype);
999         EGOTO1(error_exit, code,
1000                "Could not delete the VLDB entry for the volume %u \n",
1001                avolid);
1002     } else {
1003         MapNetworkToHost(&entry, &storeEntry);
1004         code =
1005             VLDB_ReplaceEntry(avolid, vtype, &storeEntry,
1006                               (LOCKREL_OPCODE | LOCKREL_AFSID |
1007                                LOCKREL_TIMESTAMP));
1008         EGOTO1(error_exit, code,
1009                "Could not update the VLDB entry for the volume %u \n",
1010                avolid);
1011     }
1012     islocked = 0;
1013
1014   error_exit:
1015     if (error)
1016         EPRINT(error, "\n");
1017
1018     if (notondisk && notinvldb) {
1019         EPRINT2(VOLSERNOVOL, "Volume %u does not exist %s\n", avolid,
1020                 ((notinvldb == 2) ? "on server and partition" : ""));
1021         if (!error)
1022             error = VOLSERNOVOL;
1023     } else if (notondisk) {
1024         fprintf(STDERR,
1025                 "WARNING: Volume %lu did not exist on the partition\n",
1026                 (unsigned long)avolid);
1027     } else if (notinvldb) {
1028         fprintf(STDERR, "WARNING: Volume %lu does not exist in VLDB %s\n",
1029                 (unsigned long)avolid,
1030                 ((notinvldb == 2) ? "on server and partition" : ""));
1031     }
1032
1033     if (ttid) {
1034         code = AFSVolEndTrans(aconn, ttid, &rcode);
1035         code = (code ? code : rcode);
1036         if (code) {
1037             fprintf(STDERR, "Could not end transaction on the volume %lu\n",
1038                     (unsigned long)avolid);
1039             PrintError("", code);
1040             if (!error)
1041                 error = code;
1042         }
1043     }
1044
1045     if (islocked) {
1046         code =
1047             ubik_VL_ReleaseLock(cstruct, 0, avolid, -1,
1048                                 (LOCKREL_OPCODE | LOCKREL_AFSID | 
1049                                  LOCKREL_TIMESTAMP));
1050         if (code) {
1051             EPRINT1(code,
1052                     "Could not release the lock on the VLDB entry for the volume %u \n",
1053                     avolid);
1054             if (!error)
1055                 error = code;
1056         }
1057     }
1058
1059     if (aconn)
1060         rx_DestroyConnection(aconn);
1061     return error;
1062 }
1063
1064 /* add recovery to UV_MoveVolume */
1065
1066 #define TESTC   0               /* set to test recovery code, clear for production */
1067
1068 jmp_buf env;
1069 int interrupt = 0;
1070
1071 void
1072 sigint_handler(int x)
1073 {
1074     if (interrupt)
1075         longjmp(env, 0);
1076
1077     fprintf(STDOUT, "\nSIGINT handler: vos move operation in progress\n");
1078     fprintf(STDOUT,
1079             "WARNING: may leave AFS storage and metadata in indeterminate state\n");
1080     fprintf(STDOUT, "enter second control-c to exit\n");
1081     fflush(STDOUT);
1082
1083     interrupt = 1;
1084     (void)signal(SIGINT, sigint_handler);
1085
1086     return;
1087 }
1088
1089 /* Move volume <afromvol> on <afromserver> <afrompart> to <atoserver>
1090  * <atopart>.  The operation is almost idempotent.  The following
1091  * flags are recognized:
1092  * 
1093  *     RV_NOCLONE - don't use a copy clone
1094  */
1095
1096 int
1097 UV_MoveVolume2(afs_uint32 afromvol, afs_int32 afromserver, afs_int32 afrompart,
1098                afs_int32 atoserver, afs_int32 atopart, int flags)
1099 {
1100     struct rx_connection *toconn, *fromconn;
1101     afs_int32 fromtid, totid, clonetid;
1102     char vname[64];
1103     char *volName = 0;
1104     char tmpName[VOLSER_MAXVOLNAME + 1];
1105     afs_int32 rcode;
1106     afs_int32 fromDate;
1107     struct restoreCookie cookie;
1108     register afs_int32 vcode, code;
1109     afs_uint32 newVol, volid, backupId;
1110     struct volser_status tstatus;
1111     struct destServer destination;
1112
1113     struct nvldbentry entry, storeEntry;
1114     int i, islocked, pntg;
1115     afs_int32 error;
1116     char in, lf;                /* for test code */
1117     int same;
1118     char hoststr[16];
1119
1120 #ifdef  ENABLE_BUGFIX_1165
1121     volEntries volumeInfo;
1122     struct volintInfo *infop = 0;
1123 #endif
1124
1125     islocked = 0;
1126     fromconn = (struct rx_connection *)0;
1127     toconn = (struct rx_connection *)0;
1128     fromtid = 0;
1129     totid = 0;
1130     clonetid = 0;
1131     error = 0;
1132     volid = 0;
1133     pntg = 0;
1134     backupId = 0;
1135     newVol = 0;
1136
1137     /* support control-c processing */
1138     if (setjmp(env))
1139         goto mfail;
1140     (void)signal(SIGINT, sigint_handler);
1141
1142     if (TESTC) {
1143         fprintf(STDOUT,
1144                 "\nThere are three tests points - verifies all code paths through recovery.\n");
1145         fprintf(STDOUT, "First test point - operation not started.\n");
1146         fprintf(STDOUT, "...test here (y, n)? ");
1147         fflush(STDOUT);
1148         fscanf(stdin, "%c", &in);
1149         fscanf(stdin, "%c", &lf);       /* toss away */
1150         if (in == 'y') {
1151             fprintf(STDOUT, "type control-c\n");
1152             while (1) {
1153                 fprintf(stdout, ".");
1154                 fflush(stdout);
1155                 sleep(1);
1156             }
1157         }
1158         /* or drop through */
1159     }
1160
1161     vcode = VLDB_GetEntryByID(afromvol, -1, &entry);
1162     EGOTO1(mfail, vcode,
1163            "Could not fetch the entry for the volume  %u from the VLDB \n",
1164            afromvol);
1165
1166     if (entry.volumeId[RWVOL] != afromvol) {
1167         fprintf(STDERR, "Only RW volume can be moved\n");
1168         exit(1);
1169     }
1170
1171     vcode = ubik_VL_SetLock(cstruct, 0, afromvol, RWVOL, VLOP_MOVE);
1172     EGOTO1(mfail, vcode, "Could not lock entry for volume %u \n", afromvol);
1173     islocked = 1;
1174
1175     vcode = VLDB_GetEntryByID(afromvol, RWVOL, &entry);
1176     EGOTO1(mfail, vcode,
1177            "Could not fetch the entry for the volume  %u from the VLDB \n",
1178            afromvol);
1179
1180     backupId = entry.volumeId[BACKVOL];
1181     MapHostToNetwork(&entry);
1182
1183     if (!Lp_Match(afromserver, afrompart, &entry)) {
1184         /* the from server and partition do not exist in the vldb entry corresponding to volid */
1185         if (!Lp_Match(atoserver, atopart, &entry)) {
1186             /* the to server and partition do not exist in the vldb entry corresponding to volid */
1187             fprintf(STDERR, "The volume %lu is not on the specified site. \n",
1188                     (unsigned long)afromvol);
1189             fprintf(STDERR, "The current site is :");
1190             for (i = 0; i < entry.nServers; i++) {
1191                 if (entry.serverFlags[i] == ITSRWVOL) {
1192                     char pname[10];
1193                     MapPartIdIntoName(entry.serverPartition[i], pname);
1194                     fprintf(STDERR, " server %s partition %s \n",
1195                             noresolve ? afs_inet_ntoa_r(entry.serverNumber[i], hoststr) :
1196                             hostutil_GetNameByINet(entry.serverNumber[i]),
1197                             pname);
1198                 }
1199             }
1200             vcode =
1201                 ubik_VL_ReleaseLock(cstruct, 0, afromvol, -1,
1202                           (LOCKREL_OPCODE | LOCKREL_AFSID |
1203                            LOCKREL_TIMESTAMP));
1204             EGOTO1(mfail, vcode,
1205                    " Could not release lock on the VLDB entry for the volume %u \n",
1206                    afromvol);
1207
1208             return VOLSERVOLMOVED;
1209         }
1210
1211         /* delete the volume afromvol on src_server */
1212         /* from-info does not exist but to-info does =>
1213          * we have already done the move, but the volume
1214          * may still be existing physically on from fileserver
1215          */
1216         fromconn = UV_Bind(afromserver, AFSCONF_VOLUMEPORT);
1217         fromtid = 0;
1218         pntg = 1;
1219
1220         code =
1221             AFSVolTransCreate_retry(fromconn, afromvol, afrompart, ITOffline,
1222                                     &fromtid);
1223
1224         if (!code) {            /* volume exists - delete it */
1225             VPRINT1("Setting flags on leftover source volume %u ...",
1226                     afromvol);
1227             code =
1228                 AFSVolSetFlags(fromconn, fromtid,
1229                                VTDeleteOnSalvage | VTOutOfService);
1230             EGOTO1(mfail, code,
1231                    "Failed to set flags on the leftover source volume %u\n",
1232                    afromvol);
1233             VDONE;
1234
1235             VPRINT1("Deleting leftover source volume %u ...", afromvol);
1236             code = AFSVolDeleteVolume(fromconn, fromtid);
1237             EGOTO1(mfail, code,
1238                    "Failed to delete the leftover source volume %u\n",
1239                    afromvol);
1240             VDONE;
1241
1242             VPRINT1("Ending transaction on leftover source volume %u ...",
1243                     afromvol);
1244             code = AFSVolEndTrans(fromconn, fromtid, &rcode);
1245             fromtid = 0;
1246             if (!code)
1247                 code = rcode;
1248             EGOTO1(mfail, code,
1249                    "Could not end the transaction for the leftover source volume %u \n",
1250                    afromvol);
1251             VDONE;
1252         }
1253
1254         /*delete the backup volume now */
1255         fromtid = 0;
1256         code =
1257             AFSVolTransCreate_retry(fromconn, backupId, afrompart, ITOffline,
1258                                     &fromtid);
1259
1260         if (!code) {            /* backup volume exists - delete it */
1261             VPRINT1("Setting flags on leftover backup volume %u ...",
1262                     backupId);
1263             code =
1264                 AFSVolSetFlags(fromconn, fromtid,
1265                                VTDeleteOnSalvage | VTOutOfService);
1266             EGOTO1(mfail, code,
1267                    "Failed to set flags on the backup volume %u\n", backupId);
1268             VDONE;
1269
1270             VPRINT1("Deleting leftover backup volume %u ...", backupId);
1271             code = AFSVolDeleteVolume(fromconn, fromtid);
1272             EGOTO1(mfail, code,
1273                    "Could not delete the leftover backup volume %u\n",
1274                    backupId);
1275             VDONE;
1276
1277             VPRINT1("Ending transaction on leftover backup volume %u ...",
1278                     backupId);
1279             code = AFSVolEndTrans(fromconn, fromtid, &rcode);
1280             fromtid = 0;
1281             if (!code)
1282                 code = rcode;
1283             EGOTO1(mfail, code,
1284                    "Could not end the transaction for the leftover backup volume %u\n",
1285                    backupId);
1286             VDONE;
1287         }
1288
1289         fromtid = 0;
1290         error = 0;
1291         goto mfail;
1292     }
1293
1294     /* From-info matches the vldb info about volid,
1295      * its ok start the move operation, the backup volume 
1296      * on the old site is deleted in the process 
1297      */
1298     if (afrompart == atopart) {
1299         same = VLDB_IsSameAddrs(afromserver, atoserver, &error);
1300         EGOTO2(mfail, error,
1301                "Failed to get info about server's %d address(es) from vlserver (err=%d); aborting call!\n",
1302                afromserver, error);
1303
1304         if (same) {
1305             EGOTO1(mfail, VOLSERVOLMOVED,
1306                    "Warning: Moving volume %u to its home partition ignored!\n",
1307                    afromvol);
1308         }
1309     }
1310
1311     pntg = 1;
1312     toconn = UV_Bind(atoserver, AFSCONF_VOLUMEPORT);    /* get connections to the servers */
1313     fromconn = UV_Bind(afromserver, AFSCONF_VOLUMEPORT);
1314     fromtid = totid = 0;        /* initialize to uncreated */
1315
1316     /* ***
1317      * clone the read/write volume locally.
1318      * ***/
1319
1320     VPRINT1("Starting transaction on source volume %u ...", afromvol);
1321     code = AFSVolTransCreate_retry(fromconn, afromvol, afrompart, ITBusy, &fromtid);
1322     EGOTO1(mfail, code, "Failed to create transaction on the volume %u\n",
1323            afromvol);
1324     VDONE;
1325
1326     if (!(flags & RV_NOCLONE)) {
1327         /* Get a clone id */
1328         VPRINT1("Allocating new volume id for clone of volume %u ...",
1329                 afromvol);
1330         newVol = 0;
1331         vcode = ubik_VL_GetNewVolumeId(cstruct, 0, 1, &newVol);
1332         EGOTO1(mfail, vcode,
1333                "Could not get an ID for the clone of volume %u from the VLDB\n",
1334                afromvol);
1335         VDONE;
1336
1337         /* Do the clone. Default flags on clone are set to delete on salvage and out of service */
1338         VPRINT1("Cloning source volume %u ...", afromvol);
1339         strcpy(vname, "move-clone-temp");
1340         code =
1341             AFSVolClone(fromconn, fromtid, 0, readonlyVolume, vname, &newVol);
1342         EGOTO1(mfail, code, "Failed to clone the source volume %u\n",
1343                afromvol);
1344         VDONE;
1345     }
1346
1347     /* lookup the name of the volume we just cloned */
1348     volid = afromvol;
1349     code = AFSVolGetName(fromconn, fromtid, &volName);
1350     EGOTO1(mfail, code, "Failed to get the name of the volume %u\n",
1351            afromvol);
1352
1353     VPRINT1("Ending the transaction on the source volume %u ...", afromvol);
1354     rcode = 0;
1355     code = AFSVolEndTrans(fromconn, fromtid, &rcode);
1356     fromtid = 0;
1357     if (!code)
1358         code = rcode;
1359     EGOTO1(mfail, code,
1360            "Failed to end the transaction on the source volume %u\n",
1361            afromvol);
1362     VDONE;
1363
1364     /* ***
1365      * Create the destination volume
1366      * ***/
1367
1368     if (!(flags & RV_NOCLONE)) {
1369         /* All of this is to get the fromDate */
1370         VPRINT1("Starting transaction on the cloned volume %u ...", newVol);
1371         code =
1372             AFSVolTransCreate_retry(fromconn, newVol, afrompart, ITOffline,
1373                               &clonetid);
1374         EGOTO1(mfail, code,
1375                "Failed to start a transaction on the cloned volume%u\n",
1376                newVol);
1377         VDONE;
1378
1379         VPRINT1("Setting flags on cloned volume %u ...", newVol);
1380         code =
1381             AFSVolSetFlags(fromconn, clonetid,
1382                            VTDeleteOnSalvage | VTOutOfService); /*redundant */
1383         EGOTO1(mfail, code, "Could not set flags on the cloned volume %u\n",
1384                newVol);
1385         VDONE;
1386
1387         /* remember time from which we've dumped the volume */
1388         VPRINT1("Getting status of cloned volume %u ...", newVol);
1389         code = AFSVolGetStatus(fromconn, clonetid, &tstatus);
1390         EGOTO1(mfail, code,
1391                "Failed to get the status of the cloned volume %u\n",
1392                newVol);
1393         VDONE;
1394
1395         fromDate = CLOCKADJ(tstatus.creationDate);
1396     } else {
1397         /* With RV_NOCLONE, just do a full copy from the source */
1398         fromDate = 0;
1399     }
1400
1401
1402 #ifdef  ENABLE_BUGFIX_1165
1403     /*
1404      * Get the internal volume state from the source volume. We'll use such info (i.e. dayUse)
1405      * to copy it to the new volume (via AFSSetInfo later on) so that when we move volumes we
1406      * don't use this information...
1407      */
1408     volumeInfo.volEntries_val = (volintInfo *) 0;       /*this hints the stub to allocate space */
1409     volumeInfo.volEntries_len = 0;
1410     code = AFSVolListOneVolume(fromconn, afrompart, afromvol, &volumeInfo);
1411     EGOTO1(mfail, code,
1412            "Failed to get the volint Info of the cloned volume %u\n",
1413            afromvol);
1414
1415     infop = (volintInfo *) volumeInfo.volEntries_val;
1416     infop->maxquota = -1;       /* Else it will replace the default quota */
1417     infop->creationDate = -1;   /* Else it will use the source creation date */
1418     infop->updateDate = -1;     /* Else it will use the source update date */
1419 #endif
1420
1421     /* create a volume on the target machine */
1422     volid = afromvol;
1423     code = AFSVolTransCreate_retry(toconn, volid, atopart, ITOffline, &totid);
1424     if (!code) {
1425         /* Delete the existing volume.
1426          * While we are deleting the volume in these steps, the transaction
1427          * we started against the cloned volume (clonetid above) will be
1428          * sitting idle. It will get cleaned up after 600 seconds
1429          */
1430         VPRINT1("Deleting pre-existing volume %u on destination ...", volid);
1431         code = AFSVolDeleteVolume(toconn, totid);
1432         EGOTO1(mfail, code,
1433                "Could not delete the pre-existing volume %u on destination\n",
1434                volid);
1435         VDONE;
1436
1437         VPRINT1
1438             ("Ending transaction on pre-existing volume %u on destination ...",
1439              volid);
1440         code = AFSVolEndTrans(toconn, totid, &rcode);
1441         totid = 0;
1442         if (!code)
1443             code = rcode;
1444         EGOTO1(mfail, code,
1445                "Could not end the transaction on pre-existing volume %u on destination\n",
1446                volid);
1447         VDONE;
1448     }
1449
1450     VPRINT1("Creating the destination volume %u ...", volid);
1451     code =
1452         AFSVolCreateVolume(toconn, atopart, volName, volser_RW, volid, &volid,
1453                            &totid);
1454     EGOTO1(mfail, code, "Failed to create the destination volume %u\n",
1455            volid);
1456     VDONE;
1457
1458     strncpy(tmpName, volName, VOLSER_OLDMAXVOLNAME);
1459     free(volName);
1460     volName = NULL;
1461
1462     VPRINT1("Setting volume flags on destination volume %u ...", volid);
1463     code =
1464         AFSVolSetFlags(toconn, totid, (VTDeleteOnSalvage | VTOutOfService));
1465     EGOTO1(mfail, code,
1466            "Failed to set the flags on the destination volume %u\n", volid);
1467     VDONE;
1468
1469     /***
1470      * Now dump the clone to the new volume
1471      ***/
1472
1473     destination.destHost = ntohl(atoserver);
1474     destination.destPort = AFSCONF_VOLUMEPORT;
1475     destination.destSSID = 1;
1476
1477     strncpy(cookie.name, tmpName, VOLSER_OLDMAXVOLNAME);
1478     cookie.type = RWVOL;
1479     cookie.parent = entry.volumeId[RWVOL];
1480     cookie.clone = 0;
1481
1482     if (!(flags & RV_NOCLONE)) {
1483         /* Copy the clone to the new volume */
1484         VPRINT2("Dumping from clone %u on source to volume %u on destination ...",
1485                 newVol, afromvol);
1486         code =
1487             AFSVolForward(fromconn, clonetid, 0, &destination, totid,
1488                           &cookie);
1489         EGOTO1(mfail, code, "Failed to move data for the volume %u\n", volid);
1490         VDONE;
1491
1492         VPRINT1("Ending transaction on cloned volume %u ...", newVol);
1493         code = AFSVolEndTrans(fromconn, clonetid, &rcode);
1494         if (!code)
1495             code = rcode;
1496         clonetid = 0;
1497         EGOTO1(mfail, code,
1498                "Failed to end the transaction on the cloned volume %u\n",
1499                newVol);
1500         VDONE;
1501     }
1502
1503     /* ***
1504      * reattach to the main-line volume, and incrementally dump it.
1505      * ***/
1506
1507     VPRINT1("Starting transaction on source volume %u ...", afromvol);
1508     code = AFSVolTransCreate_retry(fromconn, afromvol, afrompart, ITBusy, &fromtid);
1509     EGOTO1(mfail, code,
1510            "Failed to create a transaction on the source volume %u\n",
1511            afromvol);
1512     VDONE;
1513
1514     /* now do the incremental */
1515     VPRINT2
1516         ("Doing the%s dump from source to destination for volume %u ... ",
1517          (flags & RV_NOCLONE) ? "" : " incremental",
1518          afromvol);
1519     code =
1520         AFSVolForward(fromconn, fromtid, fromDate, &destination, totid,
1521                       &cookie);
1522     EGOTO1(mfail, code,
1523            "Failed to do the%s dump from rw volume on old site to rw volume on newsite\n",
1524           (flags & RV_NOCLONE) ? "" : " incremental");
1525     VDONE;
1526
1527     /* now adjust the flags so that the new volume becomes official */
1528     VPRINT1("Setting volume flags on old source volume %u ...", afromvol);
1529     code = AFSVolSetFlags(fromconn, fromtid, VTOutOfService);
1530     EGOTO(mfail, code,
1531           "Failed to set the flags to make old source volume offline\n");
1532     VDONE;
1533
1534     VPRINT1("Setting volume flags on new source volume %u ...", afromvol);
1535     code = AFSVolSetFlags(toconn, totid, 0);
1536     EGOTO(mfail, code,
1537           "Failed to set the flags to make new source volume online\n");
1538     VDONE;
1539
1540 #ifdef  ENABLE_BUGFIX_1165
1541     VPRINT1("Setting volume status on destination volume %u ...", volid);
1542     code = AFSVolSetInfo(toconn, totid, infop);
1543     EGOTO1(mfail, code,
1544            "Failed to set volume status on the destination volume %u\n",
1545            volid);
1546     VDONE;
1547 #endif
1548
1549     /* put new volume online */
1550     VPRINT1("Ending transaction on destination volume %u ...", afromvol);
1551     code = AFSVolEndTrans(toconn, totid, &rcode);
1552     totid = 0;
1553     if (!code)
1554         code = rcode;
1555     EGOTO1(mfail, code,
1556            "Failed to end the transaction on the volume %u on the new site\n",
1557            afromvol);
1558     VDONE;
1559
1560     Lp_SetRWValue(&entry, afromserver, afrompart, atoserver, atopart);
1561     MapNetworkToHost(&entry, &storeEntry);
1562     storeEntry.flags &= ~BACK_EXISTS;
1563
1564     if (TESTC) {
1565         fprintf(STDOUT,
1566                 "Second test point - operation in progress but not complete.\n");
1567         fprintf(STDOUT, "...test here (y, n)? ");
1568         fflush(STDOUT);
1569         fscanf(stdin, "%c", &in);
1570         fscanf(stdin, "%c", &lf);       /* toss away */
1571         if (in == 'y') {
1572             fprintf(STDOUT, "type control-c\n");
1573             while (1) {
1574                 fprintf(stdout, ".");
1575                 fflush(stdout);
1576                 sleep(1);
1577             }
1578         }
1579         /* or drop through */
1580     }
1581
1582     VPRINT1("Releasing lock on VLDB entry for volume %u ...", afromvol);
1583     vcode =
1584         VLDB_ReplaceEntry(afromvol, -1, &storeEntry,
1585                           (LOCKREL_OPCODE | LOCKREL_AFSID |
1586                            LOCKREL_TIMESTAMP));
1587     if (vcode) {
1588         fprintf(STDERR,
1589                 " Could not release the lock on the VLDB entry for the volume %s %lu \n",
1590                 storeEntry.name, (unsigned long)afromvol);
1591         error = vcode;
1592         goto mfail;
1593     }
1594     islocked = 0;
1595     VDONE;
1596
1597     if (TESTC) {
1598         fprintf(STDOUT,
1599                 "Third test point - operation complete but no cleanup.\n");
1600         fprintf(STDOUT, "...test here (y, n)? ");
1601         fflush(STDOUT);
1602         fscanf(stdin, "%c", &in);
1603         fscanf(stdin, "%c", &lf);       /* toss away */
1604         if (in == 'y') {
1605             fprintf(STDOUT, "type control-c\n");
1606             while (1) {
1607                 fprintf(stdout, ".");
1608                 fflush(stdout);
1609                 sleep(1);
1610             }
1611         }
1612         /* or drop through */
1613     }
1614 #ifdef notdef
1615     /* This is tricky.  File server is very stupid, and if you mark the volume
1616      * as VTOutOfService, it may mark the *good* instance (if you're moving
1617      * between partitions on the same machine) as out of service.  Since
1618      * we're cleaning this code up in DEcorum, we're just going to kludge around
1619      * it for now by removing this call. */
1620     /* already out of service, just zap it now */
1621     code =
1622         AFSVolSetFlags(fromconn, fromtid, VTDeleteOnSalvage | VTOutOfService);
1623     if (code) {
1624         fprintf(STDERR,
1625                 "Failed to set the flags to make the old source volume offline\n");
1626         goto mfail;
1627     }
1628 #endif
1629     if (atoserver != afromserver) {
1630         /* set forwarding pointer for moved volumes */
1631         VPRINT1("Setting forwarding pointer for volume %u ...", afromvol);
1632         code = AFSVolSetForwarding(fromconn, fromtid, atoserver);
1633         EGOTO1(mfail, code,
1634                "Failed to set the forwarding pointer for the volume %u\n",
1635                afromvol);
1636         VDONE;
1637     }
1638
1639     VPRINT1("Deleting old volume %u on source ...", afromvol);
1640     code = AFSVolDeleteVolume(fromconn, fromtid);       /* zap original volume */
1641     EGOTO1(mfail, code, "Failed to delete the old volume %u on source\n",
1642            afromvol);
1643     VDONE;
1644
1645     VPRINT1("Ending transaction on old volume %u on the source ...",
1646             afromvol);
1647     code = AFSVolEndTrans(fromconn, fromtid, &rcode);
1648     fromtid = 0;
1649     if (!code)
1650         code = rcode;
1651     EGOTO1(mfail, code,
1652            "Failed to end the transaction on the old volume %u on the source\n",
1653            afromvol);
1654     VDONE;
1655
1656     /* Delete the backup volume on the original site */
1657     VPRINT1("Creating transaction for backup volume %u on source ...",
1658             backupId);
1659     code =
1660         AFSVolTransCreate_retry(fromconn, backupId, afrompart, ITOffline, &fromtid);
1661     VDONE;
1662     if (!code) {
1663         VPRINT1("Setting flags on backup volume %u on source ...", backupId);
1664         code =
1665             AFSVolSetFlags(fromconn, fromtid,
1666                            VTDeleteOnSalvage | VTOutOfService);
1667         EGOTO1(mfail, code,
1668                "Failed to set the flags on the backup volume %u on the source\n",
1669                backupId);
1670         VDONE;
1671
1672         VPRINT1("Deleting the backup volume %u on the source ...", backupId);
1673         code = AFSVolDeleteVolume(fromconn, fromtid);
1674         EGOTO1(mfail, code,
1675                "Failed to delete the backup volume %u on the source\n",
1676                backupId);
1677         VDONE;
1678
1679         VPRINT1("Ending transaction on backup volume %u on source ...",
1680                 backupId);
1681         code = AFSVolEndTrans(fromconn, fromtid, &rcode);
1682         fromtid = 0;
1683         if (!code)
1684             code = rcode;
1685         EGOTO1(mfail, code,
1686                "Failed to end the transaction on the backup volume %u on the source\n",
1687                backupId);
1688         VDONE;
1689     } else
1690         code = 0;               /* no backup volume? that's okay */
1691
1692     fromtid = 0;
1693     if (!(flags & RV_NOCLONE)) {
1694         VPRINT1("Starting transaction on the cloned volume %u ...", newVol);
1695         code =
1696             AFSVolTransCreate_retry(fromconn, newVol, afrompart, ITOffline,
1697                               &clonetid);
1698         EGOTO1(mfail, code,
1699                "Failed to start a transaction on the cloned volume%u\n",
1700                newVol);
1701         VDONE;
1702
1703         /* now delete the clone */
1704         VPRINT1("Deleting the cloned volume %u ...", newVol);
1705         code = AFSVolDeleteVolume(fromconn, clonetid);
1706         EGOTO1(mfail, code, "Failed to delete the cloned volume %u\n",
1707                newVol);
1708         VDONE;
1709
1710         VPRINT1("Ending transaction on cloned volume %u ...", newVol);
1711         code = AFSVolEndTrans(fromconn, clonetid, &rcode);
1712         if (!code)
1713             code = rcode;
1714         clonetid = 0;
1715         EGOTO1(mfail, code,
1716                "Failed to end the transaction on the cloned volume %u\n",
1717                newVol);
1718         VDONE;
1719     }
1720
1721     /* fall through */
1722     /* END OF MOVE */
1723
1724     if (TESTC) {
1725         fprintf(STDOUT, "Fourth test point - operation complete.\n");
1726         fprintf(STDOUT, "...test here (y, n)? ");
1727         fflush(STDOUT);
1728         fscanf(stdin, "%c", &in);
1729         fscanf(stdin, "%c", &lf);       /* toss away */
1730         if (in == 'y') {
1731             fprintf(STDOUT, "type control-c\n");
1732             while (1) {
1733                 fprintf(stdout, ".");
1734                 fflush(stdout);
1735                 sleep(1);
1736             }
1737         }
1738         /* or drop through */
1739     }
1740
1741     /* normal cleanup code */
1742
1743     if (entry.flags & RO_EXISTS)
1744         fprintf(STDERR, "WARNING : readOnly copies still exist \n");
1745
1746     if (islocked) {
1747         VPRINT1("Cleanup: Releasing VLDB lock on volume %u ...", afromvol);
1748         vcode =
1749             ubik_VL_ReleaseLock(cstruct, 0, afromvol, -1,
1750                       (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP));
1751         if (vcode) {
1752             VPRINT("\n");
1753             fprintf(STDERR,
1754                     " Could not release the lock on the VLDB entry for the volume %lu \n",
1755                     (unsigned long)afromvol);
1756             if (!error)
1757                 error = vcode;
1758         }
1759         VDONE;
1760     }
1761
1762     if (fromtid) {
1763         VPRINT1("Cleanup: Ending transaction on source volume %u ...",
1764                 afromvol);
1765         code = AFSVolEndTrans(fromconn, fromtid, &rcode);
1766         if (code || rcode) {
1767             VPRINT("\n");
1768             fprintf(STDERR,
1769                     "Could not end transaction on the source volume %lu\n",
1770                     (unsigned long)afromvol);
1771             if (!error)
1772                 error = (code ? code : rcode);
1773         }
1774         VDONE;
1775     }
1776
1777     if (clonetid) {
1778         VPRINT1("Cleanup: Ending transaction on clone volume %u ...", newVol);
1779         code = AFSVolEndTrans(fromconn, clonetid, &rcode);
1780         if (code || rcode) {
1781             VPRINT("\n");
1782             fprintf(STDERR,
1783                     "Could not end transaction on the source's clone volume %lu\n",
1784                     (unsigned long)newVol);
1785             if (!error)
1786                 error = (code ? code : rcode);
1787         }
1788         VDONE;
1789     }
1790
1791     if (totid) {
1792         VPRINT1("Cleanup: Ending transaction on destination volume %u ...",
1793                 afromvol);
1794         code = AFSVolEndTrans(toconn, totid, &rcode);
1795         if (code) {
1796             VPRINT("\n");
1797             fprintf(STDERR,
1798                     "Could not end transaction on destination volume %lu\n",
1799                     (unsigned long)afromvol);
1800             if (!error)
1801                 error = (code ? code : rcode);
1802         }
1803         VDONE;
1804     }
1805     if (volName)
1806         free(volName);
1807 #ifdef  ENABLE_BUGFIX_1165
1808     if (infop)
1809         free(infop);
1810 #endif
1811     if (fromconn)
1812         rx_DestroyConnection(fromconn);
1813     if (toconn)
1814         rx_DestroyConnection(toconn);
1815     PrintError("", error);
1816     return error;
1817
1818     /* come here only when the sky falls */
1819   mfail:
1820
1821     if (pntg) {
1822         fprintf(STDOUT,
1823                 "vos move: operation interrupted, cleanup in progress...\n");
1824         fprintf(STDOUT, "clear transaction contexts\n");
1825         fflush(STDOUT);
1826     }
1827
1828     /* unlock VLDB entry */
1829     if (islocked) {
1830         VPRINT1("Recovery: Releasing VLDB lock on volume %u ...", afromvol);
1831         ubik_VL_ReleaseLock(cstruct, 0, afromvol, -1,
1832                   (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP));
1833         VDONE;
1834         islocked = 0;
1835     }
1836
1837     if (clonetid) {
1838         VPRINT("Recovery: Ending transaction on clone volume ...");
1839         AFSVolEndTrans(fromconn, clonetid, &rcode);
1840         VDONE;
1841     }
1842     if (totid) {
1843         VPRINT("Recovery: Ending transaction on destination volume ...");
1844         AFSVolEndTrans(toconn, totid, &rcode);
1845         VDONE;
1846     }
1847     if (fromtid) {              /* put it on-line */
1848         VPRINT("Recovery: Setting volume flags on source volume ...");
1849         AFSVolSetFlags(fromconn, fromtid, 0);
1850         VDONE;
1851
1852         VPRINT("Recovery: Ending transaction on source volume ...");
1853         AFSVolEndTrans(fromconn, fromtid, &rcode);
1854         VDONE;
1855     }
1856
1857     VPRINT("Recovery: Accessing VLDB.\n");
1858     vcode = VLDB_GetEntryByID(afromvol, -1, &entry);
1859     if (vcode) {
1860         fprintf(STDOUT, "FATAL: VLDB access error: abort cleanup\n");
1861         fflush(STDOUT);
1862         goto done;
1863     }
1864     MapHostToNetwork(&entry);
1865
1866     /* Delete either the volume on the source location or the target location. 
1867      * If the vldb entry still points to the source location, then we know the
1868      * volume move didn't finish so we remove the volume from the target 
1869      * location. Otherwise, we remove the volume from the source location.
1870      */
1871     if (Lp_Match(afromserver, afrompart, &entry)) {     /* didn't move - delete target volume */
1872         if (pntg) {
1873             fprintf(STDOUT,
1874                     "move incomplete - attempt cleanup of target partition - no guarantee\n");
1875             fflush(STDOUT);
1876         }
1877
1878         if (volid && toconn) {
1879             VPRINT1
1880                 ("Recovery: Creating transaction for destination volume %u ...",
1881                  volid);
1882             code =
1883                 AFSVolTransCreate_retry(toconn, volid, atopart, ITOffline, &totid);
1884
1885             if (!code) {
1886                 VDONE;
1887
1888                 VPRINT1
1889                     ("Recovery: Setting flags on destination volume %u ...",
1890                      volid);
1891                 AFSVolSetFlags(toconn, totid,
1892                                VTDeleteOnSalvage | VTOutOfService);
1893                 VDONE;
1894
1895                 VPRINT1("Recovery: Deleting destination volume %u ...",
1896                         volid);
1897                 AFSVolDeleteVolume(toconn, totid);
1898                 VDONE;
1899
1900                 VPRINT1
1901                     ("Recovery: Ending transaction on destination volume %u ...",
1902                      volid);
1903                 AFSVolEndTrans(toconn, totid, &rcode);
1904                 VDONE;
1905             } else {
1906                 VPRINT1
1907                     ("\nRecovery: Unable to start transaction on destination volume %u.\n",
1908                      afromvol);
1909             }
1910         }
1911
1912         /* put source volume on-line */
1913         if (fromconn) {
1914             VPRINT1("Recovery: Creating transaction on source volume %u ...",
1915                     afromvol);
1916             code =
1917                 AFSVolTransCreate_retry(fromconn, afromvol, afrompart, ITBusy,
1918                                   &fromtid);
1919             if (!code) {
1920                 VDONE;
1921
1922                 VPRINT1("Recovery: Setting flags on source volume %u ...",
1923                         afromvol);
1924                 AFSVolSetFlags(fromconn, fromtid, 0);
1925                 VDONE;
1926
1927                 VPRINT1
1928                     ("Recovery: Ending transaction on source volume %u ...",
1929                      afromvol);
1930                 AFSVolEndTrans(fromconn, fromtid, &rcode);
1931                 VDONE;
1932             } else {
1933                 VPRINT1
1934                     ("\nRecovery: Unable to start transaction on source volume %u.\n",
1935                      afromvol);
1936             }
1937         }
1938     } else {                    /* yep, move complete */
1939         if (pntg) {
1940             fprintf(STDOUT,
1941                     "move complete - attempt cleanup of source partition - no guarantee\n");
1942             fflush(STDOUT);
1943         }
1944
1945         /* delete backup volume */
1946         if (fromconn) {
1947             VPRINT1("Recovery: Creating transaction on backup volume %u ...",
1948                     backupId);
1949             code =
1950                 AFSVolTransCreate_retry(fromconn, backupId, afrompart, ITOffline,
1951                                   &fromtid);
1952             if (!code) {
1953                 VDONE;
1954
1955                 VPRINT1("Recovery: Setting flags on backup volume %u ...",
1956                         backupId);
1957                 AFSVolSetFlags(fromconn, fromtid,
1958                                VTDeleteOnSalvage | VTOutOfService);
1959                 VDONE;
1960
1961                 VPRINT1("Recovery: Deleting backup volume %u ...", backupId);
1962                 AFSVolDeleteVolume(fromconn, fromtid);
1963                 VDONE;
1964
1965                 VPRINT1
1966                     ("Recovery: Ending transaction on backup volume %u ...",
1967                      backupId);
1968                 AFSVolEndTrans(fromconn, fromtid, &rcode);
1969                 VDONE;
1970             } else {
1971                 VPRINT1
1972                     ("\nRecovery: Unable to start transaction on backup volume %u.\n",
1973                      backupId);
1974             }
1975
1976             /* delete source volume */
1977             VPRINT1("Recovery: Creating transaction on source volume %u ...",
1978                     afromvol);
1979             code =
1980                 AFSVolTransCreate_retry(fromconn, afromvol, afrompart, ITBusy,
1981                                   &fromtid);
1982             if (!code) {
1983                 VDONE;
1984
1985                 VPRINT1("Recovery: Setting flags on backup volume %u ...",
1986                         afromvol);
1987                 AFSVolSetFlags(fromconn, fromtid,
1988                                VTDeleteOnSalvage | VTOutOfService);
1989                 VDONE;
1990
1991                 if (atoserver != afromserver) {
1992                     VPRINT("Recovery: Setting volume forwarding pointer ...");
1993                     AFSVolSetForwarding(fromconn, fromtid, atoserver);
1994                     VDONE;
1995                 }
1996
1997                 VPRINT1("Recovery: Deleting source volume %u ...", afromvol);
1998                 AFSVolDeleteVolume(fromconn, fromtid);
1999                 VDONE;
2000
2001                 VPRINT1
2002                     ("Recovery: Ending transaction on source volume %u ...",
2003                      afromvol);
2004                 AFSVolEndTrans(fromconn, fromtid, &rcode);
2005                 VDONE;
2006             } else {
2007                 VPRINT1
2008                     ("\nRecovery: Unable to start transaction on source volume %u.\n",
2009                      afromvol);
2010             }
2011         }
2012     }
2013
2014     /* common cleanup - delete local clone */
2015     if (newVol) {
2016         VPRINT1("Recovery: Creating transaction on clone volume %u ...",
2017                 newVol);
2018         code =
2019             AFSVolTransCreate_retry(fromconn, newVol, afrompart, ITOffline,
2020                               &clonetid);
2021         if (!code) {
2022             VDONE;
2023
2024             VPRINT1("Recovery: Deleting clone volume %u ...", newVol);
2025             AFSVolDeleteVolume(fromconn, clonetid);
2026             VDONE;
2027
2028             VPRINT1("Recovery: Ending transaction on clone volume %u ...",
2029                     newVol);
2030             AFSVolEndTrans(fromconn, clonetid, &rcode);
2031             VDONE;
2032         } else {
2033             VPRINT1
2034                 ("\nRecovery: Unable to start transaction on source volume %u.\n",
2035                  afromvol);
2036         }
2037     }
2038
2039     /* unlock VLDB entry */
2040     if (islocked) {
2041         VPRINT1("Recovery: Releasing lock on VLDB entry for volume %u ...",
2042                 afromvol);
2043         ubik_VL_ReleaseLock(cstruct, 0, afromvol, -1,
2044                             (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP));
2045         VDONE;
2046         islocked = 0;
2047     }
2048   done:                 /* routine cleanup */
2049     if (volName)
2050         free(volName);
2051 #ifdef  ENABLE_BUGFIX_1165
2052     if (infop)
2053         free(infop);
2054 #endif
2055     if (fromconn)
2056         rx_DestroyConnection(fromconn);
2057     if (toconn)
2058         rx_DestroyConnection(toconn);
2059
2060     if (pntg) {
2061         fprintf(STDOUT, "cleanup complete - user verify desired result\n");
2062         fflush(STDOUT);
2063     }
2064     exit(1);
2065 }
2066
2067
2068 int
2069 UV_MoveVolume(afs_uint32 afromvol, afs_int32 afromserver, afs_int32 afrompart,
2070               afs_int32 atoserver, afs_int32 atopart)
2071 {
2072     return UV_MoveVolume2(afromvol, afromserver, afrompart,
2073                           atoserver, atopart, 0);
2074 }
2075
2076
2077 /* Copy volume <afromvol> from <afromserver> <afrompart> to <atoserver>
2078  * <atopart>.  The new volume is named by <atovolname>.  The new volume
2079  * has ID <atovolid> if that is nonzero; otherwise a new ID is allocated
2080  * from the VLDB.  the following flags are supported:
2081  * 
2082  *     RV_RDONLY  - target volume is RO
2083  *     RV_OFFLINE - leave target volume offline
2084  *     RV_CPINCR  - do incremental dump if target exists
2085  *     RV_NOVLDB  - don't create/update VLDB entry
2086  *     RV_NOCLONE - don't use a copy clone
2087  */
2088 int
2089 UV_CopyVolume2(afs_uint32 afromvol, afs_int32 afromserver, afs_int32 afrompart,
2090                char *atovolname, afs_int32 atoserver, afs_int32 atopart,
2091                afs_uint32 atovolid, int flags)
2092 {
2093     struct rx_connection *toconn, *fromconn;
2094     afs_int32 fromtid, totid, clonetid;
2095     char vname[64];
2096     afs_int32 rcode;
2097     afs_int32 fromDate, cloneFromDate;
2098     struct restoreCookie cookie;
2099     register afs_int32 vcode, code;
2100     afs_uint32 cloneVol, newVol;
2101     afs_int32 volflag;
2102     struct volser_status tstatus;
2103     struct destServer destination;
2104
2105     struct nvldbentry entry, newentry, storeEntry;
2106     int islocked, pntg;
2107     afs_int32 error;
2108     int justclone = 0;
2109
2110     islocked = 0;
2111     fromconn = (struct rx_connection *)0;
2112     toconn = (struct rx_connection *)0;
2113     fromtid = 0;
2114     totid = 0;
2115     clonetid = 0;
2116     error = 0;
2117     pntg = 0;
2118     newVol = 0;
2119
2120     /* support control-c processing */
2121     if (setjmp(env))
2122         goto mfail;
2123     (void)signal(SIGINT, sigint_handler);
2124
2125     vcode = VLDB_GetEntryByID(afromvol, -1, &entry);
2126     EGOTO1(mfail, vcode,
2127            "Could not fetch the entry for the volume  %u from the VLDB \n",
2128            afromvol);
2129     MapHostToNetwork(&entry);
2130
2131     pntg = 1;
2132     toconn = UV_Bind(atoserver, AFSCONF_VOLUMEPORT);    /* get connections to the servers */
2133     fromconn = UV_Bind(afromserver, AFSCONF_VOLUMEPORT);
2134     fromtid = totid = 0;        /* initialize to uncreated */
2135
2136
2137     /* check if we can shortcut and use a local clone instead of a full copy */
2138     if (afromserver == atoserver && afrompart == atopart) {
2139         justclone = 1;
2140     }
2141
2142     /* ***
2143      * clone the read/write volume locally.
2144      * ***/
2145
2146     cloneVol = 0;
2147     if (!(flags & RV_NOCLONE)) {
2148         VPRINT1("Starting transaction on source volume %u ...", afromvol);
2149         code = AFSVolTransCreate_retry(fromconn, afromvol, afrompart, ITBusy,
2150                                  &fromtid);
2151         EGOTO1(mfail, code, "Failed to create transaction on the volume %u\n",
2152                afromvol);
2153         VDONE;
2154
2155         /* Get a clone id */
2156         VPRINT1("Allocating new volume id for clone of volume %u ...",
2157                 afromvol);
2158         cloneVol = 0;
2159         vcode = ubik_VL_GetNewVolumeId(cstruct, 0, 1, &cloneVol);
2160         EGOTO1(mfail, vcode,
2161            "Could not get an ID for the clone of volume %u from the VLDB\n",
2162            afromvol);
2163         VDONE;
2164     }
2165
2166     if (atovolid) {
2167         newVol = atovolid;
2168     } else {
2169         /* Get a new volume id */
2170         VPRINT1("Allocating new volume id for copy of volume %u ...", afromvol);
2171         newVol = 0;
2172         vcode = ubik_VL_GetNewVolumeId(cstruct, 0, 1, &newVol);
2173         EGOTO1(mfail, vcode,
2174                "Could not get an ID for the copy of volume %u from the VLDB\n",
2175                afromvol);
2176         VDONE;
2177     }
2178
2179     if (!(flags & RV_NOCLONE)) {
2180         /* Do the clone. Default flags on clone are set to delete on salvage and out of service */
2181         VPRINT1("Cloning source volume %u ...", afromvol);
2182         strcpy(vname, "copy-clone-temp");
2183         code =
2184             AFSVolClone(fromconn, fromtid, 0, readonlyVolume, vname,
2185                         &cloneVol);
2186         EGOTO1(mfail, code, "Failed to clone the source volume %u\n",
2187                afromvol);
2188         VDONE;
2189
2190         VPRINT1("Ending the transaction on the source volume %u ...", afromvol);
2191         rcode = 0;
2192         code = AFSVolEndTrans(fromconn, fromtid, &rcode);
2193         fromtid = 0;
2194         if (!code)
2195             code = rcode;
2196         EGOTO1(mfail, code,
2197                "Failed to end the transaction on the source volume %u\n",
2198                afromvol);
2199         VDONE;
2200     }
2201
2202     /* ***
2203      * Create the destination volume
2204      * ***/
2205
2206     if (!(flags & RV_NOCLONE)) {
2207         VPRINT1("Starting transaction on the cloned volume %u ...", cloneVol);
2208         code =
2209             AFSVolTransCreate_retry(fromconn, cloneVol, afrompart, ITOffline,
2210                           &clonetid);
2211         EGOTO1(mfail, code,
2212                "Failed to start a transaction on the cloned volume%u\n",
2213                cloneVol);
2214         VDONE;
2215
2216         VPRINT1("Setting flags on cloned volume %u ...", cloneVol);
2217         code =
2218             AFSVolSetFlags(fromconn, clonetid,
2219                            VTDeleteOnSalvage | VTOutOfService); /*redundant */
2220         EGOTO1(mfail, code, "Could not set flags on the cloned volume %u\n",
2221                cloneVol);
2222         VDONE;
2223
2224         /* remember time from which we've dumped the volume */
2225         VPRINT1("Getting status of cloned volume %u ...", cloneVol);
2226         code = AFSVolGetStatus(fromconn, clonetid, &tstatus);
2227         EGOTO1(mfail, code,
2228                "Failed to get the status of the cloned volume %u\n",
2229                cloneVol);
2230         VDONE;
2231
2232         fromDate = CLOCKADJ(tstatus.creationDate);
2233     } else {
2234         fromDate = 0;
2235     }
2236
2237     /* create a volume on the target machine */
2238     cloneFromDate = 0;
2239     code = AFSVolTransCreate_retry(toconn, newVol, atopart, ITOffline, &totid);
2240     if (!code) {
2241         if ((flags & RV_CPINCR)) {
2242             VPRINT1("Getting status of pre-existing volume %u ...", newVol);
2243             code = AFSVolGetStatus(toconn, totid, &tstatus);
2244             EGOTO1(mfail, code,
2245                    "Failed to get the status of the pre-existing volume %u\n",
2246                    newVol);
2247             VDONE;
2248
2249             /* Using the update date should be OK here, but add some fudge */
2250             cloneFromDate = CLOCKADJ(tstatus.updateDate);
2251             if ((flags & RV_NOCLONE))
2252                 fromDate = cloneFromDate;
2253
2254             /* XXX We should check that the source volume's creationDate is
2255              * XXX not newer than the existing target volume, and if not,
2256              * XXX throw away the existing target and do a full dump. */
2257
2258             goto cpincr;
2259         }
2260
2261         /* Delete the existing volume.
2262          * While we are deleting the volume in these steps, the transaction
2263          * we started against the cloned volume (clonetid above) will be
2264          * sitting idle. It will get cleaned up after 600 seconds
2265          */
2266         VPRINT1("Deleting pre-existing volume %u on destination ...", newVol);
2267         code = AFSVolDeleteVolume(toconn, totid);
2268         EGOTO1(mfail, code,
2269                "Could not delete the pre-existing volume %u on destination\n",
2270                newVol);
2271         VDONE;
2272
2273         VPRINT1
2274             ("Ending transaction on pre-existing volume %u on destination ...",
2275              newVol);
2276         code = AFSVolEndTrans(toconn, totid, &rcode);
2277         totid = 0;
2278         if (!code)
2279             code = rcode;
2280         EGOTO1(mfail, code,
2281                "Could not end the transaction on pre-existing volume %u on destination\n",
2282                newVol);
2283         VDONE;
2284     }
2285
2286     VPRINT1("Creating the destination volume %u ...", newVol);
2287     code =
2288         AFSVolCreateVolume(toconn, atopart, atovolname,
2289                            (flags & RV_RDONLY) ? volser_RO : volser_RW,
2290                            newVol, &newVol, &totid);
2291     EGOTO1(mfail, code, "Failed to create the destination volume %u\n",
2292            newVol);
2293     VDONE;
2294
2295     VPRINT1("Setting volume flags on destination volume %u ...", newVol);
2296     code =
2297         AFSVolSetFlags(toconn, totid, (VTDeleteOnSalvage | VTOutOfService));
2298     EGOTO1(mfail, code,
2299            "Failed to set the flags on the destination volume %u\n", newVol);
2300     VDONE;
2301
2302 cpincr:
2303
2304     destination.destHost = ntohl(atoserver);
2305     destination.destPort = AFSCONF_VOLUMEPORT;
2306     destination.destSSID = 1;
2307
2308     strncpy(cookie.name, atovolname, VOLSER_OLDMAXVOLNAME);
2309     cookie.type = (flags & RV_RDONLY) ? ROVOL : RWVOL;
2310     cookie.parent = 0;
2311     cookie.clone = 0;
2312
2313     /***
2314      * Now dump the clone to the new volume
2315      ***/
2316
2317     if (!(flags & RV_NOCLONE)) {
2318         /* XXX probably should have some code here that checks to see if
2319          * XXX we are copying to same server and partition - if so, just
2320          * XXX use a clone to save disk space */
2321
2322         /* Copy the clone to the new volume */
2323         VPRINT2("Dumping from clone %u on source to volume %u on destination ...",
2324             cloneVol, newVol);
2325         code =
2326             AFSVolForward(fromconn, clonetid, cloneFromDate, &destination,
2327                           totid, &cookie);
2328         EGOTO1(mfail, code, "Failed to move data for the volume %u\n",
2329                newVol);
2330         VDONE;
2331
2332         VPRINT1("Ending transaction on cloned volume %u ...", cloneVol);
2333         code = AFSVolEndTrans(fromconn, clonetid, &rcode);
2334         if (!code)
2335             code = rcode;
2336         clonetid = 0;
2337         EGOTO1(mfail, code,
2338                "Failed to end the transaction on the cloned volume %u\n",
2339                cloneVol);
2340         VDONE;
2341     }
2342
2343     /* ***
2344      * reattach to the main-line volume, and incrementally dump it.
2345      * ***/
2346
2347     VPRINT1("Starting transaction on source volume %u ...", afromvol);
2348     code = AFSVolTransCreate_retry(fromconn, afromvol, afrompart, ITBusy, &fromtid);
2349     EGOTO1(mfail, code,
2350            "Failed to create a transaction on the source volume %u\n",
2351            afromvol);
2352     VDONE;
2353
2354     /* now do the incremental */
2355     VPRINT2
2356         ("Doing the%s dump from source to destination for volume %u ... ",
2357          (flags & RV_NOCLONE) ? "" : " incremental",
2358          afromvol);
2359     code =
2360         AFSVolForward(fromconn, fromtid, fromDate, &destination, totid,
2361                       &cookie);
2362     EGOTO1(mfail, code,
2363            "Failed to do the%s dump from old site to new site\n",
2364            afromvol);
2365     VDONE;
2366
2367     VPRINT1("Setting volume flags on destination volume %u ...", newVol);
2368     volflag = ((flags & RV_OFFLINE) ? VTOutOfService : 0);      /* off or on-line */
2369     code = AFSVolSetFlags(toconn, totid, volflag);
2370     EGOTO(mfail, code,
2371           "Failed to set the flags to make destination volume online\n");
2372     VDONE;
2373
2374     /* put new volume online */
2375     VPRINT1("Ending transaction on destination volume %u ...", newVol);
2376     code = AFSVolEndTrans(toconn, totid, &rcode);
2377     totid = 0;
2378     if (!code)
2379         code = rcode;
2380     EGOTO1(mfail, code,
2381            "Failed to end the transaction on the destination volume %u\n",
2382            newVol);
2383     VDONE;
2384
2385     VPRINT1("Ending transaction on source volume %u ...", afromvol);
2386     code = AFSVolEndTrans(fromconn, fromtid, &rcode);
2387     fromtid = 0;
2388     if (!code)
2389         code = rcode;
2390     EGOTO1(mfail, code,
2391            "Failed to end the transaction on the source volume %u\n",
2392            afromvol);
2393     VDONE;
2394
2395     fromtid = 0;
2396
2397     if (!(flags & RV_NOCLONE)) {
2398         VPRINT1("Starting transaction on the cloned volume %u ...", cloneVol);
2399         code =
2400             AFSVolTransCreate_retry(fromconn, cloneVol, afrompart, ITOffline,
2401                               &clonetid);
2402         EGOTO1(mfail, code,
2403                "Failed to start a transaction on the cloned volume%u\n",
2404                cloneVol);
2405         VDONE;
2406
2407         /* now delete the clone */
2408         VPRINT1("Deleting the cloned volume %u ...", cloneVol);
2409         code = AFSVolDeleteVolume(fromconn, clonetid);
2410         EGOTO1(mfail, code, "Failed to delete the cloned volume %u\n",
2411                cloneVol);
2412         VDONE;
2413
2414         VPRINT1("Ending transaction on cloned volume %u ...", cloneVol);
2415         code = AFSVolEndTrans(fromconn, clonetid, &rcode);
2416         if (!code)
2417             code = rcode;
2418         clonetid = 0;
2419         EGOTO1(mfail, code,
2420                "Failed to end the transaction on the cloned volume %u\n",
2421                cloneVol);
2422         VDONE;
2423     }
2424
2425     if (!(flags & RV_NOVLDB)) {
2426         /* create the vldb entry for the copied volume */
2427         strncpy(newentry.name, atovolname, VOLSER_OLDMAXVOLNAME);
2428         newentry.nServers = 1;
2429         newentry.serverNumber[0] = atoserver;
2430         newentry.serverPartition[0] = atopart;
2431         newentry.flags = (flags & RV_RDONLY) ? RO_EXISTS : RW_EXISTS;
2432         newentry.serverFlags[0] = (flags & RV_RDONLY) ? ITSROVOL : ITSRWVOL;
2433         newentry.volumeId[RWVOL] = newVol;
2434         newentry.volumeId[ROVOL] = (flags & RV_RDONLY) ? newVol : 0;
2435         newentry.volumeId[BACKVOL] = 0;
2436         newentry.cloneId = 0;
2437         /*map into right byte order, before passing to xdr, the stuff has to be in host
2438          * byte order. Xdr converts it into network order */
2439         MapNetworkToHost(&newentry, &storeEntry);
2440         /* create the vldb entry */
2441         vcode = VLDB_CreateEntry(&storeEntry);
2442         if (vcode) {
2443             fprintf(STDERR,
2444                     "Could not create a VLDB entry for the volume %s %lu\n",
2445                     atovolname, (unsigned long)newVol);
2446             /*destroy the created volume */
2447             VPRINT1("Deleting the newly created volume %u\n", newVol);
2448             AFSVolDeleteVolume(toconn, totid);
2449             error = vcode;
2450             goto mfail;
2451         }
2452         VPRINT2("Created the VLDB entry for the volume %s %u\n", atovolname,
2453                 newVol);
2454     }
2455
2456     /* normal cleanup code */
2457
2458     if (fromtid) {
2459         VPRINT1("Cleanup: Ending transaction on source volume %u ...",
2460                 afromvol);
2461         code = AFSVolEndTrans(fromconn, fromtid, &rcode);
2462         if (code || rcode) {
2463             VPRINT("\n");
2464             fprintf(STDERR,
2465                     "Could not end transaction on the source volume %lu\n",
2466                     (unsigned long)afromvol);
2467             if (!error)
2468                 error = (code ? code : rcode);
2469         }
2470         VDONE;
2471     }
2472
2473     if (clonetid) {
2474         VPRINT1("Cleanup: Ending transaction on clone volume %u ...",
2475                 cloneVol);
2476         code = AFSVolEndTrans(fromconn, clonetid, &rcode);
2477         if (code || rcode) {
2478             VPRINT("\n");
2479             fprintf(STDERR,
2480                     "Could not end transaction on the source's clone volume %lu\n",
2481                     (unsigned long)cloneVol);
2482             if (!error)
2483                 error = (code ? code : rcode);
2484         }
2485         VDONE;
2486     }
2487
2488     if (totid) {
2489         VPRINT1("Cleanup: Ending transaction on destination volume %u ...",
2490                 newVol);
2491         code = AFSVolEndTrans(toconn, totid, &rcode);
2492         if (code) {
2493             VPRINT("\n");
2494             fprintf(STDERR,
2495                     "Could not end transaction on destination volume %lu\n",
2496                     (unsigned long)newVol);
2497             if (!error)
2498                 error = (code ? code : rcode);
2499         }
2500         VDONE;
2501     }
2502     if (fromconn)
2503         rx_DestroyConnection(fromconn);
2504     if (toconn)
2505         rx_DestroyConnection(toconn);
2506     PrintError("", error);
2507     return error;
2508
2509     /* come here only when the sky falls */
2510   mfail:
2511
2512     if (pntg) {
2513         fprintf(STDOUT,
2514                 "vos copy: operation interrupted, cleanup in progress...\n");
2515         fprintf(STDOUT, "clear transaction contexts\n");
2516         fflush(STDOUT);
2517     }
2518
2519     if (clonetid) {
2520         VPRINT("Recovery: Ending transaction on clone volume ...");
2521         AFSVolEndTrans(fromconn, clonetid, &rcode);
2522         VDONE;
2523     }
2524     if (totid) {
2525         VPRINT("Recovery: Ending transaction on destination volume ...");
2526         AFSVolEndTrans(toconn, totid, &rcode);
2527         VDONE;
2528     }
2529     if (fromtid) {              /* put it on-line */
2530         VPRINT("Recovery: Ending transaction on source volume ...");
2531         AFSVolEndTrans(fromconn, fromtid, &rcode);
2532         VDONE;
2533     }
2534
2535     VPRINT("Recovery: Accessing VLDB.\n");
2536     vcode = VLDB_GetEntryByID(afromvol, -1, &entry);
2537     if (vcode) {
2538         fprintf(STDOUT, "FATAL: VLDB access error: abort cleanup\n");
2539         fflush(STDOUT);
2540         goto done;
2541     }
2542     MapHostToNetwork(&entry);
2543
2544     /* common cleanup - delete local clone */
2545     if (cloneVol) {
2546         VPRINT1("Recovery: Creating transaction on clone volume %u ...",
2547                 cloneVol);
2548         code =
2549             AFSVolTransCreate_retry(fromconn, cloneVol, afrompart, ITOffline,
2550                               &clonetid);
2551         if (!code) {
2552             VDONE;
2553
2554             VPRINT1("Recovery: Deleting clone volume %u ...", cloneVol);
2555             AFSVolDeleteVolume(fromconn, clonetid);
2556             VDONE;
2557
2558             VPRINT1("Recovery: Ending transaction on clone volume %u ...",
2559                     cloneVol);
2560             AFSVolEndTrans(fromconn, clonetid, &rcode);
2561             VDONE;
2562         } else {
2563             VPRINT1
2564                 ("\nRecovery: Unable to start transaction on clone volume %u.\n",
2565                  cloneVol);
2566         }
2567     }
2568
2569   done:                 /* routine cleanup */
2570     if (fromconn)
2571         rx_DestroyConnection(fromconn);
2572     if (toconn)
2573         rx_DestroyConnection(toconn);
2574
2575     if (pntg) {
2576         fprintf(STDOUT, "cleanup complete - user verify desired result\n");
2577         fflush(STDOUT);
2578     }
2579     exit(1);
2580 }
2581
2582
2583 int
2584 UV_CopyVolume(afs_uint32 afromvol, afs_int32 afromserver, afs_int32 afrompart,
2585               char *atovolname, afs_int32 atoserver, afs_int32 atopart)
2586 {
2587     return UV_CopyVolume2(afromvol, afromserver, afrompart,
2588                           atovolname, atoserver, atopart, 0, 0);
2589 }
2590
2591
2592
2593 /* Make a new backup of volume <avolid> on <aserver> and <apart> 
2594  * if one already exists, update it 
2595  */
2596
2597 int
2598 UV_BackupVolume(afs_int32 aserver, afs_int32 apart, afs_uint32 avolid)
2599 {
2600     struct rx_connection *aconn = (struct rx_connection *)0;
2601     afs_int32 ttid = 0, btid = 0;
2602     afs_uint32 backupID;
2603     afs_int32 code = 0, rcode = 0;
2604     char vname[VOLSER_MAXVOLNAME + 1];
2605     struct nvldbentry entry, storeEntry;
2606     afs_int32 error = 0;
2607     int vldblocked = 0, vldbmod = 0, backexists = 1;
2608
2609     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
2610
2611     /* the calls to VLDB will succeed only if avolid is a RW volume,
2612      * since we are following the RW hash chain for searching */
2613     code = VLDB_GetEntryByID(avolid, RWVOL, &entry);
2614     if (code) {
2615         fprintf(STDERR,
2616                 "Could not fetch the entry for the volume %lu from the VLDB \n",
2617                 (unsigned long)avolid);
2618         error = code;
2619         goto bfail;
2620     }
2621     MapHostToNetwork(&entry);
2622
2623     /* These operations require the VLDB be locked since it means the VLDB
2624      * will change or the vldb is already locked.
2625      */
2626     if (!(entry.flags & BACK_EXISTS) || /* backup volume doesnt exist */
2627         (entry.flags & VLOP_ALLOPERS) ||        /* vldb lock already held */
2628         (entry.volumeId[BACKVOL] == INVALID_BID)) {     /* no assigned backup volume id */
2629
2630         code = ubik_VL_SetLock(cstruct, 0, avolid, RWVOL, VLOP_BACKUP);
2631         if (code) {
2632             fprintf(STDERR,
2633                     "Could not lock the VLDB entry for the volume %lu\n",
2634                     (unsigned long)avolid);
2635             error = code;
2636             goto bfail;
2637         }
2638         vldblocked = 1;
2639
2640         /* Reread the vldb entry */
2641         code = VLDB_GetEntryByID(avolid, RWVOL, &entry);
2642         if (code) {
2643             fprintf(STDERR,
2644                     "Could not fetch the entry for the volume %lu from the VLDB \n",
2645                     (unsigned long)avolid);
2646             error = code;
2647             goto bfail;
2648         }
2649         MapHostToNetwork(&entry);
2650     }
2651
2652     if (!ISNAMEVALID(entry.name)) {
2653         fprintf(STDERR, "Name of the volume %s exceeds the size limit\n",
2654                 entry.name);
2655         error = VOLSERBADNAME;
2656         goto bfail;
2657     }
2658
2659     backupID = entry.volumeId[BACKVOL];
2660     if (backupID == INVALID_BID) {
2661         /* Get a backup volume id from the VLDB and update the vldb
2662          * entry with it. 
2663          */
2664         code = ubik_VL_GetNewVolumeId(cstruct, 0, 1, &backupID);
2665         if (code) {
2666             fprintf(STDERR,
2667                     "Could not allocate ID for the backup volume of  %lu from the VLDB\n",
2668                     (unsigned long)avolid);
2669             error = code;
2670             goto bfail;
2671         }
2672         entry.volumeId[BACKVOL] = backupID;
2673         vldbmod = 1;
2674     }
2675
2676     /* Test to see if the backup volume exists by trying to create
2677      * a transaction on the backup volume. We've assumed the backup exists.
2678      */
2679     code = AFSVolTransCreate_retry(aconn, backupID, apart, ITOffline, &btid);
2680     if (code) {
2681         if (code != VNOVOL) {
2682             fprintf(STDERR, "Could not reach the backup volume %lu\n",
2683                     (unsigned long)backupID);
2684             error = code;
2685             goto bfail;
2686         }
2687         backexists = 0;         /* backup volume does not exist */
2688     }
2689     if (btid) {
2690         code = AFSVolEndTrans(aconn, btid, &rcode);
2691         btid = 0;
2692         if (code || rcode) {
2693             fprintf(STDERR,
2694                     "Could not end transaction on the previous backup volume %lu\n",
2695                     (unsigned long)backupID);
2696             error = (code ? code : rcode);
2697             goto bfail;
2698         }
2699     }
2700
2701     /* Now go ahead and try to clone the RW volume.
2702      * First start a transaction on the RW volume 
2703      */
2704     code = AFSVolTransCreate_retry(aconn, avolid, apart, ITBusy, &ttid);
2705     if (code) {
2706         fprintf(STDERR, "Could not start a transaction on the volume %lu\n",
2707                 (unsigned long)avolid);
2708         error = code;
2709         goto bfail;
2710     }
2711
2712     /* Clone or reclone the volume, depending on whether the backup 
2713      * volume exists or not
2714      */
2715     if (backexists) {
2716         VPRINT1("Re-cloning backup volume %u ...", backupID);
2717
2718         code = AFSVolReClone(aconn, ttid, backupID);
2719         if (code) {
2720             fprintf(STDERR, "Could not re-clone backup volume %lu\n",
2721                     (unsigned long)backupID);
2722             error = code;
2723             goto bfail;
2724         }
2725     } else {
2726         VPRINT1("Creating a new backup clone %u ...", backupID);
2727
2728         strcpy(vname, entry.name);
2729         strcat(vname, ".backup");
2730
2731         code = AFSVolClone(aconn, ttid, 0, backupVolume, vname, &backupID);
2732         if (code) {
2733             fprintf(STDERR, "Failed to clone the volume %lu\n",
2734                     (unsigned long)avolid);
2735             error = code;
2736             goto bfail;
2737         }
2738     }
2739
2740     /* End the transaction on the RW volume */
2741     code = AFSVolEndTrans(aconn, ttid, &rcode);
2742     ttid = 0;
2743     if (code || rcode) {
2744         fprintf(STDERR,
2745                 "Failed to end the transaction on the rw volume %lu\n",
2746                 (unsigned long)avolid);
2747         error = (code ? code : rcode);
2748         goto bfail;
2749     }
2750
2751     /* Mork vldb as backup exists */
2752     if (!(entry.flags & BACK_EXISTS)) {
2753         entry.flags |= BACK_EXISTS;
2754         vldbmod = 1;
2755     }
2756
2757     /* Now go back to the backup volume and bring it on line */
2758     code = AFSVolTransCreate_retry(aconn, backupID, apart, ITOffline, &btid);
2759     if (code) {
2760         fprintf(STDERR,
2761                 "Failed to start a transaction on the backup volume %lu\n",
2762                 (unsigned long)backupID);
2763         error = code;
2764         goto bfail;
2765     }
2766
2767     code = AFSVolSetFlags(aconn, btid, 0);
2768     if (code) {
2769         fprintf(STDERR, "Could not mark the backup volume %lu on line \n",
2770                 (unsigned long)backupID);
2771         error = code;
2772         goto bfail;
2773     }
2774
2775     code = AFSVolEndTrans(aconn, btid, &rcode);
2776     btid = 0;
2777     if (code || rcode) {
2778         fprintf(STDERR,
2779                 "Failed to end the transaction on the backup volume %lu\n",
2780                 (unsigned long)backupID);
2781         error = (code ? code : rcode);
2782         goto bfail;
2783     }
2784
2785     VDONE;
2786
2787     /* Will update the vldb below */
2788
2789   bfail:
2790     if (ttid) {
2791         code = AFSVolEndTrans(aconn, ttid, &rcode);
2792         if (code || rcode) {
2793             fprintf(STDERR, "Could not end transaction on the volume %lu\n",
2794                     (unsigned long)avolid);
2795             if (!error)
2796                 error = (code ? code : rcode);
2797         }
2798     }
2799
2800     if (btid) {
2801         code = AFSVolEndTrans(aconn, btid, &rcode);
2802         if (code || rcode) {
2803             fprintf(STDERR,
2804                     "Could not end transaction the backup volume %lu\n",
2805                     (unsigned long)backupID);
2806             if (!error)
2807                 error = (code ? code : rcode);
2808         }
2809     }
2810
2811     /* Now update the vldb - if modified */
2812     if (vldblocked) {
2813         if (vldbmod) {
2814             MapNetworkToHost(&entry, &storeEntry);
2815             code =
2816                 VLDB_ReplaceEntry(avolid, RWVOL, &storeEntry,
2817                                   (LOCKREL_OPCODE | LOCKREL_AFSID |
2818                                    LOCKREL_TIMESTAMP));
2819             if (code) {
2820                 fprintf(STDERR,
2821                         "Could not update the VLDB entry for the volume %lu \n",
2822                         (unsigned long)avolid);
2823                 if (!error)
2824                     error = code;
2825             }
2826         } else {
2827             code =
2828                 ubik_VL_ReleaseLock(cstruct, 0, avolid, RWVOL,
2829                           (LOCKREL_OPCODE | LOCKREL_AFSID |
2830                            LOCKREL_TIMESTAMP));
2831             if (code) {
2832                 fprintf(STDERR,
2833                         "Could not unlock the VLDB entry for the volume %lu \n",
2834                         (unsigned long)avolid);
2835                 if (!error)
2836                     error = code;
2837             }
2838         }
2839     }
2840
2841     if (aconn)
2842         rx_DestroyConnection(aconn);
2843
2844     PrintError("", error);
2845     return error;
2846 }
2847
2848 /* Make a new clone of volume <avolid> on <aserver> and <apart> 
2849  * using volume ID <acloneid>, or a new ID allocated from the VLDB.
2850  * The new volume is named by <aname>, or by appending ".clone" to
2851  * the existing name if <aname> is NULL.  The following flags are
2852  * supported:
2853  * 
2854  *     RV_RDONLY  - target volume is RO
2855  *     RV_OFFLINE - leave target volume offline
2856  */
2857
2858 int
2859 UV_CloneVolume(afs_int32 aserver, afs_int32 apart, afs_uint32 avolid,
2860                afs_uint32 acloneid, char *aname, int flags)
2861 {
2862     struct rx_connection *aconn = (struct rx_connection *)0;
2863     afs_int32 ttid = 0, btid = 0;
2864     afs_int32 code = 0, rcode = 0;
2865     char vname[VOLSER_MAXVOLNAME + 1];
2866     afs_int32 error = 0;
2867     int backexists = 1;
2868     volEntries volumeInfo;
2869
2870     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
2871
2872     if (!aname) {
2873         volumeInfo.volEntries_val = (volintInfo *) 0;
2874         volumeInfo.volEntries_len = 0;
2875         code = AFSVolListOneVolume(aconn, apart, avolid, &volumeInfo);
2876         if (code) {
2877             fprintf(stderr, "Could not get info for volume %lu\n",
2878                     (unsigned long)avolid);
2879             error = code;
2880             goto bfail;
2881         }
2882         strncpy(vname, volumeInfo.volEntries_val[0].name,
2883                 VOLSER_OLDMAXVOLNAME - 7);
2884         vname[VOLSER_OLDMAXVOLNAME - 7] = 0;
2885         strcat(vname, ".clone");
2886         aname = vname;
2887         if (volumeInfo.volEntries_val)
2888             free(volumeInfo.volEntries_val);
2889     }
2890
2891     if (!acloneid) {
2892         /* Get a clone id */
2893         VPRINT1("Allocating new volume id for clone of volume %u ...",
2894                 avolid);
2895         code = ubik_VL_GetNewVolumeId(cstruct, 0, 1, &acloneid);
2896         EGOTO1(bfail, code,
2897            "Could not get an ID for the clone of volume %u from the VLDB\n",
2898            avolid);
2899         VDONE;
2900     }
2901
2902     /* Test to see if the clone volume exists by trying to create
2903      * a transaction on the clone volume. We've assumed the clone exists.
2904      */
2905     /* XXX I wonder what happens if the clone has some other parent... */
2906     code = AFSVolTransCreate_retry(aconn, acloneid, apart, ITOffline, &btid);
2907     if (code) {
2908         if (code != VNOVOL) {
2909             fprintf(STDERR, "Could not reach the clone volume %lu\n",
2910                     (unsigned long)acloneid);
2911             error = code;
2912             goto bfail;
2913         }
2914         backexists = 0;         /* backup volume does not exist */
2915     }
2916     if (btid) {
2917         code = AFSVolEndTrans(aconn, btid, &rcode);
2918         btid = 0;
2919         if (code || rcode) {
2920             fprintf(STDERR,
2921                     "Could not end transaction on the previous clone volume %lu\n",
2922                     (unsigned long)acloneid);
2923             error = (code ? code : rcode);
2924             goto bfail;
2925         }
2926     }
2927
2928     /* Now go ahead and try to clone the RW volume.
2929      * First start a transaction on the RW volume 
2930      */
2931     code = AFSVolTransCreate_retry(aconn, avolid, apart, ITBusy, &ttid);
2932     if (code) {
2933         fprintf(STDERR, "Could not start a transaction on the volume %lu\n",
2934                 (unsigned long)avolid);
2935         error = code;
2936         goto bfail;
2937     }
2938
2939     /* Clone or reclone the volume, depending on whether the backup 
2940      * volume exists or not
2941      */
2942     if (backexists) {
2943         VPRINT1("Re-cloning clone volume %u ...", acloneid);
2944
2945         code = AFSVolReClone(aconn, ttid, acloneid);
2946         if (code) {
2947             fprintf(STDERR, "Could not re-clone backup volume %lu\n",
2948                     (unsigned long)acloneid);
2949             error = code;
2950             goto bfail;
2951         }
2952     } else {
2953         VPRINT1("Creating a new clone %u ...", acloneid);
2954
2955         code = AFSVolClone(aconn, ttid, 0,
2956                            (flags & RV_RDONLY) ? readonlyVolume : backupVolume,
2957                            aname, &acloneid);
2958         if (code) {
2959             fprintf(STDERR, "Failed to clone the volume %lu\n",
2960                     (unsigned long)avolid);
2961             error = code;
2962             goto bfail;
2963         }
2964     }
2965
2966     /* End the transaction on the RW volume */
2967     code = AFSVolEndTrans(aconn, ttid, &rcode);
2968     ttid = 0;
2969     if (code || rcode) {
2970         fprintf(STDERR,
2971                 "Failed to end the transaction on the rw volume %lu\n",
2972                 (unsigned long)avolid);
2973         error = (code ? code : rcode);
2974         goto bfail;
2975     }
2976
2977     /* Now go back to the backup volume and bring it on line */
2978     if (!(flags & RV_OFFLINE)) {
2979         code = AFSVolTransCreate_retry(aconn, acloneid, apart, ITOffline, &btid);
2980         if (code) {
2981             fprintf(STDERR,
2982                     "Failed to start a transaction on the clone volume %lu\n",
2983                     (unsigned long)acloneid);
2984             error = code;
2985             goto bfail;
2986         }
2987
2988         code = AFSVolSetFlags(aconn, btid, 0);
2989         if (code) {
2990             fprintf(STDERR, "Could not mark the clone volume %lu on line \n",
2991                     (unsigned long)acloneid);
2992             error = code;
2993             goto bfail;
2994         }
2995
2996         code = AFSVolEndTrans(aconn, btid, &rcode);
2997         btid = 0;
2998         if (code || rcode) {
2999             fprintf(STDERR,
3000                     "Failed to end the transaction on the clone volume %lu\n",
3001                     (unsigned long)acloneid);
3002             error = (code ? code : rcode);
3003             goto bfail;
3004         }
3005     }
3006
3007     VDONE;
3008
3009   bfail:
3010     if (ttid) {
3011         code = AFSVolEndTrans(aconn, ttid, &rcode);
3012         if (code || rcode) {
3013             fprintf(STDERR, "Could not end transaction on the volume %lu\n",
3014                     (unsigned long)avolid);
3015             if (!error)
3016                 error = (code ? code : rcode);
3017         }
3018     }
3019
3020     if (btid) {
3021         code = AFSVolEndTrans(aconn, btid, &rcode);
3022         if (code || rcode) {
3023             fprintf(STDERR,
3024                     "Could not end transaction on the clone volume %lu\n",
3025                     (unsigned long)acloneid);
3026             if (!error)
3027                 error = (code ? code : rcode);
3028         }
3029     }
3030
3031     if (aconn)
3032         rx_DestroyConnection(aconn);
3033
3034     PrintError("", error);
3035     return error;
3036 }
3037
3038 static int
3039 DelVol(struct rx_connection *conn, afs_uint32 vid, afs_int32 part,
3040        afs_int32 flags)
3041 {
3042     afs_int32 acode, ccode, rcode, tid;
3043     ccode = rcode = tid = 0;
3044
3045     acode = AFSVolTransCreate_retry(conn, vid, part, flags, &tid);
3046     if (!acode) {               /* It really was there */
3047         acode = AFSVolDeleteVolume(conn, tid);
3048         if (acode) {
3049             fprintf(STDERR, "Failed to delete volume %lu.\n",
3050                     (unsigned long)vid);
3051             PrintError("", acode);
3052         }
3053         ccode = AFSVolEndTrans(conn, tid, &rcode);
3054         if (!ccode)
3055             ccode = rcode;
3056         if (ccode) {
3057             fprintf(STDERR, "Failed to end transaction on volume %lu.\n",
3058                     (unsigned long)vid);
3059             PrintError("", ccode);
3060         }
3061     }
3062
3063     return acode;
3064 }
3065
3066 #define ONERROR(ec, ep, es) if (ec) { fprintf(STDERR, (es), (ep)); error = (ec); goto rfail; }
3067 #define ERROREXIT(ec) { error = (ec); goto rfail; }
3068
3069 /* Get a "transaction" on this replica.  Create the volume 
3070  * if necessary.  Return the time from which a dump should
3071  * be made (0 if it's a new volume)
3072  */
3073 static int
3074 GetTrans(struct nvldbentry *vldbEntryPtr, afs_int32 index,
3075          struct rx_connection **connPtr, afs_int32 * transPtr,
3076          afs_int32 * crtimePtr, afs_int32 * uptimePtr)
3077 {
3078     afs_uint32 volid;
3079     struct volser_status tstatus;
3080     int code = 0;
3081     int rcode, tcode;
3082     char hoststr[16];
3083
3084     *connPtr = (struct rx_connection *)0;
3085     *transPtr = 0;
3086     *crtimePtr = 0;
3087     *uptimePtr = 0;
3088
3089     /* get connection to the replication site */
3090     *connPtr = UV_Bind(vldbEntryPtr->serverNumber[index], AFSCONF_VOLUMEPORT);
3091     if (!*connPtr)
3092         goto fail;              /* server is down */
3093
3094     volid = vldbEntryPtr->volumeId[ROVOL];
3095     if (volid)
3096         code =
3097             AFSVolTransCreate_retry(*connPtr, volid,
3098                               vldbEntryPtr->serverPartition[index], ITOffline,
3099                               transPtr);
3100
3101     /* If the volume does not exist, create it */
3102     if (!volid || code) {
3103         char volname[64];
3104         char hoststr[16];
3105
3106         if (volid && (code != VNOVOL)) {
3107             PrintError("Failed to start a transaction on the RO volume.\n",
3108                        code);
3109             goto fail;
3110         }
3111
3112         strcpy(volname, vldbEntryPtr->name);
3113         strcat(volname, ".readonly");
3114
3115         if (verbose) {
3116             fprintf(STDOUT,
3117                     "Creating new volume %lu on replication site %s: ",
3118                     (unsigned long)volid,
3119                     noresolve ? afs_inet_ntoa_r(vldbEntryPtr->
3120                                                 serverNumber[index], hoststr) :
3121                     hostutil_GetNameByINet(vldbEntryPtr->
3122                                            serverNumber[index]));
3123             fflush(STDOUT);
3124         }
3125
3126         code =
3127             AFSVolCreateVolume(*connPtr, vldbEntryPtr->serverPartition[index],
3128                                volname, volser_RO,
3129                                vldbEntryPtr->volumeId[RWVOL], &volid,
3130                                transPtr);
3131         if (code) {
3132             PrintError("Failed to create the ro volume: ", code);
3133             goto fail;
3134         }
3135         vldbEntryPtr->volumeId[ROVOL] = volid;
3136
3137         VDONE;
3138
3139         /* The following is a bit redundant, since create sets these flags by default */
3140         code =
3141             AFSVolSetFlags(*connPtr, *transPtr,
3142                            VTDeleteOnSalvage | VTOutOfService);
3143         if (code) {
3144             PrintError("Failed to set flags on the ro volume: ", code);
3145             goto fail;
3146         }
3147     }
3148
3149     /* Otherwise, the transaction did succeed, so get the creation date of the
3150      * latest RO volume on the replication site 
3151      */
3152     else {
3153         VPRINT2("Updating existing ro volume %u on %s ...\n", volid,
3154                 noresolve ? afs_inet_ntoa_r(vldbEntryPtr->
3155                                             serverNumber[index], hoststr) : 
3156                 hostutil_GetNameByINet(vldbEntryPtr->serverNumber[index]));
3157
3158         code = AFSVolGetStatus(*connPtr, *transPtr, &tstatus);
3159         if (code) {
3160             PrintError("Failed to get status of volume on destination: ",
3161                        code);
3162             goto fail;
3163         }
3164         *crtimePtr = CLOCKADJ(tstatus.creationDate);
3165         *uptimePtr = CLOCKADJ(tstatus.updateDate);
3166     }
3167
3168     return 0;
3169
3170   fail:
3171     if (*transPtr) {
3172         tcode = AFSVolEndTrans(*connPtr, *transPtr, &rcode);
3173         *transPtr = 0;
3174         if (!tcode)
3175             tcode = rcode;
3176         if (tcode)
3177             PrintError("Could not end transaction on a ro volume: ", tcode);
3178     }
3179
3180     return code;
3181 }
3182
3183 static int
3184 SimulateForwardMultiple(struct rx_connection *fromconn, afs_int32 fromtid,
3185                         afs_int32 fromdate, manyDests * tr, afs_int32 flags,
3186                         void *cookie, manyResults * results)
3187 {
3188     unsigned int i;
3189
3190     for (i = 0; i < tr->manyDests_len; i++) {
3191         results->manyResults_val[i] =
3192             AFSVolForward(fromconn, fromtid, fromdate,
3193                           &(tr->manyDests_val[i].server),
3194                           tr->manyDests_val[i].trans, cookie);
3195     }
3196     return 0;
3197 }
3198
3199
3200 /* UV_ReleaseVolume()
3201  *    Release volume <afromvol> on <afromserver> <afrompart> to all
3202  *    its RO sites (full release). Unless the previous release was
3203  *    incomplete: in which case we bring the remaining incomplete
3204  *    volumes up to date with the volumes that were released
3205  *    successfully.
3206  *    forceflag: Performs a full release.
3207  *
3208  *    Will create a clone from the RW, then dump the clone out to 
3209  *    the remaining replicas. If there is more than 1 RO sites,
3210  *    ensure that the VLDB says at least one RO is available all
3211  *    the time: Influences when we write back the VLDB entry.
3212  */
3213
3214 int
3215 UV_ReleaseVolume(afs_uint32 afromvol, afs_int32 afromserver,
3216                  afs_int32 afrompart, int forceflag)
3217 {
3218     char vname[64];
3219     afs_int32 code = 0;
3220     afs_int32 vcode, rcode, tcode;
3221     afs_uint32 cloneVolId, roVolId;
3222     struct replica *replicas = 0;
3223     struct nvldbentry entry, storeEntry;
3224     int i, volcount, m, fullrelease, vldbindex;
3225     int failure;
3226     struct restoreCookie cookie;
3227     struct rx_connection **toconns = 0;
3228     struct release *times = 0;
3229     int nservers = 0;
3230     struct rx_connection *fromconn = (struct rx_connection *)0;
3231     afs_int32 error = 0;
3232     int islocked = 0;
3233     afs_int32 clonetid = 0, onlinetid;
3234     afs_int32 fromtid = 0;
3235     afs_uint32 fromdate = 0;
3236     afs_uint32 thisdate;
3237     time_t tmv;
3238     int s;
3239     manyDests tr;
3240     manyResults results;
3241     int rwindex, roindex, roclone, roexists;
3242     afs_uint32 rwcrdate = 0;
3243     afs_uint32 rwupdate, clcrdate;
3244     struct rtime {
3245         int validtime;
3246         afs_uint32 uptime;
3247     } remembertime[NMAXNSERVERS];
3248     int releasecount = 0;
3249     struct volser_status volstatus;
3250     char hoststr[16];
3251
3252     memset((char *)remembertime, 0, sizeof(remembertime));
3253     memset((char *)&results, 0, sizeof(results));
3254
3255     vcode = ubik_VL_SetLock(cstruct, 0, afromvol, RWVOL, VLOP_RELEASE);
3256     if (vcode != VL_RERELEASE)
3257         ONERROR(vcode, afromvol,
3258                 "Could not lock the VLDB entry for the volume %u.\n");
3259     islocked = 1;
3260
3261     /* Get the vldb entry in readable format */
3262     vcode = VLDB_GetEntryByID(afromvol, RWVOL, &entry);
3263     ONERROR(vcode, afromvol,
3264             "Could not fetch the entry for the volume %u from the VLDB.\n");
3265     MapHostToNetwork(&entry);
3266
3267     if (verbose)
3268         EnumerateEntry(&entry);
3269
3270     if (!ISNAMEVALID(entry.name))
3271         ONERROR(VOLSERBADOP, entry.name,
3272                 "Volume name %s is too long, rename before releasing.\n");
3273     if (entry.volumeId[RWVOL] != afromvol)
3274         ONERROR(VOLSERBADOP, afromvol,
3275                 "The volume %u being released is not a read-write volume.\n");
3276     if (entry.nServers <= 1)
3277         ONERROR(VOLSERBADOP, afromvol,
3278                 "Volume %u has no replicas - release operation is meaningless!\n");
3279     if (strlen(entry.name) > (VOLSER_OLDMAXVOLNAME - 10))
3280         ONERROR(VOLSERBADOP, entry.name,
3281                 "RO volume name %s exceeds (VOLSER_OLDMAXVOLNAME - 10) character limit\n");
3282
3283     /* roclone is true if one of the RO volumes is on the same
3284      * partition as the RW volume. In this case, we make the RO volume
3285      * on the same partition a clone instead of a complete copy.
3286      */
3287
3288     roindex = Lp_ROMatch(afromserver, afrompart, &entry) - 1;
3289     roclone = ((roindex == -1) ? 0 : 1);
3290     rwindex = Lp_GetRwIndex(&entry);
3291     if (rwindex < 0)
3292         ONERROR(VOLSERNOVOL, 0, "There is no RW volume \n");
3293
3294     /* Make sure we have a RO volume id to work with */
3295     if (entry.volumeId[ROVOL] == INVALID_BID) {
3296         /* need to get a new RO volume id */
3297         vcode = ubik_VL_GetNewVolumeId(cstruct, 0, 1, &roVolId);
3298         ONERROR(vcode, entry.name, "Cant allocate ID for RO volume of %s\n");
3299
3300         entry.volumeId[ROVOL] = roVolId;
3301         MapNetworkToHost(&entry, &storeEntry);
3302         vcode = VLDB_ReplaceEntry(afromvol, RWVOL, &storeEntry, 0);
3303         ONERROR(vcode, entry.name, "Could not update vldb entry for %s.\n");
3304     }
3305
3306     /* Will we be completing a previously unfinished release. -force overrides */
3307     for (s = 0, m = 0, fullrelease=0, i=0; (i<entry.nServers); i++) {
3308         if (entry.serverFlags[i] & ITSROVOL) {
3309             m++;
3310             if (entry.serverFlags[i] & NEW_REPSITE) s++;
3311         }
3312     }
3313     if ((forceflag && !fullrelease) || (s == m) || (s == 0))
3314         fullrelease = 1;
3315
3316     /* Determine which volume id to use and see if it exists */
3317     cloneVolId =
3318         ((fullrelease
3319           || (entry.cloneId == 0)) ? entry.volumeId[ROVOL] : entry.cloneId);
3320     code = VolumeExists(afromserver, afrompart, cloneVolId);
3321     roexists = ((code == ENODEV) ? 0 : 1);
3322
3323     fromconn = UV_Bind(afromserver, AFSCONF_VOLUMEPORT);
3324     if (!fromconn)
3325         ONERROR(-1, afromserver,
3326                 "Cannot establish connection with server 0x%x\n");
3327
3328     if (!fullrelease) {
3329         if (!roexists)
3330             fullrelease = 1;    /* Do a full release if RO clone does not exist */
3331         else {
3332             /* Begin transaction on RW and mark it busy while we query it */
3333             code = AFSVolTransCreate_retry(
3334                         fromconn, afromvol, afrompart, ITBusy, &fromtid
3335                    );
3336             ONERROR(code, afromvol,
3337                     "Failed to start transaction on RW volume %u\n");
3338
3339             /* Query the creation date for the RW */
3340             code = AFSVolGetStatus(fromconn, fromtid, &volstatus);
3341             ONERROR(code, afromvol,
3342                     "Failed to get the status of RW volume %u\n");
3343             rwcrdate = volstatus.creationDate;
3344             rwupdate = volstatus.updateDate;
3345
3346             /* End transaction on RW */
3347             code = AFSVolEndTrans(fromconn, fromtid, &rcode);
3348             fromtid = 0;
3349             ONERROR((code ? code : rcode), afromvol,
3350                     "Failed to end transaction on RW volume %u\n");
3351
3352             /* Begin transaction on clone and mark it busy while we query it */
3353             code = AFSVolTransCreate_retry(
3354                         fromconn, cloneVolId, afrompart, ITBusy, &clonetid
3355                    );
3356             ONERROR(code, cloneVolId,
3357                     "Failed to start transaction on RW clone %u\n");
3358
3359             /* Query the creation date for the clone */
3360             code = AFSVolGetStatus(fromconn, clonetid, &volstatus);
3361             ONERROR(code, cloneVolId,
3362                     "Failed to get the status of RW clone %u\n");
3363             clcrdate = volstatus.creationDate;
3364
3365             /* End transaction on clone */
3366             code = AFSVolEndTrans(fromconn, clonetid, &rcode);
3367             clonetid = 0;
3368             ONERROR((code ? code : rcode), cloneVolId,
3369                     "Failed to end transaction on RW clone %u\n");
3370
3371             if (rwcrdate > clcrdate)
3372                 fullrelease = 2;/* Do a full release if RO clone older than RW */
3373         }
3374     }
3375
3376     if (verbose) {
3377         switch (fullrelease) {
3378             case 2:
3379                 fprintf(STDOUT, "RW %lu changed, doing a complete release\n",
3380                         (unsigned long)afromvol);
3381                 break;
3382             case 1:
3383                 fprintf(STDOUT, "This is a complete release of volume %lu\n",
3384                         (unsigned long)afromvol);
3385                 break;
3386             case 0:
3387                 fprintf(STDOUT, "This is a completion of a previous release\n");
3388                 break;
3389         }
3390     }
3391
3392     if (fullrelease) {
3393         /* If the RO clone exists, then if the clone is a temporary
3394          * clone, delete it. Or if the RO clone is marked RO_DONTUSE
3395          * (it was recently added), then also delete it. We do not
3396          * want to "reclone" a temporary RO clone.
3397          */
3398         if (roexists
3399             && (!roclone || (entry.serverFlags[roindex] & RO_DONTUSE))) {
3400             code = DelVol(fromconn, cloneVolId, afrompart, ITOffline);
3401             if (code && (code != VNOVOL))
3402                 ERROREXIT(code);
3403             roexists = 0;
3404         }
3405
3406         /* Mark all the ROs in the VLDB entry as RO_DONTUSE. We don't
3407          * write this entry out to the vlserver until after the first
3408          * RO volume is released (temp RO clones don't count).
3409          */
3410         for (i = 0; i < entry.nServers; i++) {
3411             entry.serverFlags[i] &= ~NEW_REPSITE;
3412             entry.serverFlags[i] |= RO_DONTUSE;
3413         }
3414         entry.serverFlags[rwindex] |= NEW_REPSITE;
3415         entry.serverFlags[rwindex] &= ~RO_DONTUSE;
3416
3417         /* Begin transaction on RW and mark it busy while we clone it */
3418         code =
3419             AFSVolTransCreate_retry(fromconn, afromvol, afrompart, ITBusy,
3420                               &clonetid);
3421         ONERROR(code, afromvol, "Failed to start transaction on volume %u\n");
3422
3423         /* Clone or reclone the volume */
3424         if (roexists) {
3425             VPRINT1("Recloning RW volume %u...", cloneVolId);
3426             code = AFSVolReClone(fromconn, clonetid, cloneVolId);
3427             ONERROR(code, afromvol, "Failed to reclone the RW volume %u\n");
3428             VDONE;
3429         } else {
3430             if (roclone) {
3431                 strcpy(vname, entry.name);
3432                 strcat(vname, ".readonly");
3433                 VPRINT1("Cloning RW volume %u to permanent RO...", afromvol);
3434             } else {
3435                 strcpy(vname, "readonly-clone-temp");
3436                 VPRINT1("Cloning RW volume %u to temporary RO...", afromvol);
3437             }
3438             code =
3439                 AFSVolClone(fromconn, clonetid, 0, readonlyVolume, vname,
3440                             &cloneVolId);
3441             ONERROR(code, afromvol, "Failed to clone the RW volume %u\n");
3442             VDONE;
3443         }
3444
3445         /* Get the time the RW was created for future information */
3446         VPRINT1("Getting status of RW volume %u...", afromvol);
3447         code = AFSVolGetStatus(fromconn, clonetid, &volstatus);
3448         ONERROR(code, afromvol,
3449                 "Failed to get the status of the RW volume %u\n");
3450         VDONE;
3451         rwcrdate = volstatus.creationDate;
3452         rwupdate = volstatus.updateDate;
3453
3454         /* End the transaction on the RW volume */
3455         VPRINT1("Ending cloning transaction on RW volume %u...", afromvol);
3456         code = AFSVolEndTrans(fromconn, clonetid, &rcode);
3457         clonetid = 0;
3458         ONERROR((code ? code : rcode), afromvol,
3459                 "Failed to end cloning transaction on RW %u\n");
3460         VDONE;
3461
3462         /* Remember clone volume ID in case we fail or are interrupted */
3463         entry.cloneId = cloneVolId;
3464
3465         if (roclone) {
3466             /* Bring the RO clone online - though not if it's a temporary clone */
3467             VPRINT1("Starting transaction on RO clone volume %u...",
3468                     cloneVolId);
3469             code =
3470                 AFSVolTransCreate_retry(fromconn, cloneVolId, afrompart, ITOffline,
3471                                   &onlinetid);
3472             ONERROR(code, cloneVolId,
3473                     "Failed to start transaction on volume %u\n");
3474             VDONE;
3475
3476             VPRINT1("Setting volume flags for volume %u...", cloneVolId);
3477             tcode = AFSVolSetFlags(fromconn, onlinetid, 0);
3478             VDONE;
3479
3480             VPRINT1("Ending transaction on volume %u...", cloneVolId);
3481             code = AFSVolEndTrans(fromconn, onlinetid, &rcode);
3482             ONERROR((code ? code : rcode), cloneVolId,
3483                     "Failed to end transaction on RO clone %u\n");
3484             VDONE;
3485
3486             ONERROR(tcode, cloneVolId, "Could not bring volume %u on line\n");
3487
3488             /* Sleep so that a client searching for an online volume won't
3489              * find the clone offline and then the next RO offline while the 
3490              * release brings the clone online and the next RO offline (race).
3491              * There is a fix in the 3.4 client that does not need this sleep
3492              * anymore, but we don't know what clients we have.
3493              */
3494             if (entry.nServers > 2)
3495                 sleep(5);
3496
3497             /* Mark the RO clone in the VLDB as a good site (already released) */
3498             entry.serverFlags[roindex] |= NEW_REPSITE;
3499             entry.serverFlags[roindex] &= ~RO_DONTUSE;
3500             entry.flags |= RO_EXISTS;
3501
3502             releasecount++;
3503
3504             /* Write out the VLDB entry only if the clone is not a temporary
3505              * clone. If we did this to a temporary clone then we would end
3506              * up marking all the ROs as "old release" making the ROs
3507              * temporarily unavailable.
3508              */
3509             MapNetworkToHost(&entry, &storeEntry);
3510             VPRINT1("Replacing VLDB entry for %s...", entry.name);
3511             vcode = VLDB_ReplaceEntry(afromvol, RWVOL, &storeEntry, 0);
3512             ONERROR(vcode, entry.name,
3513                     "Could not update vldb entry for %s.\n");
3514             VDONE;
3515         }
3516     }
3517
3518     /* Now we will release from the clone to the remaining RO replicas.
3519      * The first 2 ROs (counting the non-temporary RO clone) are released
3520      * individually: releasecount. This is to reduce the race condition
3521      * of clients trying to find an on-line RO volume. The remaining ROs
3522      * are released in parallel but no more than half the number of ROs
3523      * (rounded up) at a time: nservers.
3524      */
3525
3526     strcpy(vname, entry.name);
3527     strcat(vname, ".readonly");
3528     memset(&cookie, 0, sizeof(cookie));
3529     strncpy(cookie.name, vname, VOLSER_OLDMAXVOLNAME);
3530     cookie.type = ROVOL;
3531     cookie.parent = entry.volumeId[RWVOL];
3532     cookie.clone = 0;
3533
3534     nservers = entry.nServers / 2;      /* how many to do at once, excluding clone */
3535     replicas =
3536         (struct replica *)malloc(sizeof(struct replica) * nservers + 1);
3537     times = (struct release *)malloc(sizeof(struct release) * nservers + 1);
3538     toconns =
3539         (struct rx_connection **)malloc(sizeof(struct rx_connection *) *
3540                                         nservers + 1);
3541     results.manyResults_val =
3542         (afs_int32 *) malloc(sizeof(afs_int32) * nservers + 1);
3543     if (!replicas || !times || !!!results.manyResults_val || !toconns)
3544         ONERROR(ENOMEM, 0,
3545           &