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