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