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