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