1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2014-2021 Bareos GmbH & Co. KG
5 Copyright (C) 2015-2015 Planets Communications B.V.
6
7 This program is Free Software; you can redistribute it and/or
8 modify it under the terms of version three of the GNU Affero General Public
9 License as published by the Free Software Foundation, which is
10 listed in the file LICENSE.vadp.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Affero General Public License for more details.
16
17 You should have received a copy of the GNU Affero General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301, USA.
21 */
22 /*
23 * VADP Dumper - vStorage APIs for Data Protection Dumper program.
24 *
25 * Marco van Wieringen, July 2014
26 * Renout Gerrits, Oct 2017, added thumbprint
27 */
28 #include <stdio.h>
29 #include <stdint.h>
30 #include <string.h>
31 #include <fcntl.h>
32 #include <time.h>
33 #include <unistd.h>
34 #include <signal.h>
35
36 #include "copy_thread.hpp"
37
38 #include <jansson.h>
39
40 /*
41 * json_array_foreach macro was added in jansson version 2.5
42 * we can compile also against an lower version if we define it ourselves.
43 */
44 #if JANSSON_VERSION_HEX < 0x020500
45 #define json_array_foreach(array, index, value) \
46 for(index = 0; \
47 index < json_array_size(array) && (value = json_array_get(array, index)); \
48 index++)
49 #endif
50
51 #include <vixDiskLib.h>
52
53 #define VIXDISKLIB_VERSION_MAJOR 6
54 #define VIXDISKLIB_VERSION_MINOR 5
55
56 #define VSPHERE_DEFAULT_ADMIN_PORT 0
57
58 /*
59 * VixDiskLib does all processing in sectors of 512 bytes.
60 */
61 #define DEFAULT_SECTOR_SIZE VIXDISKLIB_SECTOR_SIZE
62
63 /*
64 * In each call to the VixDiskLib read/write this number of sectors.
65 * e.g. 512 means 256 Kb per call (e.g. 512 x 512 bytes)
66 */
67 #define SECTORS_PER_CALL 1024
68
69 #define MIN(a, b) ((a) < b) ? (a) : (b)
70 #define MAX(a, b) ((a) > b) ? (a) : (b)
71
72 #define CON_PARAMS_KEY "ConnParams"
73 #define CON_PARAMS_VM_MOREF_KEY "VmMoRef"
74 #define CON_PARAMS_HOST_KEY "VsphereHostName"
75 #define CON_PARAMS_THUMBPRINT_KEY "VsphereThumbPrint"
76 #define CON_PARAMS_USERNAME_KEY "VsphereUsername"
77 #define CON_PARAMS_PASSWORD_KEY "VspherePassword"
78 #define CON_PARAMS_SNAPSHOT_MOREF_KEY "VsphereSnapshotMoRef"
79
80 #define DISK_PARAMS_KEY "DiskParams"
81 #define DISK_PARAMS_DISK_PATH_KEY "diskPath"
82
83 #define CBT_DISKCHANGEINFO_KEY "DiskChangeInfo"
84 #define CBT_DISK_SIZE "length"
85 #define CBT_CHANGEDAREA_KEY "changedArea"
86 #define CBT_CHANGEDAREA_START_KEY "start"
87 #define CBT_CHANGEDAREA_LENGTH_KEY "length"
88 #define CBT_START_OFFSET "startOffset"
89
90 #define BAREOSMAGIC 0x12122012
91 #define PROTOCOL_VERSION 1
92
93 #define BAREOS_VADPDUMPER_IDENTITY "BareosVADPDumper"
94
95 struct disk_type {
96 const char *type;
97 VixDiskLibDiskType vadp_type;
98 };
99
100 static struct disk_type disk_types[] = {
101 { "monolithic_sparse", VIXDISKLIB_DISK_MONOLITHIC_SPARSE },
102 { "monolithic_flat", VIXDISKLIB_DISK_MONOLITHIC_FLAT },
103 { "split_sparse", VIXDISKLIB_DISK_SPLIT_SPARSE },
104 { "split_flat", VIXDISKLIB_DISK_SPLIT_FLAT },
105 { "vmfs_flat", VIXDISKLIB_DISK_VMFS_FLAT },
106 { "optimized", VIXDISKLIB_DISK_STREAM_OPTIMIZED },
107 { "vmfs_thin", VIXDISKLIB_DISK_VMFS_THIN },
108 { "vmfs_sparse", VIXDISKLIB_DISK_VMFS_SPARSE },
109 { NULL, VIXDISKLIB_DISK_UNKNOWN }
110 };
111
112 /*
113 * Generic identification structure, 128 bytes with padding.
114 * This includes a protocol version.
115 */
116 struct runtime_disk_info_encoding {
117 uint32_t start_magic;
118 uint32_t protocol_version;
119 uint64_t absolute_disk_length;
120 uint64_t absolute_start_offset;
121 uint32_t bios_cylinders;
122 uint32_t bios_heads;
123 uint32_t bios_sectors;
124 uint32_t phys_cylinders;
125 uint32_t phys_heads;
126 uint32_t phys_sectors;
127 uint64_t phys_capacity;
128 uint32_t adapter_type;
129 uint32_t padding[16];
130 uint32_t end_magic;
131 };
132 const int rdie_size = sizeof(struct runtime_disk_info_encoding);
133
134 /*
135 * Disk Meta data structure,
136 * Encodes what follows e.g. meta_key and meta_data.
137 * e.g. [META_META_DATA] [META_DATA_KEY] [META_DATA] ...
138 */
139 struct runtime_meta_data_encoding {
140 uint32_t start_magic;
141 uint32_t meta_key_length;
142 uint32_t meta_data_length;
143 uint32_t end_magic;
144 };
145 const int rmde_size = sizeof(struct runtime_meta_data_encoding);
146
147 /*
148 * Changed Block Tracking structure.
149 * Encodes the CBT data followed by the actual data.
150 * e.g. [CBT] [DATA] ...
151 */
152 struct runtime_cbt_encoding {
153 uint32_t start_magic;
154 uint64_t start_offset;
155 uint64_t offset_length;
156 uint32_t end_magic;
157 };
158 const int rce_size = sizeof(struct runtime_cbt_encoding);
159
160 static bool cleanup_on_start = false;
161 static bool cleanup_on_disconnect = false;
162 static bool save_metadata = false;
163 static bool verbose = false;
164 static bool check_size = true;
165 static bool create_disk = false;
166 static bool local_vmdk = false;
167 static bool multi_threaded = false;
168 static bool restore_meta_data = false;
169 static int sectors_per_call = SECTORS_PER_CALL;
170 static uint64_t absolute_start_offset = 0;
171 static char *vmdk_disk_name = NULL;
172 static char *raw_disk_name = NULL;
173 static int raw_disk_fd = -1;
174 static char *force_transport = NULL;
175 static char *disktype = NULL;
176 static VixDiskLibConnectParams cnxParams;
177 static VixDiskLibConnection connection = NULL;
178 static VixDiskLibHandle read_diskHandle = NULL;
179 static VixDiskLibHandle write_diskHandle = NULL;
180 static VixDiskLibInfo *info = NULL;
181 static json_t *json_config = NULL;
182 static int exit_code = 1;
183
184 /*
185 * Encode the VDDK VixDiskLibInfo into an internal representation.
186 */
fill_runtime_disk_info_encoding(struct runtime_disk_info_encoding * rdie)187 static inline void fill_runtime_disk_info_encoding(struct runtime_disk_info_encoding *rdie)
188 {
189 memset(rdie, 0, rdie_size);
190
191 rdie->protocol_version = PROTOCOL_VERSION;
192 rdie->start_magic = BAREOSMAGIC;
193 rdie->end_magic = BAREOSMAGIC;
194
195 if (info->biosGeo.cylinders > 0) {
196 rdie->bios_cylinders = info->biosGeo.cylinders;
197 } else {
198 rdie->bios_cylinders = info->physGeo.cylinders;
199 }
200 if (info->biosGeo.heads > 0) {
201 rdie->bios_heads = info->biosGeo.heads;
202 } else {
203 rdie->bios_heads = info->physGeo.heads;
204 }
205 if (info->biosGeo.sectors > 0) {
206 rdie->bios_sectors = info->biosGeo.sectors;
207 } else {
208 rdie->bios_sectors = info->physGeo.sectors;
209 }
210
211 rdie->phys_cylinders = info->physGeo.cylinders;
212 rdie->phys_heads = info->physGeo.heads;
213 rdie->phys_sectors = info->physGeo.sectors;
214
215 rdie->phys_capacity = info->capacity;
216 rdie->adapter_type = info->adapterType;
217 }
218
219 /*
220 * Dump the important content of the internal disk representation for verbose mode.
221 */
dump_runtime_disk_info_encoding(struct runtime_disk_info_encoding * rdie)222 static inline void dump_runtime_disk_info_encoding(struct runtime_disk_info_encoding *rdie)
223 {
224 fprintf(stderr, "Protocol version = %lld\n", rdie->protocol_version);
225 fprintf(stderr, "Absolute disk length = %lld\n", rdie->absolute_disk_length);
226 fprintf(stderr, "Absolute start offset = %lld\n", rdie->absolute_start_offset);
227 fprintf(stderr, "BIOS geometry (%ld cyl, %ld heads, %ld sectors)\n",
228 rdie->bios_cylinders, rdie->bios_heads, rdie->bios_sectors);
229 fprintf(stderr, "PHYS geometry (%ld cyl, %ld heads, %ld sectors)\n",
230 rdie->phys_cylinders, rdie->phys_heads, rdie->phys_sectors);
231 fprintf(stderr, "Physical capacity %lld\n", rdie->phys_capacity);
232 fprintf(stderr, "Adapter Type %ld\n", rdie->adapter_type);
233 }
234
235 /*
236 * Validate the disk sizes from the internal disk representation to the current VDMK settings.
237 */
validate_runtime_disk_info_encoding(struct runtime_disk_info_encoding * rdie)238 static inline char validate_runtime_disk_info_encoding(struct runtime_disk_info_encoding *rdie)
239 {
240 if (info->biosGeo.cylinders > 0 && info->biosGeo.cylinders < rdie->bios_cylinders) {
241 fprintf(stderr, "[validate_runtime_disk_info_encoding] New disk has %ld BIOS cylinders original had %ld\n",
242 info->biosGeo.cylinders, rdie->bios_cylinders);
243 goto bail_out;
244 }
245
246 if (info->biosGeo.heads > 0 && info->biosGeo.heads < rdie->bios_heads) {
247 fprintf(stderr, "[validate_runtime_disk_info_encoding] New disk has %ld BIOS heads original had %ld\n",
248 info->biosGeo.heads, rdie->bios_heads);
249 goto bail_out;
250 }
251
252 if (info->biosGeo.cylinders > 0 && info->biosGeo.cylinders < rdie->bios_cylinders) {
253 fprintf(stderr, "[validate_runtime_disk_info_encoding] New disk has %ld BIOS sectors original had %ld\n",
254 info->biosGeo.sectors, rdie->bios_sectors);
255 goto bail_out;
256 }
257
258 if (info->physGeo.cylinders < rdie->phys_cylinders) {
259 fprintf(stderr, "[validate_runtime_disk_info_encoding] New disk has %ld PHYS cylinders original had %ld\n",
260 info->physGeo.cylinders, rdie->phys_cylinders);
261 goto bail_out;
262 }
263
264 if (info->physGeo.heads < rdie->phys_heads) {
265 fprintf(stderr, "[validate_runtime_disk_info_encoding] New disk has %ld PHYS heads original had %ld\n",
266 info->biosGeo.heads, rdie->phys_heads);
267 goto bail_out;
268 }
269
270 if (info->physGeo.cylinders < rdie->phys_cylinders) {
271 fprintf(stderr, "[validate_runtime_disk_info_encoding] New disk has %ld PHYS sectors original had %ld\n",
272 info->biosGeo.sectors, rdie->phys_sectors);
273 goto bail_out;
274 }
275
276 return 1;
277
278 bail_out:
279 return 0;
280 }
281
282 /*
283 * Writer function that handles partial writes.
284 */
robust_writer(int fd,void * buffer,int size)285 static inline size_t robust_writer(int fd, void *buffer, int size)
286 {
287 size_t total_bytes = 0;
288 size_t cnt = 0;
289
290 do {
291 cnt = write(fd, (char *)buffer + total_bytes, size);
292 if (cnt > 0) {
293 size -= cnt;
294 total_bytes += cnt;
295 } else if (cnt < 0) {
296 total_bytes = -1;
297 goto bail_out;
298 }
299 } while (size > 0 && cnt > 0);
300
301 bail_out:
302 return total_bytes;
303 }
304
305 /*
306 * Reader function that handles partial reads.
307 */
robust_reader(int fd,void * buffer,int size)308 static inline size_t robust_reader(int fd, void *buffer, int size)
309 {
310 size_t total_bytes = 0;
311 size_t cnt = 0;
312
313 do {
314 cnt = read(fd, (char *)buffer + total_bytes, size);
315 if (cnt > 0) {
316 size -= cnt;
317 total_bytes += cnt;
318 } else if (cnt < 0) {
319 total_bytes = -1;
320 goto bail_out;
321 }
322 } while (size > 0 && cnt > 0);
323
324 bail_out:
325 return total_bytes;
326 }
327
328 /*
329 * VDDK helper functions.
330 */
LogFunction(const char * fmt,va_list args)331 static void LogFunction(const char *fmt, va_list args)
332 {
333 if (verbose) {
334 fprintf(stderr, "Log: ");
335 vfprintf(stderr, fmt, args);
336 }
337 }
338
WarningFunction(const char * fmt,va_list args)339 static void WarningFunction(const char *fmt, va_list args)
340 {
341 fprintf(stderr, "Warning: ");
342 vfprintf(stderr, fmt, args);
343 }
344
PanicFunction(const char * fmt,va_list args)345 static void PanicFunction(const char *fmt, va_list args)
346 {
347 fprintf(stderr, "Log: ");
348 vfprintf(stderr, fmt, args);
349 exit_code = 10;
350 exit(exit_code);
351 }
352
cleanup_cnxParams()353 static inline void cleanup_cnxParams()
354 {
355 if (cnxParams.vmxSpec) {
356 free(cnxParams.vmxSpec);
357 cnxParams.vmxSpec = NULL;
358 }
359
360 if (cnxParams.serverName) {
361 free(cnxParams.serverName);
362 cnxParams.serverName = NULL;
363 }
364
365 if (cnxParams.creds.uid.userName) {
366 free(cnxParams.creds.uid.userName);
367 cnxParams.creds.uid.userName = NULL;
368 }
369
370 if (cnxParams.creds.uid.password) {
371 free(cnxParams.creds.uid.password);
372 cnxParams.creds.uid.password = NULL;
373 }
374
375 if (cnxParams.thumbPrint) {
376 free(cnxParams.thumbPrint);
377 cnxParams.thumbPrint = NULL;
378 }
379 }
380
cleanup_vixdisklib()381 static inline void cleanup_vixdisklib()
382 {
383 uint32_t numCleanedUp, numRemaining;
384
385 VixDiskLib_Cleanup(&cnxParams, &numCleanedUp, &numRemaining);
386 }
387
388 /*
389 * Generic cleanup function.
390 */
cleanup(void)391 static void cleanup(void)
392 {
393 VixError err;
394
395 if (info) {
396 VixDiskLib_FreeInfo(info);
397 }
398
399 if (read_diskHandle) {
400 VixDiskLib_Close(read_diskHandle);
401 read_diskHandle = NULL;
402 }
403
404 if (write_diskHandle) {
405 VixDiskLib_Close(write_diskHandle);
406 write_diskHandle = NULL;
407 }
408
409 if (connection) {
410 VixDiskLib_Disconnect(connection);
411 if (cleanup_on_disconnect) {
412 cleanup_vixdisklib();
413 }
414 }
415
416 if (!local_vmdk) {
417 err = VixDiskLib_EndAccess(&cnxParams, BAREOS_VADPDUMPER_IDENTITY);
418 if (VIX_FAILED(err)) {
419 char *error_txt;
420
421 error_txt = VixDiskLib_GetErrorText(err, NULL);
422 fprintf(stderr, "Failed to End Access: %s [%d]\n", error_txt, err);
423 VixDiskLib_FreeErrorText(error_txt);
424 }
425 }
426
427 if (raw_disk_fd != -1) {
428 if (verbose) {
429 fprintf(stderr, "Log: RAWFILE: Closing RAW file\n");
430 }
431 close(raw_disk_fd);
432 }
433
434 cleanup_cnxParams();
435
436 VixDiskLib_Exit();
437
438 if (json_config) {
439 json_decref(json_config);
440 }
441
442 if (vmdk_disk_name) {
443 free(vmdk_disk_name);
444 }
445
446 if (force_transport) {
447 free(force_transport);
448 }
449
450 if (disktype) {
451 free(disktype);
452 }
453
454 _exit(exit_code);
455 }
456
457 /*
458 * Convert the configured disktype to the right VADP type.
459 */
lookup_disktype()460 static inline VixDiskLibDiskType lookup_disktype()
461 {
462 int cnt;
463
464 for (cnt = 0; disk_types[cnt].type; cnt++) {
465 if (!strcasecmp(disk_types[cnt].type, disktype)) {
466 break;
467 }
468 }
469
470 if (!disk_types[cnt].type) {
471 fprintf(stderr, "Unknown disktype %s\n", disktype);
472 exit(1);
473 }
474
475 return disk_types[cnt].vadp_type;
476 }
477
478 /*
479 * Connect using VDDK to a VSPHERE server.
480 */
do_vixdisklib_connect(const char * key,json_t * connect_params,bool readonly,bool need_snapshot_moref)481 static inline void do_vixdisklib_connect(const char *key, json_t *connect_params,
482 bool readonly, bool need_snapshot_moref)
483 {
484 int succeeded = 0;
485 VixError err;
486 const char *snapshot_moref = NULL;
487
488 memset(&cnxParams, 0, sizeof(cnxParams));
489
490 err = VixDiskLib_InitEx(VIXDISKLIB_VERSION_MAJOR,
491 VIXDISKLIB_VERSION_MINOR,
492 LogFunction,
493 WarningFunction,
494 PanicFunction,
495 "/usr/lib/vmware-vix-disklib",
496 NULL);
497
498 if (VIX_FAILED(err)) {
499 char *error_txt;
500
501 error_txt = VixDiskLib_GetErrorText(err, NULL);
502 fprintf(stderr, "Failed to initialize vixdisklib %s [%d]\n", error_txt, err);
503 VixDiskLib_FreeErrorText(error_txt);
504 goto bail_out;
505 }
506
507 /*
508 * Start extracting the wanted information from the JSON passed in.
509 */
510 if (!local_vmdk) {
511 json_t *object;
512
513 object = json_object_get(connect_params, CON_PARAMS_VM_MOREF_KEY);
514 if (!object) {
515 fprintf(stderr, "Failed to find %s in JSON definition of object %s\n", CON_PARAMS_VM_MOREF_KEY, key);
516 goto bail_out;
517 }
518 cnxParams.vmxSpec = strdup(json_string_value(object));
519 if (!cnxParams.vmxSpec) {
520 fprintf(stderr, "Failed to allocate memory for holding %s\n", CON_PARAMS_VM_MOREF_KEY);
521 goto bail_out;
522 }
523
524 object = json_object_get(connect_params, CON_PARAMS_HOST_KEY);
525 if (!object) {
526 fprintf(stderr, "Failed to find %s in JSON definition of object %s\n", CON_PARAMS_HOST_KEY, key);
527 goto bail_out;
528 }
529 cnxParams.serverName = strdup(json_string_value(object));
530 if (!cnxParams.serverName) {
531 fprintf(stderr, "Failed to allocate memory for holding %s\n", CON_PARAMS_HOST_KEY);
532 goto bail_out;
533 }
534
535 object = json_object_get(connect_params, CON_PARAMS_THUMBPRINT_KEY);
536 if (object) {
537
538 cnxParams.thumbPrint = strdup(json_string_value(object));
539 if (!cnxParams.thumbPrint) {
540 fprintf(stderr, "Failed to allocate memory for holding %s\n", CON_PARAMS_USERNAME_KEY);
541 goto bail_out;
542 }
543 }
544
545 object = json_object_get(connect_params, CON_PARAMS_USERNAME_KEY);
546 if (!object) {
547 fprintf(stderr, "Failed to find %s in JSON definition of object %s\n", CON_PARAMS_USERNAME_KEY, key);
548 goto bail_out;
549 }
550 cnxParams.credType = VIXDISKLIB_CRED_UID;
551 cnxParams.creds.uid.userName = strdup(json_string_value(object));
552 if (!cnxParams.creds.uid.userName) {
553 fprintf(stderr, "Failed to allocate memory for holding %s\n", CON_PARAMS_USERNAME_KEY);
554 goto bail_out;
555 }
556
557
558 object = json_object_get(connect_params, CON_PARAMS_PASSWORD_KEY);
559 if (!object) {
560 fprintf(stderr, "Failed to find %s in JSON definition of object %s\n", CON_PARAMS_PASSWORD_KEY, key);
561 goto bail_out;
562 }
563 cnxParams.creds.uid.password = strdup(json_string_value(object));
564 if (!cnxParams.creds.uid.password) {
565 fprintf(stderr, "Failed to allocate memory for holding %s\n", CON_PARAMS_PASSWORD_KEY);
566 goto bail_out;
567 }
568 cnxParams.port = VSPHERE_DEFAULT_ADMIN_PORT;
569
570 if (need_snapshot_moref) {
571 object = json_object_get(connect_params, CON_PARAMS_SNAPSHOT_MOREF_KEY);
572 if (!object) {
573 fprintf(stderr, "Failed to find %s in JSON definition of object %s\n", CON_PARAMS_SNAPSHOT_MOREF_KEY, key);
574 goto bail_out;
575 }
576 snapshot_moref = json_string_value(object);
577 }
578
579 if (!local_vmdk) {
580 err = VixDiskLib_PrepareForAccess(&cnxParams, BAREOS_VADPDUMPER_IDENTITY);
581 if (VIX_FAILED(err)) {
582 char *error_txt;
583
584 error_txt = VixDiskLib_GetErrorText(err, NULL);
585 fprintf(stderr, "Failed to Prepare For Access: %s [%d]\n", error_txt, err);
586 VixDiskLib_FreeErrorText(error_txt);
587 }
588 }
589 }
590
591 err = VixDiskLib_ConnectEx(&cnxParams, (readonly) ? TRUE : FALSE, snapshot_moref, force_transport, &connection);
592 if (VIX_FAILED(err)) {
593 char *error_txt;
594
595 error_txt = VixDiskLib_GetErrorText(err, NULL);
596 fprintf(stderr, "Failed to connect to %s : %s [%d]\n", cnxParams.serverName, error_txt, err);
597 VixDiskLib_FreeErrorText(error_txt);
598 goto bail_out;
599 }
600
601 /*
602 * Register our exit handler.
603 */
604 atexit(cleanup);
605
606 succeeded = 1;
607
608 bail_out:
609 if (!succeeded) {
610 exit(1);
611 }
612 }
613
614 /*
615 * Open a VMDK using VDDK.
616 */
do_vixdisklib_open(const char * key,const char * disk_name,json_t * disk_params,bool readonly,bool getdiskinfo,VixDiskLibHandle * diskHandle)617 static inline void do_vixdisklib_open(const char *key, const char *disk_name, json_t *disk_params,
618 bool readonly, bool getdiskinfo, VixDiskLibHandle *diskHandle)
619 {
620 int succeeded = 0;
621 VixError err;
622 const char *disk_path;
623 uint32_t flags;
624
625 if (!disk_name) {
626 json_t *object;
627
628 /*
629 * Start extracting the wanted information from the JSON passed in.
630 */
631 object = json_object_get(disk_params, DISK_PARAMS_DISK_PATH_KEY);
632 if (!object) {
633 fprintf(stderr, "Failed to find %s in JSON definition of object %s\n", DISK_PARAMS_DISK_PATH_KEY, key);
634 goto bail_out;
635 }
636
637 disk_path = json_string_value(object);
638 } else {
639 disk_path = vmdk_disk_name;
640 }
641
642 flags = 0;
643 if (readonly) {
644 flags |= VIXDISKLIB_FLAG_OPEN_READ_ONLY;
645 }
646
647 err = VixDiskLib_Open(connection, disk_path, flags, diskHandle);
648 if (VIX_FAILED(err)) {
649 char *error_txt;
650
651 error_txt = VixDiskLib_GetErrorText(err, NULL);
652 fprintf(stderr, "Failed to open %s : %s [%d]\n", disk_path, error_txt, err);
653 VixDiskLib_FreeErrorText(error_txt);
654 goto bail_out;
655 }
656
657 if (getdiskinfo) {
658 /*
659 * See how big the logical disk is.
660 */
661 err = VixDiskLib_GetInfo(*diskHandle, &info);
662 if (VIX_FAILED(err)) {
663 char *error_txt;
664
665 error_txt = VixDiskLib_GetErrorText(err, NULL);
666 fprintf(stderr, "Failed to get Logical Disk Info for %s, %s [%d]\n", disk_path, error_txt, err);
667 VixDiskLib_FreeErrorText(error_txt);
668 goto bail_out;
669 }
670 #ifdef VIXDISKLIBCREATEPARAMS_HAS_PHYSICALSECTORSIZE
671 if (verbose) {
672 fprintf(stderr, "DiskInfo logicalSectorSize: %u\n",
673 info->logicalSectorSize);
674 fprintf(stderr, "DiskInfo physicalSectorSize: %u\n",
675 info->physicalSectorSize);
676 }
677 #endif
678 }
679
680 if (verbose) {
681 fprintf(stderr, "Selected transport method: %s\n", VixDiskLib_GetTransportMode(*diskHandle));
682 }
683
684 succeeded = 1;
685
686 bail_out:
687 if (!succeeded) {
688 exit(1);
689 }
690 }
691
692 /*
693 * Create a VMDK using VDDK.
694 */
do_vixdisklib_create(const char * key,const char * disk_name,json_t * disk_params,uint64_t absolute_disk_length)695 static inline void do_vixdisklib_create(const char *key, const char *disk_name,
696 json_t *disk_params, uint64_t absolute_disk_length)
697 {
698 int succeeded = 0;
699 VixError err;
700 const char *disk_path;
701 VixDiskLibCreateParams createParams;
702
703 if (!local_vmdk) {
704 fprintf(stderr, "Cannot create a remote disk via VADP\n");
705 goto bail_out;
706 }
707
708 if (!disk_name) {
709 json_t *object;
710
711 /*
712 * Start extracting the wanted information from the JSON passed in.
713 */
714 object = json_object_get(disk_params, DISK_PARAMS_DISK_PATH_KEY);
715 if (!object) {
716 fprintf(stderr, "Failed to find %s in JSON definition of object %s\n", DISK_PARAMS_DISK_PATH_KEY, key);
717 goto bail_out;
718 }
719
720 disk_path = json_string_value(object);
721 } else {
722 disk_path = vmdk_disk_name;
723 }
724
725 createParams.adapterType = VIXDISKLIB_ADAPTER_SCSI_BUSLOGIC;
726 createParams.capacity = (absolute_disk_length / VIXDISKLIB_SECTOR_SIZE);
727 if (disktype) {
728 createParams.diskType = lookup_disktype();
729 } else {
730 createParams.diskType = VIXDISKLIB_DISK_MONOLITHIC_SPARSE;
731 }
732 #ifdef VIXDISKLIBCREATEPARAMS_HAS_PHYSICALSECTORSIZE
733 createParams.physicalSectorSize = VIXDISKLIB_SECTOR_SIZE;
734 createParams.logicalSectorSize = VIXDISKLIB_SECTOR_SIZE;
735 #endif
736 createParams.hwVersion = 7; /* for ESX(i)4 */
737 err = VixDiskLib_Create(connection, disk_path, &createParams, NULL, NULL);
738 if (VIX_FAILED(err)) {
739 char *error_txt;
740
741 error_txt = VixDiskLib_GetErrorText(err, NULL);
742 fprintf(stderr, "Failed to create Logical Disk for %s, %s [%d]\n", disk_path, error_txt, err);
743 VixDiskLib_FreeErrorText(error_txt);
744 goto bail_out;
745 }
746
747 succeeded = 1;
748
749 bail_out:
750 if (!succeeded) {
751 exit(1);
752 }
753 }
754
755 /*
756 * Read data from a VMDK using the VDDP functions.
757 */
read_from_vmdk(size_t sector_offset,size_t nbyte,void * buf)758 static size_t read_from_vmdk(size_t sector_offset, size_t nbyte, void *buf)
759 {
760 VixError err;
761
762 err = VixDiskLib_Read(read_diskHandle, sector_offset, nbyte / DEFAULT_SECTOR_SIZE, (uint8 *)buf);
763 if (VIX_FAILED(err)) {
764 char *error_txt;
765
766 error_txt = VixDiskLib_GetErrorText(err, NULL);
767 fprintf(stderr, "VMDK Read error: %s [%d]\n", error_txt, err);
768 return -1;
769 }
770
771 return nbyte;
772 }
773
774 /*
775 * Write data to a VMDK using the VDDP functions.
776 */
write_to_vmdk(size_t sector_offset,size_t nbyte,void * buf)777 static size_t write_to_vmdk(size_t sector_offset, size_t nbyte, void *buf)
778 {
779 VixError err;
780
781 err = VixDiskLib_Write(write_diskHandle, sector_offset, nbyte / DEFAULT_SECTOR_SIZE, (uint8 *)buf);
782 if (VIX_FAILED(err)) {
783 char *error_txt;
784
785 error_txt = VixDiskLib_GetErrorText(err, NULL);
786 fprintf(stderr, "VMDK Write error: %s [%d]\n", error_txt, err);
787 return -1;
788 }
789
790 return nbyte;
791 }
792
793 /*
794 * Read data from a stream using the robust reader function.
795 */
read_from_stream(size_t sector_offset,size_t nbyte,void * buf)796 static size_t read_from_stream(size_t sector_offset, size_t nbyte, void *buf)
797 {
798 return robust_reader(STDOUT_FILENO, buf, nbyte);
799 }
800
801 /*
802 * Write data from a stream using the robust reader function.
803 */
write_to_stream(size_t sector_offset,size_t nbyte,void * buf)804 static size_t write_to_stream(size_t sector_offset, size_t nbyte, void *buf)
805 {
806 /*
807 * Should we clone to rawdevice ?
808 */
809 if (raw_disk_fd != -1) {
810 robust_writer(raw_disk_fd, buf, nbyte);
811 }
812
813 /*
814 * Should we clone to new VMDK file ?
815 */
816 if (write_diskHandle) {
817 VixError err;
818
819 err = VixDiskLib_Write(write_diskHandle, sector_offset, nbyte / DEFAULT_SECTOR_SIZE, (uint8 *)buf);
820 if (VIX_FAILED(err)) {
821 char *error_txt;
822
823 error_txt = VixDiskLib_GetErrorText(err, NULL);
824 fprintf(stderr, "VMDK Write error: %s [%d]\n", error_txt, err);
825 }
826 }
827
828 return robust_writer(STDOUT_FILENO, buf, nbyte);
829 }
830
831 /*
832 * Encode the disk info of the disk saved into the backup output stream.
833 */
save_disk_info(const char * key,json_t * cbt,uint64_t * absolute_disk_length)834 static inline bool save_disk_info(const char *key, json_t *cbt, uint64_t *absolute_disk_length)
835 {
836 bool retval = false;
837 struct runtime_disk_info_encoding rdie;
838 json_t *object;
839
840 fill_runtime_disk_info_encoding(&rdie);
841
842 object = json_object_get(cbt, CBT_DISK_SIZE);
843 if (!object) {
844 fprintf(stderr, "Failed to find %s in JSON definition of object %s\n", CBT_DISK_SIZE, key);
845 goto bail_out;
846 }
847
848 rdie.absolute_disk_length = json_integer_value(object);
849
850 object = json_object_get(cbt, CBT_START_OFFSET);
851 if (!object) {
852 fprintf(stderr, "Failed to find %s in JSON definition of object %s\n", CBT_START_OFFSET, key);
853 goto bail_out;
854 }
855
856 rdie.absolute_start_offset = json_integer_value(object);
857
858 /*
859 * Save the absolute offset we should use.
860 */
861 absolute_start_offset = rdie.absolute_start_offset;
862
863 if (robust_writer(STDOUT_FILENO, (char *)&rdie, rdie_size) != rdie_size) {
864 fprintf(stderr, "Failed to write runtime_disk_info_encoding structure to output datastream\n");
865 goto bail_out;
866 }
867
868 retval = true;
869 if (absolute_disk_length) {
870 *absolute_disk_length = rdie.absolute_disk_length;
871 }
872
873 bail_out:
874 return retval;
875 }
876
877 /*
878 * Decode the disk info of the disk restored from the backup input stream.
879 */
process_disk_info(bool validate_only,json_t * value)880 static inline bool process_disk_info(bool validate_only, json_t *value)
881 {
882 struct runtime_disk_info_encoding rdie;
883
884 memset(&rdie, 0, rdie_size);
885 if (robust_reader(STDIN_FILENO, (char *)&rdie, rdie_size) != rdie_size) {
886 fprintf(stderr, "Failed to read a valid runtime_disk_info_encoding\n");
887 goto bail_out;
888 }
889
890 if (rdie.start_magic != BAREOSMAGIC) {
891 fprintf(stderr, "[runtime_disk_info_encoding] Failed to find valid MAGIC start marker read %lld should have been %lld\n", rdie.start_magic, BAREOSMAGIC);
892 goto bail_out;
893 }
894
895 if (rdie.end_magic != BAREOSMAGIC) {
896 fprintf(stderr, "[runtime_disk_info_encoding] Failed to find valid MAGIC end marker read %lld should have been %lld\n", rdie.end_magic, BAREOSMAGIC);
897 goto bail_out;
898 }
899
900 if (verbose) {
901 dump_runtime_disk_info_encoding(&rdie);
902 }
903
904 if (create_disk && !validate_only) {
905 do_vixdisklib_create(DISK_PARAMS_KEY, vmdk_disk_name, value, rdie.phys_capacity * VIXDISKLIB_SECTOR_SIZE);
906 do_vixdisklib_open(DISK_PARAMS_KEY, vmdk_disk_name, value, false, true, &write_diskHandle);
907
908 if (!write_diskHandle) {
909 fprintf(stderr, "Cannot process restore data as no VixDiskLib disk handle opened\n");
910 goto bail_out;
911 }
912 }
913
914 /*
915 * Validate that things make sense to restore on the opened VMDK.
916 */
917 if (!validate_only && check_size) {
918 if (!validate_runtime_disk_info_encoding(&rdie)) {
919 fprintf(stderr, "[runtime_disk_info_encoding] Invalid disk geometry for restoring to this volume\n");
920 goto bail_out;
921 }
922 }
923
924 /*
925 * Save the absolute offset we should use.
926 */
927 absolute_start_offset = rdie.absolute_start_offset;
928
929 return true;
930
931 bail_out:
932 return false;
933 }
934
935 /*
936 * Read a specific meta data key and encode it into the output stream.
937 */
read_meta_data_key(char * key)938 static inline bool read_meta_data_key(char *key)
939 {
940 bool retval = false;
941 VixError err;
942 size_t requiredLen;
943 char *buffer = NULL;
944 struct runtime_meta_data_encoding rmde;
945
946 if (verbose) {
947 fprintf(stderr, "Processing metadata key %s\n", key);
948 }
949
950 err = VixDiskLib_ReadMetadata(read_diskHandle, key, NULL, 0, &requiredLen);
951 if (err != VIX_OK && err != VIX_E_BUFFER_TOOSMALL) {
952 return false;
953 }
954
955 buffer = (char *)malloc(requiredLen);
956 if (!buffer) {
957 fprintf(stderr, "Failed to allocate memory for holding metadata keys, exiting ...\n");
958 return false;
959 }
960
961 err = VixDiskLib_ReadMetadata(read_diskHandle, key, buffer, requiredLen, NULL);
962 if (VIX_FAILED(err)) {
963 char *error_txt;
964
965 error_txt = VixDiskLib_GetErrorText(err, NULL);
966 fprintf(stderr, "Failed to read metadata for key %s : %s [%d] exiting ...\n", key, error_txt, err);
967 goto bail_out;
968 }
969
970 /*
971 * Should we clone metadata to new VMDK file ?
972 */
973 if (write_diskHandle) {
974 VixError err;
975
976 err = VixDiskLib_WriteMetadata(write_diskHandle, key, buffer);
977 if (VIX_FAILED(err)) {
978 char *error_txt;
979
980 error_txt = VixDiskLib_GetErrorText(err, NULL);
981 fprintf(stderr, "Failed to write metadata for key %s : %s [%d] exiting ...\n", key, error_txt, err);
982 goto bail_out;
983 }
984 }
985
986 rmde.start_magic = BAREOSMAGIC;
987 rmde.end_magic = BAREOSMAGIC;
988 rmde.meta_key_length = strlen(key) + 1;
989 rmde.meta_data_length = requiredLen + 1;
990
991 if (robust_writer(STDOUT_FILENO, &rmde, rmde_size) != rmde_size) {
992 fprintf(stderr, "Failed to write runtime_meta_data_encoding structure to output datastream\n");
993 goto bail_out;
994 }
995
996 if (robust_writer(STDOUT_FILENO, key, rmde.meta_key_length) != rmde.meta_key_length) {
997 fprintf(stderr, "Failed to write meta data key to output datastream\n");
998 goto bail_out;
999 }
1000
1001 if (robust_writer(STDOUT_FILENO, buffer, rmde.meta_data_length) != rmde.meta_data_length) {
1002 fprintf(stderr, "Failed to write meta data to output datastream\n");
1003 goto bail_out;
1004 }
1005
1006 retval = true;
1007
1008 bail_out:
1009 if (buffer) {
1010 free(buffer);
1011 }
1012
1013 return retval;
1014 }
1015
1016 /*
1017 * Read all meta data from a disk and encode it into the output stream.
1018 */
save_meta_data()1019 static inline bool save_meta_data()
1020 {
1021 bool retval = false;
1022 VixError err;
1023 size_t requiredLen;
1024 char *bp;
1025 char *buffer = NULL;
1026 struct runtime_meta_data_encoding rmde;
1027
1028 /*
1029 * See if we are actually saving all meta data or should only write the META data end marker.
1030 */
1031 if (save_metadata) {
1032 err = VixDiskLib_GetMetadataKeys(read_diskHandle, NULL, 0, &requiredLen);
1033 if (err != VIX_OK && err != VIX_E_BUFFER_TOOSMALL) {
1034 return false;
1035 }
1036
1037 buffer = (char *)malloc(requiredLen);
1038 if (!buffer) {
1039 fprintf(stderr, "Failed to allocate memory for holding metadata keys, exiting ...\n");
1040 return false;
1041 }
1042
1043 err = VixDiskLib_GetMetadataKeys(read_diskHandle, buffer, requiredLen, NULL);
1044 if (VIX_FAILED(err)) {
1045 char *error_txt;
1046
1047 error_txt = VixDiskLib_GetErrorText(err, NULL);
1048 fprintf(stderr, "Failed to read metadata keys : %s [%d] exiting ...\n", error_txt, err);
1049 goto bail_out;
1050 }
1051
1052 bp = buffer;
1053 while (*bp) {
1054 if (!read_meta_data_key(bp)) {
1055 goto bail_out;
1056 }
1057
1058 bp += strlen(bp) + 1;
1059 }
1060 }
1061
1062 /*
1063 * Write an META data end marker.
1064 * e.g. metadata header with key and data length == 0
1065 */
1066 rmde.start_magic = BAREOSMAGIC;
1067 rmde.end_magic = BAREOSMAGIC;
1068 rmde.meta_key_length = 0;
1069 rmde.meta_data_length = 0;
1070
1071 if (robust_writer(STDOUT_FILENO, &rmde, rmde_size) != rmde_size) {
1072 fprintf(stderr, "Failed to write runtime_meta_data_encoding structure to output datastream\n");
1073 goto bail_out;
1074 }
1075
1076 retval = true;
1077
1078 bail_out:
1079 if (buffer) {
1080 free(buffer);
1081 }
1082
1083 return retval;
1084 }
1085
1086 /*
1087 * Read a backup stream from STDIN and process its metadata.
1088 * Stop processing when we encounter the special end of metadata tag
1089 * which is when the meta_key_length and meta_data_length are zero.
1090 */
process_meta_data(bool validate_only)1091 static inline bool process_meta_data(bool validate_only)
1092 {
1093 struct runtime_meta_data_encoding rmde;
1094 char *key = NULL;
1095 char *buffer = NULL;
1096
1097 while (1) {
1098 if (robust_reader(STDIN_FILENO, &rmde, rmde_size) != rmde_size) {
1099 fprintf(stderr, "Failed to read runtime_meta_data_encoding structure from input datastream\n");
1100 goto bail_out;
1101 }
1102
1103 if (rmde.start_magic != BAREOSMAGIC) {
1104 fprintf(stderr, "[runtime_meta_data_encoding] Failed to find valid MAGIC start marker read %lld should have been %lld\n", rmde.start_magic, BAREOSMAGIC);
1105 goto bail_out;
1106 }
1107
1108 if (rmde.end_magic != BAREOSMAGIC) {
1109 fprintf(stderr, "[runtime_meta_data_encoding] Failed to find valid MAGIC end marker read %lld should have been %lld\n", rmde.end_magic, BAREOSMAGIC);
1110 goto bail_out;
1111 }
1112
1113 /*
1114 * See if we processed the last meta data item.
1115 */
1116 if (rmde.meta_key_length == 0 && rmde.meta_data_length == 0) {
1117 break;
1118 }
1119
1120 key = (char *)malloc(rmde.meta_key_length);
1121 if (!key) {
1122 fprintf(stderr, "Failed to allocate %d bytes for meta data key\n", rmde.meta_key_length);
1123 goto bail_out;
1124 }
1125
1126 if (robust_reader(STDIN_FILENO, key, rmde.meta_key_length) != rmde.meta_key_length) {
1127 fprintf(stderr, "Failed to read meta data key from input datastream\n");
1128 goto bail_out;
1129 }
1130
1131 buffer = (char *)malloc(rmde.meta_data_length);
1132 if (!key) {
1133 fprintf(stderr, "Failed to allocate %d bytes for meta data\n", rmde.meta_data_length);
1134 goto bail_out;
1135 }
1136
1137 if (robust_reader(STDIN_FILENO, buffer, rmde.meta_data_length) != rmde.meta_data_length) {
1138 fprintf(stderr, "Failed to read meta data from input datastream\n");
1139 goto bail_out;
1140 }
1141
1142 if (verbose) {
1143 fprintf(stderr, "Meta data key %s, value %s\n", key, buffer);
1144 }
1145
1146 if (!validate_only && restore_meta_data) {
1147 VixError err;
1148
1149 err = VixDiskLib_WriteMetadata(write_diskHandle, key, buffer);
1150 if (VIX_FAILED(err)) {
1151 char *error_txt;
1152
1153 error_txt = VixDiskLib_GetErrorText(err, NULL);
1154 fprintf(stderr, "Failed to write metadata for key %s : %s [%d] exiting ...\n", key, error_txt, err);
1155 goto bail_out;
1156 }
1157 }
1158
1159 free(key);
1160 free(buffer);
1161 }
1162
1163 return true;
1164
1165 bail_out:
1166 return false;
1167 }
1168
1169 /*
1170 * Process the Change Block Tracking information and write the wanted sectors
1171 * to the output stream. We self encode the data using a prefix header that describes
1172 * the data that is encoded after it including a MAGIC key and the actual CBT information
1173 * e.g. start of the read sectors and the number of sectors that follow.
1174 */
process_cbt(const char * key,json_t * cbt)1175 static inline bool process_cbt(const char *key, json_t *cbt)
1176 {
1177 bool retval = false;
1178 size_t index;
1179 json_t *object, *array_element, *start, *length;
1180 uint64_t start_offset, offset_length, current_offset, max_offset;
1181 uint64_t sector_offset, sectors_to_read;
1182 uint8 buf[DEFAULT_SECTOR_SIZE * SECTORS_PER_CALL];
1183 struct runtime_cbt_encoding rce;
1184
1185 if (!read_diskHandle) {
1186 fprintf(stderr, "Cannot process CBT data as no VixDiskLib disk handle opened\n");
1187 goto bail_out;
1188 }
1189
1190 object = json_object_get(cbt, CBT_CHANGEDAREA_KEY);
1191 if (!object) {
1192 fprintf(stderr, "Failed to find %s in JSON definition of object %s\n", CBT_CHANGEDAREA_KEY, key);
1193 goto bail_out;
1194 }
1195
1196 /*
1197 * Iterate over each element of the JSON array and get the "start" and "length" member.
1198 */
1199 rce.start_magic = BAREOSMAGIC;
1200 rce.end_magic = BAREOSMAGIC;
1201 json_array_foreach(object, index, array_element) {
1202 /*
1203 * Get the two members we are interested in.
1204 */
1205 start = json_object_get(array_element, CBT_CHANGEDAREA_START_KEY);
1206 length = json_object_get(array_element, CBT_CHANGEDAREA_LENGTH_KEY);
1207
1208 if (!start || !length) {
1209 continue;
1210 }
1211
1212 start_offset = json_integer_value(start);
1213 offset_length = json_integer_value(length);
1214
1215 if (verbose) {
1216 fprintf(stderr, "start = %lld\n", start_offset);
1217 fprintf(stderr, "length = %lld\n", offset_length);
1218 fprintf(stderr, "nr length = %lld\n", offset_length / DEFAULT_SECTOR_SIZE);
1219 fflush(stderr);
1220 }
1221
1222 rce.start_offset = start_offset;
1223 rce.offset_length = offset_length;
1224
1225 /*
1226 * Write the CBT info into the output stream.
1227 */
1228 if (robust_writer(STDOUT_FILENO, (char *)&rce, rce_size) != rce_size) {
1229 fprintf(stderr, "Failed to write runtime_cbt_encoding structure to output datastream\n");
1230 goto bail_out;
1231 }
1232
1233 if (raw_disk_fd != -1) {
1234 lseek(raw_disk_fd, start_offset, SEEK_SET);
1235 if (verbose) {
1236 fprintf(stderr, "Log: RAWFILE: Adusting seek position in file\n");
1237 }
1238 }
1239
1240 /*
1241 * Calculate the start offset and read as many sectors as defined by the
1242 * length element of the JSON structure.
1243 */
1244 current_offset = absolute_start_offset + start_offset;
1245 max_offset = current_offset + offset_length;
1246 sector_offset = current_offset / DEFAULT_SECTOR_SIZE;
1247 while (current_offset < max_offset) {
1248 /*
1249 * The number of sectors to read is the minimum of either the total number
1250 * of sectors still available in this CBT range or the upper setting specified
1251 * in the sectors_per_call variable.
1252 */
1253 sectors_to_read = MIN(sectors_per_call, (offset_length / DEFAULT_SECTOR_SIZE));
1254
1255 if (multi_threaded) {
1256 if (!send_to_copy_thread(sector_offset, sectors_to_read * DEFAULT_SECTOR_SIZE)) {
1257 goto bail_out;
1258 }
1259 } else {
1260 if (read_from_vmdk(sector_offset, sectors_to_read * DEFAULT_SECTOR_SIZE,
1261 buf) != sectors_to_read * DEFAULT_SECTOR_SIZE) {
1262 fprintf(stderr, "Read error on VMDK\n");
1263 goto bail_out;
1264 }
1265
1266 if (write_to_stream(sector_offset, sectors_to_read * DEFAULT_SECTOR_SIZE,
1267 buf) != sectors_to_read * DEFAULT_SECTOR_SIZE) {
1268 fprintf(stderr, "Failed to write data to output datastream\n");
1269 goto bail_out;
1270 }
1271 }
1272
1273 /*
1274 * Calculate the new offsets for a next run.
1275 */
1276 current_offset += (sectors_to_read * DEFAULT_SECTOR_SIZE);
1277 sector_offset += sectors_to_read;
1278 offset_length -= sectors_to_read * DEFAULT_SECTOR_SIZE;
1279 }
1280
1281 if (multi_threaded) {
1282 flush_copy_thread();
1283 }
1284
1285 if (verbose) {
1286 fflush(stderr);
1287 }
1288 }
1289
1290 if (multi_threaded) {
1291 cleanup_copy_thread();
1292 }
1293
1294 retval = true;
1295
1296 bail_out:
1297 if (read_diskHandle) {
1298 VixDiskLib_Close(read_diskHandle);
1299 read_diskHandle = NULL;
1300 }
1301
1302 return retval;
1303 }
1304
1305 /*
1306 * Read a backup stream from STDIN and process it. When validate_only is set
1307 * to true we only try to process the data but do not actually write it back
1308 * to the VMDK.
1309 */
process_restore_stream(bool validate_only,json_t * value)1310 static inline bool process_restore_stream(bool validate_only, json_t *value)
1311 {
1312 bool retval = false;
1313 size_t cnt;
1314 uint64_t current_offset, max_offset;
1315 uint64_t sector_offset, sectors_to_read;
1316 uint8 buf[DEFAULT_SECTOR_SIZE * SECTORS_PER_CALL];
1317 struct runtime_cbt_encoding rce;
1318
1319 if (!create_disk && !validate_only) {
1320 do_vixdisklib_open(DISK_PARAMS_KEY, vmdk_disk_name, value, false, true, &write_diskHandle);
1321
1322 if (!write_diskHandle) {
1323 fprintf(stderr, "Cannot process restore data as no VixDiskLib disk handle opened\n");
1324 goto bail_out;
1325 }
1326 }
1327
1328 /*
1329 * Setup multi threading if requested.
1330 */
1331 if (!validate_only && multi_threaded) {
1332 if (!setup_copy_thread(read_from_stream, write_to_vmdk)) {
1333 fprintf(stderr, "Failed to initialize multithreading\n");
1334 goto bail_out;
1335 }
1336 }
1337
1338 /*
1339 * Process the disk info data.
1340 */
1341 if (!process_disk_info(validate_only, value)) {
1342 goto bail_out;
1343 }
1344
1345 /*
1346 * Process the disk meta data,
1347 */
1348 if (!process_meta_data(validate_only)) {
1349 goto bail_out;
1350 }
1351
1352 memset(&rce, 0, rce_size);
1353 while (robust_reader(STDIN_FILENO, (char *)&rce, rce_size) == rce_size) {
1354 if (rce.start_magic != BAREOSMAGIC) {
1355 fprintf(stderr, "[runtime_cbt_encoding] Failed to find valid MAGIC start marker read %lld should have been %lld\n", rce.start_magic, BAREOSMAGIC);
1356 goto bail_out;
1357 }
1358
1359 if (rce.end_magic != BAREOSMAGIC) {
1360 fprintf(stderr, "[runtime_cbt_encoding] Failed to find valid MAGIC end marker read %lld should have been %lld\n", rce.end_magic, BAREOSMAGIC);
1361 goto bail_out;
1362 }
1363
1364 if (verbose) {
1365 fprintf(stderr, "start = %lld\n", rce.start_offset);
1366 fprintf(stderr, "length = %lld\n", rce.offset_length);
1367 fprintf(stderr, "nr length = %lld\n", rce.offset_length / DEFAULT_SECTOR_SIZE);
1368 fflush(stderr);
1369 }
1370
1371 current_offset = absolute_start_offset + rce.start_offset;
1372 max_offset = current_offset + rce.offset_length;
1373 sector_offset = current_offset / DEFAULT_SECTOR_SIZE;
1374 while (current_offset < max_offset) {
1375 /*
1376 * The number of sectors to read is the minimum of either the total number
1377 * of sectors still available in this CBT range or the upper setting specified
1378 * in the sectors_per_call variable.
1379 */
1380 sectors_to_read = MIN(sectors_per_call, (rce.offset_length / DEFAULT_SECTOR_SIZE));
1381
1382 if (!validate_only && multi_threaded) {
1383 if (!send_to_copy_thread(sector_offset, sectors_to_read * DEFAULT_SECTOR_SIZE)) {
1384 goto bail_out;
1385 }
1386 } else {
1387 cnt = robust_reader(STDIN_FILENO, (char *)buf, sectors_to_read * DEFAULT_SECTOR_SIZE);
1388 if (cnt != sectors_to_read * DEFAULT_SECTOR_SIZE) {
1389 goto bail_out;
1390 }
1391
1392 if (!validate_only) {
1393 if (write_to_vmdk(sector_offset, cnt, buf) != cnt) {
1394 goto bail_out;
1395 }
1396 }
1397 }
1398
1399 /*
1400 * Calculate the new offsets for a next run.
1401 */
1402 current_offset += (sectors_to_read * DEFAULT_SECTOR_SIZE);
1403 sector_offset += sectors_to_read;
1404 rce.offset_length -= sectors_to_read * DEFAULT_SECTOR_SIZE;
1405 }
1406
1407 if (multi_threaded) {
1408 flush_copy_thread();
1409 }
1410
1411 memset(&rce, 0, rce_size);
1412 }
1413
1414 if (multi_threaded) {
1415 cleanup_copy_thread();
1416 }
1417
1418 retval = true;
1419
1420 bail_out:
1421 if (write_diskHandle) {
1422 VixDiskLib_Close(write_diskHandle);
1423 write_diskHandle = NULL;
1424 }
1425
1426 return retval;
1427 }
1428
1429 /*
1430 * All work to this program is passed in using a JSON work file which has the needed
1431 * information to perform the wanted operation. This function loads the JSON data into
1432 * memory using the Jansson JSON library.
1433 */
process_json_work_file(const char * json_work_file)1434 static inline void process_json_work_file(const char *json_work_file)
1435 {
1436 json_error_t error;
1437
1438 /*
1439 * Open the JSON work file.
1440 */
1441 json_config = json_load_file(json_work_file, JSON_DECODE_ANY, &error);
1442 if (!json_config) {
1443 fprintf(stderr, "Failed to parse JSON config %s [%s at line %d column %d]\n",
1444 json_work_file, error.text, error.line, error.column);
1445 exit(1);
1446 }
1447
1448 if (verbose) {
1449 /*
1450 * Dump the internal parsed data in pretty print format.
1451 */
1452 json_dumpf(json_config, stderr, JSON_PRESERVE_ORDER | JSON_COMPACT | JSON_INDENT(3));
1453 fprintf(stderr, "\n");
1454 fflush(stderr);
1455 }
1456 }
1457
1458 /*
1459 * Worker function that performs the dump operation of the program.
1460 */
dump_vmdk_stream(const char * json_work_file)1461 static inline bool dump_vmdk_stream(const char *json_work_file)
1462 {
1463 json_t *value;
1464 uint64_t absolute_disk_length = 0;
1465
1466 process_json_work_file(json_work_file);
1467
1468 value = json_object_get(json_config, CON_PARAMS_KEY);
1469 if (!value) {
1470 fprintf(stderr, "Failed to find %s in JSON definition\n", CON_PARAMS_KEY);
1471 exit(1);
1472 }
1473
1474 do_vixdisklib_connect(CON_PARAMS_KEY, value, true, true);
1475
1476 if (cleanup_on_start) {
1477 cleanup_vixdisklib();
1478 }
1479
1480 value = json_object_get(json_config, DISK_PARAMS_KEY);
1481 if (!value) {
1482 fprintf(stderr, "Failed to find %s in JSON definition\n", DISK_PARAMS_KEY);
1483 exit(1);
1484 }
1485
1486 do_vixdisklib_open(DISK_PARAMS_KEY, NULL, value, true, true, &read_diskHandle);
1487
1488 value = json_object_get(json_config, CBT_DISKCHANGEINFO_KEY);
1489 if (!value) {
1490 fprintf(stderr, "Failed to find %s in JSON definition\n", CBT_DISKCHANGEINFO_KEY);
1491 exit(1);
1492 }
1493
1494 /*
1495 * Setup multi threading if requested.
1496 */
1497 if (multi_threaded) {
1498 if (!setup_copy_thread(read_from_vmdk, write_to_stream)) {
1499 fprintf(stderr, "Failed to initialize multithreading\n");
1500 exit(1);
1501 }
1502 }
1503
1504 if (!save_disk_info(CBT_DISKCHANGEINFO_KEY, value, &absolute_disk_length)) {
1505 exit(1);
1506 }
1507
1508 /*
1509 * See if we are requested to clone the content to a new VMDK.
1510 * save_disk_info() initializes absolute_disk_length.
1511 */
1512 if (vmdk_disk_name) {
1513 if (create_disk) {
1514 do_vixdisklib_create(NULL, vmdk_disk_name, value, absolute_disk_length);
1515 }
1516
1517 do_vixdisklib_open(NULL, vmdk_disk_name, value, false, false, &write_diskHandle);
1518 }
1519
1520 if (!save_meta_data()) {
1521 exit(1);
1522 }
1523
1524 /*
1525 * See if we are requested to clone the content to a rawdevice.
1526 */
1527 if (raw_disk_name) {
1528 if (verbose) {
1529 fprintf(stderr, "Log: RAWFILE: Trying to open RAW file\n");
1530 }
1531
1532 if ((raw_disk_fd = open(raw_disk_name, O_WRONLY | O_TRUNC)) == -1) {
1533 fprintf(stderr, "Error: Failed to open the RAW DISK FILE\n");
1534 exit(1);
1535 }
1536 }
1537
1538 return process_cbt(CBT_DISKCHANGEINFO_KEY, value);
1539 }
1540
1541 /*
1542 * Worker function that performs the restore operation of the program.
1543 */
restore_vmdk_stream(const char * json_work_file)1544 static inline bool restore_vmdk_stream(const char *json_work_file)
1545 {
1546 json_t *value;
1547
1548 process_json_work_file(json_work_file);
1549
1550 value = json_object_get(json_config, CON_PARAMS_KEY);
1551 if (!value) {
1552 fprintf(stderr, "Failed to find %s in JSON definition\n", CON_PARAMS_KEY);
1553 exit(1);
1554 }
1555
1556 if (cleanup_on_start) {
1557 cleanup_vixdisklib();
1558 }
1559
1560 do_vixdisklib_connect(CON_PARAMS_KEY, value, false, false);
1561
1562 value = json_object_get(json_config, DISK_PARAMS_KEY);
1563 if (!value) {
1564 fprintf(stderr, "Failed to find %s in JSON definition\n", DISK_PARAMS_KEY);
1565 exit(1);
1566 }
1567
1568 return process_restore_stream(false, value);
1569 }
1570
1571 /*
1572 * Worker function that performs the show operation of the program.
1573 */
show_backup_stream()1574 static inline int show_backup_stream()
1575 {
1576 return process_restore_stream(true, NULL);
1577 }
1578
signal_handler(int sig)1579 static void signal_handler(int sig)
1580 {
1581 exit_code = sig;
1582 exit(sig);
1583 }
1584
usage(const char * program_name)1585 void usage(const char *program_name)
1586 {
1587 fprintf(stderr, "Usage: %s [-d <vmdk_diskname>] [-f force_transport] [-s sectors_per_call] [-t disktype] [-CcDlMmRSv] dump <workfile> | restore <workfile> | show\n", program_name);
1588 fprintf(stderr, "Where:\n");
1589 fprintf(stderr, " -C - Create local VMDK\n");
1590 fprintf(stderr, " -c - Don't check size of VMDK\n");
1591 fprintf(stderr, " -D - Cleanup on Disconnect\n");
1592 fprintf(stderr, " -d - Specify local VMDK name\n");
1593 fprintf(stderr, " -f - Specify forced transport method\n");
1594 fprintf(stderr, " -h - This help text\n");
1595 fprintf(stderr, " -l - Write to a local VMDK\n");
1596 fprintf(stderr, " -M - Save metadata of VMDK on dump action\n");
1597 fprintf(stderr, " -m - Use multithreading\n");
1598 fprintf(stderr, " -r - RAW Image disk name\n");
1599 fprintf(stderr, " -R - Restore metadata of VMDK on restore action\n");
1600 fprintf(stderr, " -S - Cleanup on Start\n");
1601 fprintf(stderr, " -s - Sectors to read per call to VDDK\n");
1602 fprintf(stderr, " -t - Disktype to create for local VMDK\n");
1603 fprintf(stderr, " -v - Verbose output\n");
1604 fprintf(stderr, " -? - This help text\n");
1605 exit(1);
1606 }
1607
main(int argc,char ** argv)1608 int main(int argc, char **argv)
1609 {
1610 bool retval;
1611 const char *program_name;
1612 int ch;
1613
1614 program_name = argv[0];
1615 while ((ch = getopt(argc, argv, "CcDd:r:f:hlMmRSs:t:v?")) != -1) {
1616 switch (ch) {
1617 case 'C':
1618 create_disk = true;
1619 /*
1620 * If we create the disk we should not check for the size as that won't match.
1621 */
1622 check_size = false;
1623 break;
1624 case 'c':
1625 check_size = false;
1626 break;
1627 case 'D':
1628 cleanup_on_disconnect = true;
1629 break;
1630 case 'd':
1631 vmdk_disk_name = strdup(optarg);
1632 if (!vmdk_disk_name) {
1633 fprintf(stderr, "Failed to allocate memory to hold diskname, exiting ...\n");
1634 exit(1);
1635 }
1636 break;
1637 case 'r':
1638 raw_disk_name = strdup(optarg);
1639 if (!raw_disk_name) {
1640 fprintf(stderr, "Failed to allocate memory to hold rawdiskname, exiting ...\n");
1641 exit(1);
1642 }
1643 break;
1644 case 'f':
1645 force_transport = strdup(optarg);
1646 if (!force_transport) {
1647 fprintf(stderr, "Failed to allocate memory to hold forced transport, exiting ...\n");
1648 exit(1);
1649 }
1650 break;
1651 case 'l':
1652 local_vmdk = true;
1653 break;
1654 case 'M':
1655 save_metadata = true;
1656 break;
1657 case 'm':
1658 multi_threaded = true;
1659 break;
1660 case 'R':
1661 restore_meta_data = true;
1662 break;
1663 case 'S':
1664 cleanup_on_start = true;
1665 break;
1666 case 's':
1667 sectors_per_call = atoi(optarg);
1668 break;
1669 case 't':
1670 disktype = strdup(optarg);
1671 if (!disktype) {
1672 fprintf(stderr, "Failed to allocate memory to hold disktype, exiting ...\n");
1673 exit(1);
1674 }
1675 break;
1676 case 'v':
1677 verbose = true;
1678 break;
1679 case 'h':
1680 case '?':
1681 default:
1682 usage(program_name);
1683 break;
1684 }
1685 }
1686
1687 /*
1688 * Install signal handlers for the most important signals.
1689 */
1690 signal(SIGHUP, signal_handler);
1691 signal(SIGINT, signal_handler);
1692 signal(SIGTERM, signal_handler);
1693
1694 argc -= optind;
1695 argv += optind;
1696
1697 if (argc <= 0) {
1698 usage(program_name);
1699 }
1700
1701 if (strcasecmp(argv[0], "dump") == 0) {
1702 if (argc <= 1) {
1703 usage(program_name);
1704 }
1705
1706 retval = dump_vmdk_stream(argv[1]);
1707 } else if (strcasecmp(argv[0], "restore") == 0) {
1708 if (argc <= 1) {
1709 usage(program_name);
1710 }
1711
1712 retval = restore_vmdk_stream(argv[1]);
1713 } else if (strcasecmp(argv[0], "show") == 0) {
1714 retval = show_backup_stream();
1715 } else {
1716 fprintf(stderr, "Unknown action %s\n", argv[1]);
1717 }
1718
1719 if (retval) {
1720 exit_code = 0;
1721 }
1722
1723 exit(exit_code);
1724 }
1725