vos: move convertROtoRW core logic to vsprocs
[openafs.git] / src / volser / vsprocs.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 #include <afs/procmgmt.h>       /* signal(), kill(), wait(), etc. */
14 #include <roken.h>
15
16 #ifdef  AFS_AIX_ENV
17 #include <sys/statfs.h>
18 #endif
19
20 #include <lock.h>
21 #include <afs/voldefs.h>
22 #include <rx/xdr.h>
23 #include <rx/rx.h>
24 #include <rx/rx_queue.h>
25 #include <afs/vlserver.h>
26 #include <afs/nfs.h>
27 #include <afs/cellconfig.h>
28 #include <afs/keys.h>
29 #include <ubik.h>
30 #include <afs/afsint.h>
31 #include "volser.h"
32 #include "volint.h"
33 #include "lockdata.h"
34 #include <afs/com_err.h>
35 #include <rx/rxkad.h>
36 #include <afs/kautils.h>
37 #include <afs/cmd.h>
38 #include <afs/ihandle.h>
39 #ifdef AFS_NT40_ENV
40 #include <afs/ntops.h>
41 #endif
42 #include <afs/vnode.h>
43 #include <afs/volume.h>
44 #define ERRCODE_RANGE 8         /* from error_table.h */
45 #define CLOCKSKEW   2           /* not really skew, but resolution */
46 #define CLOCKADJ(x) (((x) < CLOCKSKEW) ? 0 : (x) - CLOCKSKEW)
47
48 /* for UV_MoveVolume() recovery */
49
50 #include <setjmp.h>
51
52 #include "volser_internal.h"
53 #include "volser_prototypes.h"
54 #include "vsutils_prototypes.h"
55 #include "lockprocs_prototypes.h"
56
57 extern struct ubik_client *cstruct;
58 int verbose = 0, noresolve = 0;
59
60 struct release {
61     afs_uint32 crtime;
62     afs_uint32 uptime;
63     afs_int32 vldbEntryIndex;
64 };
65
66 /* Utility macros used by rest of this source file */
67 #define EPRINT(ec, es) \
68 do { \
69         fprintf(STDERR, "\n"); \
70         fprintf(STDERR, (es)); \
71         PrintError("   ",ec); \
72 } while (0)
73
74 #define EPRINT1(ec, es, ep1) \
75 do { \
76         fprintf(STDERR, "\n"); \
77         fprintf(STDERR, (es), (ep1)); \
78         PrintError("   ",ec); \
79 } while (0)
80
81 #define EPRINT2(ec, es, ep1, ep2) \
82 do { \
83         fprintf(STDERR, "\n"); \
84         fprintf(STDERR, (es), (ep1), (ep2)); \
85         PrintError("   ",ec); \
86 } while (0)
87
88 #define EPRINT3(ec, es, ep1, ep2, ep3) \
89 do { \
90         fprintf(STDERR, "\n"); \
91         fprintf(STDERR, (es), (ep1), (ep2), (ep3)); \
92         PrintError("   ",ec); \
93 } while (0)
94
95 #define EGOTO(where, ec, es) \
96 do { \
97         if (ec) { \
98                 EPRINT((ec),(es)); \
99                 error = (ec); \
100                 goto where; \
101         } \
102 } while (0)
103
104 #define EGOTO1(where, ec, es, ep1) \
105 do { \
106         if (ec) { \
107                 EPRINT1((ec),(es),(ep1)); \
108                 error = (ec); \
109                 goto where; \
110         } \
111 } while (0)
112
113 #define EGOTO2(where, ec, es, ep1, ep2) \
114 do { \
115         if (ec) { \
116                 EPRINT2((ec),(es),(ep1),(ep2)); \
117                 error = (ec); \
118                 goto where; \
119         } \
120 } while (0)
121
122 #define EGOTO3(where, ec, es, ep1, ep2, ep3) \
123 do { \
124         if (ec) { \
125                 EPRINT3((ec),(es),(ep1),(ep2),(ep3)); \
126                 error = (ec); \
127                 goto where; \
128         } \
129 } while (0)
130
131 #define VPRINT(es) \
132         { if (verbose) { fprintf(STDOUT, (es)); fflush(STDOUT); } }
133 #define VPRINT1(es, p) \
134         { if (verbose) { fprintf(STDOUT, (es), (p)); fflush(STDOUT); } }
135 #define VPRINT2(es, p1, p2) \
136         { if (verbose) { fprintf(STDOUT, (es), (p1), (p2)); fflush(STDOUT); } }
137 #define VPRINT3(es, p1, p2, p3) \
138         { if (verbose) { fprintf(STDOUT, (es), (p1), (p2), (p3)); fflush(STDOUT); } }
139 #define VDONE \
140         { if (verbose) { fprintf(STDOUT, " done\n"); fflush(STDOUT); } }
141 #define VEPRINT(es) \
142         { if (verbose) { fprintf(STDERR, (es)); fflush(STDERR); } }
143 #define VEPRINT1(es, p) \
144         { if (verbose) { fprintf(STDERR, (es), (p)); fflush(STDERR); } }
145 #define VEPRINT2(es, p1, p2) \
146         { if (verbose) { fprintf(STDERR, (es), (p1), (p2)); fflush(STDERR); } }
147 #define VEPRINT3(es, p1, p2, p3) \
148         { if (verbose) { fprintf(STDERR, (es), (p1), (p2), (p3)); fflush(STDERR); } }
149 #define VEDONE \
150         { if (verbose) { fprintf(STDERR, " done\n"); fflush(STDERR); } }
151
152
153
154 /* getting rid of this */
155 #define ERROR_EXIT(code) do { \
156     error = (code); \
157     goto error_exit; \
158 } while (0)
159
160
161 /* Protos for static routines */
162 #if 0
163 static afs_int32 CheckAndDeleteVolume(struct rx_connection *aconn,
164                                       afs_int32 apart, afs_uint32 okvol,
165                                       afs_uint32 delvol);
166 #endif
167 static int GetTrans(struct nvldbentry *vldbEntryPtr, afs_int32 index,
168                     struct rx_connection **connPtr, afs_int32 * transPtr,
169                     afs_uint32 * crtimePtr, afs_uint32 * uptimePtr,
170                     afs_int32 *origflags, afs_uint32 tmpVolId);
171 static int SimulateForwardMultiple(struct rx_connection *fromconn,
172                                    afs_int32 fromtid, afs_int32 fromdate,
173                                    manyDests * tr, afs_int32 flags,
174                                    void *cookie, manyResults * results);
175 static int DoVolOnline(struct nvldbentry *vldbEntryPtr, afs_uint32 avolid,
176                        int index, char *vname, struct rx_connection *connPtr);
177 static int DoVolClone(struct rx_connection *aconn, afs_uint32 avolid,
178                       afs_int32 apart, int type, afs_uint32 cloneid,
179                       char *typestring, char *pname, char *vname, char *suffix,
180                       struct volser_status *volstatus, afs_int32 *transPtr);
181 static int DoVolDelete(struct rx_connection *aconn, afs_uint32 avolid,
182                        afs_int32 apart, char *typestring, afs_uint32 atoserver,
183                        struct volser_status *volstatus, char *pprefix);
184 static afs_int32 CheckVolume(volintInfo * volumeinfo, afs_uint32 aserver,
185                              afs_int32 apart, afs_int32 * modentry,
186                              afs_uint32 * maxvolid, struct nvldbentry *aentry);
187 static afs_int32 VolumeExists(afs_uint32 server, afs_int32 partition,
188                               afs_uint32 volumeid);
189 static afs_int32 CheckVldbRWBK(struct nvldbentry * entry,
190                                afs_int32 * modified);
191 static afs_int32 CheckVldbRO(struct nvldbentry *entry, afs_int32 * modified);
192 static afs_int32 CheckVldb(struct nvldbentry *entry, afs_int32 * modified,
193                            afs_int32 *deleted);
194 static void dump_sig_handler(int x);
195 static int sortVolumes(const void *a, const void *b);
196
197
198 /*map the partition <partId> into partition name <partName>*/
199 void
200 MapPartIdIntoName(afs_int32 partId, char *partName)
201 {
202     if (partId < 26) {          /* what if partId > = 26 ? */
203         strcpy(partName, "/vicep");
204         partName[6] = partId + 'a';
205         partName[7] = '\0';
206         return;
207     } else if (partId < VOLMAXPARTS) {
208         strcpy(partName, "/vicep");
209         partId -= 26;
210         partName[6] = 'a' + (partId / 26);
211         partName[7] = 'a' + (partId % 26);
212         partName[8] = '\0';
213         return;
214     }
215 }
216
217 int
218 PrintError(char *msg, afs_int32 errcode)
219 {
220     fprintf(STDERR, "%s", msg);
221     /*replace by a big switch statement */
222     switch (errcode) {
223     case 0:
224         break;
225     case -1:
226         fprintf(STDERR, "Possible communication failure\n");
227         break;
228     case VSALVAGE:
229         fprintf(STDERR, "Volume needs to be salvaged\n");
230         break;
231     case VNOVNODE:
232         fprintf(STDERR, "Bad vnode number quoted\n");
233         break;
234     case VNOVOL:
235         fprintf(STDERR,
236                 "Volume not attached, does not exist, or not on line\n");
237         break;
238     case VVOLEXISTS:
239         fprintf(STDERR, "Volume already exists\n");
240         break;
241     case VNOSERVICE:
242         fprintf(STDERR, "Volume is not in service\n");
243         break;
244     case VOFFLINE:
245         fprintf(STDERR, "Volume is off line\n");
246         break;
247     case VONLINE:
248         fprintf(STDERR, "Volume is already on line\n");
249         break;
250     case VDISKFULL:
251         fprintf(STDERR, "Partition is full\n");
252         break;
253     case VOVERQUOTA:
254         fprintf(STDERR, "Volume max quota exceeded\n");
255         break;
256     case VBUSY:
257         fprintf(STDERR, "Volume temporarily unavailable\n");
258         break;
259     case VMOVED:
260         fprintf(STDERR, "Volume has moved to another server\n");
261         break;
262     case VL_IDEXIST:
263         fprintf(STDERR, "VLDB: volume Id exists in the vldb\n");
264         break;
265     case VL_IO:
266         fprintf(STDERR, "VLDB: a read terminated too early\n");
267         break;
268     case VL_NAMEEXIST:
269         fprintf(STDERR, "VLDB: volume entry exists in the vldb\n");
270         break;
271     case VL_CREATEFAIL:
272         fprintf(STDERR, "VLDB: internal creation failure\n");
273         break;
274     case VL_NOENT:
275         fprintf(STDERR, "VLDB: no such entry\n");
276         break;
277     case VL_EMPTY:
278         fprintf(STDERR, "VLDB: vldb database is empty\n");
279         break;
280     case VL_ENTDELETED:
281         fprintf(STDERR, "VLDB: entry is deleted (soft delete)\n");
282         break;
283     case VL_BADNAME:
284         fprintf(STDERR, "VLDB: volume name is illegal\n");
285         break;
286     case VL_BADINDEX:
287         fprintf(STDERR, "VLDB: index was out of range\n");
288         break;
289     case VL_BADVOLTYPE:
290         fprintf(STDERR, "VLDB: bad volume type\n");
291         break;
292     case VL_BADSERVER:
293         fprintf(STDERR, "VLDB: illegal server number (not within limits)\n");
294         break;
295     case VL_BADPARTITION:
296         fprintf(STDERR, "VLDB: bad partition number\n");
297         break;
298     case VL_REPSFULL:
299         fprintf(STDERR, "VLDB: run out of space for replication sites\n");
300         break;
301     case VL_NOREPSERVER:
302         fprintf(STDERR, "VLDB: no such repsite server exists\n");
303         break;
304     case VL_DUPREPSERVER:
305         fprintf(STDERR, "VLDB: replication site server already exists\n");
306         break;
307     case VL_RWNOTFOUND:
308         fprintf(STDERR, "VLDB: parent r/w entry not found\n");
309         break;
310     case VL_BADREFCOUNT:
311         fprintf(STDERR, "VLDB: illegal reference count number\n");
312         break;
313     case VL_SIZEEXCEEDED:
314         fprintf(STDERR, "VLDB: vldb size for attributes exceeded\n");
315         break;
316     case VL_BADENTRY:
317         fprintf(STDERR, "VLDB: bad incoming vldb entry\n");
318         break;
319     case VL_BADVOLIDBUMP:
320         fprintf(STDERR, "VLDB: illegal max volid increment\n");
321         break;
322     case VL_IDALREADYHASHED:
323         fprintf(STDERR, "VLDB: (RO/BACK) Id already hashed\n");
324         break;
325     case VL_ENTRYLOCKED:
326         fprintf(STDERR, "VLDB: vldb entry is already locked\n");
327         break;
328     case VL_BADVOLOPER:
329         fprintf(STDERR, "VLDB: bad volume operation code\n");
330         break;
331     case VL_BADRELLOCKTYPE:
332         fprintf(STDERR, "VLDB: bad release lock type\n");
333         break;
334     case VL_RERELEASE:
335         fprintf(STDERR, "VLDB: status report: last release was aborted\n");
336         break;
337     case VL_BADSERVERFLAG:
338         fprintf(STDERR, "VLDB: invalid replication site server flag\n");
339         break;
340     case VL_PERM:
341         fprintf(STDERR, "VLDB: no permission access for call\n");
342         break;
343     case VOLSERREAD_DUMPERROR:
344         fprintf(STDERR,
345                 "VOLSER:  Problems encountered in reading the dump file !\n");
346         break;
347     case VOLSERDUMPERROR:
348         fprintf(STDERR, "VOLSER: Problems encountered in doing the dump !\n");
349         break;
350     case VOLSERATTACH_ERROR:
351         fprintf(STDERR, "VOLSER: Could not attach the volume\n");
352         break;
353     case VOLSERDETACH_ERROR:
354         fprintf(STDERR, "VOLSER: Could not detach the volume\n");
355         break;
356     case VOLSERILLEGAL_PARTITION:
357         fprintf(STDERR, "VOLSER: encountered illegal partition number\n");
358         break;
359     case VOLSERBAD_ACCESS:
360         fprintf(STDERR, "VOLSER: permission denied, not a super user\n");
361         break;
362     case VOLSERVLDB_ERROR:
363         fprintf(STDERR, "VOLSER: error detected in the VLDB\n");
364         break;
365     case VOLSERBADNAME:
366         fprintf(STDERR, "VOLSER: error in volume name\n");
367         break;
368     case VOLSERVOLMOVED:
369         fprintf(STDERR, "VOLSER: volume has moved\n");
370         break;
371     case VOLSERBADOP:
372         fprintf(STDERR, "VOLSER: illegal operation\n");
373         break;
374     case VOLSERBADRELEASE:
375         fprintf(STDERR, "VOLSER: release could not be completed\n");
376         break;
377     case VOLSERVOLBUSY:
378         fprintf(STDERR, "VOLSER: volume is busy\n");
379         break;
380     case VOLSERNO_MEMORY:
381         fprintf(STDERR, "VOLSER: volume server is out of memory\n");
382         break;
383     case VOLSERNOVOL:
384         fprintf(STDERR,
385                 "VOLSER: no such volume - location specified incorrectly or volume does not exist\n");
386         break;
387     case VOLSERMULTIRWVOL:
388         fprintf(STDERR,
389                 "VOLSER: multiple RW volumes with same ID, one of which should be deleted\n");
390         break;
391     case VOLSERFAILEDOP:
392         fprintf(STDERR,
393                 "VOLSER: not all entries were successfully processed\n");
394         break;
395     default:
396         {
397             initialize_RXK_error_table();
398             initialize_KTC_error_table();
399             initialize_ACFG_error_table();
400             initialize_VL_error_table();
401
402             fprintf(STDERR, "%s: %s\n", afs_error_table_name(errcode),
403                     afs_error_message(errcode));
404             break;
405         }
406     }
407     return 0;
408 }
409
410 void init_volintInfo(struct volintInfo *vinfo) {
411     memset(vinfo, 0, sizeof(struct volintInfo));
412
413     vinfo->maxquota = -1;
414     vinfo->dayUse = -1;
415     vinfo->creationDate = -1;
416     vinfo->updateDate = -1;
417     vinfo->flags = -1;
418     vinfo->spare0 = -1;
419     vinfo->spare1 = -1;
420     vinfo->spare2 = -1;
421     vinfo->spare3 = -1;
422 }
423
424 static struct rx_securityClass *uvclass = 0;
425 static int uvindex = -1;
426 /* called by VLDBClient_Init to set the security module to be used in the RPC */
427 int
428 UV_SetSecurity(struct rx_securityClass *as, afs_int32 aindex)
429 {
430     uvindex = aindex;
431     uvclass = as;
432     return 0;
433 }
434
435 /* bind to volser on <port> <aserver> */
436 /* takes server address in network order, port in host order.  dumb */
437 struct rx_connection *
438 UV_Bind(afs_uint32 aserver, afs_int32 port)
439 {
440     struct rx_connection *tc;
441
442     tc = rx_NewConnection(aserver, htons(port), VOLSERVICE_ID, uvclass,
443                           uvindex);
444     return tc;
445 }
446
447 static int
448 AFSVolCreateVolume_retry(struct rx_connection *z_conn,
449                        afs_int32 partition, char *name, afs_int32 type,
450                        afs_int32 parent, afs_uint32 *volid, afs_int32 *trans)
451 {
452     afs_int32 code;
453     int retries = 3;
454     while (retries) {
455         code = AFSVolCreateVolume(z_conn, partition, name, type, parent,
456                                   volid, trans);
457         if (code != VOLSERVOLBUSY)
458             break;
459         retries--;
460 #ifdef AFS_PTHREAD_ENV
461         sleep(3-retries);
462 #else
463         IOMGR_Sleep(3-retries);
464 #endif
465     }
466     return code;
467 }
468
469 static int
470 AFSVolTransCreate_retry(struct rx_connection *z_conn,
471                         afs_int32 volume, afs_int32 partition,
472                         afs_int32 flags, afs_int32 * trans)
473 {
474     afs_int32 code;
475     int retries = 3;
476     while (retries) {
477         code = AFSVolTransCreate(z_conn, volume, partition, flags, trans);
478         if (code != VOLSERVOLBUSY)
479             break;
480         retries--;
481 #ifdef AFS_PTHREAD_ENV
482         sleep(3-retries);
483 #else
484         IOMGR_Sleep(3-retries);
485 #endif
486     }
487     return code;
488 }
489
490 #if 0
491 /* if <okvol> is allright(indicated by beibg able to
492  * start a transaction, delete the <delvol> */
493 static afs_int32
494 CheckAndDeleteVolume(struct rx_connection *aconn, afs_int32 apart,
495                      afs_uint32 okvol, afs_uint32 delvol)
496 {
497     afs_int32 error, code, tid, rcode;
498     error = 0;
499     code = 0;
500
501     if (okvol == 0) {
502         code = AFSVolTransCreate_retry(aconn, delvol, apart, ITOffline, &tid);
503         if (!error && code)
504             error = code;
505         code = AFSVolDeleteVolume(aconn, tid);
506         if (!error && code)
507             error = code;
508         code = AFSVolEndTrans(aconn, tid, &rcode);
509         if (!code)
510             code = rcode;
511         if (!error && code)
512             error = code;
513         return error;
514     } else {
515         code = AFSVolTransCreate_retry(aconn, okvol, apart, ITOffline, &tid);
516         if (!code) {
517             code = AFSVolEndTrans(aconn, tid, &rcode);
518             if (!code)
519                 code = rcode;
520             if (!error && code)
521                 error = code;
522             code = AFSVolTransCreate_retry(aconn, delvol, apart, ITOffline, &tid);
523             if (!error && code)
524                 error = code;
525             code = AFSVolDeleteVolume(aconn, tid);
526             if (!error && code)
527                 error = code;
528             code = AFSVolEndTrans(aconn, tid, &rcode);
529             if (!code)
530                 code = rcode;
531             if (!error && code)
532                 error = code;
533         } else
534             error = code;
535         return error;
536     }
537 }
538
539 #endif
540
541 /* called by EmuerateEntry, show vldb entry in a reasonable format */
542 void
543 SubEnumerateEntry(struct nvldbentry *entry)
544 {
545     int i;
546     char pname[10];
547     int isMixed = 0;
548     char hoststr[16];
549
550 #ifdef notdef
551     fprintf(STDOUT, "   readWriteID %-10u ", entry->volumeId[RWVOL]);
552     if (entry->flags & RW_EXISTS)
553         fprintf(STDOUT, " valid \n");
554     else
555         fprintf(STDOUT, " invalid \n");
556     fprintf(STDOUT, "   readOnlyID  %-10u ", entry->volumeId[ROVOL]);
557     if (entry->flags & RO_EXISTS)
558         fprintf(STDOUT, " valid \n");
559     else
560         fprintf(STDOUT, " invalid \n");
561     fprintf(STDOUT, "   backUpID    %-10u ", entry->volumeId[BACKVOL]);
562     if (entry->flags & BACK_EXISTS)
563         fprintf(STDOUT, " valid \n");
564     else
565         fprintf(STDOUT, " invalid \n");
566     if ((entry->cloneId != 0) && (entry->flags & RO_EXISTS))
567         fprintf(STDOUT, "    releaseClone %-10u \n", entry->cloneId);
568 #else
569     if (entry->flags & RW_EXISTS)
570         fprintf(STDOUT, "    RWrite: %-10u", entry->volumeId[RWVOL]);
571     if (entry->flags & RO_EXISTS)
572         fprintf(STDOUT, "    ROnly: %-10u", entry->volumeId[ROVOL]);
573     if (entry->flags & BACK_EXISTS)
574         fprintf(STDOUT, "    Backup: %-10u", entry->volumeId[BACKVOL]);
575     if ((entry->cloneId != 0) && (entry->flags & RO_EXISTS))
576         fprintf(STDOUT, "    RClone: %-10lu", (unsigned long)entry->cloneId);
577     fprintf(STDOUT, "\n");
578 #endif
579     fprintf(STDOUT, "    number of sites -> %lu\n",
580             (unsigned long)entry->nServers);
581     for (i = 0; i < entry->nServers; i++) {
582         if (entry->serverFlags[i] & NEW_REPSITE)
583             isMixed = 1;
584     }
585     for (i = 0; i < entry->nServers; i++) {
586         MapPartIdIntoName(entry->serverPartition[i], pname);
587         fprintf(STDOUT, "       server %s partition %s ",
588                 noresolve ? afs_inet_ntoa_r(entry->serverNumber[i], hoststr) :
589                 hostutil_GetNameByINet(entry->serverNumber[i]), pname);
590         if (entry->serverFlags[i] & ITSRWVOL)
591             fprintf(STDOUT, "RW Site ");
592         else
593             fprintf(STDOUT, "RO Site ");
594         if (isMixed) {
595             if (entry->serverFlags[i] & NEW_REPSITE)
596                 fprintf(STDOUT," -- New release");
597             else
598                 if (!(entry->serverFlags[i] & ITSRWVOL))
599                     fprintf(STDOUT," -- Old release");
600         } else {
601             if (entry->serverFlags[i] & RO_DONTUSE)
602                 fprintf(STDOUT, " -- Not released");
603         }
604         fprintf(STDOUT, "\n");
605     }
606
607     return;
608
609 }
610
611 /*enumerate the vldb entry corresponding to <entry> */
612 void
613 EnumerateEntry(struct nvldbentry *entry)
614 {
615
616     fprintf(STDOUT, "\n");
617     fprintf(STDOUT, "%s \n", entry->name);
618     SubEnumerateEntry(entry);
619     return;
620 }
621
622 /* forcibly remove a volume.  Very dangerous call */
623 int
624 UV_NukeVolume(afs_uint32 server, afs_int32 partid, afs_uint32 volid)
625 {
626     struct rx_connection *tconn;
627     afs_int32 code;
628
629     tconn = UV_Bind(server, AFSCONF_VOLUMEPORT);
630     if (tconn) {
631         code = AFSVolNukeVolume(tconn, partid, volid);
632         rx_DestroyConnection(tconn);
633     } else
634         code = 0;
635     return code;
636 }
637
638 /* like df. Return usage of <pname> on <server> in <partition> */
639 int
640 UV_PartitionInfo64(afs_uint32 server, char *pname,
641                    struct diskPartition64 *partition)
642 {
643     struct rx_connection *aconn;
644     afs_int32 code = 0;
645
646     aconn = UV_Bind(server, AFSCONF_VOLUMEPORT);
647     code = AFSVolPartitionInfo64(aconn, pname, partition);
648     if (code == RXGEN_OPCODE) {
649         struct diskPartition *dpp = malloc(sizeof(struct diskPartition));
650         code = AFSVolPartitionInfo(aconn, pname, dpp);
651         if (!code) {
652             strncpy(partition->name, dpp->name, 32);
653             strncpy(partition->devName, dpp->devName, 32);
654             partition->lock_fd = dpp->lock_fd;
655             partition->free = dpp->free;
656             partition->minFree = dpp->minFree;
657         }
658         free(dpp);
659     }
660     if (code) {
661         fprintf(STDERR, "Could not get information on partition %s\n", pname);
662         PrintError("", code);
663     }
664     if (aconn)
665         rx_DestroyConnection(aconn);
666     return code;
667 }
668
669 /* old interface to create volumes */
670 int
671 UV_CreateVolume(afs_uint32 aserver, afs_int32 apart, char *aname,
672                 afs_uint32 * anewid)
673 {
674     afs_int32 code;
675     *anewid = 0;
676     code = UV_CreateVolume2(aserver, apart, aname, 5000, 0, 0, 0, 0, anewid);
677     return code;
678 }
679
680 /* less old interface to create volumes */
681 int
682 UV_CreateVolume2(afs_uint32 aserver, afs_int32 apart, char *aname,
683                  afs_int32 aquota, afs_int32 aspare1, afs_int32 aspare2,
684                  afs_int32 aspare3, afs_int32 aspare4, afs_uint32 * anewid)
685 {
686     afs_uint32 roid = 0, bkid = 0;
687     return UV_CreateVolume3(aserver, apart, aname, aquota, aspare1, aspare2,
688         aspare3, aspare4, anewid, &roid, &bkid);
689 }
690
691 /**
692  * Create a volume on the given server and partition
693  *
694  * @param aserver  server to create volume on
695  * @param spart  partition to create volume on
696  * @param aname  name of new volume
697  * @param aquota  quota for new volume
698  * @param anewid  contains the desired volume id for the new volume. If
699  *                *anewid == 0, a new id will be chosen, and will be placed
700  *                in *anewid when UV_CreateVolume3 returns.
701  * @param aroid  contains the desired RO volume id. If NULL, the RO id entry
702  *               will be unset. If *aroid == 0, an id will be chosen, and
703  *               will be placed in *anewid when UV_CreateVolume3 returns.
704  * @param abkid  same as aroid, except for the BK volume id instead of the
705  *               RO volume id.
706  * @return 0 on success, error code otherwise.
707  */
708 int
709 UV_CreateVolume3(afs_uint32 aserver, afs_int32 apart, char *aname,
710                  afs_int32 aquota, afs_int32 aspare1, afs_int32 aspare2,
711                  afs_int32 aspare3, afs_int32 aspare4, afs_uint32 * anewid,
712                  afs_uint32 * aroid, afs_uint32 * abkid)
713 {
714     struct rx_connection *aconn;
715     afs_int32 tid;
716     afs_int32 code;
717     afs_int32 error;
718     afs_int32 rcode, vcode;
719     afs_int32 lastid;
720     struct nvldbentry entry, storeEntry;        /*the new vldb entry */
721     struct volintInfo tstatus;
722
723     tid = 0;
724     error = 0;
725
726     init_volintInfo(&tstatus);
727     tstatus.maxquota = aquota;
728
729     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
730
731     if (aroid && *aroid) {
732         VPRINT1("Using RO volume ID %d.\n", *aroid);
733     }
734     if (abkid && *abkid) {
735         VPRINT1("Using BK volume ID %d.\n", *abkid);
736     }
737
738     if (*anewid) {
739         vcode = VLDB_GetEntryByID(*anewid, -1, &entry);
740         if (!vcode) {
741             fprintf(STDERR, "Volume ID %d already exists\n", *anewid);
742             return VVOLEXISTS;
743         }
744         VPRINT1("Using volume ID %d.\n", *anewid);
745     } else {
746         vcode = ubik_VL_GetNewVolumeId(cstruct, 0, 1, anewid);
747         EGOTO1(cfail, vcode, "Could not get an Id for volume %s\n", aname);
748
749         if (aroid && *aroid == 0) {
750             vcode = ubik_VL_GetNewVolumeId(cstruct, 0, 1, aroid);
751             EGOTO1(cfail, vcode, "Could not get an RO Id for volume %s\n", aname);
752         }
753
754         if (abkid && *abkid == 0) {
755             vcode = ubik_VL_GetNewVolumeId(cstruct, 0, 1, abkid);
756             EGOTO1(cfail, vcode, "Could not get a BK Id for volume %s\n", aname);
757         }
758     }
759
760     /* rw,ro, bk id are related in the default case */
761     /* If caller specified RW id, but not RO/BK ids, have them be RW+1 and RW+2 */
762     lastid = *anewid;
763     if (aroid && *aroid != 0) {
764         lastid = max(lastid, *aroid);
765     }
766     if (abkid && *abkid != 0) {
767         lastid = max(lastid, *abkid);
768     }
769     if (aroid && *aroid == 0) {
770         *aroid = ++lastid;
771     }
772     if (abkid && *abkid == 0) {
773         *abkid = ++lastid;
774     }
775
776     code =
777         AFSVolCreateVolume_retry(aconn, apart, aname, volser_RW, 0, anewid, &tid);
778     EGOTO2(cfail, code, "Failed to create the volume %s %u \n", aname,
779            *anewid);
780
781     code = AFSVolSetInfo(aconn, tid, &tstatus);
782     if (code)
783         EPRINT(code, "Could not change quota, continuing...\n");
784
785     code = AFSVolSetFlags(aconn, tid, 0);       /* bring it online (mark it InService */
786     EGOTO2(cfail, code, "Could not bring the volume %s %u online \n", aname,
787            *anewid);
788
789     VPRINT2("Volume %s %u created and brought online\n", aname, *anewid);
790
791     /* set up the vldb entry for this volume */
792     strncpy(entry.name, aname, VOLSER_OLDMAXVOLNAME);
793     entry.nServers = 1;
794     entry.serverNumber[0] = aserver;    /* this should have another
795                                          * level of indirection later */
796     entry.serverPartition[0] = apart;   /* this should also have
797                                          * another indirection level */
798     entry.flags = RW_EXISTS;    /* this records that rw volume exists */
799     entry.serverFlags[0] = ITSRWVOL;    /*this rep site has rw  vol */
800     entry.volumeId[RWVOL] = *anewid;
801     entry.volumeId[ROVOL] = aroid ? *aroid : 0;
802     entry.volumeId[BACKVOL] = abkid ? *abkid : 0;
803     entry.cloneId = 0;
804     /*map into right byte order, before passing to xdr, the stuff has to be in host
805      * byte order. Xdr converts it into network order */
806     MapNetworkToHost(&entry, &storeEntry);
807     /* create the vldb entry */
808     vcode = VLDB_CreateEntry(&storeEntry);
809     if (vcode) {
810         fprintf(STDERR,
811                 "Could not create a VLDB entry for the volume %s %lu\n",
812                 aname, (unsigned long)*anewid);
813         /*destroy the created volume */
814         VPRINT1("Deleting the newly created volume %u\n", *anewid);
815         AFSVolDeleteVolume(aconn, tid);
816         error = vcode;
817         goto cfail;
818     }
819     VPRINT2("Created the VLDB entry for the volume %s %u\n", aname, *anewid);
820     /* volume created, now terminate the transaction and release the connection */
821     code = AFSVolEndTrans(aconn, tid, &rcode);  /*if it crashes before this
822                                                  * the volume will come online anyway when transaction timesout , so if
823                                                  * vldb entry exists then the volume is guaranteed to exist too wrt create */
824     tid = 0;
825     if (code) {
826         fprintf(STDERR,
827                 "Failed to end the transaction on the volume %s %lu\n", aname,
828                 (unsigned long)*anewid);
829         error = code;
830         goto cfail;
831     }
832
833   cfail:
834     if (tid) {
835         code = AFSVolEndTrans(aconn, tid, &rcode);
836         if (code)
837             fprintf(STDERR, "WARNING: could not end transaction\n");
838     }
839     if (aconn)
840         rx_DestroyConnection(aconn);
841     PrintError("", error);
842     return error;
843 }
844
845 /* create a volume, given a server, partition number, volume name --> sends
846 * back new vol id in <anewid>*/
847 int
848 UV_AddVLDBEntry(afs_uint32 aserver, afs_int32 apart, char *aname,
849                 afs_uint32 aid)
850 {
851     struct rx_connection *aconn;
852     afs_int32 error;
853     afs_int32 vcode;
854     struct nvldbentry entry, storeEntry;        /*the new vldb entry */
855
856     aconn = (struct rx_connection *)0;
857     error = 0;
858
859     /* set up the vldb entry for this volume */
860     strncpy(entry.name, aname, VOLSER_OLDMAXVOLNAME);
861     entry.nServers = 1;
862     entry.serverNumber[0] = aserver;    /* this should have another
863                                          * level of indirection later */
864     entry.serverPartition[0] = apart;   /* this should also have
865                                          * another indirection level */
866     entry.flags = RW_EXISTS;    /* this records that rw volume exists */
867     entry.serverFlags[0] = ITSRWVOL;    /*this rep site has rw  vol */
868     entry.volumeId[RWVOL] = aid;
869 #ifdef notdef
870     entry.volumeId[ROVOL] = anewid + 1; /* rw,ro, bk id are related in the default case */
871     entry.volumeId[BACKVOL] = *anewid + 2;
872 #else
873     entry.volumeId[ROVOL] = 0;
874     entry.volumeId[BACKVOL] = 0;
875 #endif
876     entry.cloneId = 0;
877     /*map into right byte order, before passing to xdr, the stuff has to be in host
878      * byte order. Xdr converts it into network order */
879     MapNetworkToHost(&entry, &storeEntry);
880     /* create the vldb entry */
881     vcode = VLDB_CreateEntry(&storeEntry);
882     if (vcode) {
883         fprintf(STDERR,
884                 "Could not create a VLDB entry for the  volume %s %lu\n",
885                 aname, (unsigned long)aid);
886         error = vcode;
887         goto cfail;
888     }
889     VPRINT2("Created the VLDB entry for the volume %s %u\n", aname, aid);
890
891   cfail:
892     if (aconn)
893         rx_DestroyConnection(aconn);
894     PrintError("", error);
895     return error;
896 }
897
898 /* Delete the volume <volid>on <aserver> <apart>
899  * the physical entry gets removed from the vldb only if the ref count
900  * becomes zero
901  */
902 int
903 UV_DeleteVolume(afs_uint32 aserver, afs_int32 apart, afs_uint32 avolid)
904 {
905     struct rx_connection *aconn = (struct rx_connection *)0;
906     afs_int32 ttid = 0;
907     afs_int32 code, rcode;
908     afs_int32 error = 0;
909     struct nvldbentry entry, storeEntry;
910     int islocked = 0;
911     afs_int32 avoltype = -1, vtype;
912     int notondisk = 0, notinvldb = 0;
913
914     /* Find and read bhe VLDB entry for this volume */
915     code = ubik_VL_SetLock(cstruct, 0, avolid, avoltype, VLOP_DELETE);
916     if (code) {
917         if (code != VL_NOENT) {
918             EGOTO1(error_exit, code,
919                    "Could not lock VLDB entry for the volume %u\n", avolid);
920         }
921         notinvldb = 1;
922     } else {
923         islocked = 1;
924
925         code = VLDB_GetEntryByID(avolid, avoltype, &entry);
926         EGOTO1(error_exit, code, "Could not fetch VLDB entry for volume %u\n",
927                avolid);
928         MapHostToNetwork(&entry);
929
930         if (verbose)
931             EnumerateEntry(&entry);
932     }
933
934     /* Whether volume is in the VLDB or not. Delete the volume on disk */
935     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
936
937     code = DoVolDelete(aconn, avolid, apart, "the", 0, NULL, NULL);
938     if (code) {
939         if (code == VNOVOL)
940             notondisk = 1;
941         else {
942             error = code;
943             goto error_exit;
944         }
945     }
946
947     /* Now update the VLDB entry.
948      * But first, verify we have a VLDB entry.
949      * Whether volume is on disk or not. Delete the volume in VLDB.
950      */
951     if (notinvldb)
952         ERROR_EXIT(0);
953
954     if (avolid == entry.volumeId[BACKVOL]) {
955         /* Its a backup volume, modify the VLDB entry. Check that the
956          * backup volume is on the server/partition we asked to delete.
957          */
958         if (!(entry.flags & BACK_EXISTS) || !Lp_Match(aserver, apart, &entry)) {
959             notinvldb = 2;      /* Not on this server and partition */
960             ERROR_EXIT(0);
961         }
962
963         VPRINT1("Marking the backup volume %u deleted in the VLDB\n", avolid);
964
965         entry.flags &= ~BACK_EXISTS;
966         vtype = BACKVOL;
967     }
968
969     else if (avolid == entry.volumeId[ROVOL]) {
970         /* Its a read-only volume, modify the VLDB entry. Check that the
971          * readonly volume is on the server/partition we asked to delete.
972          * If flags does not have RO_EIXSTS set, then this may mean the RO
973          * hasn't been released (and could exist in VLDB).
974          */
975         if (!Lp_ROMatch(aserver, apart, &entry)) {
976             notinvldb = 2;      /* Not found on this server and partition */
977             ERROR_EXIT(0);
978         }
979
980         if (verbose)
981             fprintf(STDOUT,
982                     "Marking the readonly volume %lu deleted in the VLDB\n",
983                     (unsigned long)avolid);
984
985         Lp_SetROValue(&entry, aserver, apart, 0, 0);    /* delete the site */
986         entry.nServers--;
987         if (!Lp_ROMatch(0, 0, &entry))
988             entry.flags &= ~RO_EXISTS;  /* This was the last ro volume */
989         vtype = ROVOL;
990     }
991
992     else if (avolid == entry.volumeId[RWVOL]) {
993         /* It's a rw volume, delete the backup volume, modify the VLDB entry.
994          * Check that the readwrite volumes is on the server/partition we
995          * asked to delete.
996          */
997         if (!(entry.flags & RW_EXISTS) || !Lp_Match(aserver, apart, &entry)) {
998             notinvldb = 2;      /* Not found on this server and partition */
999             ERROR_EXIT(0);
1000         }
1001
1002         if (entry.volumeId[BACKVOL]) {
1003             /* Delete backup if it exists */
1004             code = DoVolDelete(aconn, entry.volumeId[BACKVOL], apart,
1005                                "the backup", 0, NULL, NULL);
1006             if (code && code != VNOVOL) {
1007                 error = code;
1008                 goto error_exit;
1009             }
1010         }
1011
1012         if (verbose)
1013             fprintf(STDOUT,
1014                     "Marking the readwrite volume %lu%s deleted in the VLDB\n",
1015                     (unsigned long)avolid,
1016                     ((entry.
1017                       flags & BACK_EXISTS) ? ", and its backup volume," :
1018                      ""));
1019
1020         Lp_SetRWValue(&entry, aserver, apart, 0L, 0L);
1021         entry.nServers--;
1022         entry.flags &= ~(BACK_EXISTS | RW_EXISTS);
1023         vtype = RWVOL;
1024
1025         if (entry.flags & RO_EXISTS)
1026             fprintf(STDERR, "WARNING: ReadOnly copy(s) may still exist\n");
1027     }
1028
1029     else {
1030         notinvldb = 2;          /* Not found on this server and partition */
1031         ERROR_EXIT(0);
1032     }
1033
1034     /* Either delete or replace the VLDB entry */
1035     if ((entry.nServers <= 0) || !(entry.flags & (RO_EXISTS | RW_EXISTS))) {
1036         if (verbose)
1037             fprintf(STDOUT,
1038                     "Last reference to the VLDB entry for %lu - deleting entry\n",
1039                     (unsigned long)avolid);
1040         code = ubik_VL_DeleteEntry(cstruct, 0, avolid, vtype);
1041         EGOTO1(error_exit, code,
1042                "Could not delete the VLDB entry for the volume %u \n",
1043                avolid);
1044     } else {
1045         MapNetworkToHost(&entry, &storeEntry);
1046         code =
1047             VLDB_ReplaceEntry(avolid, vtype, &storeEntry,
1048                               (LOCKREL_OPCODE | LOCKREL_AFSID |
1049                                LOCKREL_TIMESTAMP));
1050         EGOTO1(error_exit, code,
1051                "Could not update the VLDB entry for the volume %u \n",
1052                avolid);
1053     }
1054     islocked = 0;
1055
1056   error_exit:
1057     if (error)
1058         EPRINT(error, "\n");
1059
1060     if (notondisk && notinvldb) {
1061         EPRINT2(VOLSERNOVOL, "Volume %u does not exist %s\n", avolid,
1062                 ((notinvldb == 2) ? "on server and partition" : ""));
1063         if (!error)
1064             error = VOLSERNOVOL;
1065     } else if (notondisk) {
1066         fprintf(STDERR,
1067                 "WARNING: Volume %lu did not exist on the partition\n",
1068                 (unsigned long)avolid);
1069     } else if (notinvldb) {
1070         fprintf(STDERR, "WARNING: Volume %lu does not exist in VLDB %s\n",
1071                 (unsigned long)avolid,
1072                 ((notinvldb == 2) ? "on server and partition" : ""));
1073     }
1074
1075     if (ttid) {
1076         code = AFSVolEndTrans(aconn, ttid, &rcode);
1077         code = (code ? code : rcode);
1078         if (code) {
1079             fprintf(STDERR, "Could not end transaction on the volume %lu\n",
1080                     (unsigned long)avolid);
1081             PrintError("", code);
1082             if (!error)
1083                 error = code;
1084         }
1085     }
1086
1087     if (islocked) {
1088         code =
1089             ubik_VL_ReleaseLock(cstruct, 0, avolid, -1,
1090                                 (LOCKREL_OPCODE | LOCKREL_AFSID |
1091                                  LOCKREL_TIMESTAMP));
1092         if (code) {
1093             EPRINT1(code,
1094                     "Could not release the lock on the VLDB entry for the volume %u \n",
1095                     avolid);
1096             if (!error)
1097                 error = code;
1098         }
1099     }
1100
1101     if (aconn)
1102         rx_DestroyConnection(aconn);
1103     return error;
1104 }
1105
1106 /* add recovery to UV_MoveVolume */
1107
1108 #define TESTC   0               /* set to test recovery code, clear for production */
1109
1110 jmp_buf env;
1111 int interrupt = 0;
1112
1113 static void *
1114 do_interrupt(void * unused)
1115 {
1116     if (interrupt) {
1117 #if !defined(AFS_PTHREAD_ENV) && !defined(AFS_NT40_ENV)
1118         /* Avoid UNIX LWP from getting confused that our stack has suddenly
1119          * changed. This will avoid some sanity checks, but until a better way
1120          * is found, the only alternative is always crashing and burning on at
1121          * least the stack-overflow check. */
1122         lwp_cpptr->stack = NULL;
1123 #endif
1124         longjmp(env, 0);
1125     }
1126
1127     fprintf(STDOUT, "\nSIGINT handler: vos move operation in progress\n");
1128     fprintf(STDOUT,
1129             "WARNING: may leave AFS storage and metadata in indeterminate state\n");
1130     fprintf(STDOUT, "enter second control-c to exit\n");
1131     fflush(STDOUT);
1132
1133     interrupt = 1;
1134     return NULL;
1135 }
1136
1137 static void
1138 sigint_handler(int x)
1139 {
1140 #ifdef AFS_PTHREAD_ENV
1141     do_interrupt(NULL);
1142 #else
1143     IOMGR_SoftSig(do_interrupt, 0);
1144 #endif
1145     (void)signal(SIGINT, sigint_handler);
1146 }
1147
1148 static int
1149 DoVolDelete(struct rx_connection *aconn, afs_uint32 avolid,
1150             afs_int32 apart, char *ptypestring, afs_uint32 atoserver,
1151             struct volser_status *volstatus, char *pprefix)
1152 {
1153     afs_int32 ttid = 0, code, rcode, error = 0;
1154     char *prefix, *typestring;
1155     int beverbose = 0;
1156
1157     if (pprefix)
1158         prefix = pprefix;
1159     else
1160         prefix = "";
1161
1162     if (ptypestring) {
1163         typestring = ptypestring;
1164         beverbose = 1;
1165     } else
1166         typestring = "the";
1167
1168     if (beverbose)
1169         VPRINT3("%sDeleting %s volume %u ...", prefix, typestring, avolid);
1170
1171     code =
1172         AFSVolTransCreate_retry(aconn, avolid, apart, ITOffline, &ttid);
1173
1174     /* return early and quietly for VNOVOL; don't continue the attempt to delete. */
1175     if (code == VNOVOL) {
1176         error = code;
1177         goto dfail;
1178     }
1179
1180     EGOTO2(dfail, code, "%sFailed to start transaction on %u\n",
1181            prefix, avolid);
1182
1183     if (volstatus) {
1184         code = AFSVolGetStatus(aconn, ttid, volstatus);
1185         EGOTO2(dfail, code, "%sCould not get timestamp from volume %u\n",
1186                prefix, avolid);
1187     }
1188
1189     code =
1190         AFSVolSetFlags(aconn, ttid,
1191                        VTDeleteOnSalvage | VTOutOfService);
1192
1193     EGOTO2(dfail, code, "%sCould not set flags on volume %u \n",
1194            prefix, avolid);
1195
1196     if (atoserver) {
1197         VPRINT1("%sSetting volume forwarding pointer ...", prefix);
1198         AFSVolSetForwarding(aconn, ttid, atoserver);
1199         VDONE;
1200     }
1201
1202     code = AFSVolDeleteVolume(aconn, ttid);
1203     EGOTO2(dfail, code, "%sCould not delete volume %u\n", prefix, avolid);
1204
1205 dfail:
1206     if (ttid) {
1207         code = AFSVolEndTrans(aconn, ttid, &rcode);
1208         ttid = 0;
1209         if (!code)
1210             code = rcode;
1211         if (code) {
1212             fprintf(STDERR, "%sCould not end transaction on %s volume %lu \n",
1213                     prefix, typestring, (unsigned long)avolid);
1214             if (!error)
1215                 error = code;
1216         }
1217     }
1218
1219     if (beverbose && !error)
1220         VDONE;
1221     return error;
1222 }
1223
1224 static int
1225 DoVolClone(struct rx_connection *aconn, afs_uint32 avolid,
1226            afs_int32 apart, int type, afs_uint32 cloneid,
1227            char *typestring, char *pname, char *vname, char *suffix,
1228            struct volser_status *volstatus, afs_int32 *transPtr)
1229 {
1230     char cname[64];
1231     afs_int32 ttid = 0, btid = 0;
1232     afs_int32 code = 0, rcode = 0;
1233     afs_int32 error = 0;
1234     int cloneexists = 1;
1235
1236     /* Test to see if the clone volume exists by trying to create
1237      * a transaction on the clone volume. We've assumed the clone exists.
1238      */
1239     code = AFSVolTransCreate_retry(aconn, cloneid, apart, ITOffline, &btid);
1240     if (code) {
1241         if (code != VNOVOL) {
1242             EPRINT2(code, "Could not reach the %s volume %lu\n",
1243                     typestring, (unsigned long)cloneid);
1244             error = code;
1245             goto cfail;
1246         }
1247         cloneexists = 0;         /* clone volume does not exist */
1248     }
1249     if (btid) {
1250         code = AFSVolEndTrans(aconn, btid, &rcode);
1251         btid = 0;
1252         if (code || rcode) {
1253             fprintf(STDERR,
1254                     "Could not end transaction on the previous %s volume %lu\n",
1255                     typestring, (unsigned long)cloneid);
1256             error = (code ? code : rcode);
1257             goto cfail;
1258         }
1259     }
1260
1261     /* Now go ahead and try to clone the RW volume.
1262      * First start a transaction on the RW volume
1263      */
1264     code = AFSVolTransCreate_retry(aconn, avolid, apart, ITBusy, &ttid);
1265     if (code) {
1266         fprintf(STDERR, "Could not start a transaction on the volume %lu\n",
1267                 (unsigned long)avolid);
1268         error = code;
1269         goto cfail;
1270     }
1271
1272     /* Clone or reclone the volume, depending on whether the clone
1273      * volume exists or not
1274      */
1275     if (cloneexists) {
1276         VPRINT2("Re-cloning %s volume %u ...", typestring, cloneid);
1277
1278         code = AFSVolReClone(aconn, ttid, cloneid);
1279         if (code) {
1280             EPRINT2(code, "Could not re-clone %s volume %lu\n",
1281                     typestring, (unsigned long)cloneid);
1282             error = code;
1283             goto cfail;
1284         }
1285     } else {
1286         VPRINT2("Creating a new %s clone %u ...", typestring, cloneid);
1287
1288         if (!vname) {
1289             strcpy(cname, pname);
1290             strcat(cname, suffix);
1291         }
1292
1293         code = AFSVolClone(aconn, ttid, 0, type, vname?vname:cname,
1294                            &cloneid);
1295         if (code) {
1296             fprintf(STDERR, "Failed to clone the volume %lu\n",
1297                     (unsigned long)avolid);
1298             error = code;
1299             goto cfail;
1300         }
1301     }
1302
1303     VDONE;
1304
1305     if (volstatus) {
1306         VPRINT1("Getting status of parent volume %u...", avolid);
1307         code = AFSVolGetStatus(aconn, ttid, volstatus);
1308         if (code) {
1309             fprintf(STDERR, "Failed to get the status of the parent volume %lu\n",
1310                     (unsigned long)avolid);
1311             error = code;
1312             goto cfail;
1313         }
1314         VDONE;
1315     }
1316
1317 cfail:
1318     if (ttid) {
1319         code = AFSVolEndTrans(aconn, ttid, &rcode);
1320         if (code || rcode) {
1321             fprintf(STDERR, "Could not end transaction on the volume %lu\n",
1322                     (unsigned long)avolid);
1323             if (!error)
1324                 error = (code ? code : rcode);
1325         }
1326     }
1327
1328     if (btid) {
1329         code = AFSVolEndTrans(aconn, btid, &rcode);
1330         if (code || rcode) {
1331             fprintf(STDERR,
1332                     "Could not end transaction on the %s volume %lu\n",
1333                     typestring, (unsigned long)cloneid);
1334             if (!error)
1335                 error = (code ? code : rcode);
1336         }
1337     }
1338     return error;
1339 }
1340
1341 /* Convert volume from RO to RW; adjust the VLDB entry to match.
1342  * The nvldbentry passed to us has already been MapHostToNetwork'd
1343  * by the caller.
1344  */
1345
1346 int
1347 UV_ConvertRO(afs_uint32 server, afs_uint32 partition, afs_uint32 volid,
1348                 struct nvldbentry *entry)
1349 {
1350     afs_int32 code, i, same;
1351     struct nvldbentry checkEntry, storeEntry;
1352     afs_int32 vcode;
1353     afs_int32 rwindex = 0;
1354     afs_uint32 rwserver = 0;
1355     afs_int32 roindex = 0;
1356     afs_uint32 roserver = 0;
1357     struct rx_connection *aconn;
1358
1359     vcode =
1360         ubik_VL_SetLock(cstruct, 0, entry->volumeId[RWVOL], RWVOL,
1361                   VLOP_MOVE);
1362     if (vcode) {
1363         fprintf(STDERR,
1364                 "Unable to lock volume %lu, code %d\n",
1365                 (unsigned long)entry->volumeId[RWVOL],vcode);
1366         PrintError("", vcode);
1367         return -1;
1368     }
1369
1370     /* make sure the VLDB entry hasn't changed since we started */
1371     memset(&checkEntry, 0, sizeof(checkEntry));
1372     vcode = VLDB_GetEntryByID(volid, -1, &checkEntry);
1373     if (vcode) {
1374         fprintf(STDERR,
1375                 "Could not fetch the entry for volume %lu from VLDB\n",
1376                 (unsigned long)volid);
1377         PrintError("convertROtoRW ", vcode);
1378         code = vcode;
1379         goto error_exit;
1380     }
1381
1382     MapHostToNetwork(&checkEntry);
1383     entry->flags &= ~VLOP_ALLOPERS;  /* clear any stale lock operation flags */
1384     entry->flags |= VLOP_MOVE;        /* set to match SetLock operation above */
1385     if (memcmp(entry, &checkEntry, sizeof(*entry)) != 0) {
1386         fprintf(STDERR,
1387                 "VLDB entry for volume %lu has changed; please reissue the command.\n",
1388                 (unsigned long)volid);
1389         code = -1;
1390         goto error_exit;
1391     }
1392
1393     /* extract information from the original entry */
1394     for (i = 0; i < entry->nServers; i++) {
1395         if (entry->serverFlags[i] & ITSRWVOL) {
1396             rwindex = i;
1397             rwserver = entry->serverNumber[i];
1398         /*  rwpartition = entry->serverPartition[i]; */
1399             if (roserver)
1400                 break;
1401         } else if ((entry->serverFlags[i] & ITSROVOL) && !roserver) {
1402             same = VLDB_IsSameAddrs(server, entry->serverNumber[i], &code);
1403             if (code) {
1404                 fprintf(STDERR,
1405                         "Failed to get info about server's %d address(es) from vlserver (err=%d); aborting call!\n",
1406                         server, code);
1407                 code = ENOENT;
1408                 goto error_exit;
1409             }
1410             if (same) {
1411                 roindex = i;
1412                 roserver = entry->serverNumber[i];
1413         /*      ropartition = entry->serverPartition[i]; */
1414                 if (rwserver)
1415                      break;
1416             }
1417         }
1418     }
1419
1420     aconn = UV_Bind(server, AFSCONF_VOLUMEPORT);
1421     code = AFSVolConvertROtoRWvolume(aconn, partition, volid);
1422     if (code) {
1423         fprintf(STDERR,
1424                 "Converting RO volume %lu to RW volume failed with code %d\n",
1425                 (unsigned long)volid, code);
1426         PrintError("convertROtoRW ", code);
1427         goto error_exit;
1428     }
1429     /* Update the VLDB to match what we did on disk as much as possible.  */
1430     /* If the converted RO was in the VLDB, make it look like the new RW. */
1431     if (roserver) {
1432         entry->serverFlags[roindex] = ITSRWVOL;
1433     } else {
1434         /* Add a new site entry for the newly created RW.  It's possible
1435          * (but unlikely) that we are already at MAXNSERVERS and that this
1436          * new site will invalidate the whole VLDB entry;  however,
1437          * VLDB_ReplaceEntry will detect this and return VL_BADSERVER,
1438          * so we need no extra guard logic here.
1439          */
1440         afs_int32 newrwindex = entry->nServers;
1441         (entry->nServers)++;
1442         entry->serverNumber[newrwindex] = server;
1443         entry->serverPartition[newrwindex] = partition;
1444         entry->serverFlags[newrwindex] = ITSRWVOL;
1445     }
1446     entry->flags |= RW_EXISTS;
1447     entry->flags &= ~BACK_EXISTS;
1448
1449     /* if the old RW was in the VLDB, remove it by decrementing the number */
1450     /* of servers, replacing the RW entry with the last entry, and zeroing */
1451     /* out the last entry. */
1452     if (rwserver) {
1453         (entry->nServers)--;
1454         if (rwindex != entry->nServers) {
1455             entry->serverNumber[rwindex] = entry->serverNumber[entry->nServers];
1456             entry->serverPartition[rwindex] =
1457                 entry->serverPartition[entry->nServers];
1458             entry->serverFlags[rwindex] = entry->serverFlags[entry->nServers];
1459             entry->serverNumber[entry->nServers] = 0;
1460             entry->serverPartition[entry->nServers] = 0;
1461             entry->serverFlags[entry->nServers] = 0;
1462         }
1463     }
1464     entry->flags &= ~RO_EXISTS;
1465     for (i = 0; i < entry->nServers; i++) {
1466         if (entry->serverFlags[i] & ITSROVOL) {
1467             if (!(entry->serverFlags[i] & (RO_DONTUSE | NEW_REPSITE)))
1468                 entry->flags |= RO_EXISTS;
1469         }
1470     }
1471     MapNetworkToHost(entry, &storeEntry);
1472     code =
1473         VLDB_ReplaceEntry(entry->volumeId[RWVOL], RWVOL, &storeEntry,
1474                           (LOCKREL_OPCODE | LOCKREL_AFSID |
1475                            LOCKREL_TIMESTAMP));
1476     if (code) {
1477         fprintf(STDERR,
1478                 "Warning: volume converted, but vldb update failed with code %d!\n",
1479                 code);
1480     }
1481
1482   error_exit:
1483     vcode = UV_LockRelease(entry->volumeId[RWVOL]);
1484     if (vcode) {
1485         fprintf(STDERR,
1486                 "Unable to unlock volume %lu, code %d\n",
1487                 (unsigned long)entry->volumeId[RWVOL],vcode);
1488         PrintError("", vcode);
1489     }
1490     return code;
1491 }
1492
1493
1494 /* Move volume <afromvol> on <afromserver> <afrompart> to <atoserver>
1495  * <atopart>.  The operation is almost idempotent.  The following
1496  * flags are recognized:
1497  *
1498  *     RV_NOCLONE - don't use a copy clone
1499  */
1500
1501 int
1502 UV_MoveVolume2(afs_uint32 afromvol, afs_uint32 afromserver, afs_int32 afrompart,
1503                afs_uint32 atoserver, afs_int32 atopart, int flags)
1504 {
1505     /* declare stuff 'volatile' that may be used from setjmp/longjmp and may
1506      * be changing during the move */
1507     struct rx_connection * volatile toconn;
1508     struct rx_connection * volatile fromconn;
1509     afs_int32 volatile fromtid;
1510     afs_int32 volatile totid;
1511     afs_int32 volatile clonetid;
1512     afs_uint32 volatile newVol;
1513     afs_uint32 volatile volid;
1514     afs_uint32 volatile backupId;
1515     int volatile islocked;
1516     int volatile pntg;
1517
1518     char vname[64];
1519     char *volName = 0;
1520     char tmpName[VOLSER_MAXVOLNAME + 1];
1521     afs_int32 rcode;
1522     afs_int32 fromDate;
1523     afs_int32 tmp;
1524     afs_uint32 tmpVol;
1525     struct restoreCookie cookie;
1526     afs_int32 vcode, code;
1527     struct volser_status tstatus;
1528     struct destServer destination;
1529
1530     struct nvldbentry entry, storeEntry;
1531     int i;
1532     afs_int32 error;
1533     char in, lf;                /* for test code */
1534     int same;
1535     char hoststr[16];
1536
1537 #ifdef  ENABLE_BUGFIX_1165
1538     volEntries volumeInfo;
1539     struct volintInfo *infop = 0;
1540 #endif
1541
1542     islocked = 0;
1543     fromconn = (struct rx_connection *)0;
1544     toconn = (struct rx_connection *)0;
1545     fromtid = 0;
1546     totid = 0;
1547     clonetid = 0;
1548     error = 0;
1549     volid = 0;
1550     pntg = 0;
1551     backupId = 0;
1552     newVol = 0;
1553
1554     /* support control-c processing */
1555     if (setjmp(env))
1556         goto mfail;
1557     (void)signal(SIGINT, sigint_handler);
1558
1559     if (TESTC) {
1560         fprintf(STDOUT,
1561                 "\nThere are three tests points - verifies all code paths through recovery.\n");
1562         fprintf(STDOUT, "First test point - operation not started.\n");
1563         fprintf(STDOUT, "...test here (y, n)? ");
1564         fflush(STDOUT);
1565         fscanf(stdin, "%c", &in);
1566         fscanf(stdin, "%c", &lf);       /* toss away */
1567         if (in == 'y') {
1568             fprintf(STDOUT, "type control-c\n");
1569             while (1) {
1570                 fprintf(stdout, ".");
1571                 fflush(stdout);
1572                 sleep(1);
1573             }
1574         }
1575         /* or drop through */
1576     }
1577
1578     vcode = VLDB_GetEntryByID(afromvol, -1, &entry);
1579     EGOTO1(mfail, vcode,
1580            "Could not fetch the entry for the volume  %u from the VLDB \n",
1581            afromvol);
1582
1583     if (entry.volumeId[RWVOL] != afromvol) {
1584         fprintf(STDERR, "Only RW volume can be moved\n");
1585         exit(1);
1586     }
1587
1588     vcode = ubik_VL_SetLock(cstruct, 0, afromvol, RWVOL, VLOP_MOVE);
1589     EGOTO1(mfail, vcode, "Could not lock entry for volume %u \n", afromvol);
1590     islocked = 1;
1591
1592     vcode = VLDB_GetEntryByID(afromvol, RWVOL, &entry);
1593     EGOTO1(mfail, vcode,
1594            "Could not fetch the entry for the volume  %u from the VLDB \n",
1595            afromvol);
1596
1597     backupId = entry.volumeId[BACKVOL];
1598     MapHostToNetwork(&entry);
1599
1600     if (!Lp_Match(afromserver, afrompart, &entry)) {
1601         /* the from server and partition do not exist in the vldb entry corresponding to volid */
1602         if (!Lp_Match(atoserver, atopart, &entry)) {
1603             /* the to server and partition do not exist in the vldb entry corresponding to volid */
1604             fprintf(STDERR, "The volume %lu is not on the specified site. \n",
1605                     (unsigned long)afromvol);
1606             fprintf(STDERR, "The current site is :");
1607             for (i = 0; i < entry.nServers; i++) {
1608                 if (entry.serverFlags[i] == ITSRWVOL) {
1609                     char pname[10];
1610                     MapPartIdIntoName(entry.serverPartition[i], pname);
1611                     fprintf(STDERR, " server %s partition %s \n",
1612                             noresolve ? afs_inet_ntoa_r(entry.serverNumber[i], hoststr) :
1613                             hostutil_GetNameByINet(entry.serverNumber[i]),
1614                             pname);
1615                 }
1616             }
1617             vcode =
1618                 ubik_VL_ReleaseLock(cstruct, 0, afromvol, -1,
1619                           (LOCKREL_OPCODE | LOCKREL_AFSID |
1620                            LOCKREL_TIMESTAMP));
1621             EGOTO1(mfail, vcode,
1622                    " Could not release lock on the VLDB entry for the volume %u \n",
1623                    afromvol);
1624
1625             return VOLSERVOLMOVED;
1626         }
1627
1628         /* delete the volume afromvol on src_server */
1629         /* from-info does not exist but to-info does =>
1630          * we have already done the move, but the volume
1631          * may still be existing physically on from fileserver
1632          */
1633         fromconn = UV_Bind(afromserver, AFSCONF_VOLUMEPORT);
1634         pntg = 1;
1635
1636         code = DoVolDelete(fromconn, afromvol, afrompart,
1637                            "leftover", 0, NULL, NULL);
1638         if (code && code != VNOVOL) {
1639             error = code;
1640             goto mfail;
1641         }
1642
1643         code = DoVolDelete(fromconn, backupId, afrompart,
1644                            "leftover backup", 0, NULL, NULL);
1645         if (code && code != VNOVOL) {
1646             error = code;
1647             goto mfail;
1648         }
1649
1650         fromtid = 0;
1651         error = 0;
1652         goto mfail;
1653     }
1654
1655     /* From-info matches the vldb info about volid,
1656      * its ok start the move operation, the backup volume
1657      * on the old site is deleted in the process
1658      */
1659     if (afrompart == atopart) {
1660         same = VLDB_IsSameAddrs(afromserver, atoserver, &error);
1661         EGOTO2(mfail, error,
1662                "Failed to get info about server's %d address(es) from vlserver (err=%d); aborting call!\n",
1663                afromserver, error);
1664
1665         if (same) {
1666             EGOTO1(mfail, VOLSERVOLMOVED,
1667                    "Warning: Moving volume %u to its home partition ignored!\n",
1668                    afromvol);
1669         }
1670     }
1671
1672     pntg = 1;
1673     toconn = UV_Bind(atoserver, AFSCONF_VOLUMEPORT);    /* get connections to the servers */
1674     fromconn = UV_Bind(afromserver, AFSCONF_VOLUMEPORT);
1675     totid = 0;  /* initialize to uncreated */
1676
1677     /* ***
1678      * clone the read/write volume locally.
1679      * ***/
1680
1681     VPRINT1("Starting transaction on source volume %u ...", afromvol);
1682     code = AFSVolTransCreate_retry(fromconn, afromvol, afrompart, ITBusy, &tmp);
1683     fromtid = tmp;
1684     EGOTO1(mfail, code, "Failed to create transaction on the volume %u\n",
1685            afromvol);
1686     VDONE;
1687
1688     if (!(flags & RV_NOCLONE)) {
1689         /* Get a clone id */
1690         VPRINT1("Allocating new volume id for clone of volume %u ...",
1691                 afromvol);
1692         tmpVol = 0;
1693         vcode = ubik_VL_GetNewVolumeId(cstruct, 0, 1, &tmpVol);
1694         newVol = tmpVol;
1695         EGOTO1(mfail, vcode,
1696                "Could not get an ID for the clone of volume %u from the VLDB\n",
1697                afromvol);
1698         VDONE;
1699
1700         /* Do the clone. Default flags on clone are set to delete on salvage and out of service */
1701         VPRINT1("Cloning source volume %u ...", afromvol);
1702         strcpy(vname, "move-clone-temp");
1703         code =
1704             AFSVolClone(fromconn, fromtid, 0, readonlyVolume, vname, &tmpVol);
1705         newVol = tmpVol;
1706         EGOTO1(mfail, code, "Failed to clone the source volume %u\n",
1707                afromvol);
1708         VDONE;
1709     }
1710
1711     /* lookup the name of the volume we just cloned */
1712     volid = afromvol;
1713     code = AFSVolGetName(fromconn, fromtid, &volName);
1714     EGOTO1(mfail, code, "Failed to get the name of the volume %u\n",
1715            afromvol);
1716
1717     VPRINT1("Ending the transaction on the source volume %u ...", afromvol);
1718     rcode = 0;
1719     code = AFSVolEndTrans(fromconn, fromtid, &rcode);
1720     fromtid = 0;
1721     if (!code)
1722         code = rcode;
1723     EGOTO1(mfail, code,
1724            "Failed to end the transaction on the source volume %u\n",
1725            afromvol);
1726     VDONE;
1727
1728     /* ***
1729      * Create the destination volume
1730      * ***/
1731
1732     if (!(flags & RV_NOCLONE)) {
1733         /* All of this is to get the fromDate */
1734         VPRINT1("Starting transaction on the cloned volume %u ...", newVol);
1735         tmp = clonetid;
1736         code =
1737             AFSVolTransCreate_retry(fromconn, newVol, afrompart, ITOffline,
1738                               &tmp);
1739         clonetid = tmp;
1740         EGOTO1(mfail, code,
1741                "Failed to start a transaction on the cloned volume%u\n",
1742                newVol);
1743         VDONE;
1744
1745         VPRINT1("Setting flags on cloned volume %u ...", newVol);
1746         code =
1747             AFSVolSetFlags(fromconn, clonetid,
1748                            VTDeleteOnSalvage | VTOutOfService); /*redundant */
1749         EGOTO1(mfail, code, "Could not set flags on the cloned volume %u\n",
1750                newVol);
1751         VDONE;
1752
1753         /* remember time from which we've dumped the volume */
1754         VPRINT1("Getting status of cloned volume %u ...", newVol);
1755         code = AFSVolGetStatus(fromconn, clonetid, &tstatus);
1756         EGOTO1(mfail, code,
1757                "Failed to get the status of the cloned volume %u\n",
1758                newVol);
1759         VDONE;
1760
1761         fromDate = CLOCKADJ(tstatus.creationDate);
1762     } else {
1763         /* With RV_NOCLONE, just do a full copy from the source */
1764         fromDate = 0;
1765     }
1766
1767
1768 #ifdef  ENABLE_BUGFIX_1165
1769     /*
1770      * Get the internal volume state from the source volume. We'll use such info (i.e. dayUse)
1771      * to copy it to the new volume (via AFSSetInfo later on) so that when we move volumes we
1772      * don't use this information...
1773      */
1774     volumeInfo.volEntries_val = (volintInfo *) 0;       /*this hints the stub to allocate space */
1775     volumeInfo.volEntries_len = 0;
1776     code = AFSVolListOneVolume(fromconn, afrompart, afromvol, &volumeInfo);
1777     EGOTO1(mfail, code,
1778            "Failed to get the volint Info of the cloned volume %u\n",
1779            afromvol);
1780
1781     infop = (volintInfo *) volumeInfo.volEntries_val;
1782     infop->maxquota = -1;       /* Else it will replace the default quota */
1783     infop->creationDate = -1;   /* Else it will use the source creation date */
1784     infop->updateDate = -1;     /* Else it will use the source update date */
1785 #endif
1786
1787     /* create a volume on the target machine */
1788     volid = afromvol;
1789     code = DoVolDelete(toconn, volid, atopart,
1790                        "pre-existing destination", 0, NULL, NULL);
1791     if (code && code != VNOVOL) {
1792         error = code;
1793         goto mfail;
1794     }
1795
1796     VPRINT1("Creating the destination volume %u ...", volid);
1797     tmp = totid;
1798     tmpVol = volid;
1799     code =
1800         AFSVolCreateVolume(toconn, atopart, volName, volser_RW, volid, &tmpVol,
1801                            &tmp);
1802     totid = tmp;
1803     volid = tmpVol;
1804     EGOTO1(mfail, code, "Failed to create the destination volume %u\n",
1805            volid);
1806     VDONE;
1807
1808     strncpy(tmpName, volName, VOLSER_OLDMAXVOLNAME);
1809     free(volName);
1810     volName = NULL;
1811
1812     VPRINT1("Setting volume flags on destination volume %u ...", volid);
1813     code =
1814         AFSVolSetFlags(toconn, totid, (VTDeleteOnSalvage | VTOutOfService));
1815     EGOTO1(mfail, code,
1816            "Failed to set the flags on the destination volume %u\n", volid);
1817     VDONE;
1818
1819     /***
1820      * Now dump the clone to the new volume
1821      ***/
1822
1823     destination.destHost = ntohl(atoserver);
1824     destination.destPort = AFSCONF_VOLUMEPORT;
1825     destination.destSSID = 1;
1826
1827     strncpy(cookie.name, tmpName, VOLSER_OLDMAXVOLNAME);
1828     cookie.type = RWVOL;
1829     cookie.parent = entry.volumeId[RWVOL];
1830     cookie.clone = 0;
1831
1832     if (!(flags & RV_NOCLONE)) {
1833         /* Copy the clone to the new volume */
1834         VPRINT2("Dumping from clone %u on source to volume %u on destination ...",
1835                 newVol, afromvol);
1836         code =
1837             AFSVolForward(fromconn, clonetid, 0, &destination, totid,
1838                           &cookie);
1839         EGOTO1(mfail, code, "Failed to move data for the volume %u\n", volid);
1840         VDONE;
1841
1842         VPRINT1("Ending transaction on cloned volume %u ...", newVol);
1843         code = AFSVolEndTrans(fromconn, clonetid, &rcode);
1844         if (!code)
1845             code = rcode;
1846         clonetid = 0;
1847         EGOTO1(mfail, code,
1848                "Failed to end the transaction on the cloned volume %u\n",
1849                newVol);
1850         VDONE;
1851     }
1852
1853     /* ***
1854      * reattach to the main-line volume, and incrementally dump it.
1855      * ***/
1856
1857     VPRINT1("Starting transaction on source volume %u ...", afromvol);
1858     tmp = fromtid;
1859     code = AFSVolTransCreate_retry(fromconn, afromvol, afrompart, ITBusy, &tmp);
1860     fromtid = tmp;
1861     EGOTO1(mfail, code,
1862            "Failed to create a transaction on the source volume %u\n",
1863            afromvol);
1864     VDONE;
1865
1866     /* now do the incremental */
1867     VPRINT2
1868         ("Doing the%s dump from source to destination for volume %u ... ",
1869          (flags & RV_NOCLONE) ? "" : " incremental",
1870          afromvol);
1871     code =
1872         AFSVolForward(fromconn, fromtid, fromDate, &destination, totid,
1873                       &cookie);
1874     EGOTO1(mfail, code,
1875            "Failed to do the%s dump from rw volume on old site to rw volume on newsite\n",
1876           (flags & RV_NOCLONE) ? "" : " incremental");
1877     VDONE;
1878
1879     /* now adjust the flags so that the new volume becomes official */
1880     VPRINT1("Setting volume flags on old source volume %u ...", afromvol);
1881     code = AFSVolSetFlags(fromconn, fromtid, VTOutOfService);
1882     EGOTO(mfail, code,
1883           "Failed to set the flags to make old source volume offline\n");
1884     VDONE;
1885
1886     VPRINT1("Setting volume flags on new source volume %u ...", afromvol);
1887     code = AFSVolSetFlags(toconn, totid, 0);
1888     EGOTO(mfail, code,
1889           "Failed to set the flags to make new source volume online\n");
1890     VDONE;
1891
1892 #ifdef  ENABLE_BUGFIX_1165
1893     VPRINT1("Setting volume status on destination volume %u ...", volid);
1894     code = AFSVolSetInfo(toconn, totid, infop);
1895     EGOTO1(mfail, code,
1896            "Failed to set volume status on the destination volume %u\n",
1897            volid);
1898     VDONE;
1899 #endif
1900
1901     /* put new volume online */
1902     VPRINT1("Ending transaction on destination volume %u ...", afromvol);
1903     code = AFSVolEndTrans(toconn, totid, &rcode);
1904     totid = 0;
1905     if (!code)
1906         code = rcode;
1907     EGOTO1(mfail, code,
1908            "Failed to end the transaction on the volume %u on the new site\n",
1909            afromvol);
1910     VDONE;
1911
1912     Lp_SetRWValue(&entry, afromserver, afrompart, atoserver, atopart);
1913     MapNetworkToHost(&entry, &storeEntry);
1914     storeEntry.flags &= ~BACK_EXISTS;
1915
1916     if (TESTC) {
1917         fprintf(STDOUT,
1918                 "Second test point - operation in progress but not complete.\n");
1919         fprintf(STDOUT, "...test here (y, n)? ");
1920         fflush(STDOUT);
1921         fscanf(stdin, "%c", &in);
1922         fscanf(stdin, "%c", &lf);       /* toss away */
1923         if (in == 'y') {
1924             fprintf(STDOUT, "type control-c\n");
1925             while (1) {
1926                 fprintf(stdout, ".");
1927                 fflush(stdout);
1928                 sleep(1);
1929             }
1930         }
1931         /* or drop through */
1932     }
1933
1934     VPRINT1("Releasing lock on VLDB entry for volume %u ...", afromvol);
1935     vcode =
1936         VLDB_ReplaceEntry(afromvol, -1, &storeEntry,
1937                           (LOCKREL_OPCODE | LOCKREL_AFSID |
1938                            LOCKREL_TIMESTAMP));
1939     if (vcode) {
1940         fprintf(STDERR,
1941                 " Could not release the lock on the VLDB entry for the volume %s %lu \n",
1942                 storeEntry.name, (unsigned long)afromvol);
1943         error = vcode;
1944         goto mfail;
1945     }
1946     islocked = 0;
1947     VDONE;
1948
1949     if (TESTC) {
1950         fprintf(STDOUT,
1951                 "Third test point - operation complete but no cleanup.\n");
1952         fprintf(STDOUT, "...test here (y, n)? ");
1953         fflush(STDOUT);
1954         fscanf(stdin, "%c", &in);
1955         fscanf(stdin, "%c", &lf);       /* toss away */
1956         if (in == 'y') {
1957             fprintf(STDOUT, "type control-c\n");
1958             while (1) {
1959                 fprintf(stdout, ".");
1960                 fflush(stdout);
1961                 sleep(1);
1962             }
1963         }
1964         /* or drop through */
1965     }
1966 #ifdef notdef
1967     /* This is tricky.  File server is very stupid, and if you mark the volume
1968      * as VTOutOfService, it may mark the *good* instance (if you're moving
1969      * between partitions on the same machine) as out of service.  Since
1970      * we're cleaning this code up in DEcorum, we're just going to kludge around
1971      * it for now by removing this call. */
1972     /* already out of service, just zap it now */
1973     code =
1974         AFSVolSetFlags(fromconn, fromtid, VTDeleteOnSalvage | VTOutOfService);
1975     if (code) {
1976         fprintf(STDERR,
1977                 "Failed to set the flags to make the old source volume offline\n");
1978         goto mfail;
1979     }
1980 #endif
1981     if (atoserver != afromserver) {
1982         /* set forwarding pointer for moved volumes */
1983         VPRINT1("Setting forwarding pointer for volume %u ...", afromvol);
1984         code = AFSVolSetForwarding(fromconn, fromtid, atoserver);
1985         EGOTO1(mfail, code,
1986                "Failed to set the forwarding pointer for the volume %u\n",
1987                afromvol);
1988         VDONE;
1989     }
1990
1991     VPRINT1("Deleting old volume %u on source ...", afromvol);
1992     code = AFSVolDeleteVolume(fromconn, fromtid);       /* zap original volume */
1993     EGOTO1(mfail, code, "Failed to delete the old volume %u on source\n",
1994            afromvol);
1995     VDONE;
1996
1997     VPRINT1("Ending transaction on old volume %u on the source ...",
1998             afromvol);
1999     code = AFSVolEndTrans(fromconn, fromtid, &rcode);
2000     fromtid = 0;
2001     if (!code)
2002         code = rcode;
2003     EGOTO1(mfail, code,
2004            "Failed to end the transaction on the old volume %u on the source\n",
2005            afromvol);
2006     VDONE;
2007
2008     code = DoVolDelete(fromconn, backupId, afrompart,
2009                        "source backup", 0, NULL, NULL);
2010     if (code && code != VNOVOL) {
2011         error = code;
2012         goto mfail;
2013     }
2014
2015     code = 0;           /* no backup volume? that's okay */
2016
2017     fromtid = 0;
2018     if (!(flags & RV_NOCLONE)) {
2019         code = DoVolDelete(fromconn, newVol, afrompart,
2020                            "cloned", 0, NULL, NULL);
2021         if (code) {
2022             if (code == VNOVOL) {
2023                 EPRINT1(code, "Failed to start transaction on %u\n", newVol);
2024             }
2025             error = code;
2026             goto mfail;
2027         }
2028     }
2029
2030     /* fall through */
2031     /* END OF MOVE */
2032
2033     if (TESTC) {
2034         fprintf(STDOUT, "Fourth test point - operation complete.\n");
2035         fprintf(STDOUT, "...test here (y, n)? ");
2036         fflush(STDOUT);
2037         fscanf(stdin, "%c", &in);
2038         fscanf(stdin, "%c", &lf);       /* toss away */
2039         if (in == 'y') {
2040             fprintf(STDOUT, "type control-c\n");
2041             while (1) {
2042                 fprintf(stdout, ".");
2043                 fflush(stdout);
2044                 sleep(1);
2045             }
2046         }
2047         /* or drop through */
2048     }
2049
2050     /* normal cleanup code */
2051
2052     if (entry.flags & RO_EXISTS)
2053         fprintf(STDERR, "WARNING : readOnly copies still exist \n");
2054
2055     if (islocked) {
2056         VPRINT1("Cleanup: Releasing VLDB lock on volume %u ...", afromvol);
2057         vcode =
2058             ubik_VL_ReleaseLock(cstruct, 0, afromvol, -1,
2059                       (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP));
2060         if (vcode) {
2061             VPRINT("\n");
2062             fprintf(STDERR,
2063                     " Could not release the lock on the VLDB entry for the volume %lu \n",
2064                     (unsigned long)afromvol);
2065             if (!error)
2066                 error = vcode;
2067         }
2068         VDONE;
2069     }
2070
2071     if (fromtid) {
2072         VPRINT1("Cleanup: Ending transaction on source volume %u ...",
2073                 afromvol);
2074         code = AFSVolEndTrans(fromconn, fromtid, &rcode);
2075         if (code || rcode) {
2076             VPRINT("\n");
2077             fprintf(STDERR,
2078                     "Could not end transaction on the source volume %lu\n",
2079                     (unsigned long)afromvol);
2080             if (!error)
2081                 error = (code ? code : rcode);
2082         }
2083         VDONE;
2084     }
2085
2086     if (clonetid) {
2087         VPRINT1("Cleanup: Ending transaction on clone volume %u ...", newVol);
2088         code = AFSVolEndTrans(fromconn, clonetid, &rcode);
2089         if (code || rcode) {
2090             VPRINT("\n");
2091             fprintf(STDERR,
2092                     "Could not end transaction on the source's clone volume %lu\n",
2093                     (unsigned long)newVol);
2094             if (!error)
2095                 error = (code ? code : rcode);
2096         }
2097         VDONE;
2098     }
2099
2100     if (totid) {
2101         VPRINT1("Cleanup: Ending transaction on destination volume %u ...",
2102                 afromvol);
2103         code = AFSVolEndTrans(toconn, totid, &rcode);
2104         if (code) {
2105             VPRINT("\n");
2106             fprintf(STDERR,
2107                     "Could not end transaction on destination volume %lu\n",
2108                     (unsigned long)afromvol);
2109             if (!error)
2110                 error = (code ? code : rcode);
2111         }
2112         VDONE;
2113     }
2114     if (volName)
2115         free(volName);
2116 #ifdef  ENABLE_BUGFIX_1165
2117     if (infop)
2118         free(infop);
2119 #endif
2120     if (fromconn)
2121         rx_DestroyConnection(fromconn);
2122     if (toconn)
2123         rx_DestroyConnection(toconn);
2124     PrintError("", error);
2125     return error;
2126
2127     /* come here only when the sky falls */
2128   mfail:
2129
2130     if (pntg) {
2131         fprintf(STDOUT,
2132                 "vos move: operation interrupted, cleanup in progress...\n");
2133         fprintf(STDOUT, "clear transaction contexts\n");
2134         fflush(STDOUT);
2135     }
2136
2137     /* unlock VLDB entry */
2138     if (islocked) {
2139         VPRINT1("Recovery: Releasing VLDB lock on volume %u ...", afromvol);
2140         ubik_VL_ReleaseLock(cstruct, 0, afromvol, -1,
2141                   (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP));
2142         VDONE;
2143         islocked = 0;
2144     }
2145
2146     if (clonetid) {
2147         VPRINT("Recovery: Ending transaction on clone volume ...");
2148         AFSVolEndTrans(fromconn, clonetid, &rcode);
2149         VDONE;
2150     }
2151     if (totid) {
2152         VPRINT("Recovery: Ending transaction on destination volume ...");
2153         AFSVolEndTrans(toconn, totid, &rcode);
2154         VDONE;
2155     }
2156     if (fromtid) {              /* put it on-line */
2157         VPRINT("Recovery: Setting volume flags on source volume ...");
2158         AFSVolSetFlags(fromconn, fromtid, 0);
2159         VDONE;
2160
2161         VPRINT("Recovery: Ending transaction on source volume ...");
2162         AFSVolEndTrans(fromconn, fromtid, &rcode);
2163         VDONE;
2164     }
2165
2166     VPRINT("Recovery: Accessing VLDB.\n");
2167     vcode = VLDB_GetEntryByID(afromvol, -1, &entry);
2168     if (vcode) {
2169         fprintf(STDOUT, "FATAL: VLDB access error: abort cleanup\n");
2170         fflush(STDOUT);
2171         goto done;
2172     }
2173     MapHostToNetwork(&entry);
2174
2175     /* Delete either the volume on the source location or the target location.
2176      * If the vldb entry still points to the source location, then we know the
2177      * volume move didn't finish so we remove the volume from the target
2178      * location. Otherwise, we remove the volume from the source location.
2179      */
2180     if (Lp_Match(afromserver, afrompart, &entry)) {     /* didn't move - delete target volume */
2181         if (pntg) {
2182             fprintf(STDOUT,
2183                     "move incomplete - attempt cleanup of target partition - no guarantee\n");
2184             fflush(STDOUT);
2185         }
2186
2187         if (volid && toconn) {
2188             code = DoVolDelete(toconn, volid, atopart,
2189                                "destination", 0, NULL, "Recovery:");
2190             if (code == VNOVOL) {
2191                 EPRINT1(code, "Recovery: Failed to start transaction on %u\n", volid);
2192             }
2193         }
2194
2195         /* put source volume on-line */
2196         if (fromconn) {
2197             VPRINT1("Recovery: Creating transaction on source volume %u ...",
2198                     afromvol);
2199             tmp = fromtid;
2200             code =
2201                 AFSVolTransCreate_retry(fromconn, afromvol, afrompart, ITBusy,
2202                                   &tmp);
2203             fromtid = tmp;
2204             if (!code) {
2205                 VDONE;
2206
2207                 VPRINT1("Recovery: Setting flags on source volume %u ...",
2208                         afromvol);
2209                 AFSVolSetFlags(fromconn, fromtid, 0);
2210                 VDONE;
2211
2212                 VPRINT1
2213                     ("Recovery: Ending transaction on source volume %u ...",
2214                      afromvol);
2215                 AFSVolEndTrans(fromconn, fromtid, &rcode);
2216                 VDONE;
2217             } else {
2218                 VPRINT1
2219                     ("\nRecovery: Unable to start transaction on source volume %u.\n",
2220                      afromvol);
2221             }
2222         }
2223     } else {                    /* yep, move complete */
2224         if (pntg) {
2225             fprintf(STDOUT,
2226                     "move complete - attempt cleanup of source partition - no guarantee\n");
2227             fflush(STDOUT);
2228         }
2229
2230         /* delete backup volume */
2231         if (fromconn) {
2232             code = DoVolDelete(fromconn, backupId, afrompart,
2233                                "backup", 0, NULL, "Recovery:");
2234             if (code == VNOVOL) {
2235                 EPRINT1(code, "Recovery: Failed to start transaction on %u\n", backupId);
2236             }
2237
2238             code = DoVolDelete(fromconn, afromvol, afrompart, "source",
2239                                (atoserver != afromserver)?atoserver:0,
2240                         NULL, NULL);
2241             if (code == VNOVOL) {
2242                 EPRINT1(code, "Failed to start transaction on %u\n", afromvol);
2243             }
2244         }
2245     }
2246
2247     /* common cleanup - delete local clone */
2248     if (newVol) {
2249         code = DoVolDelete(fromconn, newVol, afrompart,
2250                            "clone", 0, NULL, "Recovery:");
2251         if (code == VNOVOL) {
2252             EPRINT1(code, "Recovery: Failed to start transaction on %u\n", newVol);
2253         }
2254     }
2255
2256     /* unlock VLDB entry */
2257     if (islocked) {
2258         VPRINT1("Recovery: Releasing lock on VLDB entry for volume %u ...",
2259                 afromvol);
2260         ubik_VL_ReleaseLock(cstruct, 0, afromvol, -1,
2261                             (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP));
2262         VDONE;
2263     }
2264   done:                 /* routine cleanup */
2265     if (volName)
2266         free(volName);
2267 #ifdef  ENABLE_BUGFIX_1165
2268     if (infop)
2269         free(infop);
2270 #endif
2271     if (fromconn)
2272         rx_DestroyConnection(fromconn);
2273     if (toconn)
2274         rx_DestroyConnection(toconn);
2275
2276     if (pntg) {
2277         fprintf(STDOUT, "cleanup complete - user verify desired result\n");
2278         fflush(STDOUT);
2279     }
2280     exit(1);
2281 }
2282
2283
2284 int
2285 UV_MoveVolume(afs_uint32 afromvol, afs_uint32 afromserver, afs_int32 afrompart,
2286               afs_uint32 atoserver, afs_int32 atopart)
2287 {
2288     return UV_MoveVolume2(afromvol, afromserver, afrompart,
2289                           atoserver, atopart, 0);
2290 }
2291
2292
2293 /* Copy volume <afromvol> from <afromserver> <afrompart> to <atoserver>
2294  * <atopart>.  The new volume is named by <atovolname>.  The new volume
2295  * has ID <atovolid> if that is nonzero; otherwise a new ID is allocated
2296  * from the VLDB.  the following flags are supported:
2297  *
2298  *     RV_RDONLY  - target volume is RO
2299  *     RV_OFFLINE - leave target volume offline
2300  *     RV_CPINCR  - do incremental dump if target exists
2301  *     RV_NOVLDB  - don't create/update VLDB entry
2302  *     RV_NOCLONE - don't use a copy clone
2303  */
2304 int
2305 UV_CopyVolume2(afs_uint32 afromvol, afs_uint32 afromserver, afs_int32 afrompart,
2306                char *atovolname, afs_uint32 atoserver, afs_int32 atopart,
2307                afs_uint32 atovolid, int flags)
2308 {
2309     /* declare stuff 'volatile' that may be used from setjmp/longjmp and may
2310      * be changing during the copy */
2311     int volatile pntg;
2312     afs_int32 volatile clonetid;
2313     afs_int32 volatile totid;
2314     afs_int32 volatile fromtid;
2315     struct rx_connection * volatile fromconn;
2316     struct rx_connection * volatile toconn;
2317     afs_uint32 volatile cloneVol;
2318
2319     char vname[64];
2320     afs_int32 rcode;
2321     afs_int32 fromDate, cloneFromDate;
2322     struct restoreCookie cookie;
2323     afs_int32 vcode, code;
2324     afs_uint32 newVol;
2325     afs_int32 volflag;
2326     struct volser_status tstatus;
2327     struct destServer destination;
2328     struct nvldbentry entry, newentry, storeEntry;
2329     afs_int32 error;
2330     afs_int32 tmp;
2331     afs_uint32 tmpVol;
2332
2333     fromconn = (struct rx_connection *)0;
2334     toconn = (struct rx_connection *)0;
2335     fromtid = 0;
2336     totid = 0;
2337     clonetid = 0;
2338     error = 0;
2339     pntg = 0;
2340     newVol = 0;
2341
2342     /* support control-c processing */
2343     if (setjmp(env))
2344         goto mfail;
2345     (void)signal(SIGINT, sigint_handler);
2346
2347     vcode = VLDB_GetEntryByID(afromvol, -1, &entry);
2348     EGOTO1(mfail, vcode,
2349            "Could not fetch the entry for the volume  %u from the VLDB \n",
2350            afromvol);
2351     MapHostToNetwork(&entry);
2352
2353     pntg = 1;
2354     toconn = UV_Bind(atoserver, AFSCONF_VOLUMEPORT);    /* get connections to the servers */
2355     fromconn = UV_Bind(afromserver, AFSCONF_VOLUMEPORT);
2356     fromtid = totid = 0;        /* initialize to uncreated */
2357
2358     /* ***
2359      * clone the read/write volume locally.
2360      * ***/
2361
2362     cloneVol = 0;
2363     if (!(flags & RV_NOCLONE)) {
2364         VPRINT1("Starting transaction on source volume %u ...", afromvol);
2365         tmp = fromtid;
2366         code = AFSVolTransCreate_retry(fromconn, afromvol, afrompart, ITBusy,
2367                                  &tmp);
2368         fromtid = tmp;
2369         EGOTO1(mfail, code, "Failed to create transaction on the volume %u\n",
2370                afromvol);
2371         VDONE;
2372
2373         /* Get a clone id */
2374         VPRINT1("Allocating new volume id for clone of volume %u ...",
2375                 afromvol);
2376         cloneVol = 0;
2377         tmpVol = cloneVol;
2378         vcode = ubik_VL_GetNewVolumeId(cstruct, 0, 1, &tmpVol);
2379         cloneVol = tmpVol;
2380         EGOTO1(mfail, vcode,
2381            "Could not get an ID for the clone of volume %u from the VLDB\n",
2382            afromvol);
2383         VDONE;
2384     }
2385
2386     if (atovolid) {
2387         newVol = atovolid;
2388     } else {
2389         /* Get a new volume id */
2390         VPRINT1("Allocating new volume id for copy of volume %u ...", afromvol);
2391         newVol = 0;
2392         vcode = ubik_VL_GetNewVolumeId(cstruct, 0, 1, &newVol);
2393         EGOTO1(mfail, vcode,
2394                "Could not get an ID for the copy of volume %u from the VLDB\n",
2395                afromvol);
2396         VDONE;
2397     }
2398
2399     if (!(flags & RV_NOCLONE)) {
2400         /* Do the clone. Default flags on clone are set to delete on salvage and out of service */
2401         VPRINT1("Cloning source volume %u ...", afromvol);
2402         strcpy(vname, "copy-clone-temp");
2403         tmpVol = cloneVol;
2404         code =
2405             AFSVolClone(fromconn, fromtid, 0, readonlyVolume, vname,
2406                         &tmpVol);
2407         cloneVol = tmpVol;
2408         EGOTO1(mfail, code, "Failed to clone the source volume %u\n",
2409                afromvol);
2410         VDONE;
2411
2412         VPRINT1("Ending the transaction on the source volume %u ...", afromvol);
2413         rcode = 0;
2414         code = AFSVolEndTrans(fromconn, fromtid, &rcode);
2415         fromtid = 0;
2416         if (!code)
2417             code = rcode;
2418         EGOTO1(mfail, code,
2419                "Failed to end the transaction on the source volume %u\n",
2420                afromvol);
2421         VDONE;
2422     }
2423
2424     /* ***
2425      * Create the destination volume
2426      * ***/
2427
2428     if (!(flags & RV_NOCLONE)) {
2429         VPRINT1("Starting transaction on the cloned volume %u ...", cloneVol);
2430         tmp = clonetid;
2431         code =
2432             AFSVolTransCreate_retry(fromconn, cloneVol, afrompart, ITOffline,
2433                           &tmp);
2434         clonetid = tmp;
2435         EGOTO1(mfail, code,
2436                "Failed to start a transaction on the cloned volume%u\n",
2437                cloneVol);
2438         VDONE;
2439
2440         VPRINT1("Setting flags on cloned volume %u ...", cloneVol);
2441         code =
2442             AFSVolSetFlags(fromconn, clonetid,
2443                            VTDeleteOnSalvage | VTOutOfService); /*redundant */
2444         EGOTO1(mfail, code, "Could not set flags on the cloned volume %u\n",
2445                cloneVol);
2446         VDONE;
2447
2448         /* remember time from which we've dumped the volume */
2449         VPRINT1("Getting status of cloned volume %u ...", cloneVol);
2450         code = AFSVolGetStatus(fromconn, clonetid, &tstatus);
2451         EGOTO1(mfail, code,
2452                "Failed to get the status of the cloned volume %u\n",
2453                cloneVol);
2454         VDONE;
2455
2456         fromDate = CLOCKADJ(tstatus.creationDate);
2457     } else {
2458         fromDate = 0;
2459     }
2460
2461     /* create a volume on the target machine */
2462     cloneFromDate = 0;
2463     tmp = totid;
2464     code = AFSVolTransCreate_retry(toconn, newVol, atopart, ITOffline, &tmp);
2465     totid = tmp;
2466     if (!code) {
2467         if ((flags & RV_CPINCR)) {
2468             VPRINT1("Getting status of pre-existing volume %u ...", newVol);
2469             code = AFSVolGetStatus(toconn, totid, &tstatus);
2470             EGOTO1(mfail, code,
2471                    "Failed to get the status of the pre-existing volume %u\n",
2472                    newVol);
2473             VDONE;
2474
2475             /* Using the update date should be OK here, but add some fudge */
2476             cloneFromDate = CLOCKADJ(tstatus.updateDate);
2477             if ((flags & RV_NOCLONE))
2478                 fromDate = cloneFromDate;
2479
2480             /* XXX We should check that the source volume's creationDate is
2481              * XXX not newer than the existing target volume, and if not,
2482              * XXX throw away the existing target and do a full dump. */
2483
2484             goto cpincr;
2485         }
2486
2487         /* Delete the existing volume.
2488          * While we are deleting the volume in these steps, the transaction
2489          * we started against the cloned volume (clonetid above) will be
2490          * sitting idle. It will get cleaned up after 600 seconds
2491          */
2492         VPRINT1("Deleting pre-existing volume %u on destination ...", newVol);
2493         code = AFSVolDeleteVolume(toconn, totid);
2494         EGOTO1(mfail, code,
2495                "Could not delete the pre-existing volume %u on destination\n",
2496                newVol);
2497         VDONE;
2498
2499         VPRINT1
2500             ("Ending transaction on pre-existing volume %u on destination ...",
2501              newVol);
2502         code = AFSVolEndTrans(toconn, totid, &rcode);
2503         totid = 0;
2504         if (!code)
2505             code = rcode;
2506         EGOTO1(mfail, code,
2507                "Could not end the transaction on pre-existing volume %u on destination\n",
2508                newVol);
2509         VDONE;
2510     }
2511
2512     VPRINT1("Creating the destination volume %u ...", newVol);
2513     tmp = totid;
2514     code =
2515         AFSVolCreateVolume(toconn, atopart, atovolname,
2516                            (flags & RV_RDONLY) ? volser_RO : volser_RW,
2517                            newVol, &newVol, &tmp);
2518     totid = tmp;
2519     EGOTO1(mfail, code, "Failed to create the destination volume %u\n",
2520            newVol);
2521     VDONE;
2522
2523     VPRINT1("Setting volume flags on destination volume %u ...", newVol);
2524     code =
2525         AFSVolSetFlags(toconn, totid, (VTDeleteOnSalvage | VTOutOfService));
2526     EGOTO1(mfail, code,
2527            "Failed to set the flags on the destination volume %u\n", newVol);
2528     VDONE;
2529
2530 cpincr:
2531
2532     destination.destHost = ntohl(atoserver);
2533     destination.destPort = AFSCONF_VOLUMEPORT;
2534     destination.destSSID = 1;
2535
2536     strncpy(cookie.name, atovolname, VOLSER_OLDMAXVOLNAME);
2537     cookie.type = (flags & RV_RDONLY) ? ROVOL : RWVOL;
2538     cookie.parent = 0;
2539     cookie.clone = 0;
2540
2541     /***
2542      * Now dump the clone to the new volume
2543      ***/
2544
2545     if (!(flags & RV_NOCLONE)) {
2546         /* XXX probably should have some code here that checks to see if
2547          * XXX we are copying to same server and partition - if so, just
2548          * XXX use a clone to save disk space */
2549
2550         /* Copy the clone to the new volume */
2551         VPRINT2("Dumping from clone %u on source to volume %u on destination ...",
2552             cloneVol, newVol);
2553         code =
2554             AFSVolForward(fromconn, clonetid, cloneFromDate, &destination,
2555                           totid, &cookie);
2556         EGOTO1(mfail, code, "Failed to move data for the volume %u\n",
2557                newVol);
2558         VDONE;
2559
2560         VPRINT1("Ending transaction on cloned volume %u ...", cloneVol);
2561         code = AFSVolEndTrans(fromconn, clonetid, &rcode);
2562         if (!code)
2563             code = rcode;
2564         clonetid = 0;
2565         EGOTO1(mfail, code,
2566                "Failed to end the transaction on the cloned volume %u\n",
2567                cloneVol);
2568         VDONE;
2569     }
2570
2571     /* ***
2572      * reattach to the main-line volume, and incrementally dump it.
2573      * ***/
2574
2575     VPRINT1("Starting transaction on source volume %u ...", afromvol);
2576     tmp = fromtid;
2577     code = AFSVolTransCreate_retry(fromconn, afromvol, afrompart, ITBusy, &tmp);
2578     fromtid = tmp;
2579     EGOTO1(mfail, code,
2580            "Failed to create a transaction on the source volume %u\n",
2581            afromvol);
2582     VDONE;
2583
2584     /* now do the incremental */
2585     VPRINT2
2586         ("Doing the%s dump from source to destination for volume %u ... ",
2587          (flags & RV_NOCLONE) ? "" : " incremental",
2588          afromvol);
2589     code =
2590         AFSVolForward(fromconn, fromtid, fromDate, &destination, totid,
2591                       &cookie);
2592     EGOTO1(mfail, code,
2593            "Failed to do the%s dump from old site to new site\n",
2594            (flags & RV_NOCLONE) ? "" : " incremental");
2595     VDONE;
2596
2597     VPRINT1("Setting volume flags on destination volume %u ...", newVol);
2598     volflag = ((flags & RV_OFFLINE) ? VTOutOfService : 0);      /* off or on-line */
2599     code = AFSVolSetFlags(toconn, totid, volflag);
2600     EGOTO(mfail, code,
2601           "Failed to set the flags to make destination volume online\n");
2602     VDONE;
2603
2604     /* put new volume online */
2605     VPRINT1("Ending transaction on destination volume %u ...", newVol);
2606     code = AFSVolEndTrans(toconn, totid, &rcode);
2607     totid = 0;
2608     if (!code)
2609         code = rcode;
2610     EGOTO1(mfail, code,
2611            "Failed to end the transaction on the destination volume %u\n",
2612            newVol);
2613     VDONE;
2614
2615     VPRINT1("Ending transaction on source volume %u ...", afromvol);
2616     code = AFSVolEndTrans(fromconn, fromtid, &rcode);
2617     fromtid = 0;
2618     if (!code)
2619         code = rcode;
2620     EGOTO1(mfail, code,
2621            "Failed to end the transaction on the source volume %u\n",
2622            afromvol);
2623     VDONE;
2624
2625     fromtid = 0;
2626
2627     if (!(flags & RV_NOCLONE)) {
2628         code = DoVolDelete(fromconn, cloneVol, afrompart,
2629                            "cloned", 0, NULL, NULL);
2630         if (code) {
2631             if (code == VNOVOL) {
2632                 EPRINT1(code, "Failed to start transaction on %u\n", cloneVol);
2633             }
2634             error = code;
2635             goto mfail;
2636         }
2637     }
2638
2639     if (!(flags & RV_NOVLDB)) {
2640         /* create the vldb entry for the copied volume */
2641         strncpy(newentry.name, atovolname, VOLSER_OLDMAXVOLNAME);
2642         newentry.nServers = 1;
2643         newentry.serverNumber[0] = atoserver;
2644         newentry.serverPartition[0] = atopart;
2645         newentry.flags = (flags & RV_RDONLY) ? RO_EXISTS : RW_EXISTS;
2646         newentry.serverFlags[0] = (flags & RV_RDONLY) ? ITSROVOL : ITSRWVOL;
2647         newentry.volumeId[RWVOL] = newVol;
2648         newentry.volumeId[ROVOL] = (flags & RV_RDONLY) ? newVol : 0;
2649         newentry.volumeId[BACKVOL] = 0;
2650         newentry.cloneId = 0;
2651         /*map into right byte order, before passing to xdr, the stuff has to be in host
2652          * byte order. Xdr converts it into network order */
2653         MapNetworkToHost(&newentry, &storeEntry);
2654         /* create the vldb entry */
2655         vcode = VLDB_CreateEntry(&storeEntry);
2656         if (vcode) {
2657             fprintf(STDERR,
2658                     "Could not create a VLDB entry for the volume %s %lu\n",
2659                     atovolname, (unsigned long)newVol);
2660             /*destroy the created volume */
2661             VPRINT1("Deleting the newly created volume %u\n", newVol);
2662             AFSVolDeleteVolume(toconn, totid);
2663             error = vcode;
2664             goto mfail;
2665         }
2666         VPRINT2("Created the VLDB entry for the volume %s %u\n", atovolname,
2667                 newVol);
2668     }
2669
2670     /* normal cleanup code */
2671
2672     if (fromtid) {
2673         VPRINT1("Cleanup: Ending transaction on source volume %u ...",
2674                 afromvol);
2675         code = AFSVolEndTrans(fromconn, fromtid, &rcode);
2676         if (code || rcode) {
2677             VPRINT("\n");
2678             fprintf(STDERR,
2679                     "Could not end transaction on the source volume %lu\n",
2680                     (unsigned long)afromvol);
2681             if (!error)
2682                 error = (code ? code : rcode);
2683         }
2684         VDONE;
2685     }
2686
2687     if (clonetid) {
2688         VPRINT1("Cleanup: Ending transaction on clone volume %u ...",
2689                 cloneVol);
2690         code = AFSVolEndTrans(fromconn, clonetid, &rcode);
2691         if (code || rcode) {
2692             VPRINT("\n");
2693             fprintf(STDERR,
2694                     "Could not end transaction on the source's clone volume %lu\n",
2695                     (unsigned long)cloneVol);
2696             if (!error)
2697                 error = (code ? code : rcode);
2698         }
2699         VDONE;
2700     }
2701
2702     if (totid) {
2703         VPRINT1("Cleanup: Ending transaction on destination volume %u ...",
2704                 newVol);
2705         code = AFSVolEndTrans(toconn, totid, &rcode);
2706         if (code) {
2707             VPRINT("\n");
2708             fprintf(STDERR,
2709                     "Could not end transaction on destination volume %lu\n",
2710                     (unsigned long)newVol);
2711             if (!error)
2712                 error = (code ? code : rcode);
2713         }
2714         VDONE;
2715     }
2716     if (fromconn)
2717         rx_DestroyConnection(fromconn);
2718     if (toconn)
2719         rx_DestroyConnection(toconn);
2720     PrintError("", error);
2721     return error;
2722
2723     /* come here only when the sky falls */
2724   mfail:
2725
2726     if (pntg) {
2727         fprintf(STDOUT,
2728                 "vos copy: operation interrupted, cleanup in progress...\n");
2729         fprintf(STDOUT, "clear transaction contexts\n");
2730         fflush(STDOUT);
2731     }
2732
2733     if (clonetid) {
2734         VPRINT("Recovery: Ending transaction on clone volume ...");
2735         AFSVolEndTrans(fromconn, clonetid, &rcode);
2736         VDONE;
2737     }
2738     if (totid) {
2739         VPRINT("Recovery: Ending transaction on destination volume ...");
2740         AFSVolEndTrans(toconn, totid, &rcode);
2741         VDONE;
2742     }
2743     if (fromtid) {              /* put it on-line */
2744         VPRINT("Recovery: Ending transaction on source volume ...");
2745         AFSVolEndTrans(fromconn, fromtid, &rcode);
2746         VDONE;
2747     }
2748
2749     VPRINT("Recovery: Accessing VLDB.\n");
2750     vcode = VLDB_GetEntryByID(afromvol, -1, &entry);
2751     if (vcode) {
2752         fprintf(STDOUT, "FATAL: VLDB access error: abort cleanup\n");
2753         fflush(STDOUT);
2754         goto done;
2755     }
2756     MapHostToNetwork(&entry);
2757
2758     /* common cleanup - delete local clone */
2759     if (cloneVol) {
2760         code = DoVolDelete(fromconn, cloneVol, afrompart,
2761                            "clone", 0, NULL, "Recovery:");
2762         if (code == VNOVOL) {
2763             EPRINT1(code, "Recovery: Failed to start transaction on %u\n", cloneVol);
2764         }
2765     }
2766
2767   done:                 /* routine cleanup */
2768     if (fromconn)
2769         rx_DestroyConnection(fromconn);
2770     if (toconn)
2771         rx_DestroyConnection(toconn);
2772
2773     if (pntg) {
2774         fprintf(STDOUT, "cleanup complete - user verify desired result\n");
2775         fflush(STDOUT);
2776     }
2777     exit(1);
2778 }
2779
2780
2781 int
2782 UV_CopyVolume(afs_uint32 afromvol, afs_uint32 afromserver, afs_int32 afrompart,
2783               char *atovolname, afs_uint32 atoserver, afs_int32 atopart)
2784 {
2785     return UV_CopyVolume2(afromvol, afromserver, afrompart,
2786                           atovolname, atoserver, atopart, 0, 0);
2787 }
2788
2789
2790
2791 /* Make a new backup of volume <avolid> on <aserver> and <apart>
2792  * if one already exists, update it
2793  */
2794
2795 int
2796 UV_BackupVolume(afs_uint32 aserver, afs_int32 apart, afs_uint32 avolid)
2797 {
2798     struct rx_connection *aconn = (struct rx_connection *)0;
2799     afs_int32 ttid = 0, btid = 0;
2800     afs_uint32 backupID;
2801     afs_int32 code = 0, rcode = 0;
2802     struct nvldbentry entry, storeEntry;
2803     afs_int32 error = 0;
2804     int vldblocked = 0, vldbmod = 0;
2805
2806     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
2807
2808     /* the calls to VLDB will succeed only if avolid is a RW volume,
2809      * since we are following the RW hash chain for searching */
2810     code = VLDB_GetEntryByID(avolid, RWVOL, &entry);
2811     if (code) {
2812         fprintf(STDERR,
2813                 "Could not fetch the entry for the volume %lu from the VLDB \n",
2814                 (unsigned long)avolid);
2815         error = code;
2816         goto bfail;
2817     }
2818     MapHostToNetwork(&entry);
2819
2820     /* These operations require the VLDB be locked since it means the VLDB
2821      * will change or the vldb is already locked.
2822      */
2823     if (!(entry.flags & BACK_EXISTS) || /* backup volume doesnt exist */
2824         (entry.flags & VLOP_ALLOPERS) ||        /* vldb lock already held */
2825         (entry.volumeId[BACKVOL] == INVALID_BID)) {     /* no assigned backup volume id */
2826
2827         code = ubik_VL_SetLock(cstruct, 0, avolid, RWVOL, VLOP_BACKUP);
2828         if (code) {
2829             fprintf(STDERR,
2830                     "Could not lock the VLDB entry for the volume %lu\n",
2831                     (unsigned long)avolid);
2832             error = code;
2833             goto bfail;
2834         }
2835         vldblocked = 1;
2836
2837         /* Reread the vldb entry */
2838         code = VLDB_GetEntryByID(avolid, RWVOL, &entry);
2839         if (code) {
2840             fprintf(STDERR,
2841                     "Could not fetch the entry for the volume %lu from the VLDB \n",
2842                     (unsigned long)avolid);
2843             error = code;
2844             goto bfail;
2845         }
2846         MapHostToNetwork(&entry);
2847     }
2848
2849     if (!ISNAMEVALID(entry.name)) {
2850         fprintf(STDERR, "Name of the volume %s exceeds the size limit\n",
2851                 entry.name);
2852         error = VOLSERBADNAME;
2853         goto bfail;
2854     }
2855
2856     backupID = entry.volumeId[BACKVOL];
2857     if (backupID == INVALID_BID) {
2858         /* Get a backup volume id from the VLDB and update the vldb
2859          * entry with it.
2860          */
2861         code = ubik_VL_GetNewVolumeId(cstruct, 0, 1, &backupID);
2862         if (code) {
2863             fprintf(STDERR,
2864                     "Could not allocate ID for the backup volume of  %lu from the VLDB\n",
2865                     (unsigned long)avolid);
2866             error = code;
2867             goto bfail;
2868         }
2869         entry.volumeId[BACKVOL] = backupID;
2870         vldbmod = 1;
2871     }
2872
2873     code = DoVolClone(aconn, avolid, apart, backupVolume, backupID, "backup",
2874                       entry.name, NULL, ".backup", NULL, NULL);
2875     if (code) {
2876         error = code;
2877         goto bfail;
2878     }
2879
2880     /* Mark vldb as backup exists */
2881     if (!(entry.flags & BACK_EXISTS)) {
2882         entry.flags |= BACK_EXISTS;
2883         vldbmod = 1;
2884     }
2885
2886     /* Now go back to the backup volume and bring it on line */
2887     code = AFSVolTransCreate_retry(aconn, backupID, apart, ITOffline, &btid);
2888     if (code) {
2889         fprintf(STDERR,
2890                 "Failed to start a transaction on the backup volume %lu\n",
2891                 (unsigned long)backupID);
2892         error = code;
2893         goto bfail;
2894     }
2895
2896     code = AFSVolSetFlags(aconn, btid, 0);
2897     if (code) {
2898         fprintf(STDERR, "Could not mark the backup volume %lu on line \n",
2899                 (unsigned long)backupID);
2900         error = code;
2901         goto bfail;
2902     }
2903
2904     code = AFSVolEndTrans(aconn, btid, &rcode);
2905     btid = 0;
2906     if (code || rcode) {
2907         fprintf(STDERR,
2908                 "Failed to end the transaction on the backup volume %lu\n",
2909                 (unsigned long)backupID);
2910         error = (code ? code : rcode);
2911         goto bfail;
2912     }
2913
2914     VDONE;
2915
2916     /* Will update the vldb below */
2917
2918   bfail:
2919     if (ttid) {
2920         code = AFSVolEndTrans(aconn, ttid, &rcode);
2921         if (code || rcode) {
2922             fprintf(STDERR, "Could not end transaction on the volume %lu\n",
2923                     (unsigned long)avolid);
2924             if (!error)
2925                 error = (code ? code : rcode);
2926         }
2927     }
2928
2929     if (btid) {
2930         code = AFSVolEndTrans(aconn, btid, &rcode);
2931         if (code || rcode) {
2932             fprintf(STDERR,
2933                     "Could not end transaction the backup volume %lu\n",
2934                     (unsigned long)backupID);
2935             if (!error)
2936                 error = (code ? code : rcode);
2937         }
2938     }
2939
2940     /* Now update the vldb - if modified */
2941     if (vldblocked) {
2942         if (vldbmod) {
2943             MapNetworkToHost(&entry, &storeEntry);
2944             code =
2945                 VLDB_ReplaceEntry(avolid, RWVOL, &storeEntry,
2946                                   (LOCKREL_OPCODE | LOCKREL_AFSID |
2947                                    LOCKREL_TIMESTAMP));
2948             if (code) {
2949                 fprintf(STDERR,
2950                         "Could not update the VLDB entry for the volume %lu \n",
2951                         (unsigned long)avolid);
2952                 if (!error)
2953                     error = code;
2954             }
2955         } else {
2956             code =
2957                 ubik_VL_ReleaseLock(cstruct, 0, avolid, RWVOL,
2958                           (LOCKREL_OPCODE | LOCKREL_AFSID |
2959                            LOCKREL_TIMESTAMP));
2960             if (code) {
2961                 fprintf(STDERR,
2962                         "Could not unlock the VLDB entry for the volume %lu \n",
2963                         (unsigned long)avolid);
2964                 if (!error)
2965                     error = code;
2966             }
2967         }
2968     }
2969
2970     if (aconn)
2971         rx_DestroyConnection(aconn);
2972
2973     PrintError("", error);
2974     return error;
2975 }
2976
2977 /* Make a new clone of volume <avolid> on <aserver> and <apart>
2978  * using volume ID <acloneid>, or a new ID allocated from the VLDB.
2979  * The new volume is named by <aname>, or by appending ".clone" to
2980  * the existing name if <aname> is NULL.  The following flags are
2981  * supported:
2982  *
2983  *     RV_RDONLY  - target volume is RO
2984  *     RV_OFFLINE - leave target volume offline
2985  */
2986
2987 int
2988 UV_CloneVolume(afs_uint32 aserver, afs_int32 apart, afs_uint32 avolid,
2989                afs_uint32 acloneid, char *aname, int flags)
2990 {
2991     struct rx_connection *aconn = (struct rx_connection *)0;
2992     afs_int32 ttid = 0, btid = 0;
2993     afs_int32 code = 0, rcode = 0;
2994     char vname[VOLSER_MAXVOLNAME + 1];
2995     afs_int32 error = 0;
2996     volEntries volumeInfo;
2997     int type = 0;
2998
2999     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
3000
3001     if (!aname) {
3002         volumeInfo.volEntries_val = (volintInfo *) 0;
3003         volumeInfo.volEntries_len = 0;
3004         code = AFSVolListOneVolume(aconn, apart, avolid, &volumeInfo);
3005         if (code) {
3006             fprintf(stderr, "Could not get info for volume %lu\n",
3007                     (unsigned long)avolid);
3008             error = code;
3009             goto bfail;
3010         }
3011         strncpy(vname, volumeInfo.volEntries_val[0].name,
3012                 VOLSER_OLDMAXVOLNAME - 7);
3013         vname[VOLSER_OLDMAXVOLNAME - 7] = 0;
3014         strcat(vname, ".clone");
3015         aname = vname;
3016         if (volumeInfo.volEntries_val)
3017             free(volumeInfo.volEntries_val);
3018     }
3019
3020     if (!acloneid) {
3021         /* Get a clone id */
3022         VPRINT1("Allocating new volume id for clone of volume %u ...",
3023                 avolid);
3024         code = ubik_VL_GetNewVolumeId(cstruct, 0, 1, &acloneid);
3025         EGOTO1(bfail, code,
3026            "Could not get an ID for the clone of volume %u from the VLDB\n",
3027            avolid);
3028         VDONE;
3029     }
3030
3031     if (flags & RV_RWONLY)
3032         type = readwriteVolume;
3033     else if (flags & RV_RDONLY)
3034         type = readonlyVolume;
3035     else
3036         type = backupVolume;
3037
3038     code = DoVolClone(aconn, avolid, apart, type, acloneid, "clone",
3039                       NULL, ".clone", NULL, NULL, NULL);
3040     if (code) {
3041         error = code;
3042         goto bfail;
3043     }
3044
3045     /* Now go back to the backup volume and bring it on line */
3046     if (!(flags & RV_OFFLINE)) {
3047         code = AFSVolTransCreate_retry(aconn, acloneid, apart, ITOffline, &btid);
3048         if (code) {
3049             fprintf(STDERR,
3050                     "Failed to start a transaction on the clone volume %lu\n",
3051                     (unsigned long)acloneid);
3052             error = code;
3053             goto bfail;
3054         }
3055
3056         code = AFSVolSetFlags(aconn, btid, 0);
3057         if (code) {
3058             fprintf(STDERR, "Could not mark the clone volume %lu on line \n",
3059                     (unsigned long)acloneid);
3060             error = code;
3061             goto bfail;
3062         }
3063
3064         code = AFSVolEndTrans(aconn, btid, &rcode);
3065         btid = 0;
3066         if (code || rcode) {
3067             fprintf(STDERR,
3068                     "Failed to end the transaction on the clone volume %lu\n",
3069                     (unsigned long)acloneid);
3070             error = (code ? code : rcode);
3071             goto bfail;
3072         }
3073     }
3074
3075     VDONE;
3076
3077   bfail:
3078     if (ttid) {
3079         code = AFSVolEndTrans(aconn, ttid, &rcode);
3080         if (code || rcode) {
3081             fprintf(STDERR, "Could not end transaction on the volume %lu\n",
3082                     (unsigned long)avolid);
3083             if (!error)
3084                 error = (code ? code : rcode);
3085         }
3086     }
3087
3088     if (btid) {
3089         code = AFSVolEndTrans(aconn, btid, &rcode);
3090         if (code || rcode) {
3091             fprintf(STDERR,
3092                     "Could not end transaction on the clone volume %lu\n",
3093                     (unsigned long)acloneid);
3094             if (!error)
3095                 error = (code ? code : rcode);
3096         }
3097     }
3098
3099     if (aconn)
3100         rx_DestroyConnection(aconn);
3101
3102     PrintError("", error);
3103     return error;
3104 }
3105
3106 #define ONERROR(ec, ep, es) do { \
3107     if (ec) { \
3108         fprintf(STDERR, (es), (ep)); \
3109         error = (ec); \
3110         goto rfail; \
3111     } \
3112 } while (0)
3113 #define ONERROR0(ec, es) do { \
3114     if (ec) { \
3115         fprintf(STDERR, (es)); \
3116         error = (ec); \
3117         goto rfail; \
3118     } \
3119 } while (0)
3120 #define ERROREXIT(ec) do { \
3121     error = (ec); \
3122     goto rfail; \
3123 } while (0)
3124
3125 /* Get a "transaction" on this replica.  Create the volume
3126  * if necessary.  Return the time from which a dump should
3127  * be made (0 if it's a new volume)
3128  */
3129 static int
3130 GetTrans(struct nvldbentry *vldbEntryPtr, afs_int32 index,
3131          struct rx_connection **connPtr, afs_int32 * transPtr,
3132          afs_uint32 * crtimePtr, afs_uint32 * uptimePtr,
3133          afs_int32 *origflags, afs_uint32 tmpVolId)
3134 {
3135     afs_uint32 volid;
3136     struct volser_status tstatus;
3137     int code = 0;
3138     int rcode, tcode;
3139     char hoststr[16];
3140
3141     *connPtr = (struct rx_connection *)0;
3142     *transPtr = 0;
3143     *crtimePtr = 0;
3144     *uptimePtr = 0;
3145
3146     /* get connection to the replication site */
3147     *connPtr = UV_Bind(vldbEntryPtr->serverNumber[index], AFSCONF_VOLUMEPORT);
3148     if (!*connPtr)
3149         goto fail;              /* server is down */
3150
3151     volid = vldbEntryPtr->volumeId[ROVOL];
3152
3153     if (volid) {
3154         code =
3155             AFSVolTransCreate_retry(*connPtr, volid,
3156                               vldbEntryPtr->serverPartition[index], ITOffline,
3157                               transPtr);
3158
3159         if (!code && (origflags[index] & RO_DONTUSE)) {
3160             /* If RO_DONTUSE is set, this is supposed to be an entirely new
3161              * site. Don't trust any data on it, since it is possible we
3162              * have encountered some temporary volume from some other
3163              * incomplete volume operation. It is difficult to detect if
3164              * that has happened vs if this is a legit volume, so just
3165              * delete it to be safe. */
3166
3167             VPRINT1("Deleting extant RO_DONTUSE site on %s...",
3168                     noresolve ? afs_inet_ntoa_r(vldbEntryPtr->
3169                                                 serverNumber[index], hoststr) :
3170                     hostutil_GetNameByINet(vldbEntryPtr->
3171                                            serverNumber[index]));
3172
3173             code = AFSVolDeleteVolume(*connPtr, *transPtr);
3174             if (code) {
3175                 PrintError("Failed to delete RO_DONTUSE site: ", code);
3176                 goto fail;
3177             }
3178
3179             tcode = AFSVolEndTrans(*connPtr, *transPtr, &rcode);
3180             *transPtr = 0;
3181             if (!tcode) {
3182                 tcode = rcode;
3183             }
3184             if (tcode) {
3185                 PrintError("Failed to end transaction on RO_DONTUSE site: ",
3186                            tcode);
3187                 goto fail;
3188             }
3189
3190             VDONE;
3191
3192             /* emulate what TransCreate would have returned, so we try to
3193              * create the volume below */
3194             code = VNOVOL;
3195         }
3196     }
3197
3198     /* If the volume does not exist, create it */
3199     if (!volid || code) {
3200         char volname[VL_MAXNAMELEN];
3201         char hoststr[16];
3202
3203         if (volid && (code != VNOVOL)) {
3204             PrintError("Failed to start a transaction on the RO volume.\n",
3205                        code);
3206             goto fail;
3207         }
3208
3209         strlcpy(volname, vldbEntryPtr->name, sizeof(volname));
3210
3211         if (strlcat(volname,
3212                     tmpVolId?".roclone":".readonly",
3213                     sizeof(volname)) >= sizeof(volname)) {
3214             code = ENOMEM;
3215             PrintError("Volume name is too long\n", code);
3216             goto fail;
3217         }
3218
3219         if (tmpVolId)
3220             strcat(volname, ".roclone");
3221         else
3222             strcat(volname, ".readonly");
3223
3224         if (verbose) {
3225             fprintf(STDOUT,
3226                     "Creating new volume %lu on replication site %s: ",
3227                     tmpVolId?(unsigned long)tmpVolId:(unsigned long)volid,
3228                     noresolve ? afs_inet_ntoa_r(vldbEntryPtr->
3229                                                 serverNumber[index], hoststr) :
3230                     hostutil_GetNameByINet(vldbEntryPtr->
3231                                            serverNumber[index]));
3232             fflush(STDOUT);
3233         }
3234
3235         code =
3236           AFSVolCreateVolume(*connPtr, vldbEntryPtr->serverPartition[index],
3237                              volname, volser_RO,
3238                              vldbEntryPtr->volumeId[RWVOL],
3239                              tmpVolId?&tmpVolId:&volid,
3240                              transPtr);
3241         if (code) {
3242             PrintError("Failed to create the ro volume: ", code);
3243             goto fail;
3244         }
3245         vldbEntryPtr->volumeId[ROVOL] = volid;
3246
3247         VDONE;
3248
3249         /* The following is a bit redundant, since create sets these flags by default */
3250         code =
3251             AFSVolSetFlags(*connPtr, *transPtr,
3252                            VTDeleteOnSalvage | VTOutOfService);
3253         if (code) {
3254             PrintError("Failed to set flags on the ro volume: ", code);
3255             goto fail;
3256         }
3257     }
3258
3259     /* Otherwise, the transaction did succeed, so get the creation date of the
3260      * latest RO volume on the replication site
3261      */
3262     else {
3263         VPRINT2("Updating existing ro volume %u on %s ...\n", volid,
3264                 noresolve ? afs_inet_ntoa_r(vldbEntryPtr->
3265                                             serverNumber[index], hoststr) :
3266                 hostutil_GetNameByINet(vldbEntryPtr->serverNumber[index]));
3267
3268         code = AFSVolGetStatus(*connPtr, *transPtr, &tstatus);
3269         if (code) {
3270             PrintError("Failed to get status of volume on destination: ",
3271                        code);
3272             goto fail;
3273         }
3274         if (tmpVolId) {
3275             code = AFSVolEndTrans(*connPtr, *transPtr, &rcode);
3276             *transPtr = 0;
3277             if (!code)
3278                 code = rcode;
3279             if (!code)
3280                 code = DoVolClone(*connPtr, volid,
3281                                   vldbEntryPtr->serverPartition[index],
3282                                   readonlyVolume, tmpVolId, "temporary",
3283                                   vldbEntryPtr->name, NULL, ".roclone", NULL,
3284                                   transPtr);
3285             if (code)
3286                 goto fail;
3287         }
3288         *crtimePtr = CLOCKADJ(tstatus.creationDate);
3289         *uptimePtr = CLOCKADJ(tstatus.updateDate);
3290     }
3291
3292     return 0;
3293
3294   fail:
3295     if (*transPtr) {
3296         tcode = AFSVolEndTrans(*connPtr, *transPtr, &rcode);
3297         *transPtr = 0;
3298         if (!tcode)
3299             tcode = rcode;
3300         if (tcode && tcode != ENOENT)
3301             PrintError("Could not end transaction on a ro volume: ", tcode);
3302     }
3303
3304     return code;
3305 }
3306
3307 static int
3308 SimulateForwardMultiple(struct rx_connection *fromconn, afs_int32 fromtid,
3309                         afs_int32 fromdate, manyDests * tr, afs_int32 flags,
3310                         void *cookie, manyResults * results)
3311 {
3312     unsigned int i;
3313
3314     for (i = 0; i < tr->manyDests_len; i++) {
3315         results->manyResults_val[i] =
3316             AFSVolForward(fromconn, fromtid, fromdate,
3317                           &(tr->manyDests_val[i].server),
3318                           tr->manyDests_val[i].trans, cookie);
3319     }
3320     return 0;
3321 }
3322
3323 /**
3324  * Check if a trans has timed out, and recreate it if necessary.
3325  *
3326  * @param[in] aconn  RX connection to the relevant server
3327  * @param[inout] atid  Transaction ID to check; if we recreated the trans,
3328  *                     contains the new trans ID on success
3329  * @param[in] apart  Partition for the transaction
3330  * @param[in] astat  The status of the original transaction
3331  *
3332  * @return operation status
3333  *  @retval 0 existing transaction is still valid, or we managed to recreate
3334  *            the trans successfully
3335  *  @retval nonzero Fatal error; bail out
3336  */
3337 static int
3338 CheckTrans(struct rx_connection *aconn, afs_int32 *atid, afs_int32 apart,
3339            struct volser_status *astat)
3340 {
3341     struct volser_status new_status;
3342     afs_int32 code;
3343
3344     memset(&new_status, 0, sizeof(new_status));
3345     code = AFSVolGetStatus(aconn, *atid, &new_status);
3346     if (code) {
3347         if (code == ENOENT) {
3348             *atid = 0;
3349             VPRINT1("Old transaction on cloned volume %lu timed out, "
3350                     "restarting transaction\n", (long unsigned) astat->volID);
3351             code = AFSVolTransCreate_retry(aconn, astat->volID, apart,
3352                                            ITBusy, atid);
3353             if (code) {
3354                 PrintError("Failed to recreate cloned RO volume transaction\n",
3355                            code);
3356                 return 1;
3357             }
3358
3359             memset(&new_status, 0, sizeof(new_status));
3360             code = AFSVolGetStatus(aconn, *atid, &new_status);
3361             if (code) {
3362                 PrintError("Failed to get status on recreated transaction\n",
3363                            code);
3364                 return 1;
3365             }
3366
3367             if (memcmp(&new_status, astat, sizeof(new_status)) != 0) {
3368                 PrintError("Recreated transaction on cloned RO volume, but "
3369                            "the volume has changed!\n", 0);
3370                 return 1;
3371             }
3372         } else {
3373             PrintError("Unable to get status of current cloned RO transaction\n",
3374                        code);
3375             return 1;
3376         }
3377     } else {
3378         if (memcmp(&new_status, astat, sizeof(new_status)) != 0) {
3379             /* sanity check */
3380             PrintError("Internal error: current GetStatus does not match "
3381                        "original GetStatus?\n", 0);
3382             return 1;
3383         }
3384     }
3385
3386     return 0;
3387 }
3388
3389 static void
3390 PutTrans(afs_int32 *vldbindex, struct replica *replicas,
3391          struct rx_connection **toconns, struct release *times,
3392          afs_int32 volcount)
3393 {
3394     afs_int32 s, code = 0, rcode = 0;
3395     /* End the transactions and destroy the connections */
3396     for (s = 0; s < volcount; s++) {
3397         if (replicas[s].trans) {
3398             code = AFSVolEndTrans(toconns[s], replicas[s].trans, &rcode);
3399
3400             replicas[s].trans = 0;
3401             if (!code)
3402                 code = rcode;
3403             if (code) {
3404                 if ((s == 0) || (code != ENOENT)) {
3405                     PrintError("Could not end transaction on a ro volume: ",
3406                                code);
3407                 } else {
3408                     PrintError
3409                         ("Transaction timed out on a ro volume. Will retry.\n",
3410                          0);
3411                     if (times[s].vldbEntryIndex < *vldbindex)
3412                         *vldbindex = times[s].vldbEntryIndex;
3413                 }
3414             }
3415         }
3416         if (toconns[s])
3417             rx_DestroyConnection(toconns[s]);
3418         toconns[s] = 0;
3419     }
3420 }
3421
3422 static int
3423 DoVolOnline(struct nvldbentry *vldbEntryPtr, afs_uint32 avolid, int index,
3424             char *vname, struct rx_connection *connPtr)
3425 {
3426     afs_int32 code = 0, rcode = 0, onlinetid = 0;
3427
3428     code =
3429         AFSVolTransCreate_retry(connPtr, avolid,
3430                                 vldbEntryPtr->serverPartition[index],
3431                                 ITOffline,
3432                                 &onlinetid);
3433     if (code)
3434       EPRINT(code, "Could not create transaction on readonly...\n");
3435
3436     else {
3437         code = AFSVolSetFlags(connPtr, onlinetid, 0);
3438         if (code)
3439             EPRINT(code, "Could not set flags on readonly...\n");
3440     }
3441
3442     if (!code) {
3443         code =
3444             AFSVolSetIdsTypes(connPtr, onlinetid, vname,
3445                               ROVOL, vldbEntryPtr->volumeId[RWVOL],
3446                               0, 0);
3447         if (code)
3448             EPRINT(code, "Could not set ids on readonly...\n");
3449     }
3450     if (!code)
3451         code = AFSVolEndTrans(connPtr, onlinetid, &rcode);
3452     if (!code)
3453         code = rcode;
3454     return code;
3455 }
3456
3457 /* UV_ReleaseVolume()
3458  *    Release volume <afromvol> on <afromserver> <afrompart> to all
3459  *    its RO sites (full release). Unless the previous release was
3460  *    incomplete: in which case we bring the remaining incomplete
3461  *    volumes up to date with the volumes that were released
3462  *    successfully.
3463  *    forceflag: Performs a full release.
3464  *
3465  *    Will create a clone from the RW, then dump the clone out to
3466  *    the remaining replicas. If there is more than 1 RO sites,
3467  *    ensure that the VLDB says at least one RO is available all
3468  *    the time: Influences when we write back the VLDB entry.
3469  */
3470
3471 int
3472 UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
3473                  afs_int32 afrompart, int forceflag, int stayUp)
3474 {
3475     char vname[64];
3476     afs_int32 code = 0;
3477     afs_int32 vcode, rcode, tcode;
3478     afs_uint32 cloneVolId = 0, roVolId;
3479     struct replica *replicas = 0;
3480     struct nvldbentry entry, storeEntry;
3481     int i, volcount = 0, m, vldbindex;
3482     int failure;
3483     struct restoreCookie cookie;
3484     struct rx_connection **toconns = 0;
3485     struct release *times = 0;
3486     int nservers = 0;
3487     struct rx_connection *fromconn = (struct rx_connection *)0;
3488     afs_int32 error = 0;
3489     int islocked = 0;
3490     afs_int32 clonetid = 0, onlinetid;
3491     afs_int32 fromtid = 0;
3492     afs_uint32 fromdate = 0;
3493     afs_uint32 thisdate;
3494     time_t tmv;
3495     int s;
3496     manyDests tr;
3497     manyResults results;
3498     int rwindex, roindex, roclone, roexists;
3499     afs_uint32 rwcrdate = 0, rwupdate = 0;
3500     afs_uint32 clcrdate;
3501     struct rtime {
3502         int validtime;
3503         afs_uint32 uptime;
3504     } remembertime[NMAXNSERVERS];
3505     int releasecount = 0;
3506     struct volser_status volstatus;
3507     char hoststr[16];
3508     afs_int32 origflags[NMAXNSERVERS];
3509     struct volser_status orig_status;
3510     int notreleased = 0;
3511     int tried_justnewsites = 0;
3512     int justnewsites = 0; /* are we just trying to release to new RO sites? */
3513     int sites = 0; /* number of ro sites */
3514     int new_sites = 0; /* number of ro sites markes as new */
3515
3516     typedef enum {
3517         CR_RECOVER    = 0x0000, /**< not complete: a recovery from a previous failed release */
3518         CR_FORCED     = 0x0001, /**< complete: forced by caller */
3519         CR_LAST_OK    = 0x0002, /**< complete: no sites have been marked as new release */
3520         CR_ALL_NEW    = 0x0004, /**< complete: all sites have been marked as new release */
3521         CR_NEW_RW     = 0x0008, /**< complete: read-write has changed */
3522         CR_RO_MISSING = 0x0010, /**< complete: ro clone is missing */
3523     } complete_release_t;
3524
3525     complete_release_t complete_release = CR_RECOVER;
3526
3527     memset(remembertime, 0, sizeof(remembertime));
3528     memset(&results, 0, sizeof(results));
3529     memset(origflags, 0, sizeof(origflags));
3530
3531     vcode = ubik_VL_SetLock(cstruct, 0, afromvol, RWVOL, VLOP_RELEASE);
3532     if (vcode != VL_RERELEASE)
3533         ONERROR(vcode, afromvol,
3534                 "Could not lock the VLDB entry for the volume %u.\n");
3535     islocked = 1;
3536
3537     /* Get the vldb entry in readable format */
3538     vcode = VLDB_GetEntryByID(afromvol, RWVOL, &entry);
3539     ONERROR(vcode, afromvol,
3540             "Could not fetch the entry for the volume %u from the VLDB.\n");
3541     MapHostToNetwork(&entry);
3542
3543     if (verbose)
3544         EnumerateEntry(&entry);
3545
3546     if (!ISNAMEVALID(entry.name))
3547         ONERROR(VOLSERBADOP, entry.name,
3548                 "Volume name %s is too long, rename before releasing.\n");
3549     if (entry.volumeId[RWVOL] != afromvol)
3550         ONERROR(VOLSERBADOP, afromvol,
3551                 "The volume %u being released is not a read-write volume.\n");
3552     if (entry.nServers <= 1)
3553         ONERROR(VOLSERBADOP, afromvol,
3554                 "Volume %u has no replicas - release operation is meaningless!\n");
3555     if (strlen(entry.name) > (VOLSER_OLDMAXVOLNAME - 10))
3556         ONERROR(VOLSERBADOP, entry.name,
3557                 "RO volume name %s exceeds (VOLSER_OLDMAXVOLNAME - 10) character limit\n");
3558
3559     /* roclone is true if one of the RO volumes is on the same
3560      * partition as the RW volume. In this case, we make the RO volume
3561      * on the same partition a clone instead of a complete copy.
3562      */
3563
3564     roindex = Lp_ROMatch(afromserver, afrompart, &entry) - 1;
3565     roclone = ((roindex == -1) ? 0 : 1);
3566     rwindex = Lp_GetRwIndex(&entry);
3567     if (rwindex < 0)
3568         ONERROR0(VOLSERNOVOL, "There is no RW volume \n");
3569
3570     /* Make sure we have a RO volume id to work with */
3571     if (entry.volumeId[ROVOL] == INVALID_BID) {
3572         /* need to get a new RO volume id */
3573         vcode = ubik_VL_GetNewVolumeId(cstruct, 0, 1, &roVolId);
3574         ONERROR(vcode, entry.name, "Cant allocate ID for RO volume of %s\n");
3575
3576         entry.volumeId[ROVOL] = roVolId;
3577         MapNetworkToHost(&entry, &storeEntry);
3578         vcode = VLDB_ReplaceEntry(afromvol, RWVOL, &storeEntry, 0);
3579         ONERROR(vcode, entry.name, "Could not update vldb entry for %s.\n");
3580     }
3581
3582     /*
3583      * Determine if this is to be a complete release or a recovery of a
3584      * previous unfinished release. The previous release is considered to be
3585      * unfinished when the clone was successfully distributed to at least one
3586      * (but not all) of the read-only sites, as indicated by the NEW_REPSITE
3587      * vldb flags.
3588      *
3589      * The caller can override the vldb flags check using the -force
3590      * flag, to force this to be a complete release.
3591      */
3592     for (i = 0; i < entry.nServers; i++) {
3593         if (entry.serverFlags[i] & ITSROVOL) {
3594             sites++;
3595             if (entry.serverFlags[i] & NEW_REPSITE)
3596                 new_sites++;
3597             if (entry.serverFlags[i] & RO_DONTUSE)
3598                 notreleased++;
3599         }
3600         origflags[i] = entry.serverFlags[i];
3601     }
3602
3603     if (forceflag) {
3604         complete_release |= CR_FORCED;
3605     }
3606
3607     if (new_sites == 0) {
3608         complete_release |= CR_LAST_OK;
3609     } else if (new_sites == sites) {
3610         complete_release |= CR_ALL_NEW;
3611     }
3612
3613     if ((complete_release & (CR_LAST_OK | CR_ALL_NEW))
3614         && !(complete_release & CR_FORCED)) {
3615         if (notreleased && notreleased != sites) {
3616             /* we have some new unreleased sites. try to just release to those,
3617              * if the RW has not changed. The caller can override with -force. */
3618             justnewsites = 1;
3619         }
3620     }
3621
3622     /* Determine which volume id to use and see if it exists */
3623     cloneVolId = (complete_release || entry.cloneId == 0)
3624                   ? entry.volumeId[ROVOL] : entry.cloneId;
3625
3626     code = VolumeExists(afromserver, afrompart, cloneVolId);
3627     roexists = ((code == ENODEV) ? 0 : 1);
3628
3629     /* For stayUp case, if roclone is the only site, bypass special handling */
3630     if (stayUp && roclone) {
3631         int e;
3632         error = 0;
3633
3634         for (e = 0; (e < entry.nServers) && !error; e++) {
3635             if ((entry.serverFlags[e] & ITSROVOL)) {
3636                 if (!(VLDB_IsSameAddrs(entry.serverNumber[e], afromserver,
3637                                        &error)))
3638                     break;
3639             }
3640         }
3641         if (e >= entry.nServers)
3642             stayUp = 0;
3643     }
3644
3645     /* If we had a previous release to complete, do so, else: */
3646     if (stayUp && (cloneVolId == entry.volumeId[ROVOL])) {
3647         code = ubik_VL_GetNewVolumeId(cstruct, 0, 1, &cloneVolId);
3648         ONERROR(code, afromvol,
3649                 "Cannot get temporary clone id for volume %u\n");
3650     }
3651
3652     fromconn = UV_Bind(afromserver, AFSCONF_VOLUMEPORT);
3653     if (!fromconn)
3654         ONERROR(-1, afromserver,
3655                 "Cannot establish connection with server 0x%x\n");
3656
3657     if (!complete_release) {
3658         if (!roexists) {
3659             complete_release |= CR_RO_MISSING;  /* Do a complete release if RO clone does not exist */
3660         } else {
3661             /* Begin transaction on RW and mark it busy while we query it */
3662             code = AFSVolTransCreate_retry(
3663                         fromconn, afromvol, afrompart, ITBusy, &fromtid
3664                    );
3665             ONERROR(code, afromvol,
3666                     "Failed to start transaction on RW volume %u\n");
3667
3668             /* Query the creation date for the RW */
3669             code = AFSVolGetStatus(fromconn, fromtid, &volstatus);
3670             ONERROR(code, afromvol,
3671                     "Failed to get the status of RW volume %u\n");
3672             rwcrdate = volstatus.creationDate;
3673
3674             /* End transaction on RW */
3675             code = AFSVolEndTrans(fromconn, fromtid, &rcode);
3676             fromtid = 0;
3677             ONERROR((code ? code : rcode), afromvol,
3678                     "Failed to end transaction on RW volume %u\n");
3679
3680             /* Begin transaction on clone and mark it busy while we query it */
3681             code = AFSVolTransCreate_retry(
3682                         fromconn, cloneVolId, afrompart, ITBusy, &clonetid
3683                    );
3684             ONERROR(code, cloneVolId,
3685                     "Failed to start transaction on RW clone %u\n");
3686
3687             /* Query the creation date for the clone */
3688             code = AFSVolGetStatus(fromconn, clonetid, &volstatus);
3689             ONERROR(code, cloneVolId,
3690                     "Failed to get the status of RW clone %u\n");
3691             clcrdate = volstatus.creationDate;
3692
3693             /* End transaction on clone */
3694             code = AFSVolEndTrans(fromconn, clonetid, &rcode);
3695             clonetid = 0;
3696             ONERROR((code ? code : rcode), cloneVolId,
3697                     "Failed to end transaction on RW clone %u\n");
3698
3699             if (rwcrdate > clcrdate)
3700                 complete_release |= CR_NEW_RW; /* Do a complete release if RO clone older than RW */
3701         }
3702     }
3703
3704     if (!complete_release || (complete_release & CR_NEW_RW)) {
3705         /* in case the RW has changed, and just to be safe */
3706         justnewsites = 0;
3707     }
3708
3709     if (verbose) {
3710         if (!complete_release) {
3711             fprintf(STDOUT,
3712                     "This is a recovery of previously failed release\n");
3713         } else {
3714             fprintf(STDOUT, "This is a complete release of volume %u", afromvol);
3715             /* Give the reasons for a complete release, except if only CR_LAST_OK. */
3716             if (complete_release != CR_LAST_OK) {
3717                 char *sep = " (";
3718                 if (complete_release & CR_FORCED) {
3719                     fprintf(STDOUT, "%sforced", sep);
3720                     sep = ", ";
3721                 }
3722                 if (complete_release & CR_LAST_OK) {
3723                     fprintf(STDOUT, "%slast ok", sep);
3724                     sep = ", ";
3725                 }
3726                 if (complete_release & CR_ALL_NEW) {
3727                     fprintf(STDOUT, "%sall sites are new", sep);
3728                     sep = ", ";
3729                 }
3730                 if (complete_release & CR_NEW_RW) {
3731                     fprintf(STDOUT, "%srw %u changed", sep, afromvol);
3732                     sep = ", ";
3733                 }
3734                 if (complete_release & CR_RO_MISSING) {
3735                     fprintf(STDOUT, "%sro clone missing", sep);
3736                 }
3737                 fprintf(STDOUT, ")");
3738             }
3739             fprintf(STDOUT, "\n");
3740             if (justnewsites) {
3741                 tried_justnewsites = 1;
3742                 fprintf(STDOUT, "There are new RO sites; we will try to "
3743                         "only release to new sites\n");
3744             }
3745         }
3746     }
3747
3748     if (complete_release) {
3749         afs_int32 oldest = 0;
3750         /* If the RO clone exists, then if the clone is a temporary
3751          * clone, delete it. Or if the RO clone is marked RO_DONTUSE
3752          * (it was recently added), then also delete it. We do not
3753          * want to "reclone" a temporary RO clone.
3754          */
3755         if (stayUp) {
3756             code = VolumeExists(afromserver, afrompart, cloneVolId);
3757             if (!code) {
3758                 code = DoVolDelete(fromconn, cloneVolId, afrompart, "previous clone", 0,
3759                                    NULL, NULL);
3760                 if (code && (code != VNOVOL))
3761                     ERROREXIT(code);
3762                 VDONE;
3763             }
3764         }
3765         /* clean up any previous tmp clone before starting if staying up */
3766         if (roexists
3767             && (!roclone || (entry.serverFlags[roindex] & RO_DONTUSE))) {
3768             code = DoVolDelete(fromconn,
3769                                stayUp ? entry.volumeId[ROVOL] : cloneVolId,
3770                                afrompart, "the", 0, NULL, NULL);
3771             if (code && (code != VNOVOL))
3772                 ERROREXIT(code);
3773             roexists = 0;
3774         }
3775
3776         if (justnewsites) {
3777             VPRINT("Querying old RO sites for update times...");
3778             for (vldbindex = 0; vldbindex < entry.nServers; vldbindex++) {
3779                 volEntries volumeInfo;
3780                 struct rx_connection *conn;
3781                 afs_int32 crdate;
3782
3783                 if (!(entry.serverFlags[vldbindex] & ITSROVOL)) {
3784                     continue;
3785                 }
3786                 if ((entry.serverFlags[vldbindex] & RO_DONTUSE)) {
3787                     continue;
3788                 }
3789                 conn = UV_Bind(entry.serverNumber[vldbindex], AFSCONF_VOLUMEPORT);
3790                 if (!conn) {
3791                     fprintf(STDERR, "Cannot establish connection to server %s\n",
3792                                     hostutil_GetNameByINet(entry.serverNumber[vldbindex]));
3793                     justnewsites = 0;
3794                     break;
3795                 }
3796                 volumeInfo.volEntries_val = NULL;
3797                 volumeInfo.volEntries_len = 0;
3798                 code = AFSVolListOneVolume(conn, entry.serverPartition[vldbindex],
3799                                            entry.volumeId[ROVOL],
3800                                            &volumeInfo);
3801                 if (code) {
3802                     fprintf(STDERR, "Could not fetch information about RO vol %lu from server %s\n",
3803                                     (unsigned long)entry.volumeId[ROVOL],
3804                                     hostutil_GetNameByINet(entry.serverNumber[vldbindex]));
3805                     PrintError("", code);
3806                     justnewsites = 0;
3807                     rx_DestroyConnection(conn);
3808                     break;
3809                 }
3810
3811                 crdate = CLOCKADJ(volumeInfo.volEntries_val[0].creationDate);
3812
3813                 if (oldest == 0 || crdate < oldest) {
3814                     oldest = crdate;
3815                 }
3816
3817                 rx_DestroyConnection(conn);
3818                 free(volumeInfo.volEntries_val);
3819                 volumeInfo.volEntries_val = NULL;
3820                 volumeInfo.volEntries_len = 0;
3821             }
3822             VDONE;
3823         }
3824         if (justnewsites) {
3825             volEntries volumeInfo;
3826             volumeInfo.volEntries_val = NULL;
3827             volumeInfo.volEntries_len = 0;
3828             code = AFSVolListOneVolume(fromconn, afrompart, afromvol,
3829                                        &volumeInfo);
3830             if (code) {
3831                 fprintf(STDERR, "Could not fetch information about RW vol %lu from server %s\n",
3832                                 (unsigned long)afromvol,
3833                                 hostutil_GetNameByINet(afromserver));
3834                 PrintError("", code);
3835                 justnewsites = 0;
3836             } else {
3837                 rwupdate = volumeInfo.volEntries_val[0].updateDate;
3838
3839                 free(volumeInfo.volEntries_val);
3840                 volumeInfo.volEntries_val = NULL;
3841                 volumeInfo.volEntries_len = 0;
3842             }
3843         }
3844         if (justnewsites && oldest <= rwupdate) {
3845             /* RW has changed */
3846             justnewsites = 0;
3847         }
3848
3849         /* Mark all the ROs in the VLDB entry as RO_DONTUSE. We don't
3850          * write this entry out to the vlserver until after the first
3851          * RO volume is released (temp RO clones don't count).
3852          *
3853          * If 'justnewsites' is set, we're only updating sites that have
3854          * RO_DONTUSE set, so set NEW_REPSITE for all of the others.
3855          */
3856         for (i = 0; i < entry.nServers; i++) {
3857             if (justnewsites) {
3858                 if ((entry.serverFlags[i] & RO_DONTUSE)) {
3859                     entry.serverFlags[i] &= ~NEW_REPSITE;
3860                 } else {
3861                     entry.serverFlags[i] |= NEW_REPSITE;
3862                 }
3863             } else {
3864                 entry.serverFlags[i] &= ~NEW_REPSITE;
3865                 entry.serverFlags[i] |= RO_DONTUSE;
3866             }
3867         }
3868         entry.serverFlags[rwindex] |= NEW_REPSITE;
3869         entry.serverFlags[rwindex] &= ~RO_DONTUSE;
3870     }
3871
3872     if (justnewsites && roexists) {
3873         /* if 'justnewsites' and 'roexists' are set, we don't need to do
3874          * anything with the RO clone, so skip the reclone */
3875         /* noop */
3876
3877     } else if (complete_release) {
3878
3879         if (roclone) {
3880             strcpy(vname, entry.name);
3881             if (stayUp)
3882                 strcat(vname, ".roclone");
3883             else
3884                 strcat(vname, ".readonly");
3885         } else {
3886             strcpy(vname, "readonly-clone-temp");
3887         }
3888
3889         code = DoVolClone(fromconn, afromvol, afrompart, readonlyVolume,
3890                           cloneVolId, (roclone && !stayUp)?"permanent RO":
3891                           "temporary RO", NULL, vname, NULL, &volstatus, NULL);
3892         if (code) {
3893             error = code;
3894             goto rfail;
3895         }
3896
3897         if (justnewsites && rwupdate != volstatus.updateDate) {
3898             justnewsites = 0;
3899             /* reset the serverFlags as if 'justnewsites' had never been set */
3900             for (i = 0; i < entry.nServers; i++) {
3901                 entry.serverFlags[i] &= ~NEW_REPSITE;
3902                 entry.serverFlags[i] |= RO_DONTUSE;
3903             }
3904             entry.serverFlags[rwindex] |= NEW_REPSITE;
3905             entry.serverFlags[rwindex] &= ~RO_DONTUSE;
3906         }
3907
3908         rwcrdate = volstatus.creationDate;
3909
3910         /* Remember clone volume ID in case we fail or are interrupted */
3911         entry.cloneId = cloneVolId;
3912
3913         if (roclone && !stayUp) {
3914             /* Bring the RO clone online - though not if it's a temporary clone */
3915             VPRINT1("Starting transaction on RO clone volume %u...",
3916                     cloneVolId);
3917             code =
3918                 AFSVolTransCreate_retry(fromconn, cloneVolId, afrompart, ITOffline,
3919                                   &onlinetid);
3920             ONERROR(code, cloneVolId,
3921                     "Failed to start transaction on volume %u\n");
3922             VDONE;
3923
3924             VPRINT1("Setting volume flags for volume %u...", cloneVolId);
3925             tcode = AFSVolSetFlags(fromconn, onlinetid, 0);
3926             VDONE;
3927
3928             VPRINT1("Ending transaction on volume %u...", cloneVolId);
3929             code = AFSVolEndTrans(fromconn, onlinetid, &rcode);
3930             ONERROR((code ? code : rcode), cloneVolId,
3931                     "Failed to end transaction on RO clone %u\n");
3932             VDONE;
3933
3934             ONERROR(tcode, cloneVolId, "Could not bring volume %u on line\n");
3935
3936             /* Sleep so that a client searching for an online volume won't
3937              * find the clone offline and then the next RO offline while the
3938              * release brings the clone online and the next RO offline (race).
3939              * There is a fix in the 3.4 client that does not need this sleep
3940              * anymore, but we don't know what clients we have.
3941              */
3942             if (entry.nServers > 2 && !justnewsites)
3943                 sleep(5);
3944
3945             /* Mark the RO clone in the VLDB as a good site (already released) */
3946             entry.serverFlags[roindex] |= NEW_REPSITE;
3947             entry.serverFlags[roindex] &= ~RO_DONTUSE;
3948             entry.flags |= RO_EXISTS;
3949
3950             releasecount++;
3951
3952             /* Write out the VLDB entry only if the clone is not a temporary
3953              * clone. If we did this to a temporary clone then we would end
3954              * up marking all the ROs as "old release" making the ROs
3955              * temporarily unavailable.
3956              */
3957             MapNetworkToHost(&entry, &storeEntry);
3958             VPRINT1("Replacing VLDB entry for %s...", entry.name);
3959             vcode = VLDB_ReplaceEntry(afromvol, RWVOL, &storeEntry, 0);
3960             ONERROR(vcode, entry.name,
3961                     "Could not update vldb entry for %s.\n");
3962             VDONE;
3963         }
3964     }
3965
3966     if (justnewsites) {
3967         VPRINT("RW vol has not changed; only releasing to new RO sites\n");
3968         /* act like this is a completion of a previous release */
3969         complete_release = CR_RECOVER;
3970     } else if (tried_justnewsites) {
3971         VPRINT("RW vol has changed; releasing to all sites\n");
3972     }
3973
3974     /* Now we will release from the clone to the remaining RO replicas.
3975      * The first 2 ROs (counting the non-temporary RO clone) are released
3976      * individually: releasecount. This is to reduce the race condition
3977      * of clients trying to find an on-line RO volume. The remaining ROs
3978      * are released in parallel but no more than half the number of ROs
3979      * (rounded up) at a time: nservers.
3980      */
3981
3982     strcpy(vname, entry.name);
3983     if (stayUp)
3984         strcat(vname, ".roclone");
3985     else
3986         strcat(vname, ".readonly");
3987     memset(&cookie, 0, sizeof(cookie));
3988     strncpy(cookie.name, vname, VOLSER_OLDMAXVOLNAME);
3989     cookie.type = ROVOL;
3990     cookie.parent = entry.volumeId[RWVOL];
3991     cookie.clone = 0;
3992
3993     /* how many to do at once, excluding clone */
3994     if (stayUp || justnewsites)
3995         nservers = entry.nServers; /* can do all, none offline */
3996     else
3997         nservers = entry.nServers / 2;
3998     replicas = calloc(nservers + 1, sizeof(struct replica));
3999     times = calloc(nservers + 1, sizeof(struct release));
4000     toconns = calloc(nservers + 1, sizeof(struct rx_connection *));
4001     results.manyResults_val = calloc(nservers + 1, sizeof(afs_int32));
4002     if (!replicas || !times || !results.manyResults_val || !toconns)
4003         ONERROR0(ENOMEM,
4004                 "Failed to create transaction on the release clone\n");
4005
4006     /* Create a transaction on the cloned volume */
4007     VPRINT1("Starting transaction on cloned volume %u...", cloneVolId);
4008     code =
4009         AFSVolTransCreate_retry(fromconn, cloneVolId, afrompart, ITBusy, &fromtid);
4010     if (!code) {
4011         memset(&orig_status, 0, sizeof(orig_status));
4012         code = AFSVolGetStatus(fromconn, fromtid, &orig_status);
4013     }
4014     if (!complete_release && code)
4015         ONERROR(VOLSERNOVOL, afromvol,
4016                 "Old clone is inaccessible. Try vos release -f %u.\n");
4017     ONERROR0(code, "Failed to create transaction on the release clone\n");
4018     VDONE;
4019
4020     /* if we have a clone, treat this as done, for now */
4021     if (stayUp && !complete_release) {
4022         entry.serverFlags[roindex] |= NEW_REPSITE;
4023         entry.serverFlags[roindex] &= ~RO_DONTUSE;
4024         entry.flags |= RO_EXISTS;
4025
4026         releasecount++;
4027     }
4028
4029     /* For each index in the VLDB */
4030     for (vldbindex = 0; vldbindex < entry.nServers;) {
4031         /* Get a transaction on the replicas. Pick replicas which have an old release. */
4032         for (volcount = 0;
4033              ((volcount < nservers) && (vldbindex < entry.nServers));
4034              vldbindex++) {
4035             if (!stayUp && !justnewsites) {
4036                 /* The first two RO volumes will be released individually.
4037                  * The rest are then released in parallel. This is a hack
4038                  * for clients not recognizing right away when a RO volume
4039                  * comes back on-line.
4040                  */
4041                 if ((volcount == 1) && (releasecount < 2))
4042                     break;
4043             }
4044
4045             if (vldbindex == roindex)
4046                 continue;       /* the clone    */
4047             if ((entry.serverFlags[vldbindex] & NEW_REPSITE)
4048                 && !(entry.serverFlags[vldbindex] & RO_DONTUSE))
4049                 continue;
4050             if (!(entry.serverFlags[vldbindex] & ITSROVOL))
4051                 continue;       /* not a RO vol */
4052
4053
4054             /* Get a Transaction on this replica. Get a new connection if
4055              * necessary.  Create the volume if necessary.  Return the
4056              * time from which the dump should be made (0 if it's a new
4057              * volume).  Each volume might have a different time.
4058              */
4059             replicas[volcount].server.destHost =
4060                 ntohl(entry.serverNumber[vldbindex]);
4061             replicas[volcount].server.destPort = AFSCONF_VOLUMEPORT;
4062             replicas[volcount].server.destSSID = 1;
4063             times[volcount].vldbEntryIndex = vldbindex;
4064
4065             code =
4066                 GetTrans(&entry, vldbindex, &(toconns[volcount]),
4067                          &(replicas[volcount].trans),
4068                          &(times[volcount].crtime),
4069                          &(times[volcount].uptime),
4070                          origflags, stayUp?cloneVolId:0);
4071             if (code)
4072                 continue;
4073
4074             /* Thisdate is the date from which we want to pick up all changes */
4075             if (forceflag) {
4076                 /* Do a full dump when forced by the caller. */
4077                 VPRINT("This will be a full dump: forced\n");
4078                 thisdate = 0;
4079             } else if (!complete_release) {
4080                 /* If this release is a recovery of a failed release, we can't be
4081                  * sure the creation date is good, so do a full dump.
4082                  */
4083                 VPRINT("This will be a full dump: previous release failed\n");
4084                 thisdate = 0;
4085             } else if (times[volcount].crtime == 0) {
4086                 /* A full dump is needed for a new read-only volume. */
4087                 VPRINT
4088                     ("This will be a full dump: read-only volume needs to be created\n");
4089                 thisdate = 0;
4090             } else if ((rwcrdate > times[volcount].crtime)) {
4091                 /* If the RW volume was replaced (its creation date is newer than
4092                  * the last release), then we can't be sure what has changed (so
4093                  * we do a full dump).
4094                  */
4095                 VPRINT
4096                     ("This will be a full dump: read-write volume was replaced\n");
4097                 thisdate = 0;
4098             } else if (remembertime[vldbindex].validtime) {
4099                 /* Trans was prev ended. Use the time from the prev trans
4100                  * because, prev trans may have created the volume. In which
4101                  * case time[volcount].time would be now instead of 0.
4102                  */
4103                 thisdate =
4104                     (remembertime[vldbindex].uptime < times[volcount].uptime)
4105                         ? remembertime[vldbindex].uptime
4106                         : times[volcount].uptime;
4107             } else {
4108                 thisdate = times[volcount].uptime;
4109             }
4110             remembertime[vldbindex].validtime = 1;
4111             remembertime[vldbindex].uptime = thisdate;
4112
4113             if (volcount == 0) {
4114                 fromdate = thisdate;
4115             } else {
4116                 /* Include this volume if it is within 15 minutes of the earliest */
4117                 if (((fromdate >
4118                       thisdate) ? (fromdate - thisdate) : (thisdate -
4119                                                            fromdate)) > 900) {
4120                     AFSVolEndTrans(toconns[volcount],
4121                                    replicas[volcount].trans, &rcode);
4122                     replicas[volcount].trans = 0;
4123                     break;
4124                 }
4125                 if (thisdate < fromdate)
4126                     fromdate = thisdate;
4127             }
4128             volcount++;
4129         }
4130         if (!volcount)
4131             continue;
4132
4133         code = CheckTrans(fromconn, &fromtid, afrompart, &orig_status);
4134         if (code) {
4135             code = ENOENT;
4136             goto rfail;
4137         }
4138
4139         if (verbose) {
4140             fprintf(STDOUT, "Starting ForwardMulti from %lu to %u on %s",
4141                     (unsigned long)cloneVolId, stayUp?
4142                     cloneVolId:entry.volumeId[ROVOL],
4143                     noresolve ? afs_inet_ntoa_r(entry.serverNumber[times[0].
4144                                                 vldbEntryIndex], hoststr) :
4145                     hostutil_GetNameByINet(entry.
4146                                            serverNumber[times[0].
4147                                                         vldbEntryIndex]));
4148
4149             for (s = 1; s < volcount; s++) {
4150                 fprintf(STDOUT, " and %s",
4151                         noresolve ? afs_inet_ntoa_r(entry.serverNumber[times[s].
4152                                                     vldbEntryIndex], hoststr) :
4153                         hostutil_GetNameByINet(entry.
4154                                                serverNumber[times[s].
4155                                                             vldbEntryIndex]));
4156             }
4157
4158             if (fromdate == 0)
4159                 fprintf(STDOUT, " (entire volume)");
4160             else {
4161                 tmv = fromdate;
4162                 fprintf(STDOUT, " (as of %.24s)", ctime(&tmv));
4163             }
4164             fprintf(STDOUT, ".\n");
4165             fflush(STDOUT);
4166         }
4167
4168         /* Release the ones we have collected */
4169         tr.manyDests_val = &(replicas[0]);
4170         tr.manyDests_len = results.manyResults_len = volcount;
4171         code =
4172             AFSVolForwardMultiple(fromconn, fromtid, fromdate, &tr,
4173                                   0 /*spare */ , &cookie, &results);
4174         if (code == RXGEN_OPCODE) {     /* RPC Interface Mismatch */
4175             code =
4176                 SimulateForwardMultiple(fromconn, fromtid, fromdate, &tr,
4177                                         0 /*spare */ , &cookie, &results);
4178             nservers = 1;
4179         }
4180
4181         if (code) {
4182             PrintError("Release failed: ", code);
4183         } else {
4184             for (m = 0; m < volcount; m++) {
4185                 if (results.manyResults_val[m]) {
4186                     if ((m == 0) || (results.manyResults_val[m] != ENOENT)) {
4187                         /* we retry timed out transaction. When it is
4188                          * not the first volume and the transaction wasn't found
4189                          * (assume it timed out and was garbage collected by volser).
4190                          */
4191                         PrintError
4192                             ("Failed to dump volume from clone to a ro site: ",
4193                              results.manyResults_val[m]);
4194                     }
4195                     continue;
4196                 }
4197
4198                 code =
4199                     AFSVolSetIdsTypes(toconns[m], replicas[m].trans, vname,
4200                                       ROVOL, entry.volumeId[RWVOL], 0, 0);
4201                 if (code) {
4202                     if ((m == 0) || (code != ENOENT)) {
4203                         PrintError("Failed to set correct names and ids: ",
4204                                    code);
4205                     }
4206                     continue;
4207                 }
4208
4209                 /* have to clear dest. flags to ensure new vol goes online:
4210                  * because the restore (forwarded) operation copied
4211                  * the V_inService(=0) flag over to the destination.
4212                  */
4213                 code = AFSVolSetFlags(toconns[m], replicas[m].trans, 0);
4214                 if (code) {
4215                     if ((m == 0) || (code != ENOENT)) {
4216                         PrintError("Failed to set flags on ro volume: ",
4217                                    code);
4218                     }
4219                     continue;
4220                 }
4221
4222                 entry.serverFlags[times[m].vldbEntryIndex] |= NEW_REPSITE;
4223                 entry.serverFlags[times[m].vldbEntryIndex] &= ~RO_DONTUSE;
4224                 entry.flags |= RO_EXISTS;
4225                 releasecount++;
4226             }
4227         }
4228
4229         if (!stayUp) {
4230             PutTrans(&vldbindex, replicas, toconns, times, volcount);
4231             MapNetworkToHost(&entry, &storeEntry);
4232             vcode = VLDB_ReplaceEntry(afromvol, RWVOL, &storeEntry, 0);
4233             ONERROR(vcode, afromvol,
4234                     " Could not update VLDB entry for volume %u\n");
4235         }
4236     }                           /* for each index in the vldb */
4237
4238     /* for the stayup case, put back at the end */
4239     if (stayUp) {
4240         afs_uint32 tmpVol = entry.volumeId[ROVOL];
4241         strcpy(vname, entry.name);
4242         strcat(vname, ".readonly");
4243
4244         if (roclone) {
4245             /* have to clear flags to ensure new vol goes online
4246              */
4247             code = AFSVolSetFlags(fromconn, fromtid, 0);
4248             if (code && (code != ENOENT)) {
4249                 PrintError("Failed to set flags on ro volume: ",
4250                            code);
4251             }
4252
4253             VPRINT3("%sloning to permanent RO %u on %s...", roexists?"Re-c":"C", tmpVol,
4254                     noresolve ?
4255                     afs_inet_ntoa_r(entry.serverNumber[roindex],
4256                                     hoststr) :
4257                     hostutil_GetNameByINet(entry.serverNumber[roindex]));
4258
4259             code = AFSVolClone(fromconn, fromtid, roexists?tmpVol:0,
4260                                readonlyVolume, vname, &tmpVol);
4261
4262             if (!code) {
4263                 VDONE;
4264                 VPRINT("Bringing readonly online...");
4265                 code = DoVolOnline(&entry, tmpVol, roindex, vname,
4266                                    fromconn);
4267             }
4268             if (code) {
4269                 EPRINT(code, "Failed: ");
4270                 entry.serverFlags[roindex] &= ~NEW_REPSITE;
4271                 entry.serverFlags[roindex] |= RO_DONTUSE;
4272             } else {
4273                 entry.serverFlags[roindex] |= NEW_REPSITE;
4274                 entry.serverFlags[roindex] &= ~RO_DONTUSE;
4275                 entry.flags |= RO_EXISTS;
4276                 VDONE;
4277             }
4278
4279         }
4280         for (s = 0; s < volcount; s++) {
4281             if (replicas[s].trans) {
4282                 vldbindex = times[s].vldbEntryIndex;
4283
4284                 /* ok, so now we have to end the previous transaction */
4285                 code = AFSVolEndTrans(toconns[s], replicas[s].trans, &rcode);
4286                 if (!code)
4287                     code = rcode;
4288
4289                 if (!code) {
4290                     code = AFSVolTransCreate_retry(toconns[s],
4291                                                    cloneVolId,
4292                                                    entry.serverPartition[vldbindex],
4293                                                    ITBusy,
4294                                                    &(replicas[s].trans));
4295                     if (code) {
4296                         PrintError("Unable to begin transaction on temporary clone: ", code);
4297                     }
4298                 } else {
4299                     PrintError("Unable to end transaction on temporary clone: ", code);
4300                 }
4301
4302                 VPRINT3("%sloning to permanent RO %u on %s...", times[s].crtime?"Re-c":"C",
4303                         tmpVol, noresolve ?
4304                         afs_inet_ntoa_r(htonl(replicas[s].server.destHost),
4305                                         hoststr) :
4306                         hostutil_GetNameByINet(htonl(replicas[s].server.destHost)));
4307                 if (times[s].crtime)
4308                     code = AFSVolClone(toconns[s], replicas[s].trans, tmpVol,
4309                                        readonlyVolume, vname, &tmpVol);
4310                 else
4311                     code = AFSVolClone(toconns[s], replicas[s].trans, 0,
4312                                        readonlyVolume, vname, &tmpVol);
4313
4314                 if (code) {
4315                     if (!times[s].crtime) {
4316                         entry.serverFlags[vldbindex] |= RO_DONTUSE;
4317                     }
4318                     entry.serverFlags[vldbindex] &= ~NEW_REPSITE;
4319                     PrintError("Failed: ",
4320                                code);
4321                 } else
4322                     VDONE;
4323
4324                 if (entry.serverFlags[vldbindex] != RO_DONTUSE) {
4325                     /* bring it online (mark it InService) */
4326                     VPRINT1("Bringing readonly online on %s...",
4327                             noresolve ?
4328                             afs_inet_ntoa_r(
4329                                 htonl(replicas[s].server.destHost),
4330                                 hoststr) :
4331                             hostutil_GetNameByINet(
4332                                 htonl(replicas[s].server.destHost)));
4333
4334                     code = DoVolOnline(&entry, tmpVol, vldbindex, vname,
4335                                        toconns[s]);
4336                     /* needed to come online for cloning */
4337                     if (code) {
4338                         /* technically it's still new, just not online */
4339                         entry.serverFlags[s] &= ~NEW_REPSITE;
4340                         entry.serverFlags[s] |= RO_DONTUSE;
4341                         if (code != ENOENT) {
4342                             PrintError("Failed to set correct names and ids: ",
4343                                        code);
4344                         }
4345                     } else
4346                         VDONE;
4347                 }
4348
4349                 VPRINT("Marking temporary clone for deletion...\n");
4350                 code = AFSVolSetFlags(toconns[s],
4351                                       replicas[s].trans,
4352                                       VTDeleteOnSalvage |
4353                                       VTOutOfService);
4354                 if (code)
4355                   EPRINT(code, "Failed: ");
4356                 else
4357                   VDONE;
4358
4359                 VPRINT("Ending transaction on temporary clone...\n");
4360                 code = AFSVolEndTrans(toconns[s], replicas[s].trans, &rcode);
4361                 if (!code)
4362                     rcode = code;
4363                 if (code)
4364                     PrintError("Failed: ", code);
4365                 else {
4366                     VDONE;
4367                     /* ended successfully */
4368                     replicas[s].trans = 0;
4369
4370                     VPRINT2("Deleting temporary clone %u on %s...", cloneVolId,
4371                             noresolve ?
4372                             afs_inet_ntoa_r(htonl(replicas[s].server.destHost),
4373                                             hoststr) :
4374                             hostutil_GetNameByINet(htonl(replicas[s].server.destHost)));
4375                     code = DoVolDelete(toconns[s], cloneVolId,
4376                                        entry.serverPartition[vldbindex],
4377                                        NULL, 0, NULL, NULL);
4378                     if (code) {
4379                         EPRINT(code, "Failed: ");
4380                     } else
4381                         VDONE;
4382                 }
4383             }
4384         }
4385
4386         /* done. put the vldb entry in the success tail case*/
4387         PutTrans(&vldbindex, replicas, toconns, times, volcount);
4388     }
4389
4390     /* End the transaction on the cloned volume */
4391     code = AFSVolEndTrans(fromconn, fromtid, &rcode);
4392     fromtid = 0;
4393     if (!code)
4394         code = rcode;
4395     if (code)
4396         PrintError("Failed to end transaction on rw volume: ", code);
4397
4398     /* Figure out if any volume were not released and say so */
4399     for (failure = 0, i = 0; i < entry.nServers; i++) {
4400         if (!(entry.serverFlags[i] & NEW_REPSITE))
4401             failure++;
4402     }
4403     if (failure) {
4404         char pname[10];
4405         fprintf(STDERR,
4406                 "The volume %lu could not be released to the following %d sites:\n",
4407                 (unsigned long)afromvol, failure);
4408         for (i = 0; i < entry.nServers; i++) {
4409             if (!(entry.serverFlags[i] & NEW_REPSITE)) {
4410                 MapPartIdIntoName(entry.serverPartition[i], pname);
4411                 fprintf(STDERR, "\t%35s %s\n",
4412                         noresolve ? afs_inet_ntoa_r(entry.serverNumber[i], hoststr) :
4413                         hostutil_GetNameByINet(entry.serverNumber[i]), pname);
4414             }
4415         }
4416         MapNetworkToHost(&entry, &storeEntry);
4417         vcode =
4418             VLDB_ReplaceEntry(afromvol, RWVOL, &storeEntry,
4419                               LOCKREL_TIMESTAMP);
4420         ONERROR(vcode, afromvol,
4421                 " Could not update VLDB entry for volume %u\n");
4422
4423         ERROREXIT(VOLSERBADRELEASE);
4424     }
4425
4426     entry.cloneId = 0;
4427     /* All the ROs were release successfully. Remove the temporary clone */
4428     if (!roclone || stayUp) {
4429         if (verbose) {
4430             fprintf(STDOUT, "Deleting the releaseClone %lu ...",
4431                     (unsigned long)cloneVolId);
4432             fflush(STDOUT);
4433         }
4434         code = DoVolDelete(fromconn, cloneVolId, afrompart, NULL, 0, NULL,
4435                            NULL);
4436         ONERROR(code, cloneVolId, "Failed to delete volume %u.\n");
4437         VDONE;
4438     }
4439
4440     for (i = 0; i < entry.nServers; i++)
4441         entry.serverFlags[i] &= ~NEW_REPSITE;
4442
4443     /* Update the VLDB */
4444     VPRINT("updating VLDB ...");
4445
4446     MapNetworkToHost(&entry, &storeEntry);
4447     vcode =
4448         VLDB_ReplaceEntry(afromvol, RWVOL, &storeEntry,
4449                           LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
4450     ONERROR(vcode, afromvol, " Could not update VLDB entry for volume %u\n");
4451     VDONE;
4452
4453   rfail:
4454     if (clonetid) {
4455         code = AFSVolEndTrans(fromconn, clonetid, &rcode);
4456         clonetid = 0;
4457         if (code) {
4458             fprintf(STDERR,
4459                     "Failed to end cloning transaction on the RW volume %lu\n",
4460                     (unsigned long)afromvol);
4461             if (!error)
4462                 error = code;
4463         }
4464     }
4465     if (fromtid) {
4466         code = AFSVolEndTrans(fromconn, fromtid, &rcode);
4467         fromtid = 0;
4468         if (code) {
4469             fprintf(STDERR,
4470                     "Failed to end transaction on the release clone %lu\n",
4471                     (unsigned long)cloneVolId);
4472             if (!error)
4473                 error = code;
4474         }
4475     }
4476     for (i = 0; i < nservers; i++) {
4477         if (replicas && replicas[i].trans) {
4478             code = AFSVolEndTrans(toconns[i], replicas[i].trans, &rcode);
4479             replicas[i].trans = 0;
4480             if (code) {
4481                 fprintf(STDERR,
4482                         "Failed to end transaction on ro volume %u at server %s\n",
4483                         entry.volumeId[ROVOL],
4484                         noresolve ? afs_inet_ntoa_r(htonl(replicas[i].server.
4485                                                         destHost), hoststr) :
4486                         hostutil_GetNameByINet(htonl
4487                                                (replicas[i].server.destHost)));
4488                 if (!error)
4489                     error = code;
4490             }
4491         }
4492         if (toconns && toconns[i]) {
4493             rx_DestroyConnection(toconns[i]);
4494             toconns[i] = 0;
4495         }
4496     }
4497     if (islocked) {
4498         vcode =
4499             ubik_VL_ReleaseLock(cstruct, 0, afromvol, RWVOL,
4500                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
4501         if (vcode) {
4502             fprintf(STDERR,
4503                     "Could not release lock on the VLDB entry for volume %lu\n",
4504                     (unsigned long)afromvol);
4505             if (!error)
4506                 error = vcode;
4507         }
4508     }
4509
4510     PrintError("", error);
4511
4512     if (fromconn)
4513         rx_DestroyConnection(fromconn);
4514     if (results.manyResults_val)
4515         free(results.manyResults_val);
4516     if (replicas)
4517         free(replicas);
4518     if (toconns)
4519         free(toconns);
4520     if (times)
4521         free(times);
4522     return error;
4523 }
4524
4525
4526 static void
4527 dump_sig_handler(int x)
4528 {
4529     fprintf(STDERR, "\nSignal handler: vos dump operation\n");
4530     longjmp(env, 0);
4531 }
4532
4533 /* Dump the volume <afromvol> on <afromserver> and
4534  * <afrompart> to <afilename> starting from <fromdate>.
4535  * DumpFunction does the real work behind the scenes after
4536  * extracting parameters from the rock
4537  */
4538 int
4539 UV_DumpVolume(afs_uint32 afromvol, afs_uint32 afromserver, afs_int32 afrompart,
4540               afs_int32 fromdate,
4541               afs_int32(*DumpFunction) (struct rx_call *, void *), void *rock,
4542               afs_int32 flags)
4543 {
4544     /* declare stuff 'volatile' that may be used from setjmp/longjmp and may
4545      * be changing during the dump */
4546     struct rx_call * volatile fromcall = NULL;
4547     struct rx_connection * volatile fromconn = NULL;
4548     afs_int32 volatile fromtid = 0;
4549
4550     afs_int32 rxError = 0, rcode = 0;
4551     afs_int32 code, error = 0;
4552     afs_int32 tmp;
4553     time_t tmv = fromdate;
4554
4555     if (setjmp(env))
4556         ERROR_EXIT(EPIPE);
4557 #ifndef AFS_NT40_ENV
4558     (void)signal(SIGPIPE, dump_sig_handler);
4559 #endif
4560     (void)signal(SIGINT, dump_sig_handler);
4561
4562     if (!fromdate) {
4563         VEPRINT("Full Dump ...\n");
4564     } else {
4565         VEPRINT1("Incremental Dump (as of %.24s)...\n",
4566                 ctime(&tmv));
4567     }
4568
4569     /* get connections to the servers */
4570     fromconn = UV_Bind(afromserver, AFSCONF_VOLUMEPORT);
4571
4572     VEPRINT1("Starting transaction on volume %u...", afromvol);
4573     tmp = fromtid;
4574     code = AFSVolTransCreate_retry(fromconn, afromvol, afrompart, ITBusy, &tmp);
4575     fromtid = tmp;
4576     EGOTO1(error_exit, code,
4577            "Could not start transaction on the volume %u to be dumped\n",
4578            afromvol);
4579     VEDONE;
4580
4581     fromcall = rx_NewCall(fromconn);
4582
4583     VEPRINT1("Starting volume dump on volume %u...", afromvol);
4584     if (flags & VOLDUMPV2_OMITDIRS)
4585         code = StartAFSVolDumpV2(fromcall, fromtid, fromdate, flags);
4586     else
4587         code = StartAFSVolDump(fromcall, fromtid, fromdate);
4588     EGOTO(error_exit, code, "Could not start the dump process \n");
4589     VEDONE;
4590
4591     VEPRINT1("Dumping volume %u...", afromvol);
4592     code = DumpFunction(fromcall, rock);
4593     if (code == RXGEN_OPCODE)
4594         goto error_exit;
4595     EGOTO(error_exit, code, "Error while dumping volume \n");
4596     VEDONE;
4597
4598   error_exit:
4599     if (fromcall) {
4600         code = rx_EndCall(fromcall, rxError);
4601         if (code && code != RXGEN_OPCODE)
4602             fprintf(STDERR, "Error in rx_EndCall\n");
4603         if (code && !error)
4604             error = code;
4605     }
4606     if (fromtid) {
4607         VEPRINT1("Ending transaction on volume %u...", afromvol);
4608         code = AFSVolEndTrans(fromconn, fromtid, &rcode);
4609         if (code || rcode) {
4610             fprintf(STDERR, "Could not end transaction on the volume %lu\n",
4611                     (unsigned long)afromvol);
4612             if (!error)
4613                 error = (code ? code : rcode);
4614         }
4615         VEDONE;
4616     }
4617     if (fromconn)
4618         rx_DestroyConnection(fromconn);
4619
4620     if (error != RXGEN_OPCODE)
4621         PrintError("", error);
4622     return (error);
4623 }
4624
4625 /* Clone the volume <afromvol> on <afromserver> and
4626  * <afrompart>, and then dump the clone volume to
4627  * <afilename> starting from <fromdate>.
4628  * DumpFunction does the real work behind the scenes after
4629  * extracting parameters from the rock
4630  */
4631 int
4632 UV_DumpClonedVolume(afs_uint32 afromvol, afs_uint32 afromserver,
4633                     afs_int32 afrompart, afs_int32 fromdate,
4634                     afs_int32(*DumpFunction) (struct rx_call *, void *),
4635                     void *rock, afs_int32 flags)
4636 {
4637     /* declare stuff 'volatile' that may be used from setjmp/longjmp and may
4638      * be changing during the dump */
4639     struct rx_connection * volatile fromconn = NULL;
4640     struct rx_call * volatile fromcall = NULL;
4641     afs_int32 volatile clonetid = 0;
4642     afs_uint32 volatile clonevol = 0;
4643
4644     afs_int32 tmp;
4645     afs_int32 fromtid = 0, rxError = 0, rcode = 0;
4646     afs_int32 code = 0, error = 0;
4647     afs_uint32 tmpVol;
4648     char vname[64];
4649     time_t tmv = fromdate;
4650
4651     if (setjmp(env))
4652         ERROR_EXIT(EPIPE);
4653 #ifndef AFS_NT40_ENV
4654     (void)signal(SIGPIPE, dump_sig_handler);
4655 #endif
4656     (void)signal(SIGINT, dump_sig_handler);
4657
4658     if (!fromdate) {
4659         VEPRINT("Full Dump ...\n");
4660     } else {
4661         VEPRINT1("Incremental Dump (as of %.24s)...\n",
4662                 ctime(&tmv));
4663     }
4664
4665     /* get connections to the servers */
4666     fromconn = UV_Bind(afromserver, AFSCONF_VOLUMEPORT);
4667
4668     VEPRINT1("Starting transaction on volume %u...", afromvol);
4669     code = AFSVolTransCreate_retry(fromconn, afromvol, afrompart, ITBusy, &fromtid);
4670     EGOTO1(error_exit, code,
4671            "Could not start transaction on the volume %u to be dumped\n",
4672            afromvol);
4673     VEDONE;
4674
4675     /* Get a clone id */
4676     VEPRINT1("Allocating new volume id for clone of volume %u ...", afromvol);
4677     tmpVol = clonevol;
4678     code = ubik_VL_GetNewVolumeId(cstruct, 0, 1, &tmpVol);
4679     clonevol = tmpVol;
4680     EGOTO1(error_exit, code,
4681            "Could not get an ID for the clone of volume %u from the VLDB\n",
4682            afromvol);
4683     VEDONE;
4684
4685     /* Do the clone. Default flags on clone are set to delete on salvage and out of service */
4686     VEPRINT2("Cloning source volume %u to clone volume %u...", afromvol,
4687             clonevol);
4688     strcpy(vname, "dump-clone-temp");
4689     tmpVol = clonevol;
4690     code =
4691         AFSVolClone(fromconn, fromtid, 0, readonlyVolume, vname, &tmpVol);
4692     clonevol = tmpVol;
4693     EGOTO1(error_exit, code, "Failed to clone the source volume %u\n",
4694            afromvol);
4695     VEDONE;
4696
4697     VEPRINT1("Ending the transaction on the volume %u ...", afromvol);
4698     rcode = 0;
4699     code = AFSVolEndTrans(fromconn, fromtid, &rcode);
4700     fromtid = 0;
4701     if (!code)
4702         code = rcode;
4703     EGOTO1(error_exit, code,
4704            "Failed to end the transaction on the volume %u\n", afromvol);
4705     VEDONE;
4706
4707
4708     VEPRINT1("Starting transaction on the cloned volume %u ...", clonevol);
4709     tmp = clonetid;
4710     code =
4711         AFSVolTransCreate_retry(fromconn, clonevol, afrompart, ITOffline,
4712                           &tmp);
4713     clonetid = tmp;
4714     EGOTO1(error_exit, code,
4715            "Failed to start a transaction on the cloned volume%u\n",
4716            clonevol);
4717     VEDONE;
4718
4719     VEPRINT1("Setting flags on cloned volume %u ...", clonevol);
4720     code = AFSVolSetFlags(fromconn, clonetid, VTDeleteOnSalvage | VTOutOfService);      /*redundant */
4721     EGOTO1(error_exit, code, "Could not set falgs on the cloned volume %u\n",
4722            clonevol);
4723     VEDONE;
4724
4725
4726     fromcall = rx_NewCall(fromconn);
4727
4728     VEPRINT1("Starting volume dump from cloned volume %u...", clonevol);
4729     if (flags & VOLDUMPV2_OMITDIRS)
4730         code = StartAFSVolDumpV2(fromcall, clonetid, fromdate, flags);
4731     else
4732         code = StartAFSVolDump(fromcall, clonetid, fromdate);
4733     EGOTO(error_exit, code, "Could not start the dump process \n");
4734     VEDONE;
4735
4736     VEPRINT1("Dumping volume %u...", afromvol);
4737     code = DumpFunction(fromcall, rock);
4738     EGOTO(error_exit, code, "Error while dumping volume \n");
4739     VEDONE;
4740
4741   error_exit:
4742     /* now delete the clone */
4743     VEPRINT1("Deleting the cloned volume %u ...", clonevol);
4744     code = AFSVolDeleteVolume(fromconn, clonetid);
4745     if (code) {
4746         fprintf(STDERR, "Failed to delete the cloned volume %lu\n",
4747                 (unsigned long)clonevol);
4748     } else {
4749         VEDONE;
4750     }
4751
4752     if (fromcall) {
4753         code = rx_EndCall(fromcall, rxError);
4754         if (code) {
4755             fprintf(STDERR, "Error in rx_EndCall\n");
4756             if (!error)
4757                 error = code;
4758         }
4759     }
4760     if (clonetid) {
4761         VEPRINT1("Ending transaction on cloned volume %u...", clonevol);
4762         code = AFSVolEndTrans(fromconn, clonetid, &rcode);
4763         if (code || rcode) {
4764             fprintf(STDERR,
4765                     "Could not end transaction on the cloned volume %lu\n",
4766                     (unsigned long)clonevol);
4767             if (!error)
4768                 error = (code ? code : rcode);
4769         }
4770         VEDONE;
4771     }
4772     if (fromconn)
4773         rx_DestroyConnection(fromconn);
4774
4775     PrintError("", error);
4776     return (error);
4777 }
4778
4779
4780
4781 /*
4782  * Restore a volume <tovolid> <tovolname> on <toserver> <topart> from
4783  * the dump file <afilename>. WriteData does all the real work
4784  * after extracting params from the rock
4785  */
4786 int
4787 UV_RestoreVolume2(afs_uint32 toserver, afs_int32 topart, afs_uint32 tovolid,
4788                   afs_uint32 toparentid, char tovolname[], int flags,
4789                   afs_int32(*WriteData) (struct rx_call *, void *),
4790                   void *rock)
4791 {
4792     struct rx_connection *toconn, *tempconn;
4793     struct rx_call *tocall;
4794     afs_int32 totid, code, rcode, vcode, terror = 0;
4795     afs_int32 rxError = 0;
4796     struct volser_status tstatus;
4797     struct volintInfo vinfo;
4798     char partName[10];
4799     char tovolreal[VOLSER_OLDMAXVOLNAME];
4800     afs_uint32 pvolid;
4801     afs_int32 temptid, pparentid;
4802     struct nvldbentry entry, storeEntry;
4803     afs_int32 error;
4804     int islocked;
4805     struct restoreCookie cookie;
4806     int reuseID;
4807     afs_int32 volflag, voltype, volsertype;
4808     afs_int32 oldCreateDate, oldUpdateDate, newCreateDate, newUpdateDate;
4809     int index, same, errcode;
4810     char apartName[10];
4811     char hoststr[16];
4812
4813     memset(&cookie, 0, sizeof(cookie));
4814     islocked = 0;
4815     error = 0;
4816     reuseID = 1;
4817     tocall = (struct rx_call *)0;
4818     tempconn = (struct rx_connection *)0;
4819     totid = 0;
4820     temptid = 0;
4821
4822     if (flags & RV_RDONLY) {
4823         voltype = ROVOL;
4824         volsertype = volser_RO;
4825     } else {
4826         voltype = RWVOL;
4827         volsertype = volser_RW;
4828     }
4829
4830     pvolid = tovolid;
4831     pparentid = toparentid;
4832     toconn = UV_Bind(toserver, AFSCONF_VOLUMEPORT);
4833     if (pvolid == 0) {          /*alot a new id if needed */
4834         vcode = VLDB_GetEntryByName(tovolname, &entry);
4835         if (vcode == VL_NOENT) {
4836             vcode = ubik_VL_GetNewVolumeId(cstruct, 0, 1, &pvolid);
4837             if (vcode) {
4838                 fprintf(STDERR, "Could not get an Id for the volume %s\n",
4839                         tovolname);
4840                 error = vcode;
4841                 goto refail;
4842             }
4843             reuseID = 0;
4844         } else if (flags & RV_RDONLY) {
4845             if (entry.flags & RW_EXISTS) {
4846                 fprintf(STDERR,
4847                         "Entry for ReadWrite volume %s already exists!\n",
4848                         entry.name);
4849                 error = VOLSERBADOP;
4850                 goto refail;
4851             }
4852             if (!entry.volumeId[ROVOL]) {
4853                 fprintf(STDERR,
4854                         "Existing entry for volume %s has no ReadOnly ID\n",
4855                         tovolname);
4856                 error = VOLSERBADOP;
4857                 goto refail;
4858             }
4859             pvolid = entry.volumeId[ROVOL];
4860             pparentid = entry.volumeId[RWVOL];
4861         } else {
4862             pvolid = entry.volumeId[RWVOL];
4863             pparentid = entry.volumeId[RWVOL];
4864         }
4865     }
4866     if (!pparentid) pparentid = pvolid;
4867     /* at this point we have a volume id to use/reuse for the volume to be restored */
4868     strncpy(tovolreal, tovolname, VOLSER_OLDMAXVOLNAME);
4869
4870     if (strlen(tovolname) > (VOLSER_OLDMAXVOLNAME - 1)) {
4871         EGOTO1(refail, VOLSERBADOP,
4872                "The volume name %s exceeds the maximum limit of (VOLSER_OLDMAXVOLNAME -1 ) bytes\n",
4873                tovolname);
4874     } else {
4875         if ((pparentid != pvolid) && (flags & RV_RDONLY)) {
4876             if (strlen(tovolname) > (VOLSER_OLDMAXVOLNAME - 10)) {
4877                 EGOTO1(refail, VOLSERBADOP,
4878                        "The volume name %s exceeds the maximum limit of (VOLSER_OLDMAXVOLNAME -1 ) bytes\n", tovolname);
4879             }
4880             snprintf(tovolreal, VOLSER_OLDMAXVOLNAME, "%s.readonly", tovolname);
4881         }
4882     }
4883     MapPartIdIntoName(topart, partName);
4884     fprintf(STDOUT, "Restoring volume %s Id %lu on server %s partition %s ..",
4885             tovolreal, (unsigned long)pvolid,
4886             noresolve ? afs_inet_ntoa_r(toserver, hoststr) :
4887             hostutil_GetNameByINet(toserver), partName);
4888     fflush(STDOUT);
4889     code =
4890         AFSVolCreateVolume(toconn, topart, tovolreal, volsertype, pparentid, &pvolid,
4891                            &totid);
4892     if (code) {
4893         if (flags & RV_FULLRST) {       /* full restore: delete then create anew */
4894             code = DoVolDelete(toconn, pvolid, topart, "the previous", 0,
4895                                &tstatus, NULL);
4896             if (code && code != VNOVOL) {
4897                 error = code;
4898                 goto refail;
4899             }
4900
4901             code =
4902                 AFSVolCreateVolume(toconn, topart, tovolreal, volsertype, pparentid,
4903                                    &pvolid, &totid);
4904             EGOTO1(refail, code, "Could not create new volume %u\n", pvolid);
4905         } else {
4906             code =
4907                 AFSVolTransCreate_retry(toconn, pvolid, topart, ITOffline, &totid);
4908             EGOTO1(refail, code, "Failed to start transaction on %u\n",
4909                    pvolid);
4910
4911             code = AFSVolGetStatus(toconn, totid, &tstatus);
4912             EGOTO1(refail, code, "Could not get timestamp from volume %u\n",
4913                    pvolid);
4914
4915         }
4916         oldCreateDate = tstatus.creationDate;
4917         oldUpdateDate = tstatus.updateDate;
4918     } else {
4919         oldCreateDate = 0;
4920         oldUpdateDate = 0;
4921     }
4922
4923     cookie.parent = pparentid;
4924     cookie.type = voltype;
4925     cookie.clone = 0;
4926     strncpy(cookie.name, tovolreal, VOLSER_OLDMAXVOLNAME);
4927
4928     tocall = rx_NewCall(toconn);
4929     terror = StartAFSVolRestore(tocall, totid, 1, &cookie);
4930     if (terror) {
4931         fprintf(STDERR, "Volume restore Failed \n");
4932         error = terror;
4933         goto refail;
4934     }
4935     code = WriteData(tocall, rock);
4936     if (code) {
4937         fprintf(STDERR, "Could not transmit data\n");
4938         error = code;
4939         goto refail;
4940     }
4941     terror = rx_EndCall(tocall, rxError);
4942     tocall = (struct rx_call *)0;
4943     if (terror) {
4944         fprintf(STDERR, "rx_EndCall Failed \n");
4945         error = terror;
4946         goto refail;
4947     }
4948     code = AFSVolGetStatus(toconn, totid, &tstatus);
4949     if (code) {
4950         fprintf(STDERR,
4951                 "Could not get status information about the volume %lu\n",
4952                 (unsigned long)pvolid);
4953         error = code;
4954         goto refail;
4955     }
4956     code = AFSVolSetIdsTypes(toconn, totid, tovolreal, voltype, pparentid, 0, 0);
4957     if (code) {
4958         fprintf(STDERR, "Could not set the right type and ID on %lu\n",
4959                 (unsigned long)pvolid);
4960         error = code;
4961         goto refail;
4962     }
4963
4964     if (flags & RV_CRDUMP)
4965         newCreateDate = tstatus.creationDate;
4966     else if (flags & RV_CRKEEP && oldCreateDate != 0)
4967         newCreateDate = oldCreateDate;
4968     else
4969         newCreateDate = time(0);
4970     if (flags & RV_LUDUMP)
4971         newUpdateDate = tstatus.updateDate;
4972     else if (flags & RV_LUKEEP)
4973         newUpdateDate = oldUpdateDate;
4974     else
4975         newUpdateDate = time(0);
4976     code = AFSVolSetDate(toconn,totid, newCreateDate);
4977     if (code) {
4978         fprintf(STDERR, "Could not set the 'creation' date on %u\n", pvolid);
4979         error = code;
4980         goto refail;
4981     }
4982
4983     init_volintInfo(&vinfo);
4984     vinfo.creationDate = newCreateDate;
4985     vinfo.updateDate = newUpdateDate;
4986     code = AFSVolSetInfo(toconn, totid, &vinfo);
4987     if (code) {
4988         fprintf(STDERR, "Could not set the 'last updated' date on %u\n",
4989                 pvolid);
4990         error = code;
4991         goto refail;
4992     }
4993
4994     volflag = ((flags & RV_OFFLINE) ? VTOutOfService : 0);      /* off or on-line */
4995     code = AFSVolSetFlags(toconn, totid, volflag);
4996     if (code) {
4997         fprintf(STDERR, "Could not mark %lu online\n", (unsigned long)pvolid);
4998         error = code;
4999         goto refail;
5000     }
5001
5002 /* It isn't handled right in refail */
5003     code = AFSVolEndTrans(toconn, totid, &rcode);
5004     totid = 0;
5005     if (!code)
5006         code = rcode;
5007     if (code) {
5008         fprintf(STDERR, "Could not end transaction on %lu\n",
5009                 (unsigned long)pvolid);
5010         error = code;
5011         goto refail;
5012     }
5013
5014     fprintf(STDOUT, " done\n");
5015     fflush(STDOUT);
5016     if (!reuseID || (flags & RV_FULLRST)) {
5017         /* Volume was restored on the file server, update the
5018          * VLDB to reflect the change.
5019          */
5020         vcode = VLDB_GetEntryByID(pvolid, voltype, &entry);
5021         if (vcode && vcode != VL_NOENT && vcode != VL_ENTDELETED) {
5022             fprintf(STDERR,
5023                     "Could not fetch the entry for volume number %lu from VLDB \n",
5024                     (unsigned long)pvolid);
5025             error = vcode;
5026             goto refail;
5027         }
5028         if (!vcode)
5029             MapHostToNetwork(&entry);
5030         if (vcode == VL_NOENT) {        /* it doesnot exist already */
5031             /*make the vldb return this indication specifically */
5032             VPRINT("------- Creating a new VLDB entry ------- \n");
5033             strcpy(entry.name, tovolname);
5034             entry.nServers = 1;
5035             entry.serverNumber[0] = toserver;   /*should be indirect */
5036             entry.serverPartition[0] = topart;
5037             entry.serverFlags[0] = (flags & RV_RDONLY) ? ITSROVOL : ITSRWVOL;
5038             entry.flags = (flags & RV_RDONLY) ? RO_EXISTS : RW_EXISTS;
5039             if (flags & RV_RDONLY)
5040                 entry.volumeId[ROVOL] = pvolid;
5041             else if (tstatus.cloneID != 0) {
5042                 entry.volumeId[ROVOL] = tstatus.cloneID;        /*this should come from status info on the volume if non zero */
5043             } else
5044                 entry.volumeId[ROVOL] = INVALID_BID;
5045             entry.volumeId[RWVOL] = pparentid;
5046             entry.cloneId = 0;
5047             if (tstatus.backupID != 0) {
5048                 entry.volumeId[BACKVOL] = tstatus.backupID;
5049                 /*this should come from status info on the volume if non zero */
5050             } else
5051                 entry.volumeId[BACKVOL] = INVALID_BID;
5052             MapNetworkToHost(&entry, &storeEntry);
5053             vcode = VLDB_CreateEntry(&storeEntry);
5054             if (vcode) {
5055                 fprintf(STDERR,
5056                         "Could not create the VLDB entry for volume number %lu  \n",
5057                         (unsigned long)pvolid);
5058                 error = vcode;
5059                 goto refail;
5060             }
5061             islocked = 0;
5062             if (verbose)
5063                 EnumerateEntry(&entry);
5064         } else {                /*update the existing entry */
5065             if (verbose) {
5066                 fprintf(STDOUT, "Updating the existing VLDB entry\n");
5067                 fprintf(STDOUT, "------- Old entry -------\n");
5068                 EnumerateEntry(&entry);
5069                 fprintf(STDOUT, "------- New entry -------\n");
5070             }
5071             vcode =
5072                 ubik_VL_SetLock(cstruct, 0, pvolid, voltype,
5073                           VLOP_RESTORE);
5074             if (vcode) {
5075                 fprintf(STDERR,
5076                         "Could not lock the entry for volume number %lu \n",
5077                         (unsigned long)pvolid);
5078                 error = vcode;
5079                 goto refail;
5080             }
5081             islocked = 1;
5082             strcpy(entry.name, tovolname);
5083
5084             /* Update the vlentry with the new information */
5085             if (flags & RV_RDONLY)
5086                 index = Lp_ROMatch(toserver, topart, &entry) - 1;
5087             else
5088                 index = Lp_GetRwIndex(&entry);
5089             if (index == -1) {
5090                 /* Add the new site for the volume being restored */
5091                 entry.serverNumber[entry.nServers] = toserver;
5092                 entry.serverPartition[entry.nServers] = topart;
5093                 entry.serverFlags[entry.nServers] =
5094                     (flags & RV_RDONLY) ? ITSROVOL : ITSRWVOL;
5095                 entry.nServers++;
5096             } else {
5097                 /* This volume should be deleted on the old site
5098                  * if its different from new site.
5099                  */
5100                 same =
5101                     VLDB_IsSameAddrs(toserver, entry.serverNumber[index],
5102                                      &errcode);
5103                 if (errcode)
5104                     EPRINT2(errcode,
5105                             "Failed to get info about server's %d address(es) from vlserver (err=%d)\n",
5106                             toserver, errcode);
5107                 if ((!errcode && !same)
5108                     || (entry.serverPartition[index] != topart)) {
5109                     if (flags & RV_NODEL) {
5110                         VPRINT2
5111                             ("Not deleting the previous volume %u on server %s, ...",
5112                              pvolid,
5113                              noresolve ? afs_inet_ntoa_r(entry.serverNumber[index], hoststr) :
5114                              hostutil_GetNameByINet(entry.serverNumber[index]));
5115                     } else {
5116                         tempconn =
5117                             UV_Bind(entry.serverNumber[index],
5118                                     AFSCONF_VOLUMEPORT);
5119
5120                         MapPartIdIntoName(entry.serverPartition[index],
5121                                           apartName);
5122                         VPRINT3
5123                             ("Deleting the previous volume %u on server %s, partition %s ...",
5124                              pvolid,
5125                              noresolve ? afs_inet_ntoa_r(entry.serverNumber[index], hoststr) :
5126                              hostutil_GetNameByINet(entry.serverNumber[index]),
5127                              apartName);
5128                         code = DoVolDelete(tempconn, pvolid,
5129                                            entry.serverPartition[index],
5130                                            "the", 0, NULL, NULL);
5131                         if (code && code != VNOVOL) {
5132                             error = code;
5133                             goto refail;
5134                         }
5135                         MapPartIdIntoName(entry.serverPartition[index],
5136                                           partName);
5137                     }
5138                 }
5139                 entry.serverNumber[index] = toserver;
5140                 entry.serverPartition[index] = topart;
5141             }
5142
5143             entry.flags |= (flags & RV_RDONLY) ? RO_EXISTS : RW_EXISTS;
5144             MapNetworkToHost(&entry, &storeEntry);
5145             vcode =
5146                 VLDB_ReplaceEntry(pvolid, voltype, &storeEntry,
5147                                   LOCKREL_OPCODE | LOCKREL_AFSID |
5148                                   LOCKREL_TIMESTAMP);
5149             if (vcode) {
5150                 fprintf(STDERR,
5151                         "Could not update the entry for volume number %lu  \n",
5152                         (unsigned long)pvolid);
5153                 error = vcode;
5154                 goto refail;
5155             }
5156             islocked = 0;
5157             if (verbose)
5158                 EnumerateEntry(&entry);
5159         }
5160
5161
5162     }
5163   refail:
5164     if (tocall) {
5165         code = rx_EndCall(tocall, rxError);
5166         if (!error)
5167             error = code;
5168     }
5169     if (islocked) {
5170         vcode =
5171             ubik_VL_ReleaseLock(cstruct, 0, pvolid, voltype,
5172                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
5173         if (vcode) {
5174             fprintf(STDERR,
5175                     "Could not release lock on the VLDB entry for the volume %lu\n",
5176                     (unsigned long)pvolid);
5177             if (!error)
5178                 error = vcode;
5179         }
5180     }
5181     if (totid) {
5182         code = AFSVolEndTrans(toconn, totid, &rcode);
5183         if (!code)
5184             code = rcode;
5185         if (code) {
5186             fprintf(STDERR, "Could not end transaction on the volume %lu \n",
5187                     (unsigned long)pvolid);
5188             if (!error)
5189                 error = code;
5190         }
5191     }
5192     if (temptid) {
5193         code = AFSVolEndTrans(toconn, temptid, &rcode);
5194         if (!code)
5195             code = rcode;
5196         if (code) {
5197             fprintf(STDERR, "Could not end transaction on the volume %lu \n",
5198                     (unsigned long)pvolid);
5199             if (!error)
5200                 error = code;
5201         }
5202     }
5203     if (tempconn)
5204         rx_DestroyConnection(tempconn);
5205     if (toconn)
5206         rx_DestroyConnection(toconn);
5207     PrintError("", error);
5208     return error;
5209 }
5210
5211 int
5212 UV_RestoreVolume(afs_uint32 toserver, afs_int32 topart, afs_uint32 tovolid,
5213                  char tovolname[], int flags,
5214                  afs_int32(*WriteData) (struct rx_call *, void *),
5215                  void *rock)
5216 {
5217     return UV_RestoreVolume2(toserver, topart, tovolid, 0, tovolname, flags,
5218                              WriteData, rock);
5219 }
5220
5221
5222 /*unlocks the vldb entry associated with <volid> */
5223 int
5224 UV_LockRelease(afs_uint32 volid)
5225 {
5226     afs_int32 vcode;
5227
5228     VPRINT("Binding to the VLDB server\n");
5229     vcode =
5230         ubik_VL_ReleaseLock(cstruct, 0, volid, -1,
5231                   LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
5232     if (vcode) {
5233         fprintf(STDERR,
5234                 "Could not unlock the entry for volume number %lu in VLDB \n",
5235                 (unsigned long)volid);
5236         PrintError("", vcode);
5237         return (vcode);
5238     }
5239     VPRINT("VLDB updated\n");
5240     return 0;
5241
5242 }
5243
5244 /* old interface to add rosites */
5245 int
5246 UV_AddSite(afs_uint32 server, afs_int32 part, afs_uint32 volid,
5247            afs_int32 valid)
5248 {
5249     return UV_AddSite2(server, part, volid, 0, valid);
5250 }
5251
5252 /*adds <server> and <part> as a readonly replication site for <volid>
5253 *in vldb */
5254 int
5255 UV_AddSite2(afs_uint32 server, afs_int32 part, afs_uint32 volid,
5256             afs_uint32 rovolid, afs_int32 valid)
5257 {
5258     int j, nro = 0, islocked = 0;
5259     struct nvldbentry entry, storeEntry, entry2;
5260     afs_int32 vcode, error = 0;
5261     char apartName[10];
5262
5263     error = ubik_VL_SetLock(cstruct, 0, volid, RWVOL, VLOP_ADDSITE);
5264     if (error) {
5265         fprintf(STDERR,
5266                 " Could not lock the VLDB entry for the volume %lu \n",
5267                 (unsigned long)volid);
5268         goto asfail;
5269     }
5270     islocked = 1;
5271
5272     error = VLDB_GetEntryByID(volid, RWVOL, &entry);
5273     if (error) {
5274         fprintf(STDERR,
5275                 "Could not fetch the VLDB entry for volume number %lu  \n",
5276                 (unsigned long)volid);
5277         goto asfail;
5278
5279     }
5280     if (!ISNAMEVALID(entry.name)) {
5281         fprintf(STDERR,
5282                 "Volume name %s is too long, rename before adding site\n",
5283                 entry.name);
5284         error = VOLSERBADOP;
5285         goto asfail;
5286     }
5287     MapHostToNetwork(&entry);
5288
5289     /* See if it's too many entries */
5290     if (entry.nServers >= NMAXNSERVERS) {
5291         fprintf(STDERR, "Total number of entries will exceed %u\n",
5292                 NMAXNSERVERS);
5293         error = VOLSERBADOP;
5294         goto asfail;
5295     }
5296
5297     /* See if it's on the same server */
5298     for (j = 0; j < entry.nServers; j++) {
5299         if (entry.serverFlags[j] & ITSROVOL) {
5300             nro++;
5301             if (VLDB_IsSameAddrs(server, entry.serverNumber[j], &error)) {
5302                 if (error) {
5303                     fprintf(STDERR,
5304                             "Failed to get info about server's %d address(es) from vlserver (err=%d); aborting call!\n",
5305                             server, error);
5306                 } else {
5307                     MapPartIdIntoName(entry.serverPartition[j], apartName);
5308                     fprintf(STDERR,
5309                             "RO already exists on partition %s. Multiple ROs on a single server aren't allowed\n",
5310                             apartName);
5311                     error = VOLSERBADOP;
5312                 }
5313                 goto asfail;
5314             }
5315         }
5316     }
5317
5318     /* See if it's too many RO sites - leave one for the RW */
5319     if (nro >= NMAXNSERVERS - 1) {
5320         fprintf(STDERR, "Total number of sites will exceed %u\n",
5321                 NMAXNSERVERS - 1);
5322         error = VOLSERBADOP;
5323         goto asfail;
5324     }
5325
5326     /* if rovolid == 0, we leave the RO volume id alone. If the volume doesn't
5327      * have an RO volid at this point (i.e. entry.volumeId[ROVOL] ==
5328      * INVALID_BID) and we leave it alone, it gets an RO volid at release-time.
5329      */
5330     if (rovolid) {
5331         if (entry.volumeId[ROVOL] == INVALID_BID) {
5332             vcode = VLDB_GetEntryByID(rovolid, -1, &entry2);
5333             if (!vcode) {
5334                 fprintf(STDERR, "Volume ID %d already exists\n", rovolid);
5335                 return VVOLEXISTS;
5336             }
5337             VPRINT1("Using RO volume id %d.\n", rovolid);
5338             entry.volumeId[ROVOL] = rovolid;
5339         } else {
5340             fprintf(STDERR, "Ignoring given RO id %d, since volume already has RO id %d\n",
5341                 rovolid, entry.volumeId[ROVOL]);
5342         }
5343     }
5344
5345     VPRINT("Adding a new site ...");
5346     entry.serverNumber[entry.nServers] = server;
5347     entry.serverPartition[entry.nServers] = part;
5348     if (!valid) {
5349         entry.serverFlags[entry.nServers] = (ITSROVOL | RO_DONTUSE);
5350     } else {
5351         entry.serverFlags[entry.nServers] = (ITSROVOL);
5352     }
5353     entry.nServers++;
5354
5355     MapNetworkToHost(&entry, &storeEntry);
5356     error =
5357         VLDB_ReplaceEntry(volid, RWVOL, &storeEntry,
5358                           LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
5359     if (error) {
5360         fprintf(STDERR, "Could not update entry for volume %lu \n",
5361                 (unsigned long)volid);
5362         goto asfail;
5363     }
5364     islocked = 0;
5365     VDONE;
5366
5367   asfail:
5368     if (islocked) {
5369         vcode =
5370             ubik_VL_ReleaseLock(cstruct, 0, volid, RWVOL,
5371                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
5372         if (vcode) {
5373             fprintf(STDERR,
5374                     "Could not release lock on volume entry for %lu \n",
5375                     (unsigned long)volid);
5376             PrintError("", vcode);
5377         }
5378     }
5379
5380     PrintError("", error);
5381     return error;
5382 }
5383
5384 /*removes <server> <part> as read only site for <volid> from the vldb */
5385 int
5386 UV_RemoveSite(afs_uint32 server, afs_int32 part, afs_uint32 volid)
5387 {
5388     afs_int32 vcode;
5389     struct nvldbentry entry, storeEntry;
5390
5391     vcode = ubik_VL_SetLock(cstruct, 0, volid, RWVOL, VLOP_ADDSITE);
5392     if (vcode) {
5393         fprintf(STDERR, " Could not lock the VLDB entry for volume %lu \n",
5394                 (unsigned long)volid);
5395         PrintError("", vcode);
5396         return (vcode);
5397     }
5398     vcode = VLDB_GetEntryByID(volid, RWVOL, &entry);
5399     if (vcode) {
5400         fprintf(STDERR,
5401                 "Could not fetch the entry for volume number %lu from VLDB \n",
5402                 (unsigned long)volid);
5403         PrintError("", vcode);
5404         return (vcode);
5405     }
5406     MapHostToNetwork(&entry);
5407     if (!Lp_ROMatch(server, part, &entry)) {
5408         /*this site doesnot exist  */
5409         fprintf(STDERR, "This site is not a replication site \n");
5410         vcode =
5411             ubik_VL_ReleaseLock(cstruct, 0, volid, RWVOL,
5412                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
5413         if (vcode) {
5414             fprintf(STDERR, "Could not update entry for volume %lu \n",
5415                     (unsigned long)volid);
5416             PrintError("", vcode);
5417             ubik_VL_ReleaseLock(cstruct, 0, volid, RWVOL,
5418                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
5419             return (vcode);
5420         }
5421         return VOLSERBADOP;
5422     } else {                    /*remove the rep site */
5423         Lp_SetROValue(&entry, server, part, 0, 0);
5424         entry.nServers--;
5425         if ((entry.nServers == 1) && (entry.flags & RW_EXISTS))
5426             entry.flags &= ~RO_EXISTS;
5427         if (entry.nServers < 1) {       /*this is the last ref */
5428             VPRINT1("Deleting the VLDB entry for %u ...", volid);
5429             fflush(STDOUT);
5430             vcode = ubik_VL_DeleteEntry(cstruct, 0, volid, ROVOL);
5431             if (vcode) {
5432                 fprintf(STDERR,
5433                         "Could not delete VLDB entry for volume %lu \n",
5434                         (unsigned long)volid);
5435                 PrintError("", vcode);
5436                 return (vcode);
5437             }
5438             VDONE;
5439         }
5440         MapNetworkToHost(&entry, &storeEntry);
5441         fprintf(STDOUT, "Deleting the replication site for volume %lu ...",
5442                 (unsigned long)volid);
5443         fflush(STDOUT);
5444         vcode =
5445             VLDB_ReplaceEntry(volid, RWVOL, &storeEntry,
5446                               LOCKREL_OPCODE | LOCKREL_AFSID |
5447                               LOCKREL_TIMESTAMP);
5448         if (vcode) {
5449             fprintf(STDERR,
5450                     "Could not release lock on volume entry for %lu \n",
5451                     (unsigned long)volid);
5452             PrintError("", vcode);
5453             ubik_VL_ReleaseLock(cstruct, 0, volid, RWVOL,
5454                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
5455             return (vcode);
5456         }
5457         VDONE;
5458     }
5459     return 0;
5460 }
5461
5462 /*sets <server> <part> as read/write site for <volid> in the vldb */
5463 int
5464 UV_ChangeLocation(afs_uint32 server, afs_int32 part, afs_uint32 volid)
5465 {
5466     afs_int32 vcode;
5467     struct nvldbentry entry, storeEntry;
5468     int index;
5469
5470     vcode = ubik_VL_SetLock(cstruct, 0, volid, RWVOL, VLOP_ADDSITE);
5471     if (vcode) {
5472         fprintf(STDERR, " Could not lock the VLDB entry for volume %lu \n",
5473                 (unsigned long)volid);
5474         PrintError("", vcode);
5475         return (vcode);
5476     }
5477     vcode = VLDB_GetEntryByID(volid, RWVOL, &entry);
5478     if (vcode) {
5479         fprintf(STDERR,
5480                 "Could not fetch the entry for volume number %lu from VLDB \n",
5481                 (unsigned long)volid);
5482         PrintError("", vcode);
5483         return (vcode);
5484     }
5485     MapHostToNetwork(&entry);
5486     index = Lp_GetRwIndex(&entry);
5487     if (index < 0) {
5488         /* no RW site exists  */
5489         fprintf(STDERR, "No existing RW site for volume %lu",
5490                 (unsigned long)volid);
5491         vcode =
5492             ubik_VL_ReleaseLock(cstruct, 0, volid, RWVOL,
5493                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
5494         if (vcode) {
5495             fprintf(STDERR,
5496                     "Could not release lock on entry for volume %lu \n",
5497                     (unsigned long)volid);
5498             PrintError("", vcode);
5499             return (vcode);
5500         }
5501         return VOLSERBADOP;
5502     } else {                    /* change the RW site */
5503         entry.serverNumber[index] = server;
5504         entry.serverPartition[index] = part;
5505         MapNetworkToHost(&entry, &storeEntry);
5506         vcode =
5507             VLDB_ReplaceEntry(volid, RWVOL, &storeEntry,
5508                               LOCKREL_OPCODE | LOCKREL_AFSID |
5509                               LOCKREL_TIMESTAMP);
5510         if (vcode) {
5511             fprintf(STDERR, "Could not update entry for volume %lu \n",
5512                     (unsigned long)volid);
5513             PrintError("", vcode);
5514             ubik_VL_ReleaseLock(cstruct, 0, volid, RWVOL,
5515                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
5516             return (vcode);
5517         }
5518         VDONE;
5519     }
5520     return 0;
5521 }
5522
5523 /*list all the partitions on <aserver> */
5524 int
5525 UV_ListPartitions(afs_uint32 aserver, struct partList *ptrPartList,
5526                   afs_int32 * cntp)
5527 {
5528     struct rx_connection *aconn;
5529     struct pIDs partIds;
5530     struct partEntries partEnts;
5531     int i, j = 0, code;
5532
5533     *cntp = 0;
5534     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
5535
5536     partEnts.partEntries_len = 0;
5537     partEnts.partEntries_val = NULL;
5538     code = AFSVolXListPartitions(aconn, &partEnts);     /* this is available only on new servers */
5539     if (code == RXGEN_OPCODE) {
5540         for (i = 0; i < 26; i++)        /* try old interface */
5541             partIds.partIds[i] = -1;
5542         code = AFSVolListPartitions(aconn, &partIds);
5543         if (!code) {
5544             for (i = 0; i < 26; i++) {
5545                 if ((partIds.partIds[i]) != -1) {
5546                     ptrPartList->partId[j] = partIds.partIds[i];
5547                     ptrPartList->partFlags[j] = PARTVALID;
5548                     j++;
5549                 } else
5550                     ptrPartList->partFlags[i] = 0;
5551             }
5552             *cntp = j;
5553         }
5554     } else if (!code) {
5555         *cntp = partEnts.partEntries_len;
5556         if (*cntp > VOLMAXPARTS) {
5557             fprintf(STDERR,
5558                     "Warning: number of partitions on the server too high %d (process only %d)\n",
5559                     *cntp, VOLMAXPARTS);
5560             *cntp = VOLMAXPARTS;
5561         }
5562         for (i = 0; i < *cntp; i++) {
5563             ptrPartList->partId[i] = partEnts.partEntries_val[i];
5564             ptrPartList->partFlags[i] = PARTVALID;
5565         }
5566         free(partEnts.partEntries_val);
5567     }
5568
5569    /* out: */
5570     if (code)
5571         fprintf(STDERR,
5572                 "Could not fetch the list of partitions from the server\n");
5573     PrintError("", code);
5574     if (aconn)
5575         rx_DestroyConnection(aconn);
5576     return code;
5577 }
5578
5579
5580 /*zap the list of volumes specified by volPtrArray (the volCloneId field).
5581  This is used by the backup system */
5582 int
5583 UV_ZapVolumeClones(afs_uint32 aserver, afs_int32 apart,
5584                    struct volDescription *volPtr, afs_int32 arraySize)
5585 {
5586     struct rx_connection *aconn;
5587     struct volDescription *curPtr;
5588     int curPos;
5589     afs_int32 code = 0;
5590     afs_int32 success = 1;
5591
5592     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
5593     curPos = 0;
5594     for (curPtr = volPtr; curPos < arraySize; curPtr++) {
5595         if (curPtr->volFlags & CLONEVALID) {
5596             curPtr->volFlags &= ~CLONEZAPPED;
5597             success = 1;
5598
5599             code = DoVolDelete(aconn, curPtr->volCloneId, apart,
5600                                "clone", 0, NULL, NULL);
5601             if (code)
5602                 success = 0;
5603
5604             if (success)
5605                 curPtr->volFlags |= CLONEZAPPED;
5606             if (!success)
5607                 fprintf(STDERR, "Could not zap volume %lu\n",
5608                         (unsigned long)curPtr->volCloneId);
5609             if (success)
5610                 VPRINT2("Clone of %s %u deleted\n", curPtr->volName,
5611                         curPtr->volCloneId);
5612             curPos++;
5613         }
5614     }
5615     if (aconn)
5616         rx_DestroyConnection(aconn);
5617     return 0;
5618 }
5619
5620 /*return a list of clones of the volumes specified by volPtrArray. Used by the
5621  backup system */
5622 int
5623 UV_GenerateVolumeClones(afs_uint32 aserver, afs_int32 apart,
5624                         struct volDescription *volPtr, afs_int32 arraySize)
5625 {
5626     struct rx_connection *aconn;
5627     struct volDescription *curPtr;
5628     int curPos;
5629     afs_int32 code = 0;
5630     afs_int32 rcode = 0;
5631     afs_int32 tid;
5632     int reuseCloneId = 0;
5633     afs_uint32 curCloneId = 0;
5634     char cloneName[256];        /*max vol name */
5635
5636     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
5637     curPos = 0;
5638     if ((volPtr->volFlags & REUSECLONEID) && (volPtr->volFlags & ENTRYVALID))
5639         reuseCloneId = 1;
5640     else {                      /*get a bunch of id's from vldb */
5641         code =
5642             ubik_VL_GetNewVolumeId(cstruct, 0, arraySize, &curCloneId);
5643         if (code) {
5644             fprintf(STDERR, "Could not get ID's for the clone from VLDB\n");
5645             PrintError("", code);
5646             return code;
5647         }
5648     }
5649
5650     for (curPtr = volPtr; curPos < arraySize; curPtr++) {
5651         if (curPtr->volFlags & ENTRYVALID) {
5652
5653             curPtr->volFlags |= CLONEVALID;
5654             /*make a clone of curParentId and record as curPtr->volCloneId */
5655             code =
5656                 AFSVolTransCreate_retry(aconn, curPtr->volId, apart, ITOffline,
5657                                   &tid);
5658             if (code)
5659                 VPRINT2("Clone for volume %s %u failed \n", curPtr->volName,
5660                         curPtr->volId);
5661             if (code) {
5662                 curPtr->volFlags &= ~CLONEVALID;        /*cant clone */
5663                 curPos++;
5664                 continue;
5665             }
5666             if (strlen(curPtr->volName) < (VOLSER_OLDMAXVOLNAME - 9)) {
5667                 strcpy(cloneName, curPtr->volName);
5668                 strcat(cloneName, "-tmpClone-");
5669             } else
5670                 strcpy(cloneName, "-tmpClone");
5671             if (reuseCloneId) {
5672                 curPtr->volCloneId = curCloneId;
5673                 curCloneId++;
5674             }
5675
5676             code =
5677                 AFSVolClone(aconn, tid, 0, readonlyVolume, cloneName,
5678                             &(curPtr->volCloneId));
5679             if (code) {
5680                 curPtr->volFlags &= ~CLONEVALID;
5681                 curPos++;
5682                 fprintf(STDERR, "Could not clone %s due to error %lu\n",
5683                         curPtr->volName, (unsigned long)code);
5684                 code = AFSVolEndTrans(aconn, tid, &rcode);
5685                 if (code)
5686                     fprintf(STDERR, "WARNING: could not end transaction\n");
5687                 continue;
5688             }
5689             VPRINT2("********** Cloned %s temporary %u\n", cloneName,
5690                     curPtr->volCloneId);
5691             code = AFSVolEndTrans(aconn, tid, &rcode);
5692             if (code || rcode) {
5693                 curPtr->volFlags &= ~CLONEVALID;
5694                 curPos++;
5695                 continue;
5696             }
5697
5698             curPos++;
5699         }
5700     }
5701     if (aconn)
5702         rx_DestroyConnection(aconn);
5703     return 0;
5704 }
5705
5706
5707 /*list all the volumes on <aserver> and <apart>. If all = 1, then all the
5708 * relevant fields of the volume are also returned. This is a heavy weight operation.*/
5709 int
5710 UV_ListVolumes(afs_uint32 aserver, afs_int32 apart, int all,
5711                struct volintInfo **resultPtr, afs_int32 * size)
5712 {
5713     struct rx_connection *aconn;
5714     afs_int32 code = 0;
5715     volEntries volumeInfo;
5716
5717     code = 0;
5718     *size = 0;
5719     *resultPtr = (volintInfo *) 0;
5720     volumeInfo.volEntries_val = (volintInfo *) 0;       /*this hints the stub to allocate space */
5721     volumeInfo.volEntries_len = 0;
5722
5723     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
5724     code = AFSVolListVolumes(aconn, apart, all, &volumeInfo);
5725     if (code) {
5726         fprintf(STDERR,
5727                 "Could not fetch the list of volumes from the server\n");
5728     } else {
5729         *resultPtr = volumeInfo.volEntries_val;
5730         *size = volumeInfo.volEntries_len;
5731     }
5732
5733     if (aconn)
5734         rx_DestroyConnection(aconn);
5735     PrintError("", code);
5736     return code;
5737 }
5738
5739 /*------------------------------------------------------------------------
5740  * EXPORTED UV_XListVolumes
5741  *
5742  * Description:
5743  *      List the extended information for all the volumes on a particular
5744  *      File Server and partition.  We may either return the volume's ID
5745  *      or all of its extended information.
5746  *
5747  * Arguments:
5748  *      a_serverID         : Address of the File Server for which we want
5749  *                              extended volume info.
5750  *      a_partID           : Partition for which we want the extended
5751  *                              volume info.
5752  *      a_all              : If non-zero, fetch ALL the volume info,
5753  *                              otherwise just the volume ID.
5754  *      a_resultPP         : Ptr to the address of the area containing
5755  *                              the returned volume info.
5756  *      a_numEntsInResultP : Ptr for the value we set for the number of
5757  *                              entries returned.
5758  *
5759  * Returns:
5760  *      0 on success,
5761  *      Otherise, the return value of AFSVolXListVolumes.
5762  *
5763  * Environment:
5764  *      This routine is closely related to UV_ListVolumes, which returns
5765  *      only the standard level of detail on AFS volumes. It is a
5766  *      heavyweight operation, zipping through all the volume entries for
5767  *      a given server/partition.
5768  *
5769  * Side Effects:
5770  *      As advertised.
5771  *------------------------------------------------------------------------*/
5772
5773 int
5774 UV_XListVolumes(afs_uint32 a_serverID, afs_int32 a_partID, int a_all,
5775                 struct volintXInfo **a_resultPP,
5776                 afs_int32 * a_numEntsInResultP)
5777 {
5778     struct rx_connection *rxConnP;      /*Ptr to the Rx connection involved */
5779     afs_int32 code;             /*Error code to return */
5780     volXEntries volumeXInfo;    /*Area for returned extended vol info */
5781
5782     /*
5783      * Set up our error code and the area for returned extended volume info.
5784      * We set the val field to a null pointer as a hint for the stub to
5785      * allocate space.
5786      */
5787     *a_numEntsInResultP = 0;
5788     *a_resultPP = (volintXInfo *) 0;
5789     volumeXInfo.volXEntries_val = (volintXInfo *) 0;
5790     volumeXInfo.volXEntries_len = 0;
5791
5792     /*
5793      * Bind to the Volume Server port on the File Server machine in question,
5794      * then go for it.
5795      */
5796     rxConnP = UV_Bind(a_serverID, AFSCONF_VOLUMEPORT);
5797     code = AFSVolXListVolumes(rxConnP, a_partID, a_all, &volumeXInfo);
5798     if (code)
5799         fprintf(STDERR, "[UV_XListVolumes] Couldn't fetch volume list\n");
5800     else {
5801         /*
5802          * We got the info; pull out the pointer to where the results lie
5803          * and how many entries are there.
5804          */
5805         *a_resultPP = volumeXInfo.volXEntries_val;
5806         *a_numEntsInResultP = volumeXInfo.volXEntries_len;
5807     }
5808
5809     /*
5810      * If we got an Rx connection, throw it away.
5811      */
5812     if (rxConnP)
5813         rx_DestroyConnection(rxConnP);
5814
5815     PrintError("", code);
5816     return (code);
5817 }                               /*UV_XListVolumes */
5818
5819 /* get all the information about volume <volid> on <aserver> and <apart> */
5820 int
5821 UV_ListOneVolume(afs_uint32 aserver, afs_int32 apart, afs_uint32 volid,
5822                  struct volintInfo **resultPtr)
5823 {
5824     struct rx_connection *aconn;
5825     afs_int32 code = 0;
5826     volEntries volumeInfo;
5827
5828     *resultPtr = (volintInfo *) 0;
5829     volumeInfo.volEntries_val = (volintInfo *) 0;       /*this hints the stub to allocate space */
5830     volumeInfo.volEntries_len = 0;
5831
5832     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
5833     code = AFSVolListOneVolume(aconn, apart, volid, &volumeInfo);
5834     if (code) {
5835         fprintf(STDERR,
5836                 "Could not fetch the information about volume %lu from the server\n",
5837                 (unsigned long)volid);
5838     } else {
5839         *resultPtr = volumeInfo.volEntries_val;
5840
5841     }
5842
5843     if (aconn)
5844         rx_DestroyConnection(aconn);
5845     PrintError("", code);
5846     return code;
5847 }
5848
5849 /*------------------------------------------------------------------------
5850  * EXPORTED UV_XListOneVolume
5851  *
5852  * Description:
5853  *      List the extended information for a volume on a particular File
5854  *      Server and partition.
5855  *
5856  * Arguments:
5857  *      a_serverID         : Address of the File Server for which we want
5858  *                              extended volume info.
5859  *      a_partID           : Partition for which we want the extended
5860  *                              volume info.
5861  *      a_volID            : Volume ID for which we want the info.
5862  *      a_resultPP         : Ptr to the address of the area containing
5863  *                              the returned volume info.
5864  *
5865  * Returns:
5866  *      0 on success,
5867  *      Otherise, the return value of AFSVolXListOneVolume.
5868  *
5869  * Environment:
5870  *      This routine is closely related to UV_ListOneVolume, which returns
5871  *      only the standard level of detail on the chosen AFS volume.
5872  *
5873  * Side Effects:
5874  *      As advertised.
5875  *------------------------------------------------------------------------*/
5876
5877 int
5878 UV_XListOneVolume(afs_uint32 a_serverID, afs_int32 a_partID, afs_uint32 a_volID,
5879                   struct volintXInfo **a_resultPP)
5880 {
5881     struct rx_connection *rxConnP;      /*Rx connection to Volume Server */
5882     afs_int32 code;             /*Error code */
5883     volXEntries volumeXInfo;    /*Area for returned info */
5884
5885     /*
5886      * Set up our error code, and the area we're in which we are returning
5887      * the info.  Setting the val field to a null pointer tells the stub
5888      * to allocate space for us.
5889      */
5890     *a_resultPP = (volintXInfo *) 0;
5891     volumeXInfo.volXEntries_val = (volintXInfo *) 0;
5892     volumeXInfo.volXEntries_len = 0;
5893
5894     /*
5895      * Bind to the Volume Server port on the File Server machine in question,
5896      * then go for it.
5897      */
5898     rxConnP = UV_Bind(a_serverID, AFSCONF_VOLUMEPORT);
5899     code = AFSVolXListOneVolume(rxConnP, a_partID, a_volID, &volumeXInfo);
5900     if (code)
5901         fprintf(STDERR,
5902                 "[UV_XListOneVolume] Couldn't fetch the volume information\n");
5903     else
5904         /*
5905          * We got the info; pull out the pointer to where the results lie.
5906          */
5907         *a_resultPP = volumeXInfo.volXEntries_val;
5908
5909     /*
5910      * If we got an Rx connection, throw it away.
5911      */
5912     if (rxConnP)
5913         rx_DestroyConnection(rxConnP);
5914
5915     PrintError("", code);
5916     return code;
5917 }
5918
5919 /* CheckVolume()
5920  *    Given a volume we read from a partition, check if it is
5921  *    represented in the VLDB correctly.
5922  *
5923  *    The VLDB is looked up by the RW volume id (not its name).
5924  *    The RW contains the true name of the volume (BK and RO set
5925  *       the name in the VLDB only on creation of the VLDB entry).
5926  *    We want rules strict enough that when we check all volumes
5927  *       on one partition, it does not need to be done again. IE:
5928  *       two volumes on different partitions won't constantly
5929  *       change a VLDB entry away from what the other set.
5930  *    For RW and BK volumes, we will always check the VLDB to see
5931  *       if the two exist on the server/partition. May seem redundant,
5932  *       but this is an easy check of the VLDB. IE: if the VLDB entry
5933  *       says the BK exists but no BK volume is there, we will detect
5934  *       this when we check the RW volume.
5935  *    VLDB entries are locked only when a change needs to be done.
5936  *    Output changed to look a lot like the "vos syncserv" otuput.
5937  */
5938 static afs_int32
5939 CheckVolume(volintInfo * volumeinfo, afs_uint32 aserver, afs_int32 apart,
5940             afs_int32 * modentry, afs_uint32 * maxvolid,
5941             struct nvldbentry *aentry)
5942 {
5943     int idx = 0;
5944     int j;
5945     afs_int32 code, error = 0;
5946     struct nvldbentry entry, storeEntry;
5947     char pname[10];
5948     int pass = 0, createentry, addvolume, modified, mod, doit = 1;
5949     afs_uint32 rwvolid;
5950     char hoststr[16];
5951
5952     if (modentry) {
5953         if (*modentry == 1)
5954             doit = 0;
5955         *modentry = 0;
5956     }
5957     rwvolid =
5958         ((volumeinfo->type ==
5959           RWVOL) ? volumeinfo->volid : volumeinfo->parentID);
5960
5961   retry:
5962     /* Check to see if the VLDB is ok without locking it (pass 1).
5963      * If it will change, then lock the VLDB entry, read it again,
5964      * then make the changes to it (pass 2).
5965      */
5966     if (++pass == 2) {
5967         code = ubik_VL_SetLock(cstruct, 0, rwvolid, RWVOL, VLOP_DELETE);
5968         if (code) {
5969             fprintf(STDERR, "Could not lock VLDB entry for %lu\n",
5970                     (unsigned long)rwvolid);
5971             ERROR_EXIT(code);
5972         }
5973     }
5974
5975     createentry = 0;            /* Do we need to create a VLDB entry */
5976     addvolume = 0;              /* Add this volume to the VLDB entry */
5977     modified = 0;               /* The VLDB entry was modified */
5978
5979     if (aentry) {
5980         memcpy(&entry, aentry, sizeof(entry));
5981     } else {
5982         /* Read the entry from VLDB by its RW volume id */
5983         code = VLDB_GetEntryByID(rwvolid, RWVOL, &entry);
5984         if (code) {
5985             if (code != VL_NOENT) {
5986                 fprintf(STDOUT,
5987                         "Could not retrieve the VLDB entry for volume %lu \n",
5988                         (unsigned long)rwvolid);
5989                 ERROR_EXIT(code);
5990             }
5991
5992             memset(&entry, 0, sizeof(entry));
5993             vsu_ExtractName(entry.name, volumeinfo->name);      /* Store name of RW */
5994
5995             createentry = 1;
5996         } else {
5997             MapHostToNetwork(&entry);
5998         }
5999     }
6000
6001     if (verbose && (pass == 1)) {
6002         fprintf(STDOUT, "_______________________________\n");
6003         fprintf(STDOUT, "\n-- status before -- \n");
6004         if (createentry) {
6005             fprintf(STDOUT, "\n**does not exist**\n");
6006         } else {
6007             if ((entry.flags & RW_EXISTS) || (entry.flags & RO_EXISTS)
6008                 || (entry.flags & BACK_EXISTS))
6009                 EnumerateEntry(&entry);
6010         }
6011         fprintf(STDOUT, "\n");
6012     }
6013
6014     if (volumeinfo->type == RWVOL) {    /* RW volume exists */
6015         if (createentry) {
6016             idx = 0;
6017             entry.nServers = 1;
6018             addvolume++;
6019         } else {
6020             /* Check existence of RW and BK volumes */
6021             code = CheckVldbRWBK(&entry, &mod);
6022             if (code)
6023                 ERROR_EXIT(code);
6024             if (mod)
6025                 modified++;
6026
6027             idx = Lp_GetRwIndex(&entry);
6028             if (idx == -1) {    /* RW index not found in the VLDB entry */
6029                 idx = entry.nServers;   /* put it into next index */
6030                 entry.nServers++;
6031                 addvolume++;
6032             } else {            /* RW index found in the VLDB entry. */
6033                 /* Verify if this volume's location matches where the VLDB says it is */
6034                 if (!Lp_Match(aserver, apart, &entry)) {
6035                     if (entry.flags & RW_EXISTS) {
6036                         /* The RW volume exists elsewhere - report this one a duplicate */
6037                         if (pass == 1) {
6038                             MapPartIdIntoName(apart, pname);
6039                             fprintf(STDERR,
6040                                     "*** Warning: Orphaned RW volume %lu exists on %s %s\n",
6041                                     (unsigned long)rwvolid,
6042                                     noresolve ?
6043                                     afs_inet_ntoa_r(aserver, hoststr) :
6044                                     hostutil_GetNameByINet(aserver), pname);
6045                             MapPartIdIntoName(entry.serverPartition[idx],
6046                                               pname);
6047                             fprintf(STDERR,
6048                                     "    VLDB reports RW volume %lu exists on %s %s\n",
6049                                     (unsigned long)rwvolid,
6050                                     noresolve ?
6051                                     afs_inet_ntoa_r(entry.serverNumber[idx], hoststr) :
6052                                     hostutil_GetNameByINet(entry.
6053                                                            serverNumber[idx]),
6054                                     pname);
6055                         }
6056                     } else {
6057                         /* The RW volume does not exist - have VLDB point to this one */
6058                         addvolume++;
6059
6060                         /* Check for orphaned BK volume on old partition */
6061                         if (entry.flags & BACK_EXISTS) {
6062                             if (pass == 1) {
6063                                 MapPartIdIntoName(entry.serverPartition[idx],
6064                                                   pname);
6065                                 fprintf(STDERR,
6066                                         "*** Warning: Orphaned BK volume %u exists on %s %s\n",
6067                                         entry.volumeId[BACKVOL],
6068                                         noresolve ?
6069                                         afs_inet_ntoa_r(entry.serverNumber[idx], hoststr) :
6070                                         hostutil_GetNameByINet(entry.
6071                                                                serverNumber
6072                                                                [idx]), pname);
6073                                 MapPartIdIntoName(apart, pname);
6074                                 fprintf(STDERR,
6075                                         "    VLDB reports its RW volume %lu exists on %s %s\n",
6076                                         (unsigned long)rwvolid,
6077                                         noresolve ?
6078                                         afs_inet_ntoa_r(aserver, hoststr) :
6079                                         hostutil_GetNameByINet(aserver),
6080                                         pname);
6081                             }
6082                         }
6083                     }
6084                 } else {
6085                     /* Volume location matches the VLDB location */
6086                     if ((volumeinfo->backupID && !entry.volumeId[BACKVOL])
6087                         || (volumeinfo->cloneID && !entry.volumeId[ROVOL])
6088                         ||
6089                         (strncmp
6090                          (entry.name, volumeinfo->name,
6091                           VOLSER_OLDMAXVOLNAME) != 0)) {
6092                         addvolume++;
6093                     }
6094                 }
6095             }
6096         }
6097
6098         if (addvolume) {
6099             entry.flags |= RW_EXISTS;
6100             entry.volumeId[RWVOL] = rwvolid;
6101             if (!entry.volumeId[BACKVOL])
6102                 entry.volumeId[BACKVOL] = volumeinfo->backupID;
6103             if (!entry.volumeId[ROVOL])
6104                 entry.volumeId[ROVOL] = volumeinfo->cloneID;
6105
6106             entry.serverFlags[idx] = ITSRWVOL;
6107             entry.serverNumber[idx] = aserver;
6108             entry.serverPartition[idx] = apart;
6109             strncpy(entry.name, volumeinfo->name, VOLSER_OLDMAXVOLNAME);
6110
6111             modified++;
6112
6113             /* One last check - to update BK if need to */
6114             code = CheckVldbRWBK(&entry, &mod);
6115             if (code)
6116                 ERROR_EXIT(code);
6117             if (mod)
6118                 modified++;
6119         }
6120     }
6121
6122     else if (volumeinfo->type == BACKVOL) {     /* A BK volume */
6123         if (createentry) {
6124             idx = 0;
6125             entry.nServers = 1;
6126             addvolume++;
6127         } else {
6128             /* Check existence of RW and BK volumes */
6129             code = CheckVldbRWBK(&entry, &mod);
6130             if (code)
6131                 ERROR_EXIT(code);
6132             if (mod)
6133                 modified++;
6134
6135             idx = Lp_GetRwIndex(&entry);
6136             if (idx == -1) {    /* RW index not found in the VLDB entry */
6137                 idx = entry.nServers;   /* Put it into next index */
6138                 entry.nServers++;
6139                 addvolume++;
6140             } else {            /* RW index found in the VLDB entry */
6141                 /* Verify if this volume's location matches where the VLDB says it is */
6142                 if (!Lp_Match(aserver, apart, &entry)) {
6143                     /* VLDB says RW and/or BK is elsewhere - report this BK volume orphaned */
6144                     if (pass == 1) {
6145                         MapPartIdIntoName(apart, pname);
6146                         fprintf(STDERR,
6147                                 "*** Warning: Orphaned BK volume %lu exists on %s %s\n",
6148                                 (unsigned long)volumeinfo->volid,
6149                                 noresolve ?
6150                                 afs_inet_ntoa_r(aserver, hoststr) :
6151                                 hostutil_GetNameByINet(aserver), pname);
6152                         MapPartIdIntoName(entry.serverPartition[idx], pname);
6153                         fprintf(STDERR,
6154                                 "    VLDB reports its RW/BK volume %lu exists on %s %s\n",
6155                                 (unsigned long)rwvolid,
6156                                 noresolve ?
6157                                 afs_inet_ntoa_r(entry.serverNumber[idx], hoststr) :
6158                                 hostutil_GetNameByINet(entry.
6159                                                        serverNumber[idx]),
6160                                 pname);
6161                     }
6162                 } else {
6163                     if (volumeinfo->volid != entry.volumeId[BACKVOL]) {
6164                         if (!(entry.flags & BACK_EXISTS)) {
6165                             addvolume++;
6166                         } else if (volumeinfo->volid >
6167                                    entry.volumeId[BACKVOL]) {
6168                             addvolume++;
6169
6170                             if (pass == 1) {
6171                                 MapPartIdIntoName(entry.serverPartition[idx],
6172                                                   pname);
6173                                 fprintf(STDERR,
6174                                         "*** Warning: Orphaned BK volume %u exists on %s %s\n",
6175                                         entry.volumeId[BACKVOL],
6176                                         noresolve ?
6177                                         afs_inet_ntoa_r(aserver, hoststr) :
6178                                         hostutil_GetNameByINet(aserver),
6179                                         pname);
6180                                 fprintf(STDERR,
6181                                         "    VLDB reports its BK volume ID is %lu\n",
6182                                         (unsigned long)volumeinfo->volid);
6183                             }
6184                         } else {
6185                             if (pass == 1) {
6186                                 MapPartIdIntoName(entry.serverPartition[idx],
6187                                                   pname);
6188                                 fprintf(STDERR,
6189                                         "*** Warning: Orphaned BK volume %lu exists on %s %s\n",
6190                                         (unsigned long)volumeinfo->volid,
6191                                         noresolve ?
6192                                         afs_inet_ntoa_r(aserver, hoststr) :
6193                                         hostutil_GetNameByINet(aserver),
6194                                         pname);
6195                                 fprintf(STDERR,
6196                                         "    VLDB reports its BK volume ID is %u\n",
6197                                         entry.volumeId[BACKVOL]);
6198                             }
6199                         }
6200                     } else if (!entry.volumeId[BACKVOL]) {
6201                         addvolume++;
6202                     }
6203                 }
6204             }
6205         }
6206         if (addvolume) {
6207             entry.flags |= BACK_EXISTS;
6208             entry.volumeId[RWVOL] = rwvolid;
6209             entry.volumeId[BACKVOL] = volumeinfo->volid;
6210
6211             entry.serverNumber[idx] = aserver;
6212             entry.serverPartition[idx] = apart;
6213             entry.serverFlags[idx] = ITSBACKVOL;
6214
6215             modified++;
6216         }
6217     }
6218
6219     else if (volumeinfo->type == ROVOL) {       /* A RO volume */
6220         if (volumeinfo->volid == entry.volumeId[ROVOL]) {
6221             /* This is a quick check to see if the RO entry exists in the
6222              * VLDB so we avoid the CheckVldbRO() call (which checks if each
6223              * RO volume listed in the VLDB exists).
6224              */
6225             idx = Lp_ROMatch(aserver, apart, &entry) - 1;
6226             if (idx == -1) {
6227                 idx = entry.nServers;
6228                 entry.nServers++;
6229                 addvolume++;
6230             } else {
6231                 if (!(entry.flags & RO_EXISTS)) {
6232                     addvolume++;
6233                 }
6234             }
6235         } else {
6236             /* Before we correct the VLDB entry, make sure all the
6237              * ROs listed in the VLDB exist.
6238              */
6239             code = CheckVldbRO(&entry, &mod);
6240             if (code)
6241                 ERROR_EXIT(code);
6242             if (mod)
6243                 modified++;
6244
6245             if (!(entry.flags & RO_EXISTS)) {
6246                 /* No RO exists in the VLDB entry - add this one */
6247                 idx = entry.nServers;
6248                 entry.nServers++;
6249                 addvolume++;
6250             } else if (volumeinfo->volid > entry.volumeId[ROVOL]) {
6251                 /* The volume headers's RO ID does not match that in the VLDB entry,
6252                  * and the vol hdr's ID is greater (implies more recent). So delete
6253                  * all the RO volumes listed in VLDB entry and add this volume.
6254                  */
6255                 for (j = 0; j < entry.nServers; j++) {
6256                     if (entry.serverFlags[j] & ITSROVOL) {
6257                         /* Verify this volume exists and print message we are orphaning it */
6258                         if (pass == 1) {
6259                             MapPartIdIntoName(apart, pname);
6260                             fprintf(STDERR,
6261                                     "*** Warning: Orphaned RO volume %u exists on %s %s\n",
6262                                     entry.volumeId[ROVOL],
6263                                     noresolve ?
6264                                     afs_inet_ntoa_r(entry.serverNumber[j], hoststr) :
6265                                     hostutil_GetNameByINet(entry.
6266                                                            serverNumber[j]),
6267                                     pname);
6268                             fprintf(STDERR,
6269                                     "    VLDB reports its RO volume ID is %lu\n",
6270                                     (unsigned long)volumeinfo->volid);
6271                         }
6272
6273                         Lp_SetRWValue(&entry, entry.serverNumber[idx],
6274                                       entry.serverPartition[idx], 0L, 0L);
6275                         entry.nServers--;
6276                         modified++;
6277                         j--;
6278                     }
6279                 }
6280
6281                 idx = entry.nServers;
6282                 entry.nServers++;
6283                 addvolume++;
6284             } else if (volumeinfo->volid < entry.volumeId[ROVOL]) {
6285                 /* The volume headers's RO ID does not match that in the VLDB entry,
6286                  * and the vol hdr's ID is lower (implies its older). So orphan it.
6287                  */
6288                 if (pass == 1) {
6289                     MapPartIdIntoName(apart, pname);
6290                     fprintf(STDERR,
6291                             "*** Warning: Orphaned RO volume %lu exists on %s %s\n",
6292                             (unsigned long)volumeinfo->volid,
6293                             noresolve ?
6294                             afs_inet_ntoa_r(aserver, hoststr) :
6295                             hostutil_GetNameByINet(aserver), pname);
6296                     fprintf(STDERR,
6297                             "    VLDB reports its RO volume ID is %u\n",
6298                             entry.volumeId[ROVOL]);
6299                 }
6300             } else {
6301                 /* The RO volume ID in the volume header match that in the VLDB entry,
6302                  * and there exist RO volumes in the VLDB entry. See if any of them
6303                  * are this one. If not, then we add it.
6304                  */
6305                 idx = Lp_ROMatch(aserver, apart, &entry) - 1;
6306                 if (idx == -1) {
6307                     idx = entry.nServers;
6308                     entry.nServers++;
6309                     addvolume++;
6310                 }
6311             }
6312         }
6313
6314         if (addvolume) {
6315             entry.flags |= RO_EXISTS;
6316             entry.volumeId[RWVOL] = rwvolid;
6317             entry.volumeId[ROVOL] = volumeinfo->volid;
6318
6319             entry.serverNumber[idx] = aserver;
6320             entry.serverPartition[idx] = apart;
6321             entry.serverFlags[idx] = ITSROVOL;
6322
6323             modified++;
6324         }
6325     }
6326
6327     /* Remember largest volume id */
6328     if (entry.volumeId[ROVOL] > *maxvolid)
6329         *maxvolid = entry.volumeId[ROVOL];
6330     if (entry.volumeId[BACKVOL] > *maxvolid)
6331         *maxvolid = entry.volumeId[BACKVOL];
6332     if (entry.volumeId[RWVOL] > *maxvolid)
6333         *maxvolid = entry.volumeId[RWVOL];
6334
6335     if (modified && doit) {
6336         MapNetworkToHost(&entry, &storeEntry);
6337
6338         if (createentry) {
6339             code = VLDB_CreateEntry(&storeEntry);
6340             if (code) {
6341                 fprintf(STDOUT,
6342                         "Could not create a VLDB entry for the volume %lu\n",
6343                         (unsigned long)rwvolid);
6344                 ERROR_EXIT(code);
6345             }
6346         } else {
6347             if (pass == 1)
6348                 goto retry;
6349             code =
6350                 VLDB_ReplaceEntry(rwvolid, RWVOL, &storeEntry,
6351                                   LOCKREL_OPCODE | LOCKREL_AFSID |
6352                                   LOCKREL_TIMESTAMP);
6353             if (code) {
6354                 fprintf(STDERR, "Could not update entry for %lu\n",
6355                         (unsigned long)rwvolid);
6356                 ERROR_EXIT(code);
6357             }
6358         }
6359     } else if (pass == 2) {
6360         code =
6361             ubik_VL_ReleaseLock(cstruct, 0, rwvolid, RWVOL,
6362                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
6363         if (code) {
6364             PrintError("Could not unlock VLDB entry ", code);
6365         }
6366     }
6367
6368     if (modified && modentry) {
6369         *modentry = 1;
6370     }
6371
6372     if (aentry) {
6373         memcpy(aentry, &entry, sizeof(entry));
6374     }
6375
6376     if (verbose) {
6377         fprintf(STDOUT, "-- status after --\n");
6378         if (modified)
6379             EnumerateEntry(&entry);
6380         else
6381             fprintf(STDOUT, "\n**no change**\n");
6382     }
6383
6384   error_exit:
6385     VPRINT("\n_______________________________\n");
6386     return (error);
6387 }
6388
6389 static int
6390 sortVolumes(const void *a, const void *b)
6391 {
6392     volintInfo *v1 = (volintInfo *) a;
6393     volintInfo *v2 = (volintInfo *) b;
6394     afs_uint32 rwvolid1, rwvolid2;
6395
6396     rwvolid1 = ((v1->type == RWVOL) ? v1->volid : v1->parentID);
6397     rwvolid2 = ((v2->type == RWVOL) ? v2->volid : v2->parentID);
6398
6399     if (rwvolid1 > rwvolid2)
6400         return -1;              /* lower RW id goes first */
6401     if (rwvolid1 < rwvolid2)
6402         return 1;
6403
6404     if (v1->type == RWVOL)
6405         return -1;              /* RW vols go first */
6406     if (v2->type == RWVOL)
6407         return 1;
6408
6409     if ((v1->type == BACKVOL) && (v2->type == ROVOL))
6410         return -1;              /* BK vols next */
6411     if ((v1->type == ROVOL) && (v2->type == BACKVOL))
6412         return 1;
6413
6414     if (v1->volid < v2->volid)
6415         return 1;               /* larger volids first */
6416     if (v1->volid > v2->volid)
6417         return -1;
6418     return 0;
6419 }
6420
6421 /* UV_SyncVolume()
6422  *      Synchronise <aserver> <apart>(if flags = 1) <avolid>.
6423  *      Synchronize an individual volume against a sever and partition.
6424  *      Checks the VLDB entry (similar to syncserv) as well as checks
6425  *      if the volume exists on specified servers (similar to syncvldb).
6426  */
6427 int
6428 UV_SyncVolume(afs_uint32 aserver, afs_int32 apart, char *avolname, int flags)
6429 {
6430     struct rx_connection *aconn = 0;
6431     afs_int32 j, k, code, vcode, error = 0;
6432     afs_int32 tverbose;
6433     afs_int32 mod, modified = 0, deleted = 0;
6434     struct nvldbentry vldbentry;
6435     afs_uint32 volumeid = 0;
6436     volEntries volumeInfo;
6437     struct partList PartList;
6438     afs_int32 pcnt;
6439     afs_uint32 maxvolid = 0;
6440
6441     volumeInfo.volEntries_val = (volintInfo *) 0;
6442     volumeInfo.volEntries_len = 0;
6443
6444     /* Turn verbose logging off and do our own verbose logging */
6445     /* tverbose must be set before we call ERROR_EXIT() */
6446
6447     tverbose = verbose;
6448     if (flags & 2)
6449         tverbose = 1;
6450     verbose = 0;
6451
6452     if (!aserver && (flags & 1)) {
6453         /* fprintf(STDERR,"Partition option requires a server option\n"); */
6454         ERROR_EXIT(EINVAL);
6455     }
6456
6457     /* Read the VLDB entry */
6458     vcode = VLDB_GetEntryByName(avolname, &vldbentry);
6459     if (vcode && (vcode != VL_NOENT)) {
6460         fprintf(STDERR, "Could not access the VLDB for volume %s\n",
6461                 avolname);
6462         ERROR_EXIT(vcode);
6463     } else if (!vcode) {
6464         MapHostToNetwork(&vldbentry);
6465     }
6466
6467     if (tverbose) {
6468         fprintf(STDOUT, "Processing VLDB entry %s ...\n", avolname);
6469         fprintf(STDOUT, "_______________________________\n");
6470         fprintf(STDOUT, "\n-- status before -- \n");
6471         if (vcode) {
6472             fprintf(STDOUT, "\n**does not exist**\n");
6473         } else {
6474             if ((vldbentry.flags & RW_EXISTS) || (vldbentry.flags & RO_EXISTS)
6475                 || (vldbentry.flags & BACK_EXISTS))
6476                 EnumerateEntry(&vldbentry);
6477         }
6478         fprintf(STDOUT, "\n");
6479     }
6480
6481     /* Verify that all of the VLDB entries exist on the repective servers
6482      * and partitions (this does not require that avolname be a volume ID).
6483      * Equivalent to a syncserv.
6484      */
6485     if (!vcode) {
6486         /* Tell CheckVldb not to update if appropriate */
6487         if (flags & 2)
6488             mod = 1;
6489         else
6490             mod = 0;
6491         code = CheckVldb(&vldbentry, &mod, &deleted);
6492         if (code) {
6493             fprintf(STDERR, "Could not process VLDB entry for volume %s\n",
6494                     vldbentry.name);
6495             ERROR_EXIT(code);
6496         }
6497         if (mod)
6498             modified++;
6499     }
6500
6501     /* If aserver is given, we will search for the desired volume on it */
6502     if (aserver) {
6503         /* Generate array of partitions on the server that we will check */
6504         if (!(flags & 1)) {
6505             code = UV_ListPartitions(aserver, &PartList, &pcnt);
6506             if (code) {
6507                 fprintf(STDERR,
6508                         "Could not fetch the list of partitions from the server\n");
6509                 ERROR_EXIT(code);
6510             }
6511         } else {
6512             PartList.partId[0] = apart;
6513             pcnt = 1;
6514         }
6515
6516         aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
6517
6518         /* If a volume ID were given, search for it on each partition */
6519         if ((volumeid = atol(avolname))) {
6520             for (j = 0; j < pcnt; j++) {
6521                 code =
6522                     AFSVolListOneVolume(aconn, PartList.partId[j], volumeid,
6523                                         &volumeInfo);
6524                 if (code) {
6525                     if (code != ENODEV) {
6526                         fprintf(STDERR, "Could not query server\n");
6527                         ERROR_EXIT(code);
6528                     }
6529                 } else {
6530                     if (flags & 2)
6531                         mod = 1;
6532                     else
6533                         mod = 0;
6534                     /* Found one, sync it with VLDB entry */
6535                     code =
6536                         CheckVolume(volumeInfo.volEntries_val, aserver,
6537                                     PartList.partId[j], &mod, &maxvolid, &vldbentry);
6538                     if (code)
6539                         ERROR_EXIT(code);
6540                     if (mod)
6541                         modified++;
6542                 }
6543
6544                 if (volumeInfo.volEntries_val)
6545                     free(volumeInfo.volEntries_val);
6546                 volumeInfo.volEntries_val = (volintInfo *) 0;
6547                 volumeInfo.volEntries_len = 0;
6548             }
6549         }
6550
6551         /* Check to see if the RW, BK, and RO IDs exist on any
6552          * partitions. We get the volume IDs from the VLDB.
6553          */
6554         for (j = 0; j < MAXTYPES; j++) {        /* for RW, RO, and BK IDs */
6555             if (vldbentry.volumeId[j] == 0)
6556                 continue;
6557
6558             for (k = 0; k < pcnt; k++) {        /* For each partition */
6559                 volumeInfo.volEntries_val = (volintInfo *) 0;
6560                 volumeInfo.volEntries_len = 0;
6561                 code =
6562                     AFSVolListOneVolume(aconn, PartList.partId[k],
6563                                         vldbentry.volumeId[j], &volumeInfo);
6564                 if (code) {
6565                     if (code != ENODEV) {
6566                         fprintf(STDERR, "Could not query server\n");
6567                         ERROR_EXIT(code);
6568                     }
6569                 } else {
6570                     if (flags & 2)
6571                         mod = 1;
6572                     else
6573                         mod = 0;
6574                     /* Found one, sync it with VLDB entry */
6575                     code =
6576                         CheckVolume(volumeInfo.volEntries_val, aserver,
6577                                     PartList.partId[k], &mod, &maxvolid, &vldbentry);
6578                     if (code)
6579                         ERROR_EXIT(code);
6580                     if (mod)
6581                         modified++;
6582                 }
6583
6584                 if (volumeInfo.volEntries_val)
6585                     free(volumeInfo.volEntries_val);
6586                 volumeInfo.volEntries_val = (volintInfo *) 0;
6587                 volumeInfo.volEntries_len = 0;
6588             }
6589         }
6590     }
6591
6592     /* if (aserver) */
6593     /* If verbose output, print a summary of what changed */
6594     if (tverbose) {
6595         fprintf(STDOUT, "-- status after --\n");
6596         if (deleted) {
6597             fprintf(STDOUT, "\n**entry deleted**\n");
6598         } else if (modified) {
6599             EnumerateEntry(&vldbentry);
6600         } else {
6601             fprintf(STDOUT, "\n**no change**\n");
6602         }
6603         fprintf(STDOUT, "\n_______________________________\n");
6604     }
6605
6606   error_exit:
6607     /* Now check if the maxvolid is larger than that stored in the VLDB */
6608     if (maxvolid) {
6609         afs_uint32 maxvldbid = 0;
6610         code = ubik_VL_GetNewVolumeId(cstruct, 0, 0, &maxvldbid);
6611         if (code) {
6612             fprintf(STDERR,
6613                     "Could not get the highest allocated volume id from the VLDB\n");
6614             if (!error)
6615                 error = code;
6616         } else if (maxvolid > maxvldbid) {
6617             afs_uint32 id, nid;
6618             id = maxvolid - maxvldbid + 1;
6619             code = ubik_VL_GetNewVolumeId(cstruct, 0, id, &nid);
6620             if (code) {
6621                 fprintf(STDERR,
6622                         "Error in increasing highest allocated volume id in VLDB\n");
6623                 if (!error)
6624                     error = code;
6625             }
6626         }
6627     }
6628
6629     verbose = tverbose;
6630     if (verbose) {
6631         if (error)
6632             fprintf(STDOUT, "...error encountered");
6633         else
6634             fprintf(STDOUT, "...done entry\n");
6635     }
6636     if (aconn)
6637         rx_DestroyConnection(aconn);
6638     if (volumeInfo.volEntries_val)
6639         free(volumeInfo.volEntries_val);
6640
6641     PrintError("", error);
6642     return error;
6643 }
6644
6645 /* UV_SyncVldb()
6646  *      Synchronise vldb with the file server <aserver> and,
6647  *      optionally, <apart>.
6648  */
6649 int
6650 UV_SyncVldb(afs_uint32 aserver, afs_int32 apart, int flags, int force)
6651 {
6652     struct rx_connection *aconn;
6653     afs_int32 code, error = 0;
6654     int i, pfail;
6655     unsigned int j;
6656     volEntries volumeInfo;
6657     struct partList PartList;
6658     afs_int32 pcnt;
6659     char pname[10];
6660     volintInfo *vi;
6661     afs_int32 failures = 0, modifications = 0, tentries = 0;
6662     afs_int32 modified;
6663     afs_uint32 maxvolid = 0;
6664     char hoststr[16];
6665
6666     volumeInfo.volEntries_val = (volintInfo *) 0;
6667     volumeInfo.volEntries_len = 0;
6668
6669     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
6670
6671     /* Generate array of partitions to check */
6672     if (!(flags & 1)) {
6673         code = UV_ListPartitions(aserver, &PartList, &pcnt);
6674         if (code) {
6675             fprintf(STDERR,
6676                     "Could not fetch the list of partitions from the server\n");
6677             ERROR_EXIT(code);
6678         }
6679     } else {
6680         PartList.partId[0] = apart;
6681         pcnt = 1;
6682     }
6683
6684     VPRINT("Processing volume entries ...\n");
6685
6686     /* Step through the array of partitions */
6687     for (i = 0; i < pcnt; i++) {
6688         apart = PartList.partId[i];
6689         MapPartIdIntoName(apart, pname);
6690
6691         volumeInfo.volEntries_val = (volintInfo *) 0;
6692         volumeInfo.volEntries_len = 0;
6693         code = AFSVolListVolumes(aconn, apart, 1, &volumeInfo);
6694         if (code) {
6695             fprintf(STDERR,
6696                     "Could not fetch the list of volumes from the server\n");
6697             ERROR_EXIT(code);
6698         }
6699
6700         /* May want to sort the entries: RW, BK (high to low), RO (high to low) */
6701         qsort((char *)volumeInfo.volEntries_val, volumeInfo.volEntries_len,
6702               sizeof(volintInfo), sortVolumes);
6703
6704         pfail = 0;
6705         for (vi = volumeInfo.volEntries_val, j = 0;
6706              j < volumeInfo.volEntries_len; j++, vi++) {
6707             if (!vi->status)
6708                 continue;
6709
6710             tentries++;
6711
6712             if (verbose) {
6713                 fprintf(STDOUT,
6714                         "Processing volume entry %d: %s (%lu) on server %s %s...\n",
6715                         j + 1, vi->name, (unsigned long)vi->volid,
6716                         noresolve ?
6717                         afs_inet_ntoa_r(aserver, hoststr) :
6718                         hostutil_GetNameByINet(aserver), pname);
6719                 fflush(STDOUT);
6720             }
6721
6722             if (flags & 2)
6723                 modified = 1;
6724             else
6725                 modified = 0;
6726             code = CheckVolume(vi, aserver, apart, &modified, &maxvolid, NULL);
6727             if (code) {
6728                 PrintError("", code);
6729                 failures++;
6730                 pfail++;
6731             } else if (modified) {
6732                 modifications++;
6733             }
6734
6735             if (verbose) {
6736                 if (code) {
6737                     fprintf(STDOUT, "...error encountered\n\n");
6738                 } else {
6739                     fprintf(STDOUT, "...done entry %d\n\n", j + 1);
6740                 }
6741             }
6742         }
6743
6744         if (pfail) {
6745             fprintf(STDERR,
6746                     "Could not process entries on server %s partition %s\n",
6747                     noresolve ?
6748                     afs_inet_ntoa_r(aserver, hoststr) :
6749                     hostutil_GetNameByINet(aserver), pname);
6750         }
6751         if (volumeInfo.volEntries_val) {
6752             free(volumeInfo.volEntries_val);
6753             volumeInfo.volEntries_val = 0;
6754         }
6755
6756     }                           /* thru all partitions */
6757
6758     if (flags & 2) {
6759         VPRINT3("Total entries: %u, Failed to process %d, Would change %d\n",
6760                 tentries, failures, modifications);
6761     } else {
6762         VPRINT3("Total entries: %u, Failed to process %d, Changed %d\n",
6763                 tentries, failures, modifications);
6764     }
6765
6766   error_exit:
6767     /* Now check if the maxvolid is larger than that stored in the VLDB */
6768     if (maxvolid) {
6769         afs_uint32 maxvldbid = 0;
6770         code = ubik_VL_GetNewVolumeId(cstruct, 0, 0, &maxvldbid);
6771         if (code) {
6772             fprintf(STDERR,
6773                     "Could not get the highest allocated volume id from the VLDB\n");
6774             if (!error)
6775                 error = code;
6776         } else if (maxvolid > maxvldbid) {
6777             afs_uint32 id, nid;
6778             id = maxvolid - maxvldbid + 1;
6779             code = ubik_VL_GetNewVolumeId(cstruct, 0, id, &nid);
6780             if (code) {
6781                 fprintf(STDERR,
6782                         "Error in increasing highest allocated volume id in VLDB\n");
6783                 if (!error)
6784                     error = code;
6785             }
6786         }
6787     }
6788
6789     if (aconn)
6790         rx_DestroyConnection(aconn);
6791     if (volumeInfo.volEntries_val)
6792         free(volumeInfo.volEntries_val);
6793     PrintError("", error);
6794     return (error);
6795 }
6796
6797 /* VolumeExists()
6798  *      Determine if a volume exists on a server and partition.
6799  *      Try creating a transaction on the volume. If we can,
6800  *      the volume exists, if not, then return the error code.
6801  *      Some error codes mean the volume is unavailable but
6802  *      still exists - so we catch these error codes.
6803  */
6804 static afs_int32
6805 VolumeExists(afs_uint32 server, afs_int32 partition, afs_uint32 volumeid)
6806 {
6807     struct rx_connection *conn = (struct rx_connection *)0;
6808     afs_int32 code = -1;
6809     volEntries volumeInfo;
6810
6811     conn = UV_Bind(server, AFSCONF_VOLUMEPORT);
6812     if (conn) {
6813         volumeInfo.volEntries_val = (volintInfo *) 0;
6814         volumeInfo.volEntries_len = 0;
6815         code = AFSVolListOneVolume(conn, partition, volumeid, &volumeInfo);
6816         if (volumeInfo.volEntries_val)
6817             free(volumeInfo.volEntries_val);
6818         if (code == VOLSERILLEGAL_PARTITION)
6819             code = ENODEV;
6820         rx_DestroyConnection(conn);
6821     }
6822     return code;
6823 }
6824
6825 /* CheckVldbRWBK()
6826  *
6827  */
6828 static afs_int32
6829 CheckVldbRWBK(struct nvldbentry * entry, afs_int32 * modified)
6830 {
6831     int modentry = 0;
6832     int idx;
6833     afs_int32 code, error = 0;
6834     char pname[10];
6835     char hoststr[16];
6836
6837     if (modified)
6838         *modified = 0;
6839     idx = Lp_GetRwIndex(entry);
6840
6841     /* Check to see if the RW volume exists and set the RW_EXISTS
6842      * flag accordingly.
6843      */
6844     if (idx == -1) {            /* Did not find a RW entry */
6845         if (entry->flags & RW_EXISTS) { /* ... yet entry says RW exists */
6846             entry->flags &= ~RW_EXISTS; /* ... so say RW does not exist */
6847             modentry++;
6848         }
6849     } else {
6850         code =
6851             VolumeExists(entry->serverNumber[idx],
6852                          entry->serverPartition[idx], entry->volumeId[RWVOL]);
6853         if (code == 0) {        /* RW volume exists */
6854             if (!(entry->flags & RW_EXISTS)) {  /* ... yet entry says RW does not exist */
6855                 entry->flags |= RW_EXISTS;      /* ... so say RW does exist */
6856                 modentry++;
6857             }
6858         } else if (code == ENODEV) {    /* RW volume does not exist */
6859             if (entry->flags & RW_EXISTS) {     /* ... yet entry says RW exists */
6860                 entry->flags &= ~RW_EXISTS;     /* ... so say RW does not exist */
6861                 modentry++;
6862             }
6863         } else {
6864             /* If VLDB says it didn't exist, then ignore error */
6865             if (entry->flags & RW_EXISTS) {
6866                 MapPartIdIntoName(entry->serverPartition[idx], pname);
6867                 fprintf(STDERR,
6868                         "Transaction call failed for RW volume %u on server %s %s\n",
6869                         entry->volumeId[RWVOL],
6870                         noresolve ?
6871                         afs_inet_ntoa_r(entry->serverNumber[idx], hoststr) :
6872                         hostutil_GetNameByINet(entry->serverNumber[idx]),
6873                         pname);
6874                 ERROR_EXIT(code);
6875             }
6876         }
6877     }
6878
6879     /* Check to see if the BK volume exists and set the BACK_EXISTS
6880      * flag accordingly. idx already ponts to the RW entry.
6881      */
6882     if (idx == -1) {            /* Did not find a RW entry */
6883         if (entry->flags & BACK_EXISTS) {       /* ... yet entry says BK exists */
6884             entry->flags &= ~BACK_EXISTS;       /* ... so say BK does not exist */
6885             modentry++;
6886         }
6887     } else {                    /* Found a RW entry */
6888         code =
6889             VolumeExists(entry->serverNumber[idx],
6890                          entry->serverPartition[idx],
6891                          entry->volumeId[BACKVOL]);
6892         if (code == 0) {        /* BK volume exists */
6893             if (!(entry->flags & BACK_EXISTS)) {        /* ... yet entry says BK does not exist */
6894                 entry->flags |= BACK_EXISTS;    /* ... so say BK does exist */
6895                 modentry++;
6896             }
6897         } else if (code == ENODEV) {    /* BK volume does not exist */
6898             if (entry->flags & BACK_EXISTS) {   /* ... yet entry says BK exists */
6899                 entry->flags &= ~BACK_EXISTS;   /* ... so say BK does not exist */
6900                 modentry++;
6901             }
6902         } else {
6903             /* If VLDB says it didn't exist, then ignore error */
6904             if (entry->flags & BACK_EXISTS) {
6905                 MapPartIdIntoName(entry->serverPartition[idx], pname);
6906                 fprintf(STDERR,
6907                         "Transaction call failed for BK volume %u on server %s %s\n",
6908                         entry->volumeId[BACKVOL],
6909                         noresolve ?
6910                         afs_inet_ntoa_r(entry->serverNumber[idx], hoststr) :
6911                         hostutil_GetNameByINet(entry->serverNumber[idx]),
6912                         pname);
6913                 ERROR_EXIT(code);
6914             }
6915         }
6916     }
6917
6918     /* If there is an idx but the BK and RW volumes no
6919      * longer exist, then remove the RW entry.
6920      */
6921     if ((idx != -1) && !(entry->flags & RW_EXISTS)
6922         && !(entry->flags & BACK_EXISTS)) {
6923         Lp_SetRWValue(entry, entry->serverNumber[idx],
6924                       entry->serverPartition[idx], 0L, 0L);
6925         entry->nServers--;
6926         modentry++;
6927     }
6928
6929   error_exit:
6930     if (modified)
6931         *modified = modentry;
6932     return (error);
6933 }
6934
6935 static afs_int32
6936 CheckVldbRO(struct nvldbentry *entry, afs_int32 * modified)
6937 {
6938     int idx;
6939     int foundro = 0, modentry = 0;
6940     afs_int32 code, error = 0;
6941     char pname[10];
6942     char hoststr[16];
6943
6944     if (modified)
6945         *modified = 0;
6946
6947     /* Check to see if the RO volumes exist and set the RO_EXISTS
6948      * flag accordingly.
6949      */
6950     for (idx = 0; idx < entry->nServers; idx++) {
6951         if (!(entry->serverFlags[idx] & ITSROVOL)) {
6952             continue;           /* not a RO */
6953         }
6954
6955         code =
6956             VolumeExists(entry->serverNumber[idx],
6957                          entry->serverPartition[idx], entry->volumeId[ROVOL]);
6958         if (code == 0) {        /* RO volume exists */
6959             foundro++;
6960         } else if (code == ENODEV) {    /* RW volume does not exist */
6961             Lp_SetROValue(entry, entry->serverNumber[idx],
6962                           entry->serverPartition[idx], 0L, 0L);
6963             entry->nServers--;
6964             idx--;
6965             modentry++;
6966         } else {
6967             MapPartIdIntoName(entry->serverPartition[idx], pname);
6968             fprintf(STDERR,
6969                     "Transaction call failed for RO %u on server %s %s\n",
6970                     entry->volumeId[ROVOL],
6971                     noresolve ?
6972                     afs_inet_ntoa_r(entry->serverNumber[idx], hoststr) :
6973                     hostutil_GetNameByINet(entry->serverNumber[idx]), pname);
6974             ERROR_EXIT(code);
6975         }
6976     }
6977
6978     if (foundro) {              /* A RO volume exists */
6979         if (!(entry->flags & RO_EXISTS)) {      /* ... yet entry says RW does not exist */
6980             entry->flags |= RO_EXISTS;  /* ... so say RW does exist */
6981             modentry++;
6982         }
6983     } else {                    /* A RO volume does not exist */
6984         if (entry->flags & RO_EXISTS) { /* ... yet entry says RO exists */
6985             entry->flags &= ~RO_EXISTS; /* ... so say RO does not exist */
6986             modentry++;
6987         }
6988     }
6989
6990   error_exit:
6991     if (modified)
6992         *modified = modentry;
6993     return (error);
6994 }
6995
6996 /* CheckVldb()
6997  *      Ensure that <entry> matches with the info on file servers
6998  */
6999 static afs_int32
7000 CheckVldb(struct nvldbentry * entry, afs_int32 * modified, afs_int32 * deleted)
7001 {
7002     afs_int32 code, error = 0;
7003     struct nvldbentry storeEntry;
7004     int islocked = 0, mod, modentry, delentry = 0;
7005     int pass = 0, doit=1;
7006
7007     if (modified) {
7008         if (*modified == 1)
7009             doit = 0;
7010         *modified = 0;
7011     }
7012     if (verbose) {
7013         fprintf(STDOUT, "_______________________________\n");
7014         fprintf(STDOUT, "\n-- status before -- \n");
7015         if ((entry->flags & RW_EXISTS) || (entry->flags & RO_EXISTS)
7016             || (entry->flags & BACK_EXISTS))
7017             EnumerateEntry(entry);
7018         fprintf(STDOUT, "\n");
7019     }
7020
7021     if (strlen(entry->name) > (VOLSER_OLDMAXVOLNAME - 10)) {
7022         fprintf(STDERR, "Volume name %s exceeds limit of %d characters\n",
7023                 entry->name, VOLSER_OLDMAXVOLNAME - 10);
7024     }
7025
7026   retry:
7027     /* Check to see if the VLDB is ok without locking it (pass 1).
7028      * If it will change, then lock the VLDB entry, read it again,
7029      * then make the changes to it (pass 2).
7030      */
7031     if (++pass == 2) {
7032         code =
7033             ubik_VL_SetLock(cstruct, 0, entry->volumeId[RWVOL], RWVOL,
7034                       VLOP_DELETE);
7035         if (code) {
7036             fprintf(STDERR, "Could not lock VLDB entry for %u \n",
7037                     entry->volumeId[RWVOL]);
7038             ERROR_EXIT(code);
7039         }
7040         islocked = 1;
7041
7042         code = VLDB_GetEntryByID(entry->volumeId[RWVOL], RWVOL, entry);
7043         if (code) {
7044             fprintf(STDERR, "Could not read VLDB entry for volume %s\n",
7045                     entry->name);
7046             ERROR_EXIT(code);
7047         } else {
7048             MapHostToNetwork(entry);
7049         }
7050     }
7051
7052     modentry = 0;
7053
7054     /* Check if the RW and BK entries are ok */
7055     code = CheckVldbRWBK(entry, &mod);
7056     if (code)
7057         ERROR_EXIT(code);
7058     if (mod && (pass == 1) && doit)
7059         goto retry;
7060     if (mod)
7061         modentry++;
7062
7063     /* Check if the RO volumes entries are ok */
7064     code = CheckVldbRO(entry, &mod);
7065     if (code)
7066         ERROR_EXIT(code);
7067     if (mod && (pass == 1) && doit)
7068         goto retry;
7069     if (mod)
7070         modentry++;
7071
7072     /* The VLDB entry has been updated. If it as been modified, then
7073      * write the entry back out the the VLDB.
7074      */
7075     if (modentry && doit) {
7076         if (pass == 1)
7077             goto retry;
7078
7079         if (!(entry->flags & RW_EXISTS) && !(entry->flags & BACK_EXISTS)
7080             && !(entry->flags & RO_EXISTS) && doit) {
7081             /* The RW, BK, nor RO volumes do not exist. Delete the VLDB entry */
7082             code =
7083                 ubik_VL_DeleteEntry(cstruct, 0, entry->volumeId[RWVOL],
7084                           RWVOL);
7085             if (code) {
7086                 fprintf(STDERR,
7087                         "Could not delete VLDB entry for volume %u \n",
7088                         entry->volumeId[RWVOL]);
7089                 ERROR_EXIT(code);
7090             }
7091             delentry = 1;
7092         } else {
7093             /* Replace old entry with our new one */
7094             MapNetworkToHost(entry, &storeEntry);
7095             code =
7096                 VLDB_ReplaceEntry(entry->volumeId[RWVOL], RWVOL, &storeEntry,
7097                                   (LOCKREL_OPCODE | LOCKREL_AFSID |
7098                                    LOCKREL_TIMESTAMP));
7099             if (code) {
7100                 fprintf(STDERR, "Could not update VLDB entry for volume %u\n",
7101                         entry->volumeId[RWVOL]);
7102                 ERROR_EXIT(code);
7103             }
7104         }
7105         islocked = 0;
7106     }
7107
7108     if (modified && modentry) {
7109         *modified = 1;
7110     }
7111     if (deleted && delentry) {
7112         *deleted = 1;
7113     }
7114
7115     if (verbose) {
7116         fprintf(STDOUT, "-- status after --\n");
7117         if (delentry)
7118             fprintf(STDOUT, "\n**entry deleted**\n");
7119         else if (modentry)
7120             EnumerateEntry(entry);
7121         else
7122             fprintf(STDOUT, "\n**no change**\n");
7123     }
7124
7125   error_exit:
7126     VPRINT("\n_______________________________\n");
7127
7128     if (islocked) {
7129         code =
7130             ubik_VL_ReleaseLock(cstruct, 0, entry->volumeId[RWVOL],
7131                       RWVOL,
7132                       (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP));
7133         if (code) {
7134             fprintf(STDERR,
7135                     "Could not release lock on VLDB entry for volume %u\n",
7136                     entry->volumeId[RWVOL]);
7137             if (!error)
7138                 error = code;
7139         }
7140     }
7141     return error;
7142 }
7143
7144 /* UV_SyncServer()
7145  *      Synchronise <aserver> <apart>(if flags = 1) with the VLDB.
7146  */
7147 int
7148 UV_SyncServer(afs_uint32 aserver, afs_int32 apart, int flags, int force)
7149 {
7150     struct rx_connection *aconn;
7151     afs_int32 code, error = 0;
7152     afs_int32 nentries, tentries = 0;
7153     struct VldbListByAttributes attributes;
7154     nbulkentries arrayEntries;
7155     afs_int32 failures = 0, modified, modifications = 0;
7156     struct nvldbentry *vlentry;
7157     afs_int32 si, nsi, j;
7158
7159     if (flags & 2)
7160         verbose = 1;
7161
7162     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
7163
7164     /* Set up attributes to search VLDB  */
7165     attributes.server = ntohl(aserver);
7166     attributes.Mask = VLLIST_SERVER;
7167     if ((flags & 1)) {
7168         attributes.partition = apart;
7169         attributes.Mask |= VLLIST_PARTITION;
7170     }
7171
7172     VPRINT("Processing VLDB entries ...\n");
7173
7174     /* While we need to collect more VLDB entries */
7175     for (si = 0; si != -1; si = nsi) {
7176         memset(&arrayEntries, 0, sizeof(arrayEntries));
7177
7178         /* Collect set of VLDB entries */
7179         code =
7180             VLDB_ListAttributesN2(&attributes, 0, si, &nentries,
7181                                   &arrayEntries, &nsi);
7182         if (code == RXGEN_OPCODE) {
7183             code = VLDB_ListAttributes(&attributes, &nentries, &arrayEntries);
7184             nsi = -1;
7185         }
7186         if (code) {
7187             fprintf(STDERR, "Could not access the VLDB for attributes\n");
7188             ERROR_EXIT(code);
7189         }
7190         tentries += nentries;
7191
7192         for (j = 0; j < nentries; j++) {
7193             vlentry = &arrayEntries.nbulkentries_val[j];
7194             MapHostToNetwork(vlentry);
7195
7196             VPRINT1("Processing VLDB entry %d ...\n", j + 1);
7197
7198             /* Tell CheckVldb not to update if appropriate */
7199             if (flags & 2)
7200                 modified = 1;
7201             else
7202                 modified = 0;
7203             code = CheckVldb(vlentry, &modified, NULL);
7204             if (code) {
7205                 PrintError("", code);
7206                 fprintf(STDERR,
7207                         "Could not process VLDB entry for volume %s\n",
7208                         vlentry->name);
7209                 failures++;
7210             } else if (modified) {
7211                 modifications++;
7212             }
7213
7214             if (verbose) {
7215                 if (code) {
7216                     fprintf(STDOUT, "...error encountered\n\n");
7217                 } else {
7218                     fprintf(STDOUT, "...done entry %d\n\n", j + 1);
7219                 }
7220             }
7221         }
7222
7223         if (arrayEntries.nbulkentries_val) {
7224             free(arrayEntries.nbulkentries_val);
7225             arrayEntries.nbulkentries_val = 0;
7226         }
7227     }
7228
7229     if (flags & 2) {
7230         VPRINT3("Total entries: %u, Failed to process %d, Would change %d\n",
7231                 tentries, failures, modifications);
7232     } else {
7233         VPRINT3("Total entries: %u, Failed to process %d, Changed %d\n",
7234                 tentries, failures, modifications);
7235     }
7236
7237   error_exit:
7238     if (aconn)
7239         rx_DestroyConnection(aconn);
7240     if (arrayEntries.nbulkentries_val)
7241         free(arrayEntries.nbulkentries_val);
7242
7243     if (failures)
7244         error = VOLSERFAILEDOP;
7245     return error;
7246 }
7247
7248 /*rename volume <oldname> to <newname>, changing the names of the related
7249  *readonly and backup volumes. This operation is also idempotent.
7250  *salvager is capable of recovering from rename operation stopping halfway.
7251  *to recover run syncserver on the affected machines,it will force renaming to completion. name clashes should have been detected before calling this proc */
7252 int
7253 UV_RenameVolume(struct nvldbentry *entry, char oldname[], char newname[])
7254 {
7255     struct nvldbentry storeEntry;
7256     afs_int32 vcode, code, rcode, error;
7257     int i, index;
7258     char nameBuffer[256];
7259     afs_int32 tid;
7260     struct rx_connection *aconn;
7261     int islocked;
7262     char hoststr[16];
7263
7264     error = 0;
7265     aconn = (struct rx_connection *)0;
7266     tid = 0;
7267     islocked = 0;
7268
7269     vcode = ubik_VL_SetLock(cstruct, 0, entry->volumeId[RWVOL], RWVOL, VLOP_ADDSITE);   /*last param is dummy */
7270     if (vcode) {
7271         fprintf(STDERR,
7272                 " Could not lock the VLDB entry for the  volume %u \n",
7273                 entry->volumeId[RWVOL]);
7274         error = vcode;
7275         goto rvfail;
7276     }
7277     islocked = 1;
7278     strncpy(entry->name, newname, VOLSER_OLDMAXVOLNAME);
7279     MapNetworkToHost(entry, &storeEntry);
7280     vcode = VLDB_ReplaceEntry(entry->volumeId[RWVOL], RWVOL, &storeEntry, 0);
7281     if (vcode) {
7282         fprintf(STDERR, "Could not update VLDB entry for %u\n",
7283                 entry->volumeId[RWVOL]);
7284         error = vcode;
7285         goto rvfail;
7286     }
7287     VPRINT1("Recorded the new name %s in VLDB\n", newname);
7288     /*at this stage the intent to rename is recorded in the vldb, as far as the vldb
7289      * is concerned, oldname is lost */
7290     if (entry->flags & RW_EXISTS) {
7291         index = Lp_GetRwIndex(entry);
7292         if (index == -1) {      /* there is a serious discrepancy */
7293             fprintf(STDERR,
7294                     "There is a serious discrepancy in VLDB entry for volume %u\n",
7295                     entry->volumeId[RWVOL]);
7296             fprintf(STDERR, "try building VLDB from scratch\n");
7297             error = VOLSERVLDB_ERROR;
7298             goto rvfail;
7299         }
7300         aconn = UV_Bind(entry->serverNumber[index], AFSCONF_VOLUMEPORT);
7301         code =
7302             AFSVolTransCreate_retry(aconn, entry->volumeId[RWVOL],
7303                               entry->serverPartition[index], ITOffline, &tid);
7304         if (code) {             /*volume doesnot exist */
7305             fprintf(STDERR,
7306                     "Could not start transaction on the rw volume %u\n",
7307                     entry->volumeId[RWVOL]);
7308             error = code;
7309             goto rvfail;
7310         } else {                /*volume exists, process it */
7311
7312             code =
7313                 AFSVolSetIdsTypes(aconn, tid, newname, RWVOL,
7314                                   entry->volumeId[RWVOL],
7315                                   entry->volumeId[ROVOL],
7316                                   entry->volumeId[BACKVOL]);
7317             if (!code) {
7318                 VPRINT2("Renamed rw volume %s to %s\n", oldname, newname);
7319                 code = AFSVolEndTrans(aconn, tid, &rcode);
7320                 tid = 0;
7321                 if (code) {
7322                     fprintf(STDERR,
7323                             "Could not  end transaction on volume %s %u\n",
7324                             entry->name, entry->volumeId[RWVOL]);
7325                     error = code;
7326                     goto rvfail;
7327                 }
7328             } else {
7329                 fprintf(STDERR, "Could not  set parameters on volume %s %u\n",
7330                         entry->name, entry->volumeId[RWVOL]);
7331                 error = code;
7332                 goto rvfail;
7333             }
7334         }
7335         if (aconn)
7336             rx_DestroyConnection(aconn);
7337         aconn = (struct rx_connection *)0;
7338     }
7339     /*end rw volume processing */
7340     if (entry->flags & BACK_EXISTS) {   /*process the backup volume */
7341         index = Lp_GetRwIndex(entry);
7342         if (index == -1) {      /* there is a serious discrepancy */
7343             fprintf(STDERR,
7344                     "There is a serious discrepancy in the VLDB entry for the backup volume %u\n",
7345                     entry->volumeId[BACKVOL]);
7346             fprintf(STDERR, "try building VLDB from scratch\n");
7347             error = VOLSERVLDB_ERROR;
7348             goto rvfail;
7349         }
7350         aconn = UV_Bind(entry->serverNumber[index], AFSCONF_VOLUMEPORT);
7351         code =
7352             AFSVolTransCreate_retry(aconn, entry->volumeId[BACKVOL],
7353                               entry->serverPartition[index], ITOffline, &tid);
7354         if (code) {             /*volume doesnot exist */
7355             fprintf(STDERR,
7356                     "Could not start transaction on the backup volume  %u\n",
7357                     entry->volumeId[BACKVOL]);
7358             error = code;
7359             goto rvfail;
7360         } else {                /*volume exists, process it */
7361             if (strlen(newname) > (VOLSER_OLDMAXVOLNAME - 8)) {
7362                 fprintf(STDERR,
7363                         "Volume name %s.backup exceeds the limit of %u characters\n",
7364                         newname, VOLSER_OLDMAXVOLNAME);
7365                 error = code;
7366                 goto rvfail;
7367             }
7368             strcpy(nameBuffer, newname);
7369             strcat(nameBuffer, ".backup");
7370
7371             code =
7372                 AFSVolSetIdsTypes(aconn, tid, nameBuffer, BACKVOL,
7373                                   entry->volumeId[RWVOL], 0, 0);
7374             if (!code) {
7375                 VPRINT1("Renamed backup volume to %s \n", nameBuffer);
7376                 code = AFSVolEndTrans(aconn, tid, &rcode);
7377                 tid = 0;
7378                 if (code) {
7379                     fprintf(STDERR,
7380                             "Could not  end transaction on the backup volume %u\n",
7381                             entry->volumeId[BACKVOL]);
7382                     error = code;
7383                     goto rvfail;
7384                 }
7385             } else {
7386                 fprintf(STDERR,
7387                         "Could not  set parameters on the backup volume %u\n",
7388                         entry->volumeId[BACKVOL]);
7389                 error = code;
7390                 goto rvfail;
7391             }
7392         }
7393     }                           /* end backup processing */
7394     if (aconn)
7395         rx_DestroyConnection(aconn);
7396     aconn = (struct rx_connection *)0;
7397     if (entry->flags & RO_EXISTS) {     /*process the ro volumes */
7398         for (i = 0; i < entry->nServers; i++) {
7399             if (entry->serverFlags[i] & ITSROVOL) {
7400                 aconn = UV_Bind(entry->serverNumber[i], AFSCONF_VOLUMEPORT);
7401                 code =
7402                     AFSVolTransCreate_retry(aconn, entry->volumeId[ROVOL],
7403                                       entry->serverPartition[i], ITOffline,
7404                                       &tid);
7405                 if (code) {     /*volume doesnot exist */
7406                     fprintf(STDERR,
7407                             "Could not start transaction on the ro volume %u\n",
7408                             entry->volumeId[ROVOL]);
7409                     error = code;
7410                     goto rvfail;
7411                 } else {        /*volume exists, process it */
7412                     strcpy(nameBuffer, newname);
7413                     strcat(nameBuffer, ".readonly");
7414                     if (strlen(nameBuffer) > (VOLSER_OLDMAXVOLNAME - 1)) {
7415                         fprintf(STDERR,
7416                                 "Volume name %s exceeds the limit of %u characters\n",
7417                                 nameBuffer, VOLSER_OLDMAXVOLNAME);
7418                         error = code;
7419                         goto rvfail;
7420                     }
7421                     code =
7422                         AFSVolSetIdsTypes(aconn, tid, nameBuffer, ROVOL,
7423                                           entry->volumeId[RWVOL], 0, 0);
7424                     if (!code) {
7425                         VPRINT2("Renamed RO volume %s on host %s\n",
7426                                 nameBuffer,
7427                                 noresolve ?
7428                                 afs_inet_ntoa_r(entry->serverNumber[i], hoststr) :
7429                                 hostutil_GetNameByINet(entry->
7430                                                        serverNumber[i]));
7431                         code = AFSVolEndTrans(aconn, tid, &rcode);
7432                         tid = 0;
7433                         if (code) {
7434                             fprintf(STDERR,
7435                                     "Could not  end transaction on volume %u\n",
7436                                     entry->volumeId[ROVOL]);
7437                             error = code;
7438                             goto rvfail;
7439                         }
7440                     } else {
7441                         fprintf(STDERR,
7442                                 "Could not  set parameters on the ro volume %u\n",
7443                                 entry->volumeId[ROVOL]);
7444                         error = code;
7445                         goto rvfail;
7446                     }
7447                 }
7448                 if (aconn)
7449                     rx_DestroyConnection(aconn);
7450                 aconn = (struct rx_connection *)0;
7451             }
7452         }
7453     }
7454   rvfail:
7455     if (islocked) {
7456         vcode =
7457             ubik_VL_ReleaseLock(cstruct, 0, entry->volumeId[RWVOL],
7458                       RWVOL,
7459                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
7460         if (vcode) {
7461             fprintf(STDERR,
7462                     "Could not unlock the VLDB entry for the volume %s %u\n",
7463                     entry->name, entry->volumeId[RWVOL]);
7464             if (!error)
7465                 error = vcode;
7466         }
7467     }
7468     if (tid) {
7469         code = AFSVolEndTrans(aconn, tid, &rcode);
7470         if (!code)
7471             code = rcode;
7472         if (code) {
7473             fprintf(STDERR, "Failed to end transaction on a volume \n");
7474             if (!error)
7475                 error = code;
7476         }
7477     }
7478     if (aconn)
7479         rx_DestroyConnection(aconn);
7480     PrintError("", error);
7481     return error;
7482
7483 }
7484
7485 /*report on all the active transactions on volser */
7486 int
7487 UV_VolserStatus(afs_uint32 server, transDebugInfo ** rpntr, afs_int32 * rcount)
7488 {
7489     struct rx_connection *aconn;
7490     transDebugEntries transInfo;
7491     afs_int32 code = 0;
7492
7493     aconn = UV_Bind(server, AFSCONF_VOLUMEPORT);
7494     transInfo.transDebugEntries_val = (transDebugInfo *) 0;
7495     transInfo.transDebugEntries_len = 0;
7496     code = AFSVolMonitor(aconn, &transInfo);
7497     if (code) {
7498         fprintf(STDERR,
7499                 "Could not access status information about the server\n");
7500         PrintError("", code);
7501         if (transInfo.transDebugEntries_val)
7502             free(transInfo.transDebugEntries_val);
7503         if (aconn)
7504             rx_DestroyConnection(aconn);
7505         return code;
7506     } else {
7507         *rcount = transInfo.transDebugEntries_len;
7508         *rpntr = transInfo.transDebugEntries_val;
7509         if (aconn)
7510             rx_DestroyConnection(aconn);
7511         return 0;
7512     }
7513
7514
7515 }
7516
7517 /*delete the volume without interacting with the vldb */
7518 int
7519 UV_VolumeZap(afs_uint32 server, afs_int32 part, afs_uint32 volid)
7520 {
7521     afs_int32 error;
7522     struct rx_connection *aconn;
7523
7524     aconn = UV_Bind(server, AFSCONF_VOLUMEPORT);
7525     error = DoVolDelete(aconn, volid, part,
7526                         "the", 0, NULL, NULL);
7527     if (error == VNOVOL) {
7528         EPRINT1(error, "Failed to start transaction on %u\n", volid);
7529     }
7530
7531     PrintError("", error);
7532     if (aconn)
7533         rx_DestroyConnection(aconn);
7534     return error;
7535 }
7536
7537 int
7538 UV_SetVolume(afs_uint32 server, afs_int32 partition, afs_uint32 volid,
7539              afs_int32 transflag, afs_int32 setflag, int sleeptime)
7540 {
7541     struct rx_connection *conn = 0;
7542     afs_int32 tid = 0;
7543     afs_int32 code, error = 0, rcode;
7544
7545     conn = UV_Bind(server, AFSCONF_VOLUMEPORT);
7546     if (!conn) {
7547         fprintf(STDERR, "SetVolumeStatus: Bind Failed");
7548         ERROR_EXIT(-1);
7549     }
7550
7551     code = AFSVolTransCreate_retry(conn, volid, partition, transflag, &tid);
7552     if (code) {
7553         fprintf(STDERR, "SetVolumeStatus: TransCreate Failed\n");
7554         ERROR_EXIT(code);
7555     }
7556
7557     code = AFSVolSetFlags(conn, tid, setflag);
7558     if (code) {
7559         fprintf(STDERR, "SetVolumeStatus: SetFlags Failed\n");
7560         ERROR_EXIT(code);
7561     }
7562
7563     if (sleeptime) {
7564 #ifdef AFS_PTHREAD_ENV
7565         sleep(sleeptime);
7566 #else
7567         IOMGR_Sleep(sleeptime);
7568 #endif
7569     }
7570
7571   error_exit:
7572     if (tid) {
7573         rcode = 0;
7574         code = AFSVolEndTrans(conn, tid, &rcode);
7575         if (code || rcode) {
7576             fprintf(STDERR, "SetVolumeStatus: EndTrans Failed\n");
7577             if (!error)
7578                 error = (code ? code : rcode);
7579         }
7580     }
7581
7582     if (conn)
7583         rx_DestroyConnection(conn);
7584     return (error);
7585 }
7586
7587 int
7588 UV_SetVolumeInfo(afs_uint32 server, afs_int32 partition, afs_uint32 volid,
7589                  volintInfo * infop)
7590 {
7591     struct rx_connection *conn = 0;
7592     afs_int32 tid = 0;
7593     afs_int32 code, error = 0, rcode;
7594
7595     conn = UV_Bind(server, AFSCONF_VOLUMEPORT);
7596     if (!conn) {
7597         fprintf(STDERR, "SetVolumeInfo: Bind Failed");
7598         ERROR_EXIT(-1);
7599     }
7600
7601     code = AFSVolTransCreate_retry(conn, volid, partition, ITOffline, &tid);
7602     if (code) {
7603         fprintf(STDERR, "SetVolumeInfo: TransCreate Failed\n");
7604         ERROR_EXIT(code);
7605     }
7606
7607     code = AFSVolSetInfo(conn, tid, infop);
7608     if (code) {
7609         fprintf(STDERR, "SetVolumeInfo: SetInfo Failed\n");
7610         ERROR_EXIT(code);
7611     }
7612
7613   error_exit:
7614     if (tid) {
7615         rcode = 0;
7616         code = AFSVolEndTrans(conn, tid, &rcode);
7617         if (code || rcode) {
7618             fprintf(STDERR, "SetVolumeInfo: EndTrans Failed\n");
7619             if (!error)
7620                 error = (code ? code : rcode);
7621         }
7622     }
7623
7624     if (conn)
7625         rx_DestroyConnection(conn);
7626     return (error);
7627 }
7628
7629 int
7630 UV_GetSize(afs_uint32 afromvol, afs_uint32 afromserver, afs_int32 afrompart,
7631            afs_int32 fromdate, struct volintSize *vol_size)
7632 {
7633     struct rx_connection *aconn = (struct rx_connection *)0;
7634     afs_int32 tid = 0, rcode = 0;
7635     afs_int32 code, error = 0;
7636
7637
7638     /* get connections to the servers */
7639     aconn = UV_Bind(afromserver, AFSCONF_VOLUMEPORT);
7640
7641     VPRINT1("Starting transaction on volume %u...", afromvol);
7642     code = AFSVolTransCreate_retry(aconn, afromvol, afrompart, ITBusy, &tid);
7643     EGOTO1(error_exit, code,
7644            "Could not start transaction on the volume %u to be measured\n",
7645            afromvol);
7646     VDONE;
7647
7648     VPRINT1("Getting size of volume on volume %u...", afromvol);
7649     code = AFSVolGetSize(aconn, tid, fromdate, vol_size);
7650     EGOTO(error_exit, code, "Could not start the measurement process \n");
7651     VDONE;
7652
7653   error_exit:
7654     if (tid) {
7655         VPRINT1("Ending transaction on volume %u...", afromvol);
7656         code = AFSVolEndTrans(aconn, tid, &rcode);
7657         if (code || rcode) {
7658             fprintf(STDERR, "Could not end transaction on the volume %u\n",
7659                     afromvol);
7660             fprintf(STDERR, "error codes: %d and %d\n", code, rcode);
7661             if (!error)
7662                 error = (code ? code : rcode);
7663         }
7664         VDONE;
7665     }
7666     if (aconn)
7667         rx_DestroyConnection(aconn);
7668
7669     PrintError("", error);
7670     return (error);
7671 }
7672
7673 /*maps the host addresses in <old > (present in network byte order) to
7674  that in< new> (present in host byte order )*/
7675 void
7676 MapNetworkToHost(struct nvldbentry *old, struct nvldbentry *new)
7677 {
7678     int i, count;
7679
7680     /*copy all the fields */
7681     strcpy(new->name, old->name);
7682 /*    new->volumeType = old->volumeType;*/
7683     new->nServers = old->nServers;
7684     count = old->nServers;
7685     if (count < NMAXNSERVERS)
7686         count++;
7687     for (i = 0; i < count; i++) {
7688         new->serverNumber[i] = ntohl(old->serverNumber[i]);
7689         new->serverPartition[i] = old->serverPartition[i];
7690         new->serverFlags[i] = old->serverFlags[i];
7691     }
7692     new->volumeId[RWVOL] = old->volumeId[RWVOL];
7693     new->volumeId[ROVOL] = old->volumeId[ROVOL];
7694     new->volumeId[BACKVOL] = old->volumeId[BACKVOL];
7695     new->cloneId = old->cloneId;
7696     new->flags = old->flags;
7697 }
7698
7699 /*maps the host entries in <entry> which are present in host byte order to network byte order */
7700 void
7701 MapHostToNetwork(struct nvldbentry *entry)
7702 {
7703     int i, count;
7704
7705     count = entry->nServers;
7706     if (count < NMAXNSERVERS)
7707         count++;
7708     for (i = 0; i < count; i++) {
7709         entry->serverNumber[i] = htonl(entry->serverNumber[i]);
7710     }
7711 }