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