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