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