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