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