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