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