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