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