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