release-avoid-negative-time-20060124
[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     int s;
3163     manyDests tr;
3164     manyResults results;
3165     int rwindex, roindex, roclone, roexists;
3166     afs_int32 rwcrdate, rwupdate, clcrdate;
3167     struct rtime {
3168         int validtime;
3169         afs_uint32 uptime;
3170     } remembertime[NMAXNSERVERS];
3171     int releasecount = 0;
3172     struct volser_status volstatus;
3173
3174     memset((char *)remembertime, 0, sizeof(remembertime));
3175     memset((char *)&results, 0, sizeof(results));
3176
3177     vcode = ubik_Call(VL_SetLock, cstruct, 0, afromvol, RWVOL, VLOP_RELEASE);
3178     if (vcode != VL_RERELEASE)
3179         ONERROR(vcode, afromvol,
3180                 "Could not lock the VLDB entry for the volume %u.\n");
3181     islocked = 1;
3182
3183     /* Get the vldb entry in readable format */
3184     vcode = VLDB_GetEntryByID(afromvol, RWVOL, &entry);
3185     ONERROR(vcode, afromvol,
3186             "Could not fetch the entry for the volume %u from the VLDB.\n");
3187     MapHostToNetwork(&entry);
3188
3189     if (verbose)
3190         EnumerateEntry(&entry);
3191
3192     if (!ISNAMEVALID(entry.name))
3193         ONERROR(VOLSERBADOP, entry.name,
3194                 "Volume name %s is too long, rename before releasing.\n");
3195     if (entry.volumeId[RWVOL] != afromvol)
3196         ONERROR(VOLSERBADOP, afromvol,
3197                 "The volume %u being released is not a read-write volume.\n");
3198     if (entry.nServers <= 1)
3199         ONERROR(VOLSERBADOP, afromvol,
3200                 "Volume %u has no replicas - release operation is meaningless!\n");
3201     if (strlen(entry.name) > (VOLSER_OLDMAXVOLNAME - 10))
3202         ONERROR(VOLSERBADOP, entry.name,
3203                 "RO volume name %s exceeds (VOLSER_OLDMAXVOLNAME - 10) character limit\n");
3204
3205     /* roclone is true if one of the RO volumes is on the same
3206      * partition as the RW volume. In this case, we make the RO volume
3207      * on the same partition a clone instead of a complete copy.
3208      */
3209
3210     roindex = Lp_ROMatch(afromserver, afrompart, &entry) - 1;
3211     roclone = ((roindex == -1) ? 0 : 1);
3212     rwindex = Lp_GetRwIndex(&entry);
3213     if (rwindex < 0)
3214         ONERROR(VOLSERNOVOL, 0, "There is no RW volume \n");
3215
3216     /* Make sure we have a RO volume id to work with */
3217     if (entry.volumeId[ROVOL] == INVALID_BID) {
3218         /* need to get a new RO volume id */
3219         vcode = ubik_Call(VL_GetNewVolumeId, cstruct, 0, 1, &roVolId);
3220         ONERROR(vcode, entry.name, "Cant allocate ID for RO volume of %s\n");
3221
3222         entry.volumeId[ROVOL] = roVolId;
3223         MapNetworkToHost(&entry, &storeEntry);
3224         vcode = VLDB_ReplaceEntry(afromvol, RWVOL, &storeEntry, 0);
3225         ONERROR(vcode, entry.name, "Could not update vldb entry for %s.\n");
3226     }
3227
3228     /* Will we be completing a previously unfinished release. -force overrides */
3229     for (s = 0, m = 0, fullrelease=0, i=0; (i<entry.nServers); i++) {
3230         if (entry.serverFlags[i] & ITSROVOL) {
3231             m++;
3232             if (entry.serverFlags[i] & NEW_REPSITE) s++;
3233         }
3234     }
3235     if ((forceflag && !fullrelease) || (s == m) || (s == 0))
3236         fullrelease = 1;
3237
3238     /* Determine which volume id to use and see if it exists */
3239     cloneVolId =
3240         ((fullrelease
3241           || (entry.cloneId == 0)) ? entry.volumeId[ROVOL] : entry.cloneId);
3242     code = VolumeExists(afromserver, afrompart, cloneVolId);
3243     roexists = ((code == ENODEV) ? 0 : 1);
3244
3245     fromconn = UV_Bind(afromserver, AFSCONF_VOLUMEPORT);
3246     if (!fromconn)
3247         ONERROR(-1, afromserver,
3248                 "Cannot establish connection with server 0x%x\n");
3249
3250     if (!fullrelease) {
3251         if (!roexists)
3252             fullrelease = 1;    /* Do a full release if RO clone does not exist */
3253         else {
3254             /* Begin transaction on RW and mark it busy while we query it */
3255             code = AFSVolTransCreate(
3256                         fromconn, afromvol, afrompart, ITBusy, &fromtid
3257                    );
3258             ONERROR(code, afromvol,
3259                     "Failed to start transaction on RW volume %u\n");
3260
3261             /* Query the creation date for the RW */
3262             code = AFSVolGetStatus(fromconn, fromtid, &volstatus);
3263             ONERROR(code, afromvol,
3264                     "Failed to get the status of RW volume %u\n");
3265             rwcrdate = volstatus.creationDate;
3266             rwupdate = volstatus.updateDate;
3267
3268             /* End transaction on RW */
3269             code = AFSVolEndTrans(fromconn, fromtid, &rcode);
3270             fromtid = 0;
3271             ONERROR((code ? code : rcode), afromvol,
3272                     "Failed to end transaction on RW volume %u\n");
3273
3274             /* Begin transaction on clone and mark it busy while we query it */
3275             code = AFSVolTransCreate(
3276                         fromconn, cloneVolId, afrompart, ITBusy, &clonetid
3277                    );
3278             ONERROR(code, cloneVolId,
3279                     "Failed to start transaction on RW clone %u\n");
3280
3281             /* Query the creation date for the clone */
3282             code = AFSVolGetStatus(fromconn, clonetid, &volstatus);
3283             ONERROR(code, cloneVolId,
3284                     "Failed to get the status of RW clone %u\n");
3285             clcrdate = volstatus.creationDate;
3286
3287             /* End transaction on clone */
3288             code = AFSVolEndTrans(fromconn, clonetid, &rcode);
3289             clonetid = 0;
3290             ONERROR((code ? code : rcode), cloneVolId,
3291                     "Failed to end transaction on RW clone %u\n");
3292
3293             if (rwcrdate > clcrdate)
3294                 fullrelease = 2;/* Do a full release if RO clone older than RW */
3295         }
3296     }
3297
3298     if (verbose) {
3299         switch (fullrelease) {
3300             case 2:
3301                 fprintf(STDOUT, "RW %lu changed, doing a complete release\n",
3302                         (unsigned long)afromvol);
3303                 break;
3304             case 1:
3305                 fprintf(STDOUT, "This is a complete release of volume %lu\n",
3306                         (unsigned long)afromvol);
3307                 break;
3308             case 0:
3309                 fprintf(STDOUT, "This is a completion of a previous release\n");
3310                 break;
3311         }
3312     }
3313
3314     if (fullrelease) {
3315         /* If the RO clone exists, then if the clone is a temporary
3316          * clone, delete it. Or if the RO clone is marked RO_DONTUSE
3317          * (it was recently added), then also delete it. We do not
3318          * want to "reclone" a temporary RO clone.
3319          */
3320         if (roexists
3321             && (!roclone || (entry.serverFlags[roindex] & RO_DONTUSE))) {
3322             code = DelVol(fromconn, cloneVolId, afrompart, ITOffline);
3323             if (code && (code != VNOVOL))
3324                 ERROREXIT(code);
3325             roexists = 0;
3326         }
3327
3328         /* Mark all the ROs in the VLDB entry as RO_DONTUSE. We don't
3329          * write this entry out to the vlserver until after the first
3330          * RO volume is released (temp RO clones don't count).
3331          */
3332         for (i = 0; i < entry.nServers; i++) {
3333             entry.serverFlags[i] &= ~NEW_REPSITE;
3334             entry.serverFlags[i] |= RO_DONTUSE;
3335         }
3336         entry.serverFlags[rwindex] |= NEW_REPSITE;
3337         entry.serverFlags[rwindex] &= ~RO_DONTUSE;
3338
3339         /* Begin transaction on RW and mark it busy while we clone it */
3340         code =
3341             AFSVolTransCreate(fromconn, afromvol, afrompart, ITBusy,
3342                               &clonetid);
3343         ONERROR(code, afromvol, "Failed to start transaction on volume %u\n");
3344
3345         /* Clone or reclone the volume */
3346         if (roexists) {
3347             VPRINT1("Recloning RW volume %u...", cloneVolId);
3348             code = AFSVolReClone(fromconn, clonetid, cloneVolId);
3349             ONERROR(code, afromvol, "Failed to reclone the RW volume %u\n");
3350             VDONE;
3351         } else {
3352             if (roclone) {
3353                 strcpy(vname, entry.name);
3354                 strcat(vname, ".readonly");
3355                 VPRINT1("Cloning RW volume %u to permanent RO...", afromvol);
3356             } else {
3357                 strcpy(vname, "readonly-clone-temp");
3358                 VPRINT1("Cloning RW volume %u to temporary RO...", afromvol);
3359             }
3360             code =
3361                 AFSVolClone(fromconn, clonetid, 0, readonlyVolume, vname,
3362                             &cloneVolId);
3363             ONERROR(code, afromvol, "Failed to clone the RW volume %u\n");
3364             VDONE;
3365         }
3366
3367         /* Get the time the RW was created for future information */
3368         VPRINT1("Getting status of RW volume %u...", afromvol);
3369         code = AFSVolGetStatus(fromconn, clonetid, &volstatus);
3370         ONERROR(code, afromvol,
3371                 "Failed to get the status of the RW volume %u\n");
3372         VDONE;
3373         rwcrdate = volstatus.creationDate;
3374         rwupdate = volstatus.updateDate;
3375
3376         /* End the transaction on the RW volume */
3377         VPRINT1("Ending cloning transaction on RW volume %u...", afromvol);
3378         code = AFSVolEndTrans(fromconn, clonetid, &rcode);
3379         clonetid = 0;
3380         ONERROR((code ? code : rcode), afromvol,
3381                 "Failed to end cloning transaction on RW %u\n");
3382         VDONE;
3383
3384         /* Remember clone volume ID in case we fail or are interrupted */
3385         entry.cloneId = cloneVolId;
3386
3387         if (roclone) {
3388             /* Bring the RO clone online - though not if it's a temporary clone */
3389             VPRINT1("Starting transaction on RO clone volume %u...",
3390                     cloneVolId);
3391             code =
3392                 AFSVolTransCreate(fromconn, cloneVolId, afrompart, ITOffline,
3393                                   &onlinetid);
3394             ONERROR(code, cloneVolId,
3395                     "Failed to start transaction on volume %u\n");
3396             VDONE;
3397
3398             VPRINT1("Setting volume flags for volume %u...", cloneVolId);
3399             tcode = AFSVolSetFlags(fromconn, onlinetid, 0);
3400             VDONE;
3401
3402             VPRINT1("Ending transaction on volume %u...", cloneVolId);
3403             code = AFSVolEndTrans(fromconn, onlinetid, &rcode);
3404             ONERROR((code ? code : rcode), cloneVolId,
3405                     "Failed to end transaction on RO clone %u\n");
3406             VDONE;
3407
3408             ONERROR(tcode, cloneVolId, "Could not bring volume %u on line\n");
3409
3410             /* Sleep so that a client searching for an online volume won't
3411              * find the clone offline and then the next RO offline while the 
3412              * release brings the clone online and the next RO offline (race).
3413              * There is a fix in the 3.4 client that does not need this sleep
3414              * anymore, but we don't know what clients we have.
3415              */
3416             if (entry.nServers > 2)
3417                 sleep(5);
3418
3419             /* Mark the RO clone in the VLDB as a good site (already released) */
3420             entry.serverFlags[roindex] |= NEW_REPSITE;
3421             entry.serverFlags[roindex] &= ~RO_DONTUSE;
3422             entry.flags |= RO_EXISTS;
3423
3424             releasecount++;
3425
3426             /* Write out the VLDB entry only if the clone is not a temporary
3427              * clone. If we did this to a temporary clone then we would end
3428              * up marking all the ROs as "old release" making the ROs
3429              * temporarily unavailable.
3430              */
3431             MapNetworkToHost(&entry, &storeEntry);
3432             VPRINT1("Replacing VLDB entry for %s...", entry.name);
3433             vcode = VLDB_ReplaceEntry(afromvol, RWVOL, &storeEntry, 0);
3434             ONERROR(vcode, entry.name,
3435                     "Could not update vldb entry for %s.\n");
3436             VDONE;
3437         }
3438     }
3439
3440     /* Now we will release from the clone to the remaining RO replicas.
3441      * The first 2 ROs (counting the non-temporary RO clone) are released
3442      * individually: releasecount. This is to reduce the race condition
3443      * of clients trying to find an on-line RO volume. The remaining ROs
3444      * are released in parallel but no more than half the number of ROs
3445      * (rounded up) at a time: nservers.
3446      */
3447
3448     strcpy(vname, entry.name);
3449     strcat(vname, ".readonly");
3450     memset(&cookie, 0, sizeof(cookie));
3451     strncpy(cookie.name, vname, VOLSER_OLDMAXVOLNAME);
3452     cookie.type = ROVOL;
3453     cookie.parent = entry.volumeId[RWVOL];
3454     cookie.clone = 0;
3455
3456     nservers = entry.nServers / 2;      /* how many to do at once, excluding clone */
3457     replicas =
3458         (struct replica *)malloc(sizeof(struct replica) * nservers + 1);
3459     times = (struct release *)malloc(sizeof(struct release) * nservers + 1);
3460     toconns =
3461         (struct rx_connection **)malloc(sizeof(struct rx_connection *) *
3462                                         nservers + 1);
3463     results.manyResults_val =
3464         (afs_int32 *) malloc(sizeof(afs_int32) * nservers + 1);
3465     if (!replicas || !times || !!!results.manyResults_val || !toconns)
3466         ONERROR(ENOMEM, 0,
3467                 "Failed to create transaction on the release clone\n");
3468
3469     memset(replicas, 0, (sizeof(struct replica) * nservers + 1));
3470     memset(times, 0, (sizeof(struct release) * nservers + 1));
3471     memset(toconns, 0, (sizeof(struct rx_connection *) * nservers + 1));
3472     memset(results.manyResults_val, 0, (sizeof(afs_int32) * nservers + 1));
3473
3474     /* Create a transaction on the cloned volume */
3475     VPRINT1("Starting transaction on cloned volume %u...", cloneVolId);
3476     code =
3477         AFSVolTransCreate(fromconn, cloneVolId, afrompart, ITBusy, &fromtid);
3478     if (!fullrelease && code)
3479         ONERROR(VOLSERNOVOL, afromvol,
3480                 "Old clone is inaccessible. Try vos release -f %u.\n");
3481     ONERROR(code, 0, "Failed to create transaction on the release clone\n");
3482     VDONE;
3483
3484     /* For each index in the VLDB */
3485     for (vldbindex = 0; vldbindex < entry.nServers;) {
3486
3487         /* Get a transaction on the replicas. Pick replacas which have an old release. */
3488         for (volcount = 0;
3489              ((volcount < nservers) && (vldbindex < entry.nServers));
3490              vldbindex++) {
3491             /* The first two RO volumes will be released individually.
3492              * The rest are then released in parallel. This is a hack
3493              * for clients not recognizing right away when a RO volume
3494              * comes back on-line.
3495              */
3496             if ((volcount == 1) && (releasecount < 2))
3497                 break;
3498
3499             if (vldbindex == roindex)
3500                 continue;       /* the clone    */
3501             if ((entry.serverFlags[vldbindex] & NEW_REPSITE)
3502                 && !(entry.serverFlags[vldbindex] & RO_DONTUSE))
3503                 continue;
3504             if (!(entry.serverFlags[vldbindex] & ITSROVOL))
3505                 continue;       /* not a RO vol */
3506
3507
3508             /* Get a Transaction on this replica. Get a new connection if
3509              * necessary.  Create the volume if necessary.  Return the
3510              * time from which the dump should be made (0 if it's a new
3511              * volume).  Each volume might have a different time. 
3512              */
3513             replicas[volcount].server.destHost =
3514                 ntohl(entry.serverNumber[vldbindex]);
3515             replicas[volcount].server.destPort = AFSCONF_VOLUMEPORT;
3516             replicas[volcount].server.destSSID = 1;
3517             times[volcount].vldbEntryIndex = vldbindex;
3518
3519             code =
3520                 GetTrans(&entry, vldbindex, &(toconns[volcount]),
3521                          &(replicas[volcount].trans),
3522                          &(times[volcount].crtime),
3523                          &(times[volcount].uptime));
3524             if (code)
3525                 continue;
3526
3527             /* Thisdate is the date from which we want to pick up all changes */
3528             if (forceflag || !fullrelease
3529                 || (rwcrdate > times[volcount].crtime)) {
3530                 /* If the forceflag is set, then we want to do a full dump.
3531                  * If it's not a full release, we can't be sure that the creation
3532                  *  date is good (so we also do a full dump).
3533                  * If the RW volume was replaced (its creation date is newer than
3534                  *  the last release), then we can't be sure what has changed (so
3535                  *  we do a full dump).
3536                  */
3537                 thisdate = 0;
3538             } else if (remembertime[vldbindex].validtime) {
3539                 /* Trans was prev ended. Use the time from the prev trans
3540                  * because, prev trans may have created the volume. In which
3541                  * case time[volcount].time would be now instead of 0.
3542                  */
3543                 thisdate =
3544                     (remembertime[vldbindex].uptime < times[volcount].uptime)
3545                         ? remembertime[vldbindex].uptime
3546                         : times[volcount].uptime;
3547             } else {
3548                 thisdate = times[volcount].uptime;
3549             }
3550             remembertime[vldbindex].validtime = 1;
3551             remembertime[vldbindex].uptime = thisdate;
3552
3553             if (volcount == 0) {
3554                 fromdate = thisdate;
3555             } else {
3556                 /* Include this volume if it is within 15 minutes of the earliest */
3557                 if (((fromdate >
3558                       thisdate) ? (fromdate - thisdate) : (thisdate -
3559                                                            fromdate)) > 900) {
3560                     AFSVolEndTrans(toconns[volcount],
3561                                    replicas[volcount].trans, &rcode);
3562                     replicas[volcount].trans = 0;
3563                     break;
3564                 }
3565                 if (thisdate < fromdate)
3566                     fromdate = thisdate;
3567             }
3568             volcount++;
3569         }
3570         if (!volcount)
3571             continue;
3572
3573         if (verbose) {
3574             fprintf(STDOUT, "Starting ForwardMulti from %lu to %u on %s",
3575                     (unsigned long)cloneVolId, entry.volumeId[ROVOL],
3576                     hostutil_GetNameByINet(entry.
3577                                            serverNumber[times[0].
3578                                                         vldbEntryIndex]));
3579
3580             for (s = 1; s < volcount; s++) {
3581                 fprintf(STDOUT, " and %s",
3582                         hostutil_GetNameByINet(entry.
3583                                                serverNumber[times[s].
3584                                                             vldbEntryIndex]));
3585             }
3586
3587             if (fromdate == 0)
3588                 fprintf(STDOUT, " (full release)");
3589             else
3590                 fprintf(STDOUT, " (as of %.24s)", ctime((time_t *)&fromdate));
3591             fprintf(STDOUT, ".\n");
3592             fflush(STDOUT);
3593         }
3594
3595         /* Release the ones we have collected */
3596         tr.manyDests_val = &(replicas[0]);
3597         tr.manyDests_len = results.manyResults_len = volcount;
3598         code =
3599             AFSVolForwardMultiple(fromconn, fromtid, fromdate, &tr,
3600                                   0 /*spare */ , &cookie, &results);
3601         if (code == RXGEN_OPCODE) {     /* RPC Interface Mismatch */
3602             code =
3603                 SimulateForwardMultiple(fromconn, fromtid, fromdate, &tr,
3604                                         0 /*spare */ , &cookie, &results);
3605             nservers = 1;
3606         }
3607
3608         if (code) {
3609             PrintError("Release failed: ", code);
3610         } else {
3611             for (m = 0; m < volcount; m++) {
3612                 if (results.manyResults_val[m]) {
3613                     if ((m == 0) || (results.manyResults_val[m] != ENOENT)) {
3614                         /* we retry timed out transaction. When it is
3615                          * not the first volume and the transaction wasn't found
3616                          * (assume it timed out and was garbage collected by volser).
3617                          */
3618                         PrintError
3619                             ("Failed to dump volume from clone to a ro site: ",
3620                              results.manyResults_val[m]);
3621                     }
3622                     continue;
3623                 }
3624
3625                 code =
3626                     AFSVolSetIdsTypes(toconns[m], replicas[m].trans, vname,
3627                                       ROVOL, entry.volumeId[RWVOL], 0, 0);
3628                 if (code) {
3629                     if ((m == 0) || (code != ENOENT)) {
3630                         PrintError("Failed to set correct names and ids: ",
3631                                    code);
3632                     }
3633                     continue;
3634                 }
3635
3636                 /* have to clear dest. flags to ensure new vol goes online:
3637                  * because the restore (forwarded) operation copied
3638                  * the V_inService(=0) flag over to the destination. 
3639                  */
3640                 code = AFSVolSetFlags(toconns[m], replicas[m].trans, 0);
3641                 if (code) {
3642                     if ((m == 0) || (code != ENOENT)) {
3643                         PrintError("Failed to set flags on ro volume: ",
3644                                    code);
3645                     }
3646                     continue;
3647                 }
3648
3649                 entry.serverFlags[times[m].vldbEntryIndex] |= NEW_REPSITE;
3650                 entry.serverFlags[times[m].vldbEntryIndex] &= ~RO_DONTUSE;
3651                 entry.flags |= RO_EXISTS;
3652                 releasecount++;
3653             }
3654         }
3655
3656         /* End the transactions and destroy the connections */
3657         for (s = 0; s < volcount; s++) {
3658             if (replicas[s].trans)
3659                 code = AFSVolEndTrans(toconns[s], replicas[s].trans, &rcode);
3660             replicas[s].trans = 0;
3661             if (!code)
3662                 code = rcode;
3663             if (code) {
3664                 if ((s == 0) || (code != ENOENT)) {
3665                     PrintError("Could not end transaction on a ro volume: ",
3666                                code);
3667                 } else {
3668                     PrintError
3669                         ("Transaction timed out on a ro volume. Will retry.\n",
3670                          0);
3671                     if (times[s].vldbEntryIndex < vldbindex)
3672                         vldbindex = times[s].vldbEntryIndex;
3673                 }
3674             }
3675
3676             if (toconns[s])
3677                 rx_DestroyConnection(toconns[s]);
3678             toconns[s] = 0;
3679         }
3680
3681         MapNetworkToHost(&entry, &storeEntry);
3682         vcode = VLDB_ReplaceEntry(afromvol, RWVOL, &storeEntry, 0);
3683         ONERROR(vcode, afromvol,
3684                 " Could not update VLDB entry for volume %u\n");
3685     }                           /* for each index in the vldb */
3686
3687     /* End the transaction on the cloned volume */
3688     code = AFSVolEndTrans(fromconn, fromtid, &rcode);
3689     fromtid = 0;
3690     if (!code)
3691         code = rcode;
3692     if (code)
3693         PrintError("Failed to end transaction on rw volume: ", code);
3694
3695     /* Figure out if any volume were not released and say so */
3696     for (failure = 0, i = 0; i < entry.nServers; i++) {
3697         if (!(entry.serverFlags[i] & NEW_REPSITE))
3698             failure++;
3699     }
3700     if (failure) {
3701         char pname[10];
3702         fprintf(STDERR,
3703                 "The volume %lu could not be released to the following %d sites:\n",
3704                 (unsigned long)afromvol, failure);
3705         for (i = 0; i < entry.nServers; i++) {
3706             if (!(entry.serverFlags[i] & NEW_REPSITE)) {
3707                 MapPartIdIntoName(entry.serverPartition[i], pname);
3708                 fprintf(STDERR, "\t%35s %s\n",
3709                         hostutil_GetNameByINet(entry.serverNumber[i]), pname);
3710             }
3711         }
3712
3713         MapNetworkToHost(&entry, &storeEntry);
3714         vcode =
3715             VLDB_ReplaceEntry(afromvol, RWVOL, &storeEntry,
3716                               LOCKREL_TIMESTAMP);
3717         ONERROR(vcode, afromvol,
3718                 " Could not update VLDB entry for volume %u\n");
3719
3720         ERROREXIT(VOLSERBADRELEASE);
3721     }
3722
3723     /* All the ROs were release successfully. Remove the temporary clone */
3724     if (!roclone) {
3725         if (verbose) {
3726             fprintf(STDOUT, "Deleting the releaseClone %lu ...",
3727                     (unsigned long)cloneVolId);
3728             fflush(STDOUT);
3729         }
3730         code = DelVol(fromconn, cloneVolId, afrompart, ITOffline);
3731         ONERROR(code, cloneVolId, "Failed to delete volume %u.\n");
3732         VDONE;
3733     }
3734     entry.cloneId = 0;
3735
3736     for (i = 0; i < entry.nServers; i++)
3737         entry.serverFlags[i] &= ~NEW_REPSITE;
3738
3739     /* Update the VLDB */
3740     VPRINT("updating VLDB ...");
3741
3742     MapNetworkToHost(&entry, &storeEntry);
3743     vcode =
3744         VLDB_ReplaceEntry(afromvol, RWVOL, &storeEntry,
3745                           LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
3746     ONERROR(vcode, afromvol, " Could not update VLDB entry for volume %u\n");
3747     VDONE;
3748
3749   rfail:
3750     if (clonetid) {
3751         code = AFSVolEndTrans(fromconn, clonetid, &rcode);
3752         clonetid = 0;
3753         if (code) {
3754             fprintf(STDERR,
3755                     "Failed to end cloning transaction on the RW volume %lu\n",
3756                     (unsigned long)afromvol);
3757             if (!error)
3758                 error = code;
3759         }
3760     }
3761     if (fromtid) {
3762         code = AFSVolEndTrans(fromconn, fromtid, &rcode);
3763         fromtid = 0;
3764         if (code) {
3765             fprintf(STDERR,
3766                     "Failed to end transaction on the release clone %lu\n",
3767                     (unsigned long)cloneVolId);
3768             if (!error)
3769                 error = code;
3770         }
3771     }
3772     for (i = 0; i < nservers; i++) {
3773         if (replicas && replicas[i].trans) {
3774             code = AFSVolEndTrans(toconns[i], replicas[i].trans, &rcode);
3775             replicas[i].trans = 0;
3776             if (code) {
3777                 fprintf(STDERR,
3778                         "Failed to end transaction on ro volume %u at server %s\n",
3779                         entry.volumeId[ROVOL],
3780                         hostutil_GetNameByINet(htonl
3781                                                (replicas[i].server.
3782                                                 destHost)));
3783                 if (!error)
3784                     error = code;
3785             }
3786         }
3787         if (toconns && toconns[i]) {
3788             rx_DestroyConnection(toconns[i]);
3789             toconns[i] = 0;
3790         }
3791     }
3792     if (islocked) {
3793         vcode =
3794             ubik_Call(VL_ReleaseLock, cstruct, 0, afromvol, RWVOL,
3795                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
3796         if (vcode) {
3797             fprintf(STDERR,
3798                     "Could not release lock on the VLDB entry for volume %lu\n",
3799                     (unsigned long)afromvol);
3800             if (!error)
3801                 error = vcode;
3802         }
3803     }
3804
3805     PrintError("", error);
3806
3807     if (fromconn)
3808         rx_DestroyConnection(fromconn);
3809     if (results.manyResults_val)
3810         free(results.manyResults_val);
3811     if (replicas)
3812         free(replicas);
3813     if (toconns)
3814         free(toconns);
3815     if (times)
3816         free(times);
3817     return error;
3818 }
3819
3820
3821 void
3822 dump_sig_handler(int x)
3823 {
3824     fprintf(STDERR, "\nSignal handler: vos dump operation\n");
3825     longjmp(env, 0);
3826 }
3827
3828 /* Dump the volume <afromvol> on <afromserver> and
3829  * <afrompart> to <afilename> starting from <fromdate>.
3830  * DumpFunction does the real work behind the scenes after
3831  * extracting parameters from the rock 
3832  */
3833 int
3834 UV_DumpVolume(afs_int32 afromvol, afs_int32 afromserver, afs_int32 afrompart,
3835               afs_int32 fromdate, afs_int32(*DumpFunction) (), char *rock)
3836 {
3837     struct rx_connection *fromconn = (struct rx_connection *)0;
3838     struct rx_call *fromcall = (struct rx_call *)0;
3839     afs_int32 fromtid = 0, rxError = 0, rcode = 0;
3840     afs_int32 code, error = 0;
3841
3842     if (setjmp(env))
3843         ERROR_EXIT(EPIPE);
3844 #ifndef AFS_NT40_ENV
3845     (void)signal(SIGPIPE, dump_sig_handler);
3846 #endif
3847     (void)signal(SIGINT, dump_sig_handler);
3848
3849     if (!fromdate) {
3850         VPRINT("Full Dump ...\n");
3851     } else {
3852         VPRINT1("Incremental Dump (as of %.24s)...\n",
3853                 ctime((time_t *) & fromdate));
3854     }
3855
3856     /* get connections to the servers */
3857     fromconn = UV_Bind(afromserver, AFSCONF_VOLUMEPORT);
3858
3859     VPRINT1("Starting transaction on volume %u...", afromvol);
3860     code = AFSVolTransCreate(fromconn, afromvol, afrompart, ITBusy, &fromtid);
3861     EGOTO1(error_exit, code,
3862            "Could not start transaction on the volume %u to be dumped\n",
3863            afromvol);
3864     VDONE;
3865
3866     fromcall = rx_NewCall(fromconn);
3867
3868     VPRINT1("Starting volume dump on volume %u...", afromvol);
3869     code = StartAFSVolDump(fromcall, fromtid, fromdate);
3870     EGOTO(error_exit, code, "Could not start the dump process \n");
3871     VDONE;
3872
3873     VPRINT1("Dumping volume %u...", afromvol);
3874     code = DumpFunction(fromcall, rock);
3875     EGOTO(error_exit, code, "Error while dumping volume \n");
3876     VDONE;
3877
3878   error_exit:
3879     if (fromcall) {
3880         code = rx_EndCall(fromcall, rxError);
3881         if (code) {
3882             fprintf(STDERR, "Error in rx_EndCall\n");
3883             if (!error)
3884                 error = code;
3885         }
3886     }
3887     if (fromtid) {
3888         VPRINT1("Ending transaction on volume %u...", afromvol);
3889         code = AFSVolEndTrans(fromconn, fromtid, &rcode);
3890         if (code || rcode) {
3891             fprintf(STDERR, "Could not end transaction on the volume %lu\n",
3892                     (unsigned long)afromvol);
3893             if (!error)
3894                 error = (code ? code : rcode);
3895         }
3896         VDONE;
3897     }
3898     if (fromconn)
3899         rx_DestroyConnection(fromconn);
3900
3901     PrintError("", error);
3902     return (error);
3903 }
3904
3905 /* Clone the volume <afromvol> on <afromserver> and
3906  * <afrompart>, and then dump the clone volume to 
3907  * <afilename> starting from <fromdate>.
3908  * DumpFunction does the real work behind the scenes after
3909  * extracting parameters from the rock 
3910  */
3911 int
3912 UV_DumpClonedVolume(afs_int32 afromvol, afs_int32 afromserver,
3913                     afs_int32 afrompart, afs_int32 fromdate,
3914                     afs_int32(*DumpFunction) (), char *rock)
3915 {
3916     struct rx_connection *fromconn = (struct rx_connection *)0;
3917     struct rx_call *fromcall = (struct rx_call *)0;
3918     afs_int32 fromtid = 0, rxError = 0, rcode = 0;
3919     afs_int32 clonetid = 0;
3920     afs_int32 code = 0, vcode = 0, error = 0;
3921     afs_int32 clonevol = 0;
3922     char vname[64];
3923
3924     if (setjmp(env))
3925         ERROR_EXIT(EPIPE);
3926 #ifndef AFS_NT40_ENV
3927     (void)signal(SIGPIPE, dump_sig_handler);
3928 #endif
3929     (void)signal(SIGINT, dump_sig_handler);
3930
3931     if (!fromdate) {
3932         VPRINT("Full Dump ...\n");
3933     } else {
3934         VPRINT1("Incremental Dump (as of %.24s)...\n",
3935                 ctime((time_t *) & fromdate));
3936     }
3937
3938     /* get connections to the servers */
3939     fromconn = UV_Bind(afromserver, AFSCONF_VOLUMEPORT);
3940
3941     VPRINT1("Starting transaction on volume %u...", afromvol);
3942     code = AFSVolTransCreate(fromconn, afromvol, afrompart, ITBusy, &fromtid);
3943     EGOTO1(error_exit, code,
3944            "Could not start transaction on the volume %u to be dumped\n",
3945            afromvol);
3946     VDONE;
3947
3948     /* Get a clone id */
3949     VPRINT1("Allocating new volume id for clone of volume %u ...", afromvol);
3950     code = ubik_Call(VL_GetNewVolumeId, cstruct, 0, 1, &clonevol);
3951     EGOTO1(error_exit, code,
3952            "Could not get an ID for the clone of volume %u from the VLDB\n",
3953            afromvol);
3954     VDONE;
3955
3956     /* Do the clone. Default flags on clone are set to delete on salvage and out of service */
3957     VPRINT2("Cloning source volume %u to clone volume %u...", afromvol,
3958             clonevol);
3959     strcpy(vname, "dump-clone-temp");
3960     code =
3961         AFSVolClone(fromconn, fromtid, 0, readonlyVolume, vname, &clonevol);
3962     EGOTO1(error_exit, code, "Failed to clone the source volume %u\n",
3963            afromvol);
3964     VDONE;
3965
3966     VPRINT1("Ending the transaction on the volume %u ...", afromvol);
3967     rcode = 0;
3968     code = AFSVolEndTrans(fromconn, fromtid, &rcode);
3969     fromtid = 0;
3970     if (!code)
3971         code = rcode;
3972     EGOTO1(error_exit, code,
3973            "Failed to end the transaction on the volume %u\n", afromvol);
3974     VDONE;
3975
3976
3977     VPRINT1("Starting transaction on the cloned volume %u ...", clonevol);
3978     code =
3979         AFSVolTransCreate(fromconn, clonevol, afrompart, ITOffline,
3980                           &clonetid);
3981     EGOTO1(error_exit, code,
3982            "Failed to start a transaction on the cloned volume%u\n",
3983            clonevol);
3984     VDONE;
3985
3986     VPRINT1("Setting flags on cloned volume %u ...", clonevol);
3987     code = AFSVolSetFlags(fromconn, clonetid, VTDeleteOnSalvage | VTOutOfService);      /*redundant */
3988     EGOTO1(error_exit, code, "Could not set falgs on the cloned volume %u\n",
3989            clonevol);
3990     VDONE;
3991
3992
3993     fromcall = rx_NewCall(fromconn);
3994
3995     VPRINT1("Starting volume dump from cloned volume %u...", clonevol);
3996     code = StartAFSVolDump(fromcall, clonetid, fromdate);
3997     EGOTO(error_exit, code, "Could not start the dump process \n");
3998     VDONE;
3999
4000     VPRINT1("Dumping volume %u...", afromvol);
4001     code = DumpFunction(fromcall, rock);
4002     EGOTO(error_exit, code, "Error while dumping volume \n");
4003     VDONE;
4004
4005   error_exit:
4006     /* now delete the clone */
4007     VPRINT1("Deleting the cloned volume %u ...", clonevol);
4008     code = AFSVolDeleteVolume(fromconn, clonetid);
4009     if (code) {
4010         fprintf(STDERR, "Failed to delete the cloned volume %lu\n",
4011                 (unsigned long)clonevol);
4012     } else {
4013         VDONE;
4014     }
4015
4016     if (fromcall) {
4017         code = rx_EndCall(fromcall, rxError);
4018         if (code) {
4019             fprintf(STDERR, "Error in rx_EndCall\n");
4020             if (!error)
4021                 error = code;
4022         }
4023     }
4024     if (clonetid) {
4025         VPRINT1("Ending transaction on cloned volume %u...", clonevol);
4026         code = AFSVolEndTrans(fromconn, clonetid, &rcode);
4027         if (code || rcode) {
4028             fprintf(STDERR,
4029                     "Could not end transaction on the cloned volume %lu\n",
4030                     (unsigned long)clonevol);
4031             if (!error)
4032                 error = (code ? code : rcode);
4033         }
4034         VDONE;
4035     }
4036     if (fromconn)
4037         rx_DestroyConnection(fromconn);
4038
4039     PrintError("", error);
4040     return (error);
4041 }
4042
4043
4044
4045 /*
4046  * Restore a volume <tovolid> <tovolname> on <toserver> <topart> from
4047  * the dump file <afilename>. WriteData does all the real work
4048  * after extracting params from the rock 
4049  */
4050 int
4051 UV_RestoreVolume2(afs_int32 toserver, afs_int32 topart, afs_int32 tovolid,
4052                   afs_int32 toparentid, char tovolname[], int flags,
4053                   afs_int32(*WriteData) (), char *rock)
4054 {
4055     struct rx_connection *toconn, *tempconn;
4056     struct rx_call *tocall;
4057     afs_int32 totid, code, rcode, vcode, terror = 0;
4058     afs_int32 rxError = 0;
4059     struct volser_status tstatus;
4060     struct volintInfo vinfo;
4061     char partName[10];
4062     afs_int32 pvolid, pparentid;
4063     afs_int32 temptid;
4064     int success;
4065     struct nvldbentry entry, storeEntry;
4066     afs_int32 error;
4067     int islocked;
4068     struct restoreCookie cookie;
4069     int reuseID;
4070     afs_int32 volflag, voltype, volsertype;
4071     afs_int32 oldCreateDate, oldUpdateDate, newCreateDate, newUpdateDate;
4072     int index, same, errcode;
4073     char apartName[10];
4074
4075
4076     memset(&cookie, 0, sizeof(cookie));
4077     islocked = 0;
4078     success = 0;
4079     error = 0;
4080     reuseID = 1;
4081     tocall = (struct rx_call *)0;
4082     toconn = (struct rx_connection *)0;
4083     tempconn = (struct rx_connection *)0;
4084     totid = 0;
4085     temptid = 0;
4086
4087     if (flags & RV_RDONLY) {
4088         voltype = ROVOL;
4089         volsertype = volser_RO;
4090     } else {
4091         voltype = RWVOL;
4092         volsertype = volser_RW;
4093     }
4094
4095     pvolid = tovolid;
4096     pparentid = toparentid;
4097     toconn = UV_Bind(toserver, AFSCONF_VOLUMEPORT);
4098     if (pvolid == 0) {          /*alot a new id if needed */
4099         vcode = VLDB_GetEntryByName(tovolname, &entry);
4100         if (vcode == VL_NOENT) {
4101             vcode = ubik_Call(VL_GetNewVolumeId, cstruct, 0, 1, &pvolid);
4102             if (vcode) {
4103                 fprintf(STDERR, "Could not get an Id for the volume %s\n",
4104                         tovolname);
4105                 error = vcode;
4106                 goto refail;
4107             }
4108             reuseID = 0;
4109         } else if (flags & RV_RDONLY) {
4110             if (entry.flags & RW_EXISTS) {
4111                 fprintf(STDERR,
4112                         "Entry for ReadWrite volume %s already exists!\n",
4113                         entry.name);
4114                 error = VOLSERBADOP;
4115                 goto refail;
4116             }
4117             if (!entry.volumeId[ROVOL]) {
4118                 fprintf(STDERR,
4119                         "Existing entry for volume %s has no ReadOnly ID\n",
4120                         tovolname);
4121                 error = VOLSERBADOP;
4122                 goto refail;
4123             }
4124             pvolid = entry.volumeId[ROVOL];
4125             pparentid = entry.volumeId[RWVOL];
4126         } else {
4127             pvolid = entry.volumeId[RWVOL];
4128             pparentid = entry.volumeId[RWVOL];
4129         }
4130     }
4131     if (!pparentid) pparentid = pvolid;
4132     /* at this point we have a volume id to use/reuse for the volume to be restored */
4133     if (strlen(tovolname) > (VOLSER_OLDMAXVOLNAME - 1)) {
4134         EGOTO1(refail, VOLSERBADOP,
4135                "The volume name %s exceeds the maximum limit of (VOLSER_OLDMAXVOLNAME -1 ) bytes\n",
4136                tovolname);
4137     }
4138     MapPartIdIntoName(topart, partName);
4139     fprintf(STDOUT, "Restoring volume %s Id %lu on server %s partition %s ..",
4140             tovolname, (unsigned long)pvolid,
4141             hostutil_GetNameByINet(toserver), partName);
4142     fflush(STDOUT);
4143     code =
4144         AFSVolCreateVolume(toconn, topart, tovolname, volsertype, pparentid, &pvolid,
4145                            &totid);
4146     if (code) {
4147         if (flags & RV_FULLRST) {       /* full restore: delete then create anew */
4148             VPRINT1("Deleting the previous volume %u ...", pvolid);
4149
4150             code =
4151                 AFSVolTransCreate(toconn, pvolid, topart, ITOffline, &totid);
4152             EGOTO1(refail, code, "Failed to start transaction on %u\n",
4153                    pvolid);
4154
4155             code = AFSVolGetStatus(toconn, totid, &tstatus);
4156             EGOTO1(refail, code, "Could not get timestamp from volume %u\n",
4157                    pvolid);
4158
4159             oldCreateDate = tstatus.creationDate;
4160             oldUpdateDate = tstatus.updateDate;
4161
4162             code =
4163                 AFSVolSetFlags(toconn, totid,
4164                                VTDeleteOnSalvage | VTOutOfService);
4165             EGOTO1(refail, code, "Could not set flags on volume %u \n",
4166                    pvolid);
4167
4168             code = AFSVolDeleteVolume(toconn, totid);
4169             EGOTO1(refail, code, "Could not delete volume %u\n", pvolid);
4170
4171             code = AFSVolEndTrans(toconn, totid, &rcode);
4172             totid = 0;
4173             if (!code)
4174                 code = rcode;
4175             EGOTO1(refail, code, "Could not end transaction on %u\n", pvolid);
4176
4177             VDONE;
4178
4179             code =
4180                 AFSVolCreateVolume(toconn, topart, tovolname, volsertype, pparentid,
4181                                    &pvolid, &totid);
4182             EGOTO1(refail, code, "Could not create new volume %u\n", pvolid);
4183         } else {
4184             code =
4185                 AFSVolTransCreate(toconn, pvolid, topart, ITOffline, &totid);
4186             EGOTO1(refail, code, "Failed to start transaction on %u\n",
4187                    pvolid);
4188
4189             code = AFSVolGetStatus(toconn, totid, &tstatus);
4190             EGOTO1(refail, code, "Could not get timestamp from volume %u\n",
4191                    pvolid);
4192
4193             oldCreateDate = tstatus.creationDate;
4194             oldUpdateDate = tstatus.updateDate;
4195         }
4196     } else {
4197         oldCreateDate = 0;
4198         oldUpdateDate = 0;
4199     }
4200
4201     cookie.parent = pparentid;
4202     cookie.type = voltype;
4203     cookie.clone = 0;
4204     strncpy(cookie.name, tovolname, VOLSER_OLDMAXVOLNAME);
4205
4206     tocall = rx_NewCall(toconn);
4207     terror = StartAFSVolRestore(tocall, totid, 1, &cookie);
4208     if (terror) {
4209         fprintf(STDERR, "Volume restore Failed \n");
4210         error = terror;
4211         goto refail;
4212     }
4213     code = WriteData(tocall, rock);
4214     if (code) {
4215         fprintf(STDERR, "Could not transmit data\n");
4216         error = code;
4217         goto refail;
4218     }
4219     terror = rx_EndCall(tocall, rxError);
4220     tocall = (struct rx_call *)0;
4221     if (terror) {
4222         fprintf(STDERR, "rx_EndCall Failed \n");
4223         error = terror;
4224         goto refail;
4225     }
4226     code = AFSVolGetStatus(toconn, totid, &tstatus);
4227     if (code) {
4228         fprintf(STDERR,
4229                 "Could not get status information about the volume %lu\n",
4230                 (unsigned long)pvolid);
4231         error = code;
4232         goto refail;
4233     }
4234     code = AFSVolSetIdsTypes(toconn, totid, tovolname, voltype, pparentid, 0, 0);
4235     if (code) {
4236         fprintf(STDERR, "Could not set the right type and ID on %lu\n",
4237                 (unsigned long)pvolid);
4238         error = code;
4239         goto refail;
4240     }
4241
4242     if (flags & RV_CRDUMP)
4243         newCreateDate = tstatus.creationDate;
4244     else if (flags & RV_CRKEEP && oldCreateDate != 0)
4245         newCreateDate = oldCreateDate;
4246     else
4247         newCreateDate = time(0);
4248     if (flags & RV_LUDUMP)
4249         newUpdateDate = tstatus.updateDate;
4250     else if (flags & RV_LUKEEP)
4251         newUpdateDate = oldUpdateDate;
4252     else
4253         newUpdateDate = time(0);
4254     code = AFSVolSetDate(toconn,totid, newCreateDate);
4255     if (code) {
4256         fprintf(STDERR, "Could not set the 'creation' date on %u\n", pvolid);
4257         error = code;
4258         goto refail;
4259     }
4260
4261     init_volintInfo(&vinfo);
4262     vinfo.creationDate = newCreateDate;
4263     vinfo.updateDate = newUpdateDate;
4264     code = AFSVolSetInfo(toconn, totid, &vinfo);
4265     if (code) {
4266         fprintf(STDERR, "Could not set the 'last updated' date on %u\n",
4267                 pvolid);
4268         error = code;
4269         goto refail;
4270     }
4271
4272     volflag = ((flags & RV_OFFLINE) ? VTOutOfService : 0);      /* off or on-line */
4273     code = AFSVolSetFlags(toconn, totid, volflag);
4274     if (code) {
4275         fprintf(STDERR, "Could not mark %lu online\n", (unsigned long)pvolid);
4276         error = code;
4277         goto refail;
4278     }
4279
4280 /* It isn't handled right in refail */
4281     code = AFSVolEndTrans(toconn, totid, &rcode);
4282     totid = 0;
4283     if (!code)
4284         code = rcode;
4285     if (code) {
4286         fprintf(STDERR, "Could not end transaction on %lu\n",
4287                 (unsigned long)pvolid);
4288         error = code;
4289         goto refail;
4290     }
4291
4292     success = 1;
4293     fprintf(STDOUT, " done\n");
4294     fflush(STDOUT);
4295     if (success && (!reuseID || (flags & RV_FULLRST))) {
4296         /* Volume was restored on the file server, update the 
4297          * VLDB to reflect the change.
4298          */
4299         vcode = VLDB_GetEntryByID(pvolid, voltype, &entry);
4300         if (vcode && vcode != VL_NOENT && vcode != VL_ENTDELETED) {
4301             fprintf(STDERR,
4302                     "Could not fetch the entry for volume number %lu from VLDB \n",
4303                     (unsigned long)pvolid);
4304             error = vcode;
4305             goto refail;
4306         }
4307         if (!vcode)
4308             MapHostToNetwork(&entry);
4309         if (vcode == VL_NOENT) {        /* it doesnot exist already */
4310             /*make the vldb return this indication specifically */
4311             VPRINT("------- Creating a new VLDB entry ------- \n");
4312             strcpy(entry.name, tovolname);
4313             entry.nServers = 1;
4314             entry.serverNumber[0] = toserver;   /*should be indirect */
4315             entry.serverPartition[0] = topart;
4316             entry.serverFlags[0] = (flags & RV_RDONLY) ? ITSROVOL : ITSRWVOL;
4317             entry.flags = (flags & RV_RDONLY) ? RO_EXISTS : RW_EXISTS;
4318             if (flags & RV_RDONLY)
4319                 entry.volumeId[ROVOL] = pvolid;
4320             else if (tstatus.cloneID != 0) {
4321                 entry.volumeId[ROVOL] = tstatus.cloneID;        /*this should come from status info on the volume if non zero */
4322             } else
4323                 entry.volumeId[ROVOL] = INVALID_BID;
4324             entry.volumeId[RWVOL] = pparentid;
4325             entry.cloneId = 0;
4326             if (tstatus.backupID != 0) {
4327                 entry.volumeId[BACKVOL] = tstatus.backupID;
4328                 /*this should come from status info on the volume if non zero */
4329             } else
4330                 entry.volumeId[BACKVOL] = INVALID_BID;
4331             MapNetworkToHost(&entry, &storeEntry);
4332             vcode = VLDB_CreateEntry(&storeEntry);
4333             if (vcode) {
4334                 fprintf(STDERR,
4335                         "Could not create the VLDB entry for volume number %lu  \n",
4336                         (unsigned long)pvolid);
4337                 error = vcode;
4338                 goto refail;
4339             }
4340             islocked = 0;
4341             if (verbose)
4342                 EnumerateEntry(&entry);
4343         } else {                /*update the existing entry */
4344             if (verbose) {
4345                 fprintf(STDOUT, "Updating the existing VLDB entry\n");
4346                 fprintf(STDOUT, "------- Old entry -------\n");
4347                 EnumerateEntry(&entry);
4348                 fprintf(STDOUT, "------- New entry -------\n");
4349             }
4350             vcode =
4351                 ubik_Call(VL_SetLock, cstruct, 0, pvolid, voltype,
4352                           VLOP_RESTORE);
4353             if (vcode) {
4354                 fprintf(STDERR,
4355                         "Could not lock the entry for volume number %lu \n",
4356                         (unsigned long)pvolid);
4357                 error = vcode;
4358                 goto refail;
4359             }
4360             islocked = 1;
4361             strcpy(entry.name, tovolname);
4362
4363             /* Update the vlentry with the new information */
4364             if (flags & RV_RDONLY)
4365                 index = Lp_ROMatch(toserver, topart, &entry) - 1;
4366             else
4367                 index = Lp_GetRwIndex(&entry);
4368             if (index == -1) {
4369                 /* Add the new site for the volume being restored */
4370                 entry.serverNumber[entry.nServers] = toserver;
4371                 entry.serverPartition[entry.nServers] = topart;
4372                 entry.serverFlags[entry.nServers] =
4373                     (flags & RV_RDONLY) ? ITSROVOL : ITSRWVOL;
4374                 entry.nServers++;
4375             } else {
4376                 /* This volume should be deleted on the old site
4377                  * if its different from new site.
4378                  */
4379                 same =
4380                     VLDB_IsSameAddrs(toserver, entry.serverNumber[index],
4381                                      &errcode);
4382                 EPRINT2(errcode,
4383                         "Failed to get info about server's %d address(es) from vlserver (err=%d)\n",
4384                         toserver, errcode);
4385                 if ((!errcode && !same)
4386                     || (entry.serverPartition[index] != topart)) {
4387                     tempconn =
4388                         UV_Bind(entry.serverNumber[index],
4389                                 AFSCONF_VOLUMEPORT);
4390
4391                     MapPartIdIntoName(entry.serverPartition[index],
4392                                       apartName);
4393                     VPRINT3
4394                         ("Deleting the previous volume %u on server %s, partition %s ...",
4395                          pvolid,
4396                          hostutil_GetNameByINet(entry.serverNumber[index]),
4397                          apartName);
4398                     code =
4399                         AFSVolTransCreate(tempconn, pvolid,
4400                                           entry.serverPartition[index],
4401                                           ITOffline, &temptid);
4402                     if (!code) {
4403                         code =
4404                             AFSVolSetFlags(tempconn, temptid,
4405                                            VTDeleteOnSalvage |
4406                                            VTOutOfService);
4407                         if (code) {
4408                             fprintf(STDERR,
4409                                     "Could not set flags on volume %lu on the older site\n",
4410                                     (unsigned long)pvolid);
4411                             error = code;
4412                             goto refail;
4413                         }
4414                         code = AFSVolDeleteVolume(tempconn, temptid);
4415                         if (code) {
4416                             fprintf(STDERR,
4417                                     "Could not delete volume %lu on the older site\n",
4418                                     (unsigned long)pvolid);
4419                             error = code;
4420                             goto refail;
4421                         }
4422                         code = AFSVolEndTrans(tempconn, temptid, &rcode);
4423                         temptid = 0;
4424                         if (!code)
4425                             code = rcode;
4426                         if (code) {
4427                             fprintf(STDERR,
4428                                     "Could not end transaction on volume %lu on the older site\n",
4429                                     (unsigned long)pvolid);
4430                             error = code;
4431                             goto refail;
4432                         }
4433                         VDONE;
4434                         MapPartIdIntoName(entry.serverPartition[index],
4435                                           partName);
4436                     }
4437                 }
4438                 entry.serverNumber[index] = toserver;
4439                 entry.serverPartition[index] = topart;
4440             }
4441
4442             entry.flags |= (flags & RV_RDONLY) ? RO_EXISTS : RW_EXISTS;
4443             MapNetworkToHost(&entry, &storeEntry);
4444             vcode =
4445                 VLDB_ReplaceEntry(pvolid, voltype, &storeEntry,
4446                                   LOCKREL_OPCODE | LOCKREL_AFSID |
4447                                   LOCKREL_TIMESTAMP);
4448             if (vcode) {
4449                 fprintf(STDERR,
4450                         "Could not update the entry for volume number %lu  \n",
4451                         (unsigned long)pvolid);
4452                 error = vcode;
4453                 goto refail;
4454             }
4455             islocked = 0;
4456             if (verbose)
4457                 EnumerateEntry(&entry);
4458         }
4459
4460
4461     }
4462   refail:
4463     if (tocall) {
4464         code = rx_EndCall(tocall, rxError);
4465         if (!error)
4466             error = code;
4467     }
4468     if (islocked) {
4469         vcode =
4470             ubik_Call(VL_ReleaseLock, cstruct, 0, pvolid, voltype,
4471                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
4472         if (vcode) {
4473             fprintf(STDERR,
4474                     "Could not release lock on the VLDB entry for the volume %lu\n",
4475                     (unsigned long)pvolid);
4476             if (!error)
4477                 error = vcode;
4478         }
4479     }
4480     if (totid) {
4481         code = AFSVolEndTrans(toconn, totid, &rcode);
4482         if (!code)
4483             code = rcode;
4484         if (code) {
4485             fprintf(STDERR, "Could not end transaction on the volume %lu \n",
4486                     (unsigned long)pvolid);
4487             if (!error)
4488                 error = code;
4489         }
4490     }
4491     if (temptid) {
4492         code = AFSVolEndTrans(toconn, temptid, &rcode);
4493         if (!code)
4494             code = rcode;
4495         if (code) {
4496             fprintf(STDERR, "Could not end transaction on the volume %lu \n",
4497                     (unsigned long)pvolid);
4498             if (!error)
4499                 error = code;
4500         }
4501     }
4502     if (tempconn)
4503         rx_DestroyConnection(tempconn);
4504     if (toconn)
4505         rx_DestroyConnection(toconn);
4506     PrintError("", error);
4507     return error;
4508 }
4509
4510 int
4511 UV_RestoreVolume(afs_int32 toserver, afs_int32 topart, afs_int32 tovolid,
4512                  char tovolname[], int flags, afs_int32(*WriteData) (),
4513                  char *rock)
4514 {
4515     return UV_RestoreVolume2(toserver, topart, tovolid, 0, tovolname, flags,
4516                              WriteData, rock);
4517 }
4518
4519
4520 /*unlocks the vldb entry associated with <volid> */
4521 int
4522 UV_LockRelease(afs_int32 volid)
4523 {
4524
4525
4526     afs_int32 vcode;
4527
4528     VPRINT("Binding to the VLDB server\n");
4529     vcode =
4530         ubik_Call(VL_ReleaseLock, cstruct, 0, volid, -1,
4531                   LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
4532     if (vcode) {
4533         fprintf(STDERR,
4534                 "Could not unlock the entry for volume number %lu in VLDB \n",
4535                 (unsigned long)volid);
4536         PrintError("", vcode);
4537         return (vcode);
4538     }
4539     VPRINT("VLDB updated\n");
4540     return 0;
4541
4542 }
4543
4544 /*adds <server> and <part> as a readonly replication site for <volid>
4545 *in vldb */
4546 int
4547 UV_AddSite(afs_int32 server, afs_int32 part, afs_int32 volid)
4548 {
4549     int j, nro = 0, islocked = 0;
4550     struct nvldbentry entry, storeEntry;
4551     afs_int32 vcode, error = 0;
4552     char apartName[10];
4553
4554     error = ubik_Call(VL_SetLock, cstruct, 0, volid, RWVOL, VLOP_ADDSITE);
4555     if (error) {
4556         fprintf(STDERR,
4557                 " Could not lock the VLDB entry for the volume %lu \n",
4558                 (unsigned long)volid);
4559         goto asfail;
4560     }
4561     islocked = 1;
4562
4563     error = VLDB_GetEntryByID(volid, RWVOL, &entry);
4564     if (error) {
4565         fprintf(STDERR,
4566                 "Could not fetch the VLDB entry for volume number %lu  \n",
4567                 (unsigned long)volid);
4568         goto asfail;
4569
4570     }
4571     if (!ISNAMEVALID(entry.name)) {
4572         fprintf(STDERR,
4573                 "Volume name %s is too long, rename before adding site\n",
4574                 entry.name);
4575         error = VOLSERBADOP;
4576         goto asfail;
4577     }
4578     MapHostToNetwork(&entry);
4579
4580     /* See if it's too many entries */
4581     if (entry.nServers >= NMAXNSERVERS) {
4582         fprintf(STDERR, "Total number of entries will exceed %u\n",
4583                 NMAXNSERVERS);
4584         error = VOLSERBADOP;
4585         goto asfail;
4586     }
4587
4588     /* See if it's on the same server */
4589     for (j = 0; j < entry.nServers; j++) {
4590         if (entry.serverFlags[j] & ITSROVOL) {
4591             nro++;
4592             if (VLDB_IsSameAddrs(server, entry.serverNumber[j], &error)) {
4593                 if (error) {
4594                     fprintf(STDERR,
4595                             "Failed to get info about server's %d address(es) from vlserver (err=%d); aborting call!\n",
4596                             server, error);
4597                 } else {
4598                     MapPartIdIntoName(entry.serverPartition[j], apartName);
4599                     fprintf(STDERR,
4600                             "RO already exists on partition %s. Multiple ROs on a single server aren't allowed\n",
4601                             apartName);
4602                     error = VOLSERBADOP;
4603                 }
4604                 goto asfail;
4605             }
4606         }
4607     }
4608
4609     /* See if it's too many RO sites - leave one for the RW */
4610     if (nro >= NMAXNSERVERS - 1) {
4611         fprintf(STDERR, "Total number of sites will exceed %u\n",
4612                 NMAXNSERVERS - 1);
4613         error = VOLSERBADOP;
4614         goto asfail;
4615     }
4616
4617     VPRINT("Adding a new site ...");
4618     entry.serverNumber[entry.nServers] = server;
4619     entry.serverPartition[entry.nServers] = part;
4620     entry.serverFlags[entry.nServers] = (ITSROVOL | RO_DONTUSE);
4621     entry.nServers++;
4622
4623     MapNetworkToHost(&entry, &storeEntry);
4624     error =
4625         VLDB_ReplaceEntry(volid, RWVOL, &storeEntry,
4626                           LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
4627     if (error) {
4628         fprintf(STDERR, "Could not update entry for volume %lu \n",
4629                 (unsigned long)volid);
4630         goto asfail;
4631     }
4632     islocked = 0;
4633     VDONE;
4634
4635   asfail:
4636     if (islocked) {
4637         vcode =
4638             ubik_Call(VL_ReleaseLock, cstruct, 0, volid, RWVOL,
4639                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
4640         if (vcode) {
4641             fprintf(STDERR,
4642                     "Could not release lock on volume entry for %lu \n",
4643                     (unsigned long)volid);
4644             PrintError("", vcode);
4645         }
4646     }
4647
4648     PrintError("", error);
4649     return error;
4650 }
4651
4652 /*removes <server> <part> as read only site for <volid> from the vldb */
4653 int
4654 UV_RemoveSite(afs_int32 server, afs_int32 part, afs_int32 volid)
4655 {
4656     afs_int32 vcode;
4657     struct nvldbentry entry, storeEntry;
4658     int islocked;
4659
4660     vcode = ubik_Call(VL_SetLock, cstruct, 0, volid, RWVOL, VLOP_ADDSITE);
4661     if (vcode) {
4662         fprintf(STDERR, " Could not lock the VLDB entry for volume %lu \n",
4663                 (unsigned long)volid);
4664         PrintError("", vcode);
4665         return (vcode);
4666     }
4667     islocked = 1;
4668     vcode = VLDB_GetEntryByID(volid, RWVOL, &entry);
4669     if (vcode) {
4670         fprintf(STDERR,
4671                 "Could not fetch the entry for volume number %lu from VLDB \n",
4672                 (unsigned long)volid);
4673         PrintError("", vcode);
4674         return (vcode);
4675     }
4676     MapHostToNetwork(&entry);
4677     if (!Lp_ROMatch(server, part, &entry)) {
4678         /*this site doesnot exist  */
4679         fprintf(STDERR, "This site is not a replication site \n");
4680         vcode =
4681             ubik_Call(VL_ReleaseLock, cstruct, 0, volid, RWVOL,
4682                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
4683         if (vcode) {
4684             fprintf(STDERR, "Could not update entry for volume %lu \n",
4685                     (unsigned long)volid);
4686             PrintError("", vcode);
4687             ubik_Call(VL_ReleaseLock, cstruct, 0, volid, RWVOL,
4688                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
4689             return (vcode);
4690         }
4691         return VOLSERBADOP;
4692     } else {                    /*remove the rep site */
4693         Lp_SetROValue(&entry, server, part, 0, 0);
4694         entry.nServers--;
4695         if ((entry.nServers == 1) && (entry.flags & RW_EXISTS))
4696             entry.flags &= ~RO_EXISTS;
4697         if (entry.nServers < 1) {       /*this is the last ref */
4698             VPRINT1("Deleting the VLDB entry for %u ...", volid);
4699             fflush(STDOUT);
4700             vcode = ubik_Call(VL_DeleteEntry, cstruct, 0, volid, ROVOL);
4701             if (vcode) {
4702                 fprintf(STDERR,
4703                         "Could not delete VLDB entry for volume %lu \n",
4704                         (unsigned long)volid);
4705                 PrintError("", vcode);
4706                 return (vcode);
4707             }
4708             VDONE;
4709         }
4710         MapNetworkToHost(&entry, &storeEntry);
4711         fprintf(STDOUT, "Deleting the replication site for volume %lu ...",
4712                 (unsigned long)volid);
4713         fflush(STDOUT);
4714         vcode =
4715             VLDB_ReplaceEntry(volid, RWVOL, &storeEntry,
4716                               LOCKREL_OPCODE | LOCKREL_AFSID |
4717                               LOCKREL_TIMESTAMP);
4718         if (vcode) {
4719             fprintf(STDERR,
4720                     "Could not release lock on volume entry for %lu \n",
4721                     (unsigned long)volid);
4722             PrintError("", vcode);
4723             ubik_Call(VL_ReleaseLock, cstruct, 0, volid, RWVOL,
4724                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
4725             return (vcode);
4726         }
4727         VDONE;
4728     }
4729     return 0;
4730 }
4731
4732 /*sets <server> <part> as read/write site for <volid> in the vldb */
4733 int
4734 UV_ChangeLocation(afs_int32 server, afs_int32 part, afs_int32 volid)
4735 {
4736     afs_int32 vcode;
4737     struct nvldbentry entry, storeEntry;
4738     int index;
4739
4740     vcode = ubik_Call(VL_SetLock, cstruct, 0, volid, RWVOL, VLOP_ADDSITE);
4741     if (vcode) {
4742         fprintf(STDERR, " Could not lock the VLDB entry for volume %lu \n",
4743                 (unsigned long)volid);
4744         PrintError("", vcode);
4745         return (vcode);
4746     }
4747     vcode = VLDB_GetEntryByID(volid, RWVOL, &entry);
4748     if (vcode) {
4749         fprintf(STDERR,
4750                 "Could not fetch the entry for volume number %lu from VLDB \n",
4751                 (unsigned long)volid);
4752         PrintError("", vcode);
4753         return (vcode);
4754     }
4755     MapHostToNetwork(&entry);
4756     index = Lp_GetRwIndex(&entry);
4757     if (index < 0) {
4758         /* no RW site exists  */
4759         fprintf(STDERR, "No existing RW site for volume %lu",
4760                 (unsigned long)volid);
4761         vcode =
4762             ubik_Call(VL_ReleaseLock, cstruct, 0, volid, RWVOL,
4763                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
4764         if (vcode) {
4765             fprintf(STDERR,
4766                     "Could not release lock on entry for volume %lu \n",
4767                     (unsigned long)volid);
4768             PrintError("", vcode);
4769             return (vcode);
4770         }
4771         return VOLSERBADOP;
4772     } else {                    /* change the RW site */
4773         entry.serverNumber[index] = server;
4774         entry.serverPartition[index] = part;
4775         MapNetworkToHost(&entry, &storeEntry);
4776         vcode =
4777             VLDB_ReplaceEntry(volid, RWVOL, &storeEntry,
4778                               LOCKREL_OPCODE | LOCKREL_AFSID |
4779                               LOCKREL_TIMESTAMP);
4780         if (vcode) {
4781             fprintf(STDERR, "Could not update entry for volume %lu \n",
4782                     (unsigned long)volid);
4783             PrintError("", vcode);
4784             ubik_Call(VL_ReleaseLock, cstruct, 0, volid, RWVOL,
4785                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
4786             return (vcode);
4787         }
4788         VDONE;
4789     }
4790     return 0;
4791 }
4792
4793 /*list all the partitions on <aserver> */
4794 int
4795 UV_ListPartitions(afs_int32 aserver, struct partList *ptrPartList,
4796                   afs_int32 * cntp)
4797 {
4798     struct rx_connection *aconn;
4799     struct pIDs partIds;
4800     struct partEntries partEnts;
4801     register int i, j = 0, code;
4802
4803     *cntp = 0;
4804     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
4805
4806     partEnts.partEntries_len = 0;
4807     partEnts.partEntries_val = NULL;
4808     code = AFSVolXListPartitions(aconn, &partEnts);     /* this is available only on new servers */
4809     if (code == RXGEN_OPCODE) {
4810         for (i = 0; i < 26; i++)        /* try old interface */
4811             partIds.partIds[i] = -1;
4812         code = AFSVolListPartitions(aconn, &partIds);
4813         if (!code) {
4814             for (i = 0; i < 26; i++) {
4815                 if ((partIds.partIds[i]) != -1) {
4816                     ptrPartList->partId[j] = partIds.partIds[i];
4817                     ptrPartList->partFlags[j] = PARTVALID;
4818                     j++;
4819                 } else
4820                     ptrPartList->partFlags[i] = 0;
4821             }
4822             *cntp = j;
4823         }
4824     } else if (!code) {
4825         *cntp = partEnts.partEntries_len;
4826         if (*cntp > VOLMAXPARTS) {
4827             fprintf(STDERR,
4828                     "Warning: number of partitions on the server too high %d (process only %d)\n",
4829                     *cntp, VOLMAXPARTS);
4830             *cntp = VOLMAXPARTS;
4831         }
4832         for (i = 0; i < *cntp; i++) {
4833             ptrPartList->partId[i] = partEnts.partEntries_val[i];
4834             ptrPartList->partFlags[i] = PARTVALID;
4835         }
4836         free(partEnts.partEntries_val);
4837     }
4838
4839    /* out: */
4840     if (code)
4841         fprintf(STDERR,
4842                 "Could not fetch the list of partitions from the server\n");
4843     PrintError("", code);
4844     if (aconn)
4845         rx_DestroyConnection(aconn);
4846     return code;
4847 }
4848
4849
4850 /*zap the list of volumes specified by volPtrArray (the volCloneId field).
4851  This is used by the backup system */
4852 int
4853 UV_ZapVolumeClones(afs_int32 aserver, afs_int32 apart,
4854                    struct volDescription *volPtr, afs_int32 arraySize)
4855 {
4856     struct rx_connection *aconn;
4857     struct volDescription *curPtr;
4858     int curPos;
4859     afs_int32 code = 0;
4860     afs_int32 rcode = 0;
4861     afs_int32 success = 1;
4862     afs_int32 tid;
4863
4864     aconn = (struct rx_connection *)0;
4865     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
4866     curPos = 0;
4867     for (curPtr = volPtr; curPos < arraySize; curPtr++) {
4868         if (curPtr->volFlags & CLONEVALID) {
4869             curPtr->volFlags &= ~CLONEZAPPED;
4870             success = 1;
4871             code =
4872                 AFSVolTransCreate(aconn, curPtr->volCloneId, apart, ITOffline,
4873                                   &tid);
4874             if (code)
4875                 success = 0;
4876             else {
4877                 code = AFSVolDeleteVolume(aconn, tid);
4878                 if (code)
4879                     success = 0;
4880                 code = AFSVolEndTrans(aconn, tid, &rcode);
4881                 if (code || rcode)
4882                     success = 0;
4883             }
4884             if (success)
4885                 curPtr->volFlags |= CLONEZAPPED;
4886             if (!success)
4887                 fprintf(STDERR, "Could not zap volume %lu\n",
4888                         (unsigned long)curPtr->volCloneId);
4889             if (success)
4890                 VPRINT2("Clone of %s %u deleted\n", curPtr->volName,
4891                         curPtr->volCloneId);
4892             curPos++;
4893             tid = 0;
4894         }
4895     }
4896     if (aconn)
4897         rx_DestroyConnection(aconn);
4898     return 0;
4899 }
4900
4901 /*return a list of clones of the volumes specified by volPtrArray. Used by the 
4902  backup system */
4903 int
4904 UV_GenerateVolumeClones(afs_int32 aserver, afs_int32 apart,
4905                         struct volDescription *volPtr, afs_int32 arraySize)
4906 {
4907     struct rx_connection *aconn;
4908     struct volDescription *curPtr;
4909     int curPos;
4910     afs_int32 code = 0;
4911     afs_int32 rcode = 0;
4912     afs_int32 tid;
4913     int reuseCloneId = 0;
4914     afs_int32 curCloneId = 0;
4915     char cloneName[256];        /*max vol name */
4916
4917     aconn = (struct rx_connection *)0;
4918     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
4919     curPos = 0;
4920     if ((volPtr->volFlags & REUSECLONEID) && (volPtr->volFlags & ENTRYVALID))
4921         reuseCloneId = 1;
4922     else {                      /*get a bunch of id's from vldb */
4923         code =
4924             ubik_Call(VL_GetNewVolumeId, cstruct, 0, arraySize, &curCloneId);
4925         if (code) {
4926             fprintf(STDERR, "Could not get ID's for the clone from VLDB\n");
4927             PrintError("", code);
4928             return code;
4929         }
4930     }
4931
4932     for (curPtr = volPtr; curPos < arraySize; curPtr++) {
4933         if (curPtr->volFlags & ENTRYVALID) {
4934
4935             curPtr->volFlags |= CLONEVALID;
4936             /*make a clone of curParentId and record as curPtr->volCloneId */
4937             code =
4938                 AFSVolTransCreate(aconn, curPtr->volId, apart, ITOffline,
4939                                   &tid);
4940             if (code)
4941                 VPRINT2("Clone for volume %s %u failed \n", curPtr->volName,
4942                         curPtr->volId);
4943             if (code) {
4944                 curPtr->volFlags &= ~CLONEVALID;        /*cant clone */
4945                 curPos++;
4946                 continue;
4947             }
4948             if (strlen(curPtr->volName) < (VOLSER_OLDMAXVOLNAME - 9)) {
4949                 strcpy(cloneName, curPtr->volName);
4950                 strcat(cloneName, "-tmpClone-");
4951             } else
4952                 strcpy(cloneName, "-tmpClone");
4953             if (reuseCloneId) {
4954                 curPtr->volCloneId = curCloneId;
4955                 curCloneId++;
4956             }
4957
4958             code =
4959                 AFSVolClone(aconn, tid, 0, readonlyVolume, cloneName,
4960                             &(curPtr->volCloneId));
4961             if (code) {
4962                 curPtr->volFlags &= ~CLONEVALID;
4963                 curPos++;
4964                 fprintf(STDERR, "Could not clone %s due to error %lu\n",
4965                         curPtr->volName, (unsigned long)code);
4966                 code = AFSVolEndTrans(aconn, tid, &rcode);
4967                 if (code)
4968                     fprintf(STDERR, "WARNING: could not end transaction\n");
4969                 continue;
4970             }
4971             VPRINT2("********** Cloned %s temporary %u\n", cloneName,
4972                     curPtr->volCloneId);
4973             code = AFSVolEndTrans(aconn, tid, &rcode);
4974             if (code || rcode) {
4975                 curPtr->volFlags &= ~CLONEVALID;
4976                 curPos++;
4977                 continue;
4978             }
4979
4980             curPos++;
4981         }
4982     }
4983     if (aconn)
4984         rx_DestroyConnection(aconn);
4985     return 0;
4986 }
4987
4988
4989 /*list all the volumes on <aserver> and <apart>. If all = 1, then all the
4990 * relevant fields of the volume are also returned. This is a heavy weight operation.*/
4991 int
4992 UV_ListVolumes(afs_int32 aserver, afs_int32 apart, int all,
4993                struct volintInfo **resultPtr, afs_int32 * size)
4994 {
4995     struct rx_connection *aconn;
4996     afs_int32 code = 0;
4997     volEntries volumeInfo;
4998
4999     code = 0;
5000     *size = 0;
5001     *resultPtr = (volintInfo *) 0;
5002     volumeInfo.volEntries_val = (volintInfo *) 0;       /*this hints the stub to allocate space */
5003     volumeInfo.volEntries_len = 0;
5004
5005     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
5006     code = AFSVolListVolumes(aconn, apart, all, &volumeInfo);
5007     if (code) {
5008         fprintf(STDERR,
5009                 "Could not fetch the list of volumes from the server\n");
5010     } else {
5011         *resultPtr = volumeInfo.volEntries_val;
5012         *size = volumeInfo.volEntries_len;
5013     }
5014
5015     if (aconn)
5016         rx_DestroyConnection(aconn);
5017     PrintError("", code);
5018     return code;
5019 }
5020
5021 /*------------------------------------------------------------------------
5022  * EXPORTED UV_XListVolumes
5023  *
5024  * Description:
5025  *      List the extended information for all the volumes on a particular
5026  *      File Server and partition.  We may either return the volume's ID
5027  *      or all of its extended information.
5028  *
5029  * Arguments:
5030  *      a_serverID         : Address of the File Server for which we want
5031  *                              extended volume info.
5032  *      a_partID           : Partition for which we want the extended
5033  *                              volume info.
5034  *      a_all              : If non-zero, fetch ALL the volume info,
5035  *                              otherwise just the volume ID.
5036  *      a_resultPP         : Ptr to the address of the area containing
5037  *                              the returned volume info.
5038  *      a_numEntsInResultP : Ptr for the value we set for the number of
5039  *                              entries returned.
5040  *
5041  * Returns:
5042  *      0 on success,
5043  *      Otherise, the return value of AFSVolXListVolumes.
5044  *
5045  * Environment:
5046  *      This routine is closely related to UV_ListVolumes, which returns
5047  *      only the standard level of detail on AFS volumes. It is a
5048  *      heavyweight operation, zipping through all the volume entries for
5049  *      a given server/partition.
5050  *
5051  * Side Effects:
5052  *      As advertised.
5053  *------------------------------------------------------------------------*/
5054
5055 int
5056 UV_XListVolumes(afs_int32 a_serverID, afs_int32 a_partID, int a_all,
5057                 struct volintXInfo **a_resultPP,
5058                 afs_int32 * a_numEntsInResultP)
5059 {
5060     struct rx_connection *rxConnP;      /*Ptr to the Rx connection involved */
5061     afs_int32 code;             /*Error code to return */
5062     volXEntries volumeXInfo;    /*Area for returned extended vol info */
5063
5064     /*
5065      * Set up our error code and the area for returned extended volume info.
5066      * We set the val field to a null pointer as a hint for the stub to
5067      * allocate space.
5068      */
5069     code = 0;
5070     *a_numEntsInResultP = 0;
5071     *a_resultPP = (volintXInfo *) 0;
5072     volumeXInfo.volXEntries_val = (volintXInfo *) 0;
5073     volumeXInfo.volXEntries_len = 0;
5074
5075     /*
5076      * Bind to the Volume Server port on the File Server machine in question,
5077      * then go for it.
5078      */
5079     rxConnP = UV_Bind(a_serverID, AFSCONF_VOLUMEPORT);
5080     code = AFSVolXListVolumes(rxConnP, a_partID, a_all, &volumeXInfo);
5081     if (code)
5082         fprintf(STDERR, "[UV_XListVolumes] Couldn't fetch volume list\n");
5083     else {
5084         /*
5085          * We got the info; pull out the pointer to where the results lie
5086          * and how many entries are there.
5087          */
5088         *a_resultPP = volumeXInfo.volXEntries_val;
5089         *a_numEntsInResultP = volumeXInfo.volXEntries_len;
5090     }
5091
5092     /*
5093      * If we got an Rx connection, throw it away.
5094      */
5095     if (rxConnP)
5096         rx_DestroyConnection(rxConnP);
5097
5098     PrintError("", code);
5099     return (code);
5100 }                               /*UV_XListVolumes */
5101
5102 /* get all the information about volume <volid> on <aserver> and <apart> */
5103 int
5104 UV_ListOneVolume(afs_int32 aserver, afs_int32 apart, afs_int32 volid,
5105                  struct volintInfo **resultPtr)
5106 {
5107     struct rx_connection *aconn;
5108     afs_int32 code = 0;
5109     volEntries volumeInfo;
5110
5111     code = 0;
5112
5113     *resultPtr = (volintInfo *) 0;
5114     volumeInfo.volEntries_val = (volintInfo *) 0;       /*this hints the stub to allocate space */
5115     volumeInfo.volEntries_len = 0;
5116
5117     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
5118     code = AFSVolListOneVolume(aconn, apart, volid, &volumeInfo);
5119     if (code) {
5120         fprintf(STDERR,
5121                 "Could not fetch the information about volume %lu from the server\n",
5122                 (unsigned long)volid);
5123     } else {
5124         *resultPtr = volumeInfo.volEntries_val;
5125
5126     }
5127
5128     if (aconn)
5129         rx_DestroyConnection(aconn);
5130     PrintError("", code);
5131     return code;
5132 }
5133
5134 /*------------------------------------------------------------------------
5135  * EXPORTED UV_XListOneVolume
5136  *
5137  * Description:
5138  *      List the extended information for a volume on a particular File
5139  *      Server and partition.
5140  *
5141  * Arguments:
5142  *      a_serverID         : Address of the File Server for which we want
5143  *                              extended volume info.
5144  *      a_partID           : Partition for which we want the extended
5145  *                              volume info.
5146  *      a_volID            : Volume ID for which we want the info.
5147  *      a_resultPP         : Ptr to the address of the area containing
5148  *                              the returned volume info.
5149  *
5150  * Returns:
5151  *      0 on success,
5152  *      Otherise, the return value of AFSVolXListOneVolume.
5153  *
5154  * Environment:
5155  *      This routine is closely related to UV_ListOneVolume, which returns
5156  *      only the standard level of detail on the chosen AFS volume.
5157  *
5158  * Side Effects:
5159  *      As advertised.
5160  *------------------------------------------------------------------------*/
5161
5162 int
5163 UV_XListOneVolume(afs_int32 a_serverID, afs_int32 a_partID, afs_int32 a_volID,
5164                   struct volintXInfo **a_resultPP)
5165 {
5166     struct rx_connection *rxConnP;      /*Rx connection to Volume Server */
5167     afs_int32 code;             /*Error code */
5168     volXEntries volumeXInfo;    /*Area for returned info */
5169
5170     /*
5171      * Set up our error code, and the area we're in which we are returning
5172      * the info.  Setting the val field to a null pointer tells the stub
5173      * to allocate space for us.
5174      */
5175     code = 0;
5176     *a_resultPP = (volintXInfo *) 0;
5177     volumeXInfo.volXEntries_val = (volintXInfo *) 0;
5178     volumeXInfo.volXEntries_len = 0;
5179
5180     /*
5181      * Bind to the Volume Server port on the File Server machine in question,
5182      * then go for it.
5183      */
5184     rxConnP = UV_Bind(a_serverID, AFSCONF_VOLUMEPORT);
5185     code = AFSVolXListOneVolume(rxConnP, a_partID, a_volID, &volumeXInfo);
5186     if (code)
5187         fprintf(STDERR,
5188                 "[UV_XListOneVolume] Couldn't fetch the volume information\n");
5189     else
5190         /*
5191          * We got the info; pull out the pointer to where the results lie.
5192          */
5193         *a_resultPP = volumeXInfo.volXEntries_val;
5194
5195     /*
5196      * If we got an Rx connection, throw it away.
5197      */
5198     if (rxConnP)
5199         rx_DestroyConnection(rxConnP);
5200
5201     PrintError("", code);
5202     return code;
5203 }
5204
5205 /* CheckVolume()
5206  *    Given a volume we read from a partition, check if it is 
5207  *    represented in the VLDB correctly.
5208  * 
5209  *    The VLDB is looked up by the RW volume id (not its name).
5210  *    The RW contains the true name of the volume (BK and RO set
5211  *       the name in the VLDB only on creation of the VLDB entry).
5212  *    We want rules strict enough that when we check all volumes
5213  *       on one partition, it does not need to be done again. IE:
5214  *       two volumes on different partitions won't constantly 
5215  *       change a VLDB entry away from what the other set.
5216  *    For RW and BK volumes, we will always check the VLDB to see 
5217  *       if the two exist on the server/partition. May seem redundant,
5218  *       but this is an easy check of the VLDB. IE: if the VLDB entry
5219  *       says the BK exists but no BK volume is there, we will detect
5220  *       this when we check the RW volume.
5221  *    VLDB entries are locked only when a change needs to be done.
5222  *    Output changed to look a lot like the "vos syncserv" otuput.
5223  */
5224 static afs_int32
5225 CheckVolume(volintInfo * volumeinfo, afs_int32 aserver, afs_int32 apart,
5226             afs_int32 * modentry, afs_uint32 * maxvolid)
5227 {
5228     int idx, j;
5229     afs_int32 code, error = 0;
5230     struct nvldbentry entry, storeEntry;
5231     char pname[10];
5232     int pass = 0, islocked = 0, createentry, addvolume, modified, mod;
5233     afs_int32 rwvolid;
5234
5235     if (modentry)
5236         *modentry = 0;
5237     rwvolid =
5238         ((volumeinfo->type ==
5239           RWVOL) ? volumeinfo->volid : volumeinfo->parentID);
5240
5241   retry:
5242     /* Check to see if the VLDB is ok without locking it (pass 1).
5243      * If it will change, then lock the VLDB entry, read it again,
5244      * then make the changes to it (pass 2).
5245      */
5246     if (++pass == 2) {
5247         code = ubik_Call(VL_SetLock, cstruct, 0, rwvolid, RWVOL, VLOP_DELETE);
5248         if (code) {
5249             fprintf(STDERR, "Could not lock VLDB entry for %lu\n",
5250                     (unsigned long)rwvolid);
5251             ERROR_EXIT(code);
5252         }
5253         islocked = 1;
5254     }
5255
5256     createentry = 0;            /* Do we need to create a VLDB entry */
5257     addvolume = 0;              /* Add this volume to the VLDB entry */
5258     modified = 0;               /* The VLDB entry was modified */
5259
5260     /* Read the entry from VLDB by its RW volume id */
5261     code = VLDB_GetEntryByID(rwvolid, RWVOL, &entry);
5262     if (code) {
5263         if (code != VL_NOENT) {
5264             fprintf(STDOUT,
5265                     "Could not retreive the VLDB entry for volume %lu \n",
5266                     (unsigned long)rwvolid);
5267             ERROR_EXIT(code);
5268         }
5269
5270         memset(&entry, 0, sizeof(entry));
5271         vsu_ExtractName(entry.name, volumeinfo->name);  /* Store name of RW */
5272
5273         createentry = 1;
5274     } else {
5275         MapHostToNetwork(&entry);
5276     }
5277
5278     if (verbose && (pass == 1)) {
5279         fprintf(STDOUT, "_______________________________\n");
5280         fprintf(STDOUT, "\n-- status before -- \n");
5281         if (createentry) {
5282             fprintf(STDOUT, "\n**does not exist**\n");
5283         } else {
5284             if ((entry.flags & RW_EXISTS) || (entry.flags & RO_EXISTS)
5285                 || (entry.flags & BACK_EXISTS))
5286                 EnumerateEntry(&entry);
5287         }
5288         fprintf(STDOUT, "\n");
5289     }
5290
5291     if (volumeinfo->type == RWVOL) {    /* RW volume exists */
5292         if (createentry) {
5293             idx = 0;
5294             entry.nServers = 1;
5295             addvolume++;
5296         } else {
5297             /* Check existence of RW and BK volumes */
5298             code = CheckVldbRWBK(&entry, &mod);
5299             if (code)
5300                 ERROR_EXIT(code);
5301             if (mod)
5302                 modified++;
5303
5304             idx = Lp_GetRwIndex(&entry);
5305             if (idx == -1) {    /* RW index not found in the VLDB entry */
5306                 idx = entry.nServers;   /* put it into next index */
5307                 entry.nServers++;
5308                 addvolume++;
5309             } else {            /* RW index found in the VLDB entry. */
5310                 /* Verify if this volume's location matches where the VLDB says it is */
5311                 if (!Lp_Match(aserver, apart, &entry)) {
5312                     if (entry.flags & RW_EXISTS) {
5313                         /* The RW volume exists elsewhere - report this one a duplicate */
5314                         if (pass == 1) {
5315                             MapPartIdIntoName(apart, pname);
5316                             fprintf(STDERR,
5317                                     "*** Warning: Orphaned RW volume %lu exists on %s %s\n",
5318                                     (unsigned long)rwvolid,
5319                                     hostutil_GetNameByINet(aserver), pname);
5320                             MapPartIdIntoName(entry.serverPartition[idx],
5321                                               pname);
5322                             fprintf(STDERR,
5323                                     "    VLDB reports RW volume %lu exists on %s %s\n",
5324                                     (unsigned long)rwvolid,
5325                                     hostutil_GetNameByINet(entry.
5326                                                            serverNumber[idx]),
5327                                     pname);
5328                         }
5329                     } else {
5330                         /* The RW volume does not exist - have VLDB point to this one */
5331                         addvolume++;
5332
5333                         /* Check for orphaned BK volume on old partition */
5334                         if (entry.flags & BACK_EXISTS) {
5335                             if (pass == 1) {
5336                                 MapPartIdIntoName(entry.serverPartition[idx],
5337                                                   pname);
5338                                 fprintf(STDERR,
5339                                         "*** Warning: Orphaned BK volume %u exists on %s %s\n",
5340                                         entry.volumeId[BACKVOL],
5341                                         hostutil_GetNameByINet(entry.
5342                                                                serverNumber
5343                                                                [idx]), pname);
5344                                 MapPartIdIntoName(apart, pname);
5345                                 fprintf(STDERR,
5346                                         "    VLDB reports its RW volume %lu exists on %s %s\n",
5347                                         (unsigned long)rwvolid,
5348                                         hostutil_GetNameByINet(aserver),
5349                                         pname);
5350                             }
5351                         }
5352                     }
5353                 } else {
5354                     /* Volume location matches the VLDB location */
5355                     if ((volumeinfo->backupID && !entry.volumeId[BACKVOL])
5356                         || (volumeinfo->cloneID && !entry.volumeId[ROVOL])
5357                         ||
5358                         (strncmp
5359                          (entry.name, volumeinfo->name,
5360                           VOLSER_OLDMAXVOLNAME) != 0)) {
5361                         addvolume++;
5362                     }
5363                 }
5364             }
5365         }
5366
5367         if (addvolume) {
5368             entry.flags |= RW_EXISTS;
5369             entry.volumeId[RWVOL] = rwvolid;
5370             if (!entry.volumeId[BACKVOL])
5371                 entry.volumeId[BACKVOL] = volumeinfo->backupID;
5372             if (!entry.volumeId[ROVOL])
5373                 entry.volumeId[ROVOL] = volumeinfo->cloneID;
5374
5375             entry.serverFlags[idx] = ITSRWVOL;
5376             entry.serverNumber[idx] = aserver;
5377             entry.serverPartition[idx] = apart;
5378             strncpy(entry.name, volumeinfo->name, VOLSER_OLDMAXVOLNAME);
5379
5380             modified++;
5381
5382             /* One last check - to update BK if need to */
5383             code = CheckVldbRWBK(&entry, &mod);
5384             if (code)
5385                 ERROR_EXIT(code);
5386             if (mod)
5387                 modified++;
5388         }
5389     }
5390
5391     else if (volumeinfo->type == BACKVOL) {     /* A BK volume */
5392         if (createentry) {
5393             idx = 0;
5394             entry.nServers = 1;
5395             addvolume++;
5396         } else {
5397             /* Check existence of RW and BK volumes */
5398             code = CheckVldbRWBK(&entry, &mod);
5399             if (code)
5400                 ERROR_EXIT(code);
5401             if (mod)
5402                 modified++;
5403
5404             idx = Lp_GetRwIndex(&entry);
5405             if (idx == -1) {    /* RW index not found in the VLDB entry */
5406                 idx = entry.nServers;   /* Put it into next index */
5407                 entry.nServers++;
5408                 addvolume++;
5409             } else {            /* RW index found in the VLDB entry */
5410                 /* Verify if this volume's location matches where the VLDB says it is */
5411                 if (!Lp_Match(aserver, apart, &entry)) {
5412                     /* VLDB says RW and/or BK is elsewhere - report this BK volume orphaned */
5413                     if (pass == 1) {
5414                         MapPartIdIntoName(apart, pname);
5415                         fprintf(STDERR,
5416                                 "*** Warning: Orphaned BK volume %lu exists on %s %s\n",
5417                                 (unsigned long)volumeinfo->volid,
5418                                 hostutil_GetNameByINet(aserver), pname);
5419                         MapPartIdIntoName(entry.serverPartition[idx], pname);
5420                         fprintf(STDERR,
5421                                 "    VLDB reports its RW/BK volume %lu exists on %s %s\n",
5422                                 (unsigned long)rwvolid,
5423                                 hostutil_GetNameByINet(entry.
5424                                                        serverNumber[idx]),
5425                                 pname);
5426                     }
5427                 } else {
5428                     if (volumeinfo->volid != entry.volumeId[BACKVOL]) {
5429                         if (!(entry.flags & BACK_EXISTS)) {
5430                             addvolume++;
5431                         } else if (volumeinfo->volid >
5432                                    entry.volumeId[BACKVOL]) {
5433                             addvolume++;
5434
5435                             if (pass == 1) {
5436                                 MapPartIdIntoName(entry.serverPartition[idx],
5437                                                   pname);
5438                                 fprintf(STDERR,
5439                                         "*** Warning: Orphaned BK volume %u exists on %s %s\n",
5440                                         entry.volumeId[BACKVOL],
5441                                         hostutil_GetNameByINet(aserver),
5442                                         pname);
5443                                 fprintf(STDERR,
5444                                         "    VLDB reports its BK volume ID is %lu\n",
5445                                         (unsigned long)volumeinfo->volid);
5446                             }
5447                         } else {
5448                             if (pass == 1) {
5449                                 MapPartIdIntoName(entry.serverPartition[idx],
5450                                                   pname);
5451                                 fprintf(STDERR,
5452                                         "*** Warning: Orphaned BK volume %lu exists on %s %s\n",
5453                                         (unsigned long)volumeinfo->volid,
5454                                         hostutil_GetNameByINet(aserver),
5455                                         pname);
5456                                 fprintf(STDERR,
5457                                         "    VLDB reports its BK volume ID is %u\n",
5458                                         entry.volumeId[BACKVOL]);
5459                             }
5460                         }
5461                     } else if (!entry.volumeId[BACKVOL]) {
5462                         addvolume++;
5463                     }
5464                 }
5465             }
5466         }
5467         if (addvolume) {
5468             entry.flags |= BACK_EXISTS;
5469             entry.volumeId[RWVOL] = rwvolid;
5470             entry.volumeId[BACKVOL] = volumeinfo->volid;
5471
5472             entry.serverNumber[idx] = aserver;
5473             entry.serverPartition[idx] = apart;
5474             entry.serverFlags[idx] = ITSRWVOL;
5475
5476             modified++;
5477         }
5478     }
5479
5480     else if (volumeinfo->type == ROVOL) {       /* A RO volume */
5481         if (volumeinfo->volid == entry.volumeId[ROVOL]) {
5482             /* This is a quick check to see if the RO entry exists in the 
5483              * VLDB so we avoid the CheckVldbRO() call (which checks if each
5484              * RO volume listed in the VLDB exists).
5485              */
5486             idx = Lp_ROMatch(aserver, apart, &entry) - 1;
5487             if (idx == -1) {
5488                 idx = entry.nServers;
5489                 entry.nServers++;
5490                 addvolume++;
5491             } else {
5492                 if (!(entry.flags & RO_EXISTS)) {
5493                     addvolume++;
5494                 }
5495             }
5496         } else {
5497             /* Before we correct the VLDB entry, make sure all the
5498              * ROs listed in the VLDB exist.
5499              */
5500             code = CheckVldbRO(&entry, &mod);
5501             if (code)
5502                 ERROR_EXIT(code);
5503             if (mod)
5504                 modified++;
5505
5506             if (!(entry.flags & RO_EXISTS)) {
5507                 /* No RO exists in the VLDB entry - add this one */
5508                 idx = entry.nServers;
5509                 entry.nServers++;
5510                 addvolume++;
5511             } else if (volumeinfo->volid > entry.volumeId[ROVOL]) {
5512                 /* The volume headers's RO ID does not match that in the VLDB entry,
5513                  * and the vol hdr's ID is greater (implies more recent). So delete
5514                  * all the RO volumes listed in VLDB entry and add this volume.
5515                  */
5516                 for (j = 0; j < entry.nServers; j++) {
5517                     if (entry.serverFlags[j] & ITSROVOL) {
5518                         /* Verify this volume exists and print message we are orphaning it */
5519                         if (pass == 1) {
5520                             MapPartIdIntoName(apart, pname);
5521                             fprintf(STDERR,
5522                                     "*** Warning: Orphaned RO volume %u exists on %s %s\n",
5523                                     entry.volumeId[ROVOL],
5524                                     hostutil_GetNameByINet(entry.
5525                                                            serverNumber[j]),
5526                                     pname);
5527                             fprintf(STDERR,
5528                                     "    VLDB reports its RO volume ID is %lu\n",
5529                                     (unsigned long)volumeinfo->volid);
5530                         }
5531
5532                         Lp_SetRWValue(entry, entry.serverNumber[idx],
5533                                       entry.serverPartition[idx], 0L, 0L);
5534                         entry.nServers--;
5535                         modified++;
5536                         j--;
5537                     }
5538                 }
5539
5540                 idx = entry.nServers;
5541                 entry.nServers++;
5542                 addvolume++;
5543             } else if (volumeinfo->volid < entry.volumeId[ROVOL]) {
5544                 /* The volume headers's RO ID does not match that in the VLDB entry,
5545                  * and the vol hdr's ID is lower (implies its older). So orphan it.
5546                  */
5547                 if (pass == 1) {
5548                     MapPartIdIntoName(apart, pname);
5549                     fprintf(STDERR,
5550                             "*** Warning: Orphaned RO volume %lu exists on %s %s\n",
5551                             (unsigned long)volumeinfo->volid,
5552                             hostutil_GetNameByINet(aserver), pname);
5553                     fprintf(STDERR,
5554                             "    VLDB reports its RO volume ID is %u\n",
5555                             entry.volumeId[ROVOL]);
5556                 }
5557             } else {
5558                 /* The RO volume ID in the volume header match that in the VLDB entry,
5559                  * and there exist RO volumes in the VLDB entry. See if any of them
5560                  * are this one. If not, then we add it.
5561                  */
5562                 idx = Lp_ROMatch(aserver, apart, &entry) - 1;
5563                 if (idx == -1) {
5564                     idx = entry.nServers;
5565                     entry.nServers++;
5566                     addvolume++;
5567                 }
5568             }
5569         }
5570
5571         if (addvolume) {
5572             entry.flags |= RO_EXISTS;
5573             entry.volumeId[RWVOL] = rwvolid;
5574             entry.volumeId[ROVOL] = volumeinfo->volid;
5575
5576             entry.serverNumber[idx] = aserver;
5577             entry.serverPartition[idx] = apart;
5578             entry.serverFlags[idx] = ITSROVOL;
5579
5580             modified++;
5581         }
5582     }
5583
5584     /* Remember largest volume id */
5585     if (entry.volumeId[ROVOL] > *maxvolid)
5586         *maxvolid = entry.volumeId[ROVOL];
5587     if (entry.volumeId[BACKVOL] > *maxvolid)
5588         *maxvolid = entry.volumeId[BACKVOL];
5589     if (entry.volumeId[RWVOL] > *maxvolid)
5590         *maxvolid = entry.volumeId[RWVOL];
5591
5592     if (modified) {
5593         MapNetworkToHost(&entry, &storeEntry);
5594
5595         if (createentry) {
5596             code = VLDB_CreateEntry(&storeEntry);
5597             if (code) {
5598                 fprintf(STDOUT,
5599                         "Could not create a VLDB entry for the volume %lu\n",
5600                         (unsigned long)rwvolid);
5601                 ERROR_EXIT(code);
5602             }
5603         } else {
5604             if (pass == 1)
5605                 goto retry;
5606             code =
5607                 VLDB_ReplaceEntry(rwvolid, RWVOL, &storeEntry,
5608                                   LOCKREL_OPCODE | LOCKREL_AFSID |
5609                                   LOCKREL_TIMESTAMP);
5610             if (code) {
5611                 fprintf(STDERR, "Could not update entry for %lu\n",
5612                         (unsigned long)rwvolid);
5613                 ERROR_EXIT(code);
5614             }
5615         }
5616         if (modentry)
5617             *modentry = modified;
5618     } else if (pass == 2) {
5619         code =
5620             ubik_Call(VL_ReleaseLock, cstruct, 0, rwvolid, RWVOL,
5621                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
5622         if (code) {
5623             PrintError("Could not unlock VLDB entry ", code);
5624         }
5625     }
5626
5627     if (verbose) {
5628         fprintf(STDOUT, "-- status after --\n");
5629         if (modified)
5630             EnumerateEntry(&entry);
5631         else
5632             fprintf(STDOUT, "\n**no change**\n");
5633     }
5634
5635   error_exit:
5636     VPRINT("\n_______________________________\n");
5637     return (error);
5638 }
5639
5640 int
5641 sortVolumes(const void *a, const void *b)
5642 {
5643     volintInfo *v1 = (volintInfo *) a;
5644     volintInfo *v2 = (volintInfo *) b;
5645     afs_int32 rwvolid1, rwvolid2;
5646
5647     rwvolid1 = ((v1->type == RWVOL) ? v1->volid : v1->parentID);
5648     rwvolid2 = ((v2->type == RWVOL) ? v2->volid : v2->parentID);
5649
5650     if (rwvolid1 > rwvolid2)
5651         return -1;              /* lower RW id goes first */
5652     if (rwvolid1 < rwvolid2)
5653         return 1;
5654
5655     if (v1->type == RWVOL)
5656         return -1;              /* RW vols go first */
5657     if (v2->type == RWVOL)
5658         return 1;
5659
5660     if ((v1->type == BACKVOL) && (v2->type == ROVOL))
5661         return -1;              /* BK vols next */
5662     if ((v1->type == ROVOL) && (v2->type == BACKVOL))
5663         return 1;
5664
5665     if (v1->volid < v2->volid)
5666         return 1;               /* larger volids first */
5667     if (v1->volid > v2->volid)
5668         return -1;
5669     return 0;
5670 }
5671
5672 /* UV_SyncVolume()
5673  *      Synchronise <aserver> <apart>(if flags = 1) <avolid>.
5674  *      Synchronize an individual volume against a sever and partition.
5675  *      Checks the VLDB entry (similar to syncserv) as well as checks
5676  *      if the volume exists on specified servers (similar to syncvldb).
5677  */
5678 int
5679 UV_SyncVolume(afs_int32 aserver, afs_int32 apart, char *avolname, int flags)
5680 {
5681     struct rx_connection *aconn = 0;
5682     afs_int32 j, k, code, vcode, error = 0;
5683     afs_int32 tverbose, mod, modified = 0;
5684     struct nvldbentry vldbentry;
5685     afs_int32 volumeid = 0;
5686     volEntries volumeInfo;
5687     struct partList PartList;
5688     afs_int32 pcnt, rv;
5689     afs_int32 maxvolid = 0;
5690
5691     volumeInfo.volEntries_val = (volintInfo *) 0;
5692     volumeInfo.volEntries_len = 0;
5693
5694     if (!aserver && flags) {
5695         /* fprintf(STDERR,"Partition option requires a server option\n"); */
5696         ERROR_EXIT(EINVAL);
5697     }
5698
5699     /* Turn verbose logging off and do our own verbose logging */
5700     tverbose = verbose;
5701     verbose = 0;
5702
5703     /* Read the VLDB entry */
5704     vcode = VLDB_GetEntryByName(avolname, &vldbentry);
5705     if (vcode && (vcode != VL_NOENT)) {
5706         fprintf(STDERR, "Could not access the VLDB for volume %s\n",
5707                 avolname);
5708         ERROR_EXIT(vcode);
5709     } else if (!vcode) {
5710         MapHostToNetwork(&vldbentry);
5711     }
5712
5713     if (tverbose) {
5714         fprintf(STDOUT, "Processing VLDB entry %s ...\n", avolname);
5715         fprintf(STDOUT, "_______________________________\n");
5716         fprintf(STDOUT, "\n-- status before -- \n");
5717         if (vcode) {
5718             fprintf(STDOUT, "\n**does not exist**\n");
5719         } else {
5720             if ((vldbentry.flags & RW_EXISTS) || (vldbentry.flags & RO_EXISTS)
5721                 || (vldbentry.flags & BACK_EXISTS))
5722                 EnumerateEntry(&vldbentry);
5723         }
5724         fprintf(STDOUT, "\n");
5725     }
5726
5727     /* Verify that all of the VLDB entries exist on the repective servers 
5728      * and partitions (this does not require that avolname be a volume ID).
5729      * Equivalent to a syncserv.
5730      */
5731     if (!vcode) {
5732         code = CheckVldb(&vldbentry, &mod);
5733         if (code) {
5734             fprintf(STDERR, "Could not process VLDB entry for volume %s\n",
5735                     vldbentry.name);
5736             ERROR_EXIT(code);
5737         }
5738         if (mod)
5739             modified++;
5740     }
5741
5742     /* If aserver is given, we will search for the desired volume on it */
5743     if (aserver) {
5744         /* Generate array of partitions on the server that we will check */
5745         if (!flags) {
5746             code = UV_ListPartitions(aserver, &PartList, &pcnt);
5747             if (code) {
5748                 fprintf(STDERR,
5749                         "Could not fetch the list of partitions from the server\n");
5750                 ERROR_EXIT(code);
5751             }
5752         } else {
5753             PartList.partId[0] = apart;
5754             pcnt = 1;
5755         }
5756
5757         aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
5758
5759         /* If a volume ID were given, search for it on each partition */
5760         if ((volumeid = atol(avolname))) {
5761             for (j = 0; j < pcnt; j++) {
5762                 code =
5763                     AFSVolListOneVolume(aconn, PartList.partId[j], volumeid,
5764                                         &volumeInfo);
5765                 if (code) {
5766                     if (code != ENODEV) {
5767                         fprintf(STDERR, "Could not query server\n");
5768                         ERROR_EXIT(code);
5769                     }
5770                 } else {
5771                     /* Found one, sync it with VLDB entry */
5772                     code =
5773                         CheckVolume(volumeInfo.volEntries_val, aserver,
5774                                     PartList.partId[j], &mod, &maxvolid);
5775                     if (code)
5776                         ERROR_EXIT(code);
5777                     if (mod)
5778                         modified++;
5779                 }
5780
5781                 if (volumeInfo.volEntries_val)
5782                     free(volumeInfo.volEntries_val);
5783                 volumeInfo.volEntries_val = (volintInfo *) 0;
5784                 volumeInfo.volEntries_len = 0;
5785             }
5786         }
5787
5788         /* Check to see if the RW, BK, and RO IDs exist on any
5789          * partitions. We get the volume IDs from the VLDB.
5790          */
5791         rv = 1;                 /* Read the VLDB entry ? */
5792         for (j = 0; j < MAXTYPES; j++) {        /* for RW, RO, and BK IDs */
5793             if (rv) {
5794                 vcode = VLDB_GetEntryByName(avolname, &vldbentry);
5795                 if (vcode) {
5796                     if (vcode == VL_NOENT)
5797                         break;
5798                     fprintf(STDERR,
5799                             "Could not access the VLDB for volume %s\n",
5800                             avolname);
5801                     ERROR_EXIT(vcode);
5802                 }
5803                 rv = 0;
5804             }
5805
5806             if (vldbentry.volumeId[j] == 0)
5807                 continue;
5808
5809             for (k = 0; k < pcnt; k++) {        /* For each partition */
5810                 volumeInfo.volEntries_val = (volintInfo *) 0;
5811                 volumeInfo.volEntries_len = 0;
5812                 code =
5813                     AFSVolListOneVolume(aconn, PartList.partId[k],
5814                                         vldbentry.volumeId[j], &volumeInfo);
5815                 if (code) {
5816                     if (code != ENODEV) {
5817                         fprintf(STDERR, "Could not query server\n");
5818                         ERROR_EXIT(code);
5819                     }
5820                 } else {
5821                     /* Found one, sync it with VLDB entry */
5822                     code =
5823                         CheckVolume(volumeInfo.volEntries_val, aserver,
5824                                     PartList.partId[k], &mod, &maxvolid);
5825                     if (code)
5826                         ERROR_EXIT(code);
5827                     if (mod)
5828                         modified++, rv++;
5829                 }
5830
5831                 if (volumeInfo.volEntries_val)
5832                     free(volumeInfo.volEntries_val);
5833                 volumeInfo.volEntries_val = (volintInfo *) 0;
5834                 volumeInfo.volEntries_len = 0;
5835             }
5836         }
5837     }
5838
5839     /* if (aserver) */
5840     /* If verbose output, print a summary of what changed */
5841     if (tverbose) {
5842         fprintf(STDOUT, "-- status after --\n");
5843         code = VLDB_GetEntryByName(avolname, &vldbentry);
5844         if (code && (code != VL_NOENT)) {
5845             fprintf(STDERR, "Could not access the VLDB for volume %s\n",
5846                     avolname);
5847             ERROR_EXIT(code);
5848         }
5849         if (modified && (code == VL_NOENT)) {
5850             fprintf(STDOUT, "\n**entry deleted**\n");
5851         } else if (modified) {
5852             EnumerateEntry(&vldbentry);
5853         } else {
5854             fprintf(STDOUT, "\n**no change**\n");
5855         }
5856         fprintf(STDOUT, "\n_______________________________\n");
5857     }
5858
5859   error_exit:
5860     /* Now check if the maxvolid is larger than that stored in the VLDB */
5861     if (maxvolid) {
5862         afs_int32 maxvldbid = 0;
5863         code = ubik_Call(VL_GetNewVolumeId, cstruct, 0, 0, &maxvldbid);
5864         if (code) {
5865             fprintf(STDERR,
5866                     "Could not get the highest allocated volume id from the VLDB\n");
5867             if (!error)
5868                 error = code;
5869         } else if (maxvolid > maxvldbid) {
5870             afs_uint32 id, nid;
5871             id = maxvolid - maxvldbid + 1;
5872             code = ubik_Call(VL_GetNewVolumeId, cstruct, 0, id, &nid);
5873             if (code) {
5874                 fprintf(STDERR,
5875                         "Error in increasing highest allocated volume id in VLDB\n");
5876                 if (!error)
5877                     error = code;
5878             }
5879         }
5880     }
5881
5882     verbose = tverbose;
5883     if (verbose) {
5884         if (error)
5885             fprintf(STDOUT, "...error encountered");
5886         else
5887             fprintf(STDOUT, "...done entry\n");
5888     }
5889     if (aconn)
5890         rx_DestroyConnection(aconn);
5891     if (volumeInfo.volEntries_val)
5892         free(volumeInfo.volEntries_val);
5893
5894     PrintError("", error);
5895     return error;
5896 }
5897
5898 /* UV_SyncVldb()
5899  *      Synchronise vldb with the file server <aserver> and,
5900  *      optionally, <apart>.
5901  */
5902 int
5903 UV_SyncVldb(afs_int32 aserver, afs_int32 apart, int flags, int force)
5904 {
5905     struct rx_connection *aconn;
5906     afs_int32 code, error = 0;
5907     int i, j, pfail;
5908     volEntries volumeInfo;
5909     struct partList PartList;
5910     afs_int32 pcnt;
5911     char pname[10];
5912     volintInfo *vi;
5913     afs_int32 failures = 0, modifications = 0, tentries = 0;
5914     afs_int32 modified;
5915     afs_uint32 maxvolid = 0;
5916
5917     volumeInfo.volEntries_val = (volintInfo *) 0;
5918     volumeInfo.volEntries_len = 0;
5919
5920     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
5921
5922     /* Generate array of partitions to check */
5923     if (!flags) {
5924         code = UV_ListPartitions(aserver, &PartList, &pcnt);
5925         if (code) {
5926             fprintf(STDERR,
5927                     "Could not fetch the list of partitions from the server\n");
5928             ERROR_EXIT(code);
5929         }
5930     } else {
5931         PartList.partId[0] = apart;
5932         pcnt = 1;
5933     }
5934
5935     VPRINT("Processing volume entries ...\n");
5936
5937     /* Step through the array of partitions */
5938     for (i = 0; i < pcnt; i++) {
5939         apart = PartList.partId[i];
5940         MapPartIdIntoName(apart, pname);
5941
5942         volumeInfo.volEntries_val = (volintInfo *) 0;
5943         volumeInfo.volEntries_len = 0;
5944         code = AFSVolListVolumes(aconn, apart, 1, &volumeInfo);
5945         if (code) {
5946             fprintf(STDERR,
5947                     "Could not fetch the list of volumes from the server\n");
5948             ERROR_EXIT(code);
5949         }
5950
5951         /* May want to sort the entries: RW, BK (high to low), RO (high to low) */
5952         qsort((char *)volumeInfo.volEntries_val, volumeInfo.volEntries_len,
5953               sizeof(volintInfo), sortVolumes);
5954
5955         pfail = 0;
5956         for (vi = volumeInfo.volEntries_val, j = 0;
5957              j < volumeInfo.volEntries_len; j++, vi++) {
5958             if (!vi->status)
5959                 continue;
5960
5961             tentries++;
5962
5963             if (verbose) {
5964                 fprintf(STDOUT,
5965                         "Processing volume entry %d: %s (%lu) on server %s %s...\n",
5966                         j + 1, vi->name, (unsigned long)vi->volid,
5967                         hostutil_GetNameByINet(aserver), pname);
5968                 fflush(STDOUT);
5969             }
5970
5971             code = CheckVolume(vi, aserver, apart, &modified, &maxvolid);
5972             if (code) {
5973                 PrintError("", code);
5974                 failures++;
5975                 pfail++;
5976             } else if (modified) {
5977                 modifications++;
5978             }
5979
5980             if (verbose) {
5981                 if (code) {
5982                     fprintf(STDOUT, "...error encountered\n\n");
5983                 } else {
5984                     fprintf(STDOUT, "...done entry %d\n\n", j + 1);
5985                 }
5986             }
5987         }
5988
5989         if (pfail) {
5990             fprintf(STDERR,
5991                     "Could not process entries on server %s partition %s\n",
5992                     hostutil_GetNameByINet(aserver), pname);
5993         }
5994         if (volumeInfo.volEntries_val) {
5995             free(volumeInfo.volEntries_val);
5996             volumeInfo.volEntries_val = 0;
5997         }
5998
5999     }                           /* thru all partitions */
6000
6001     VPRINT3("Total entries: %u, Failed to process %d, Changed %d\n", tentries,
6002             failures, modifications);
6003
6004   error_exit:
6005     /* Now check if the maxvolid is larger than that stored in the VLDB */
6006     if (maxvolid) {
6007         afs_uint32 maxvldbid = 0;
6008         code = ubik_Call(VL_GetNewVolumeId, cstruct, 0, 0, &maxvldbid);
6009         if (code) {
6010             fprintf(STDERR,
6011                     "Could not get the highest allocated volume id from the VLDB\n");
6012             if (!error)
6013                 error = code;
6014         } else if (maxvolid > maxvldbid) {
6015             afs_uint32 id, nid;
6016             id = maxvolid - maxvldbid + 1;
6017             code = ubik_Call(VL_GetNewVolumeId, cstruct, 0, id, &nid);
6018             if (code) {
6019                 fprintf(STDERR,
6020                         "Error in increasing highest allocated volume id in VLDB\n");
6021                 if (!error)
6022                     error = code;
6023             }
6024         }
6025     }
6026
6027     if (aconn)
6028         rx_DestroyConnection(aconn);
6029     if (volumeInfo.volEntries_val)
6030         free(volumeInfo.volEntries_val);
6031     PrintError("", error);
6032     return (error);
6033 }
6034
6035 /* VolumeExists()
6036  *      Determine if a volume exists on a server and partition.
6037  *      Try creating a transaction on the volume. If we can,
6038  *      the volume exists, if not, then return the error code.
6039  *      Some error codes mean the volume is unavailable but
6040  *      still exists - so we catch these error codes.
6041  */
6042 afs_int32
6043 VolumeExists(afs_int32 server, afs_int32 partition, afs_int32 volumeid)
6044 {
6045     struct rx_connection *conn = (struct rx_connection *)0;
6046     afs_int32 code = -1;
6047     volEntries volumeInfo;
6048
6049     conn = UV_Bind(server, AFSCONF_VOLUMEPORT);
6050     if (conn) {
6051         volumeInfo.volEntries_val = (volintInfo *) 0;
6052         volumeInfo.volEntries_len = 0;
6053         code = AFSVolListOneVolume(conn, partition, volumeid, &volumeInfo);
6054         if (volumeInfo.volEntries_val)
6055             free(volumeInfo.volEntries_val);
6056         if (code == VOLSERILLEGAL_PARTITION)
6057             code = ENODEV;
6058         rx_DestroyConnection(conn);
6059     }
6060     return code;
6061 }
6062
6063 /* CheckVldbRWBK()
6064  *
6065  */
6066 afs_int32
6067 CheckVldbRWBK(struct nvldbentry * entry, afs_int32 * modified)
6068 {
6069     int modentry = 0;
6070     int idx;
6071     afs_int32 code, error = 0;
6072     char pname[10];
6073
6074     if (modified)
6075         *modified = 0;
6076     idx = Lp_GetRwIndex(entry);
6077
6078     /* Check to see if the RW volume exists and set the RW_EXISTS
6079      * flag accordingly.
6080      */
6081     if (idx == -1) {            /* Did not find a RW entry */
6082         if (entry->flags & RW_EXISTS) { /* ... yet entry says RW exists */
6083             entry->flags &= ~RW_EXISTS; /* ... so say RW does not exist */
6084             modentry++;
6085         }
6086     } else {
6087         code =
6088             VolumeExists(entry->serverNumber[idx],
6089                          entry->serverPartition[idx], entry->volumeId[RWVOL]);
6090         if (code == 0) {        /* RW volume exists */
6091             if (!(entry->flags & RW_EXISTS)) {  /* ... yet entry says RW does not exist */
6092                 entry->flags |= RW_EXISTS;      /* ... so say RW does exist */
6093                 modentry++;
6094             }
6095         } else if (code == ENODEV) {    /* RW volume does not exist */
6096             if (entry->flags & RW_EXISTS) {     /* ... yet entry says RW exists */
6097                 entry->flags &= ~RW_EXISTS;     /* ... so say RW does not exist */
6098                 modentry++;
6099             }
6100         } else {
6101             /* If VLDB says it didn't exist, then ignore error */
6102             if (entry->flags & RW_EXISTS) {
6103                 MapPartIdIntoName(entry->serverPartition[idx], pname);
6104                 fprintf(STDERR,
6105                         "Transaction call failed for RW volume %u on server %s %s\n",
6106                         entry->volumeId[RWVOL],
6107                         hostutil_GetNameByINet(entry->serverNumber[idx]),
6108                         pname);
6109                 ERROR_EXIT(code);
6110             }
6111         }
6112     }
6113
6114     /* Check to see if the BK volume exists and set the BACK_EXISTS
6115      * flag accordingly. idx already ponts to the RW entry.
6116      */
6117     if (idx == -1) {            /* Did not find a RW entry */
6118         if (entry->flags & BACK_EXISTS) {       /* ... yet entry says BK exists */
6119             entry->flags &= ~BACK_EXISTS;       /* ... so say BK does not exist */
6120             modentry++;
6121         }
6122     } else {                    /* Found a RW entry */
6123         code =
6124             VolumeExists(entry->serverNumber[idx],
6125                          entry->serverPartition[idx],
6126                          entry->volumeId[BACKVOL]);
6127         if (code == 0) {        /* BK volume exists */
6128             if (!(entry->flags & BACK_EXISTS)) {        /* ... yet entry says BK does not exist */
6129                 entry->flags |= BACK_EXISTS;    /* ... so say BK does exist */
6130                 modentry++;
6131             }
6132         } else if (code == ENODEV) {    /* BK volume does not exist */
6133             if (entry->flags & BACK_EXISTS) {   /* ... yet entry says BK exists */
6134                 entry->flags &= ~BACK_EXISTS;   /* ... so say BK does not exist */
6135                 modentry++;
6136             }
6137         } else {
6138             /* If VLDB says it didn't exist, then ignore error */
6139             if (entry->flags & BACK_EXISTS) {
6140                 MapPartIdIntoName(entry->serverPartition[idx], pname);
6141                 fprintf(STDERR,
6142                         "Transaction call failed for BK volume %u on server %s %s\n",
6143                         entry->volumeId[BACKVOL],
6144                         hostutil_GetNameByINet(entry->serverNumber[idx]),
6145                         pname);
6146                 ERROR_EXIT(code);
6147             }
6148         }
6149     }
6150
6151     /* If there is an idx but the BK and RW volumes no
6152      * longer exist, then remove the RW entry.
6153      */
6154     if ((idx != -1) && !(entry->flags & RW_EXISTS)
6155         && !(entry->flags & BACK_EXISTS)) {
6156         Lp_SetRWValue(entry, entry->serverNumber[idx],
6157                       entry->serverPartition[idx], 0L, 0L);
6158         entry->nServers--;
6159         modentry++;
6160     }
6161
6162   error_exit:
6163     if (modified)
6164         *modified = modentry;
6165     return (error);
6166 }
6167
6168 int
6169 CheckVldbRO(struct nvldbentry *entry, afs_int32 * modified)
6170 {
6171     int idx;
6172     int foundro = 0, modentry = 0;
6173     afs_int32 code, error = 0;
6174     char pname[10];
6175
6176     if (modified)
6177         *modified = 0;
6178
6179     /* Check to see if the RO volumes exist and set the RO_EXISTS
6180      * flag accordingly. 
6181      */
6182     for (idx = 0; idx < entry->nServers; idx++) {
6183         if (!(entry->serverFlags[idx] & ITSROVOL)) {
6184             continue;           /* not a RO */
6185         }
6186
6187         code =
6188             VolumeExists(entry->serverNumber[idx],
6189                          entry->serverPartition[idx], entry->volumeId[ROVOL]);
6190         if (code == 0) {        /* RO volume exists */
6191             foundro++;
6192         } else if (code == ENODEV) {    /* RW volume does not exist */
6193             Lp_SetROValue(entry, entry->serverNumber[idx],
6194                           entry->serverPartition[idx], 0L, 0L);
6195             entry->nServers--;
6196             idx--;
6197             modentry++;
6198         } else {
6199             MapPartIdIntoName(entry->serverPartition[idx], pname);
6200             fprintf(STDERR,
6201                     "Transaction call failed for RO %u on server %s %s\n",
6202                     entry->volumeId[ROVOL],
6203                     hostutil_GetNameByINet(entry->serverNumber[idx]), pname);
6204             ERROR_EXIT(code);
6205         }
6206     }
6207
6208     if (foundro) {              /* A RO volume exists */
6209         if (!(entry->flags & RO_EXISTS)) {      /* ... yet entry says RW does not exist */
6210             entry->flags |= RO_EXISTS;  /* ... so say RW does exist */
6211             modentry++;
6212         }
6213     } else {                    /* A RO volume does not exist */
6214         if (entry->flags & RO_EXISTS) { /* ... yet entry says RO exists */
6215             entry->flags &= ~RO_EXISTS; /* ... so say RO does not exist */
6216             modentry++;
6217         }
6218     }
6219
6220   error_exit:
6221     if (modified)
6222         *modified = modentry;
6223     return (error);
6224 }
6225
6226 /* CheckVldb()
6227  *      Ensure that <entry> matches with the info on file servers
6228  */
6229 afs_int32
6230 CheckVldb(struct nvldbentry * entry, afs_int32 * modified)
6231 {
6232     afs_int32 code, error = 0;
6233     struct nvldbentry storeEntry;
6234     int islocked = 0, mod, modentry, delentry = 0;
6235     int pass = 0;
6236
6237     if (modified)
6238         *modified = 0;
6239     if (verbose) {
6240         fprintf(STDOUT, "_______________________________\n");
6241         fprintf(STDOUT, "\n-- status before -- \n");
6242         if ((entry->flags & RW_EXISTS) || (entry->flags & RO_EXISTS)
6243             || (entry->flags & BACK_EXISTS))
6244             EnumerateEntry(entry);
6245         fprintf(STDOUT, "\n");
6246     }
6247
6248     if (strlen(entry->name) > (VOLSER_OLDMAXVOLNAME - 10)) {
6249         fprintf(STDERR, "Volume name %s exceeds limit of %d characters\n",
6250                 entry->name, VOLSER_OLDMAXVOLNAME - 10);
6251     }
6252
6253   retry:
6254     /* Check to see if the VLDB is ok without locking it (pass 1).
6255      * If it will change, then lock the VLDB entry, read it again,
6256      * then make the changes to it (pass 2).
6257      */
6258     if (++pass == 2) {
6259         code =
6260             ubik_Call(VL_SetLock, cstruct, 0, entry->volumeId[RWVOL], RWVOL,
6261                       VLOP_DELETE);
6262         if (code) {
6263             fprintf(STDERR, "Could not lock VLDB entry for %u \n",
6264                     entry->volumeId[RWVOL]);
6265             ERROR_EXIT(code);
6266         }
6267         islocked = 1;
6268
6269         code = VLDB_GetEntryByID(entry->volumeId[RWVOL], RWVOL, entry);
6270         if (code) {
6271             fprintf(STDERR, "Could not read VLDB entry for volume %s\n",
6272                     entry->name);
6273             ERROR_EXIT(code);
6274         } else {
6275             MapHostToNetwork(entry);
6276         }
6277     }
6278
6279     modentry = 0;
6280
6281     /* Check if the RW and BK entries are ok */
6282     code = CheckVldbRWBK(entry, &mod);
6283     if (code)
6284         ERROR_EXIT(code);
6285     if (mod && (pass == 1))
6286         goto retry;
6287     if (mod)
6288         modentry++;
6289
6290     /* Check if the RO volumes entries are ok */
6291     code = CheckVldbRO(entry, &mod);
6292     if (code)
6293         ERROR_EXIT(code);
6294     if (mod && (pass == 1))
6295         goto retry;
6296     if (mod)
6297         modentry++;
6298
6299     /* The VLDB entry has been updated. If it as been modified, then 
6300      * write the entry back out the the VLDB.
6301      */
6302     if (modentry) {
6303         if (pass == 1)
6304             goto retry;
6305
6306         if (!(entry->flags & RW_EXISTS) && !(entry->flags & BACK_EXISTS)
6307             && !(entry->flags & RO_EXISTS)) {
6308             /* The RW, BK, nor RO volumes do not exist. Delete the VLDB entry */
6309             code =
6310                 ubik_Call(VL_DeleteEntry, cstruct, 0, entry->volumeId[RWVOL],
6311                           RWVOL);
6312             if (code) {
6313                 fprintf(STDERR,
6314                         "Could not delete VLDB entry for volume %u \n",
6315                         entry->volumeId[RWVOL]);
6316                 ERROR_EXIT(code);
6317             }
6318             delentry = 1;
6319         } else {
6320             /* Replace old entry with our new one */
6321             MapNetworkToHost(entry, &storeEntry);
6322             code =
6323                 VLDB_ReplaceEntry(entry->volumeId[RWVOL], RWVOL, &storeEntry,
6324                                   (LOCKREL_OPCODE | LOCKREL_AFSID |
6325                                    LOCKREL_TIMESTAMP));
6326             if (code) {
6327                 fprintf(STDERR, "Could not update VLDB entry for volume %u\n",
6328                         entry->volumeId[RWVOL]);
6329                 ERROR_EXIT(code);
6330             }
6331         }
6332         if (modified)
6333             *modified = 1;
6334         islocked = 0;
6335     }
6336
6337     if (verbose) {
6338         fprintf(STDOUT, "-- status after --\n");
6339         if (delentry)
6340             fprintf(STDOUT, "\n**entry deleted**\n");
6341         else if (modentry)
6342             EnumerateEntry(entry);
6343         else
6344             fprintf(STDOUT, "\n**no change**\n");
6345     }
6346
6347   error_exit:
6348     VPRINT("\n_______________________________\n");
6349
6350     if (islocked) {
6351         code =
6352             ubik_Call(VL_ReleaseLock, cstruct, 0, entry->volumeId[RWVOL],
6353                       RWVOL,
6354                       (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP));
6355         if (code) {
6356             fprintf(STDERR,
6357                     "Could not release lock on VLDB entry for volume %u\n",
6358                     entry->volumeId[RWVOL]);
6359             if (!error)
6360                 error = code;
6361         }
6362     }
6363     return error;
6364 }
6365
6366 /* UV_SyncServer()
6367  *      Synchronise <aserver> <apart>(if flags = 1) with the VLDB.
6368  */
6369 int
6370 UV_SyncServer(afs_int32 aserver, afs_int32 apart, int flags, int force)
6371 {
6372     struct rx_connection *aconn;
6373     afs_int32 code, error = 0;
6374     afs_int32 nentries, tentries = 0;
6375     struct VldbListByAttributes attributes;
6376     nbulkentries arrayEntries;
6377     afs_int32 failures = 0, modified, modifications = 0;
6378     struct nvldbentry *vlentry;
6379     afs_int32 si, nsi, j;
6380
6381     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
6382
6383     /* Set up attributes to search VLDB  */
6384     attributes.server = ntohl(aserver);
6385     attributes.Mask = VLLIST_SERVER;
6386     if (flags) {
6387         attributes.partition = apart;
6388         attributes.Mask |= VLLIST_PARTITION;
6389     }
6390
6391     VPRINT("Processing VLDB entries ...\n");
6392
6393     /* While we need to collect more VLDB entries */
6394     for (si = 0; si != -1; si = nsi) {
6395         memset(&arrayEntries, 0, sizeof(arrayEntries));
6396
6397         /* Collect set of VLDB entries */
6398         code =
6399             VLDB_ListAttributesN2(&attributes, 0, si, &nentries,
6400                                   &arrayEntries, &nsi);
6401         if (code == RXGEN_OPCODE) {
6402             code = VLDB_ListAttributes(&attributes, &nentries, &arrayEntries);
6403             nsi = -1;
6404         }
6405         if (code) {
6406             fprintf(STDERR, "Could not access the VLDB for attributes\n");
6407             ERROR_EXIT(code);
6408         }
6409         tentries += nentries;
6410
6411         for (j = 0; j < nentries; j++) {
6412             vlentry = &arrayEntries.nbulkentries_val[j];
6413             MapHostToNetwork(vlentry);
6414
6415             VPRINT1("Processing VLDB entry %d ...\n", j + 1);
6416
6417             code = CheckVldb(vlentry, &modified);
6418             if (code) {
6419                 PrintError("", code);
6420                 fprintf(STDERR,
6421                         "Could not process VLDB entry for volume %s\n",
6422                         vlentry->name);
6423                 failures++;
6424             } else if (modified) {
6425                 modifications++;
6426             }
6427
6428             if (verbose) {
6429                 if (code) {
6430                     fprintf(STDOUT, "...error encountered\n\n");
6431                 } else {
6432                     fprintf(STDOUT, "...done entry %d\n\n", j + 1);
6433                 }
6434             }
6435         }
6436
6437         if (arrayEntries.nbulkentries_val) {
6438             free(arrayEntries.nbulkentries_val);
6439             arrayEntries.nbulkentries_val = 0;
6440         }
6441     }
6442
6443     VPRINT3("Total entries: %u, Failed to process %d, Changed %d\n", tentries,
6444             failures, modifications);
6445
6446   error_exit:
6447     if (aconn)
6448         rx_DestroyConnection(aconn);
6449     if (arrayEntries.nbulkentries_val)
6450         free(arrayEntries.nbulkentries_val);
6451
6452     if (failures)
6453         error = VOLSERFAILEDOP;
6454     return error;
6455 }
6456
6457 /*rename volume <oldname> to <newname>, changing the names of the related 
6458  *readonly and backup volumes. This operation is also idempotent.
6459  *salvager is capable of recovering from rename operation stopping halfway.
6460  *to recover run syncserver on the affected machines,it will force renaming to completion. name clashes should have been detected before calling this proc */
6461 int
6462 UV_RenameVolume(struct nvldbentry *entry, char oldname[], char newname[])
6463 {
6464     struct nvldbentry storeEntry;
6465     afs_int32 vcode, code, rcode, error;
6466     int i, index;
6467     char nameBuffer[256];
6468     afs_int32 tid;
6469     struct rx_connection *aconn;
6470     int islocked;
6471
6472     error = 0;
6473     aconn = (struct rx_connection *)0;
6474     tid = 0;
6475     islocked = 0;
6476
6477     vcode = ubik_Call(VL_SetLock, cstruct, 0, entry->volumeId[RWVOL], RWVOL, VLOP_ADDSITE);     /*last param is dummy */
6478     if (vcode) {
6479         fprintf(STDERR,
6480                 " Could not lock the VLDB entry for the  volume %u \n",
6481                 entry->volumeId[RWVOL]);
6482         error = vcode;
6483         goto rvfail;
6484     }
6485     islocked = 1;
6486     strncpy(entry->name, newname, VOLSER_OLDMAXVOLNAME);
6487     MapNetworkToHost(entry, &storeEntry);
6488     vcode = VLDB_ReplaceEntry(entry->volumeId[RWVOL], RWVOL, &storeEntry, 0);
6489     if (vcode) {
6490         fprintf(STDERR, "Could not update VLDB entry for %u\n",
6491                 entry->volumeId[RWVOL]);
6492         error = vcode;
6493         goto rvfail;
6494     }
6495     VPRINT1("Recorded the new name %s in VLDB\n", newname);
6496     /*at this stage the intent to rename is recorded in the vldb, as far as the vldb 
6497      * is concerned, oldname is lost */
6498     if (entry->flags & RW_EXISTS) {
6499         index = Lp_GetRwIndex(entry);
6500         if (index == -1) {      /* there is a serious discrepancy */
6501             fprintf(STDERR,
6502                     "There is a serious discrepancy in VLDB entry for volume %u\n",
6503                     entry->volumeId[RWVOL]);
6504             fprintf(STDERR, "try building VLDB from scratch\n");
6505             error = VOLSERVLDB_ERROR;
6506             goto rvfail;
6507         }
6508         aconn = UV_Bind(entry->serverNumber[index], AFSCONF_VOLUMEPORT);
6509         code =
6510             AFSVolTransCreate(aconn, entry->volumeId[RWVOL],
6511                               entry->serverPartition[index], ITOffline, &tid);
6512         if (code) {             /*volume doesnot exist */
6513             fprintf(STDERR,
6514                     "Could not start transaction on the rw volume %u\n",
6515                     entry->volumeId[RWVOL]);
6516             error = code;
6517             goto rvfail;
6518         } else {                /*volume exists, process it */
6519
6520             code =
6521                 AFSVolSetIdsTypes(aconn, tid, newname, RWVOL,
6522                                   entry->volumeId[RWVOL],
6523                                   entry->volumeId[ROVOL],
6524                                   entry->volumeId[BACKVOL]);
6525             if (!code) {
6526                 VPRINT2("Renamed rw volume %s to %s\n", oldname, newname);
6527                 code = AFSVolEndTrans(aconn, tid, &rcode);
6528                 tid = 0;
6529                 if (code) {
6530                     fprintf(STDERR,
6531                             "Could not  end transaction on volume %s %u\n",
6532                             entry->name, entry->volumeId[RWVOL]);
6533                     error = code;
6534                     goto rvfail;
6535                 }
6536             } else {
6537                 fprintf(STDERR, "Could not  set parameters on volume %s %u\n",
6538                         entry->name, entry->volumeId[RWVOL]);
6539                 error = code;
6540                 goto rvfail;
6541             }
6542         }
6543         if (aconn)
6544             rx_DestroyConnection(aconn);
6545         aconn = (struct rx_connection *)0;
6546     }
6547     /*end rw volume processing */
6548     if (entry->flags & BACK_EXISTS) {   /*process the backup volume */
6549         index = Lp_GetRwIndex(entry);
6550         if (index == -1) {      /* there is a serious discrepancy */
6551             fprintf(STDERR,
6552                     "There is a serious discrepancy in the VLDB entry for the backup volume %u\n",
6553                     entry->volumeId[BACKVOL]);
6554             fprintf(STDERR, "try building VLDB from scratch\n");
6555             error = VOLSERVLDB_ERROR;
6556             goto rvfail;
6557         }
6558         aconn = UV_Bind(entry->serverNumber[index], AFSCONF_VOLUMEPORT);
6559         code =
6560             AFSVolTransCreate(aconn, entry->volumeId[BACKVOL],
6561                               entry->serverPartition[index], ITOffline, &tid);
6562         if (code) {             /*volume doesnot exist */
6563             fprintf(STDERR,
6564                     "Could not start transaction on the backup volume  %u\n",
6565                     entry->volumeId[BACKVOL]);
6566             error = code;
6567             goto rvfail;
6568         } else {                /*volume exists, process it */
6569             if (strlen(newname) > (VOLSER_OLDMAXVOLNAME - 8)) {
6570                 fprintf(STDERR,
6571                         "Volume name %s.backup exceeds the limit of %u characters\n",
6572                         newname, VOLSER_OLDMAXVOLNAME);
6573                 error = code;
6574                 goto rvfail;
6575             }
6576             strcpy(nameBuffer, newname);
6577             strcat(nameBuffer, ".backup");
6578
6579             code =
6580                 AFSVolSetIdsTypes(aconn, tid, nameBuffer, BACKVOL,
6581                                   entry->volumeId[RWVOL], 0, 0);
6582             if (!code) {
6583                 VPRINT1("Renamed backup volume to %s \n", nameBuffer);
6584                 code = AFSVolEndTrans(aconn, tid, &rcode);
6585                 tid = 0;
6586                 if (code) {
6587                     fprintf(STDERR,
6588                             "Could not  end transaction on the backup volume %u\n",
6589                             entry->volumeId[BACKVOL]);
6590                     error = code;
6591                     goto rvfail;
6592                 }
6593             } else {
6594                 fprintf(STDERR,
6595                         "Could not  set parameters on the backup volume %u\n",
6596                         entry->volumeId[BACKVOL]);
6597                 error = code;
6598                 goto rvfail;
6599             }
6600         }
6601     }                           /* end backup processing */
6602     if (aconn)
6603         rx_DestroyConnection(aconn);
6604     aconn = (struct rx_connection *)0;
6605     if (entry->flags & RO_EXISTS) {     /*process the ro volumes */
6606         for (i = 0; i < entry->nServers; i++) {
6607             if (entry->serverFlags[i] & ITSROVOL) {
6608                 aconn = UV_Bind(entry->serverNumber[i], AFSCONF_VOLUMEPORT);
6609                 code =
6610                     AFSVolTransCreate(aconn, entry->volumeId[ROVOL],
6611                                       entry->serverPartition[i], ITOffline,
6612                                       &tid);
6613                 if (code) {     /*volume doesnot exist */
6614                     fprintf(STDERR,
6615                             "Could not start transaction on the ro volume %u\n",
6616                             entry->volumeId[ROVOL]);
6617                     error = code;
6618                     goto rvfail;
6619                 } else {        /*volume exists, process it */
6620                     strcpy(nameBuffer, newname);
6621                     strcat(nameBuffer, ".readonly");
6622                     if (strlen(nameBuffer) > (VOLSER_OLDMAXVOLNAME - 1)) {
6623                         fprintf(STDERR,
6624                                 "Volume name %s exceeds the limit of %u characters\n",
6625                                 nameBuffer, VOLSER_OLDMAXVOLNAME);
6626                         error = code;
6627                         goto rvfail;
6628                     }
6629                     code =
6630                         AFSVolSetIdsTypes(aconn, tid, nameBuffer, ROVOL,
6631                                           entry->volumeId[RWVOL], 0, 0);
6632                     if (!code) {
6633                         VPRINT2("Renamed RO volume %s on host %s\n",
6634                                 nameBuffer,
6635                                 hostutil_GetNameByINet(entry->
6636                                                        serverNumber[i]));
6637                         code = AFSVolEndTrans(aconn, tid, &rcode);
6638                         tid = 0;
6639                         if (code) {
6640                             fprintf(STDERR,
6641                                     "Could not  end transaction on volume %u\n",
6642                                     entry->volumeId[ROVOL]);
6643                             error = code;
6644                             goto rvfail;
6645                         }
6646                     } else {
6647                         fprintf(STDERR,
6648                                 "Could not  set parameters on the ro volume %u\n",
6649                                 entry->volumeId[ROVOL]);
6650                         error = code;
6651                         goto rvfail;
6652                     }
6653                 }
6654                 if (aconn)
6655                     rx_DestroyConnection(aconn);
6656                 aconn = (struct rx_connection *)0;
6657             }
6658         }
6659     }
6660   rvfail:
6661     if (islocked) {
6662         vcode =
6663             ubik_Call(VL_ReleaseLock, cstruct, 0, entry->volumeId[RWVOL],
6664                       RWVOL,
6665                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
6666         if (vcode) {
6667             fprintf(STDERR,
6668                     "Could not unlock the VLDB entry for the volume %s %u\n",
6669                     entry->name, entry->volumeId[RWVOL]);
6670             if (!error)
6671                 error = vcode;
6672         }
6673     }
6674     if (tid) {
6675         code = AFSVolEndTrans(aconn, tid, &rcode);
6676         if (!code)
6677             code = rcode;
6678         if (code) {
6679             fprintf(STDERR, "Failed to end transaction on a volume \n");
6680             if (!error)
6681                 error = code;
6682         }
6683     }
6684     if (aconn)
6685         rx_DestroyConnection(aconn);
6686     PrintError("", error);
6687     return error;
6688
6689 }
6690
6691 /*report on all the active transactions on volser */
6692 int
6693 UV_VolserStatus(afs_int32 server, transDebugInfo ** rpntr, afs_int32 * rcount)
6694 {
6695     struct rx_connection *aconn;
6696     transDebugEntries transInfo;
6697     afs_int32 code = 0;
6698
6699     aconn = UV_Bind(server, AFSCONF_VOLUMEPORT);
6700     transInfo.transDebugEntries_val = (transDebugInfo *) 0;
6701     transInfo.transDebugEntries_len = 0;
6702     code = AFSVolMonitor(aconn, &transInfo);
6703     if (code) {
6704         fprintf(STDERR,
6705                 "Could not access status information about the server\n");
6706         PrintError("", code);
6707         if (transInfo.transDebugEntries_val)
6708             free(transInfo.transDebugEntries_val);
6709         if (aconn)
6710             rx_DestroyConnection(aconn);
6711         return code;
6712     } else {
6713         *rcount = transInfo.transDebugEntries_len;
6714         *rpntr = transInfo.transDebugEntries_val;
6715         if (aconn)
6716             rx_DestroyConnection(aconn);
6717         return 0;
6718     }
6719
6720
6721 }
6722
6723 /*delete the volume without interacting with the vldb */
6724 int
6725 UV_VolumeZap(afs_int32 server, afs_int32 part, afs_int32 volid)
6726 {
6727     afs_int32 rcode, ttid, error, code;
6728     struct rx_connection *aconn;
6729
6730     code = 0;
6731     error = 0;
6732     ttid = 0;
6733
6734     aconn = UV_Bind(server, AFSCONF_VOLUMEPORT);
6735     code = AFSVolTransCreate(aconn, volid, part, ITOffline, &ttid);
6736     if (code) {
6737         fprintf(STDERR, "Could not start transaction on volume %lu\n",
6738                 (unsigned long)volid);
6739         error = code;
6740         goto zfail;
6741     }
6742     code = AFSVolDeleteVolume(aconn, ttid);
6743     if (code) {
6744         fprintf(STDERR, "Could not delete volume %lu\n",
6745                 (unsigned long)volid);
6746         error = code;
6747         goto zfail;
6748     }
6749     code = AFSVolEndTrans(aconn, ttid, &rcode);
6750     ttid = 0;
6751     if (!code)
6752         code = rcode;
6753     if (code) {
6754         fprintf(STDERR, "Could not end transaction on volume %lu\n",
6755                 (unsigned long)volid);
6756         error = code;
6757         goto zfail;
6758     }
6759   zfail:
6760     if (ttid) {
6761         code = AFSVolEndTrans(aconn, ttid, &rcode);
6762         if (!code)
6763             code = rcode;
6764         if (!error)
6765             error = code;
6766     }
6767     PrintError("", error);
6768     if (aconn)
6769         rx_DestroyConnection(aconn);
6770     return error;
6771 }
6772
6773 int
6774 UV_SetVolume(afs_int32 server, afs_int32 partition, afs_int32 volid,
6775              afs_int32 transflag, afs_int32 setflag, int sleeptime)
6776 {
6777     struct rx_connection *conn = 0;
6778     afs_int32 tid = 0;
6779     afs_int32 code, error = 0, rcode;
6780
6781     conn = UV_Bind(server, AFSCONF_VOLUMEPORT);
6782     if (!conn) {
6783         fprintf(STDERR, "SetVolumeStatus: Bind Failed");
6784         ERROR_EXIT(-1);
6785     }
6786
6787     code = AFSVolTransCreate(conn, volid, partition, transflag, &tid);
6788     if (code) {
6789         fprintf(STDERR, "SetVolumeStatus: TransCreate Failed\n");
6790         ERROR_EXIT(code);
6791     }
6792
6793     code = AFSVolSetFlags(conn, tid, setflag);
6794     if (code) {
6795         fprintf(STDERR, "SetVolumeStatus: SetFlags Failed\n");
6796         ERROR_EXIT(code);
6797     }
6798
6799     if (sleeptime) {
6800 #ifdef AFS_PTHREAD_ENV
6801         sleep(sleeptime);
6802 #else
6803         IOMGR_Sleep(sleeptime);
6804 #endif
6805     }
6806
6807   error_exit:
6808     if (tid) {
6809         rcode = 0;
6810         code = AFSVolEndTrans(conn, tid, &rcode);
6811         if (code || rcode) {
6812             fprintf(STDERR, "SetVolumeStatus: EndTrans Failed\n");
6813             if (!error)
6814                 error = (code ? code : rcode);
6815         }
6816     }
6817
6818     if (conn)
6819         rx_DestroyConnection(conn);
6820     return (error);
6821 }
6822
6823 int
6824 UV_SetVolumeInfo(afs_int32 server, afs_int32 partition, afs_int32 volid,
6825                  volintInfo * infop)
6826 {
6827     struct rx_connection *conn = 0;
6828     afs_int32 tid = 0;
6829     afs_int32 code, error = 0, rcode;
6830
6831     conn = UV_Bind(server, AFSCONF_VOLUMEPORT);
6832     if (!conn) {
6833         fprintf(STDERR, "SetVolumeInfo: Bind Failed");
6834         ERROR_EXIT(-1);
6835     }
6836
6837     code = AFSVolTransCreate(conn, volid, partition, ITOffline, &tid);
6838     if (code) {
6839         fprintf(STDERR, "SetVolumeInfo: TransCreate Failed\n");
6840         ERROR_EXIT(code);
6841     }
6842
6843     code = AFSVolSetInfo(conn, tid, infop);
6844     if (code) {
6845         fprintf(STDERR, "SetVolumeInfo: SetInfo Failed\n");
6846         ERROR_EXIT(code);
6847     }
6848
6849   error_exit:
6850     if (tid) {
6851         rcode = 0;
6852         code = AFSVolEndTrans(conn, tid, &rcode);
6853         if (code || rcode) {
6854             fprintf(STDERR, "SetVolumeInfo: EndTrans Failed\n");
6855             if (!error)
6856                 error = (code ? code : rcode);
6857         }
6858     }
6859
6860     if (conn)
6861         rx_DestroyConnection(conn);
6862     return (error);
6863 }
6864
6865 int
6866 UV_GetSize(afs_int32 afromvol, afs_int32 afromserver, afs_int32 afrompart,
6867            afs_int32 fromdate, struct volintSize *vol_size)
6868 {
6869     struct rx_connection *aconn = (struct rx_connection *)0;
6870     afs_int32 tid = 0, rcode = 0;
6871     afs_int32 code, error = 0;
6872
6873
6874     /* get connections to the servers */
6875     aconn = UV_Bind(afromserver, AFSCONF_VOLUMEPORT);
6876
6877     VPRINT1("Starting transaction on volume %u...", afromvol);
6878     code = AFSVolTransCreate(aconn, afromvol, afrompart, ITBusy, &tid);
6879     EGOTO1(error_exit, code,
6880            "Could not start transaction on the volume %u to be measured\n",
6881            afromvol);
6882     VDONE;
6883
6884     VPRINT1("Getting size of volume on volume %u...", afromvol);
6885     code = AFSVolGetSize(aconn, tid, fromdate, vol_size);
6886     EGOTO(error_exit, code, "Could not start the measurement process \n");
6887     VDONE;
6888
6889   error_exit:
6890     if (tid) {
6891         VPRINT1("Ending transaction on volume %u...", afromvol);
6892         code = AFSVolEndTrans(aconn, tid, &rcode);
6893         if (code || rcode) {
6894             fprintf(STDERR, "Could not end transaction on the volume %u\n",
6895                     afromvol);
6896             fprintf(STDERR, "error codes: %d and %d\n", code, rcode);
6897             if (!error)
6898                 error = (code ? code : rcode);
6899         }
6900         VDONE;
6901     }
6902     if (aconn)
6903         rx_DestroyConnection(aconn);
6904
6905     PrintError("", error);
6906     return (error);
6907 }
6908
6909 /*maps the host addresses in <old > (present in network byte order) to
6910  that in< new> (present in host byte order )*/
6911 void
6912 MapNetworkToHost(struct nvldbentry *old, struct nvldbentry *new)
6913 {
6914     int i, count;
6915
6916     /*copy all the fields */
6917     strcpy(new->name, old->name);
6918 /*    new->volumeType = old->volumeType;*/
6919     new->nServers = old->nServers;
6920     count = old->nServers;
6921     if (count < NMAXNSERVERS)
6922         count++;
6923     for (i = 0; i < count; i++) {
6924         new->serverNumber[i] = ntohl(old->serverNumber[i]);
6925         new->serverPartition[i] = old->serverPartition[i];
6926         new->serverFlags[i] = old->serverFlags[i];
6927     }
6928     new->volumeId[RWVOL] = old->volumeId[RWVOL];
6929     new->volumeId[ROVOL] = old->volumeId[ROVOL];
6930     new->volumeId[BACKVOL] = old->volumeId[BACKVOL];
6931     new->cloneId = old->cloneId;
6932     new->flags = old->flags;
6933 }
6934
6935 /*maps the host entries in <entry> which are present in host byte order to network byte order */
6936 void
6937 MapHostToNetwork(struct nvldbentry *entry)
6938 {
6939     int i, count;
6940
6941     count = entry->nServers;
6942     if (count < NMAXNSERVERS)
6943         count++;
6944     for (i = 0; i < count; i++) {
6945         entry->serverNumber[i] = htonl(entry->serverNumber[i]);
6946     }
6947 }