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