1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2 From: Dietmar Maurer <dietmar@proxmox.com>
3 Date: Mon, 6 Apr 2020 12:17:01 +0200
4 Subject: [PATCH] PVE-Backup: pbs-restore - new command to restore from proxmox
7 Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
10 pbs-restore.c | 217 ++++++++++++++++++++++++++++++++++++++++++++++++++
11 2 files changed, 220 insertions(+), 1 deletion(-)
12 create mode 100644 pbs-restore.c
14 diff --git a/Makefile b/Makefile
15 index aec216968d..b73da29f24 100644
18 @@ -479,7 +479,7 @@ dummy := $(call unnest-vars,, \
20 include $(SRC_PATH)/tests/Makefile.include
22 -all: $(DOCS) $(if $(BUILD_DOCS),sphinxdocs) $(TOOLS) vma$(EXESUF) $(HELPERS-y) recurse-all modules $(vhost-user-json-y)
23 +all: $(DOCS) $(if $(BUILD_DOCS),sphinxdocs) $(TOOLS) vma$(EXESUF) pbs-restore$(EXESUF) $(HELPERS-y) recurse-all modules $(vhost-user-json-y)
26 $(call quiet-command, \
27 @@ -604,6 +604,8 @@ qemu-io$(EXESUF): qemu-io.o $(authz-obj-y) $(block-obj-y) $(crypto-obj-y) $(io-o
28 qemu-storage-daemon$(EXESUF): qemu-storage-daemon.o $(authz-obj-y) $(block-obj-y) $(crypto-obj-y) $(chardev-obj-y) $(io-obj-y) $(qom-obj-y) $(storage-daemon-obj-y) $(COMMON_LDADDS)
29 qemu-storage-daemon$(EXESUF): LIBS += -lproxmox_backup_qemu
30 vma$(EXESUF): vma.o vma-reader.o $(authz-obj-y) $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
31 +pbs-restore$(EXESUF): pbs-restore.o $(authz-obj-y) $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
32 +pbs-restore$(EXESUF): LIBS += -lproxmox_backup_qemu
34 qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o $(COMMON_LDADDS)
36 diff --git a/pbs-restore.c b/pbs-restore.c
38 index 0000000000..4bf37ef1fa
43 + * Qemu image restore helper for Proxmox Backup
45 + * Copyright (C) 2019 Proxmox Server Solutions
48 + * Dietmar Maurer (dietmar@proxmox.com)
50 + * This work is licensed under the terms of the GNU GPL, version 2 or later.
51 + * See the COPYING file in the top-level directory.
55 +#include "qemu/osdep.h"
60 +#include "qemu-common.h"
61 +#include "qemu/module.h"
62 +#include "qemu/error-report.h"
63 +#include "qemu/main-loop.h"
64 +#include "qemu/cutils.h"
65 +#include "qapi/error.h"
66 +#include "qapi/qmp/qdict.h"
67 +#include "sysemu/block-backend.h"
69 +#include <proxmox-backup-qemu.h>
71 +static void help(void)
73 + const char *help_msg =
74 + "usage: pbs-restore [--repository <repo>] snapshot archive-name target [command options]\n"
77 + printf("%s", help_msg);
81 +typedef struct CallbackData {
82 + BlockBackend *target;
83 + uint64_t last_offset;
87 +static int write_callback(
88 + void *callback_data_ptr,
90 + const unsigned char *data,
95 + CallbackData *callback_data = (CallbackData *)callback_data_ptr;
97 + uint64_t last_offset = callback_data->last_offset;
98 + if (offset > last_offset) callback_data->last_offset = offset;
100 + if (data == NULL) {
101 + if (callback_data->skip_zero && offset > last_offset) {
104 + res = blk_pwrite_zeroes(callback_data->target, offset, data_len, 0);
106 + res = blk_pwrite(callback_data->target, offset, data, data_len, 0);
110 + fprintf(stderr, "blk_pwrite failed at offset %ld length %ld (%d) - %s\n", offset, data_len, res, strerror(-res));
117 +int main(int argc, char **argv)
119 + Error *main_loop_err = NULL;
120 + const char *format = "raw";
121 + const char *repository = NULL;
122 + const char *keyfile = NULL;
123 + int verbose = false;
124 + bool skip_zero = false;
126 + error_init(argv[0]);
129 + static const struct option long_options[] = {
130 + {"help", no_argument, 0, 'h'},
131 + {"skip-zero", no_argument, 0, 'S'},
132 + {"verbose", no_argument, 0, 'v'},
133 + {"format", required_argument, 0, 'f'},
134 + {"repository", required_argument, 0, 'r'},
135 + {"keyfile", required_argument, 0, 'k'},
138 + int c = getopt_long(argc, argv, "hvf:r:k:", long_options, NULL);
144 + fprintf(stderr, "missing argument for option '%s'\n", argv[optind - 1]);
147 + fprintf(stderr, "unrecognized option '%s'\n", argv[optind - 1]);
150 + format = g_strdup(argv[optind - 1]);
153 + repository = g_strdup(argv[optind - 1]);
156 + keyfile = g_strdup(argv[optind - 1]);
170 + if (optind >= argc - 2) {
171 + fprintf(stderr, "missing arguments\n");
176 + if (repository == NULL) {
177 + repository = getenv("PBS_REPOSITORY");
180 + if (repository == NULL) {
181 + fprintf(stderr, "no repository specified\n");
186 + char *snapshot = argv[optind++];
187 + char *archive_name = argv[optind++];
188 + char *target = argv[optind++];
190 + const char *password = getenv("PBS_PASSWORD");
191 + const char *fingerprint = getenv("PBS_FINGERPRINT");
192 + const char *key_password = getenv("PBS_ENCRYPTION_PASSWORD");
194 + if (qemu_init_main_loop(&main_loop_err)) {
195 + g_error("%s", error_get_pretty(main_loop_err));
199 + module_call_init(MODULE_INIT_QOM);
202 + fprintf(stderr, "connecting to repository '%s'\n", repository);
204 + char *pbs_error = NULL;
205 + ProxmoxRestoreHandle *conn = proxmox_restore_connect(
206 + repository, snapshot, password, keyfile, key_password, fingerprint, &pbs_error);
207 + if (conn == NULL) {
208 + fprintf(stderr, "restore failed: %s\n", pbs_error);
212 + QDict *options = qdict_new();
215 + qdict_put_str(options, "driver", format);
220 + fprintf(stderr, "open block backend for target '%s'\n", target);
222 + Error *local_err = NULL;
223 + int flags = BDRV_O_RDWR;
224 + BlockBackend *blk = blk_new_open(target, NULL, options, flags, &local_err);
226 + fprintf(stderr, "%s\n", error_get_pretty(local_err));
230 + CallbackData *callback_data = calloc(sizeof(CallbackData), 1);
232 + callback_data->target = blk;
233 + callback_data->skip_zero = skip_zero;
234 + callback_data->last_offset = 0;
236 + // blk_set_enable_write_cache(blk, !writethrough);
239 + fprintf(stderr, "starting to restore snapshot '%s'\n", snapshot);
240 + fflush(stderr); // ensure we do not get printed after the progress log
242 + int res = proxmox_restore_image(
250 + proxmox_restore_disconnect(conn);
253 + fprintf(stderr, "restore failed: %s\n", pbs_error);