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