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