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