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