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