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