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