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