]> git.proxmox.com Git - pve-qemu.git/blame - debian/patches/pve/0032-PVE-Backup-pbs-restore-new-command-to-restore-from-p.patch
pbs-restore: flush verbose log before calling into library
[pve-qemu.git] / debian / patches / pve / 0032-PVE-Backup-pbs-restore-new-command-to-restore-from-p.patch
CommitLineData
6402d961
TL
1From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2From: Dietmar Maurer <dietmar@proxmox.com>
83faa3fe
TL
3Date: Mon, 6 Apr 2020 12:17:01 +0200
4Subject: [PATCH] PVE-Backup: pbs-restore - new command to restore from proxmox
5 backup server
6402d961 6
bce72611 7Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
6402d961
TL
8---
9 Makefile | 4 +-
fff7e250
TL
10 pbs-restore.c | 217 ++++++++++++++++++++++++++++++++++++++++++++++++++
11 2 files changed, 220 insertions(+), 1 deletion(-)
6402d961
TL
12 create mode 100644 pbs-restore.c
13
14diff --git a/Makefile b/Makefile
b7e851a5 15index dbd9542ae4..7c1fb58e18 100644
6402d961
TL
16--- a/Makefile
17+++ b/Makefile
83faa3fe 18@@ -479,7 +479,7 @@ dummy := $(call unnest-vars,, \
6402d961
TL
19
20 include $(SRC_PATH)/tests/Makefile.include
21
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)
24
25 qemu-version.h: FORCE
26 $(call quiet-command, \
83faa3fe
TL
27@@ -610,6 +610,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
6402d961
TL
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
33
34 qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o $(COMMON_LDADDS)
35
36diff --git a/pbs-restore.c b/pbs-restore.c
37new file mode 100644
fff7e250 38index 0000000000..fc881de560
6402d961
TL
39--- /dev/null
40+++ b/pbs-restore.c
fff7e250 41@@ -0,0 +1,217 @@
6402d961
TL
42+/*
43+ * Qemu image restore helper for Proxmox Backup
44+ *
45+ * Copyright (C) 2019 Proxmox Server Solutions
46+ *
47+ * Authors:
48+ * Dietmar Maurer (dietmar@proxmox.com)
49+ *
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.
52+ *
53+ */
54+
55+#include "qemu/osdep.h"
56+#include <glib.h>
57+#include <getopt.h>
58+#include <string.h>
59+
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"
68+
69+#include <proxmox-backup-qemu.h>
70+
71+static void help(void)
72+{
73+ const char *help_msg =
74+ "usage: pbs-restore [--repository <repo>] snapshot archive-name target [command options]\n"
75+ ;
76+
77+ printf("%s", help_msg);
78+ exit(1);
79+}
80+
81+typedef struct CallbackData {
82+ BlockBackend *target;
83+ uint64_t last_offset;
84+ bool skip_zero;
85+} CallbackData;
86+
87+static int write_callback(
88+ void *callback_data_ptr,
89+ uint64_t offset,
90+ const unsigned char *data,
91+ uint64_t data_len)
92+{
93+ int res = -1;
94+
95+ CallbackData *callback_data = (CallbackData *)callback_data_ptr;
96+
97+ uint64_t last_offset = callback_data->last_offset;
98+ if (offset > last_offset) callback_data->last_offset = offset;
99+
100+ if (data == NULL) {
101+ if (callback_data->skip_zero && offset > last_offset) {
102+ return 0;
103+ }
104+ res = blk_pwrite_zeroes(callback_data->target, offset, data_len, 0);
105+ } else {
106+ res = blk_pwrite(callback_data->target, offset, data, data_len, 0);
107+ }
108+
109+ if (res < 0) {
110+ fprintf(stderr, "blk_pwrite failed at offset %ld length %ld (%d) - %s\n", offset, data_len, res, strerror(-res));
111+ return res;
112+ }
113+
114+ return 0;
115+}
116+
117+int main(int argc, char **argv)
118+{
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;
125+
126+ error_init(argv[0]);
127+
c6979241 128+ for (;;) {
6402d961
TL
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'},
136+ {0, 0, 0, 0}
137+ };
138+ int c = getopt_long(argc, argv, "hvf:r:k:", long_options, NULL);
139+ if (c == -1) {
140+ break;
141+ }
c6979241
TL
142+ switch (c) {
143+ case ':':
144+ fprintf(stderr, "missing argument for option '%s'\n", argv[optind - 1]);
145+ return -1;
146+ case '?':
147+ fprintf(stderr, "unrecognized option '%s'\n", argv[optind - 1]);
148+ return -1;
149+ case 'f':
150+ format = g_strdup(argv[optind - 1]);
151+ break;
152+ case 'r':
153+ repository = g_strdup(argv[optind - 1]);
154+ break;
155+ case 'k':
156+ keyfile = g_strdup(argv[optind - 1]);
157+ break;
158+ case 'v':
159+ verbose = true;
160+ break;
161+ case 'S':
162+ skip_zero = true;
163+ break;
164+ case 'h':
165+ help();
166+ return 0;
6402d961
TL
167+ }
168+ }
169+
170+ if (optind >= argc - 2) {
171+ fprintf(stderr, "missing arguments\n");
172+ help();
173+ return -1;
174+ }
175+
176+ if (repository == NULL) {
177+ repository = getenv("PBS_REPOSITORY");
178+ }
179+
180+ if (repository == NULL) {
181+ fprintf(stderr, "no repository specified\n");
182+ help();
183+ return -1;
184+ }
185+
186+ char *snapshot = argv[optind++];
187+ char *archive_name = argv[optind++];
188+ char *target = argv[optind++];
189+
190+ const char *password = getenv("PBS_PASSWORD");
191+ const char *fingerprint = getenv("PBS_FINGERPRINT");
192+ const char *key_password = getenv("PBS_ENCRYPTION_PASSWORD");
193+
194+ if (qemu_init_main_loop(&main_loop_err)) {
195+ g_error("%s", error_get_pretty(main_loop_err));
196+ }
197+
198+ bdrv_init();
199+ module_call_init(MODULE_INIT_QOM);
200+
bce72611
TL
201+ if (verbose) {
202+ fprintf(stderr, "connecting to repository '%s'\n", repository);
203+ }
6402d961
TL
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);
209+ return -1;
210+ }
211+
212+ QDict *options = qdict_new();
6402d961
TL
213+
214+ if (format) {
215+ qdict_put_str(options, "driver", format);
216+ }
217+
bce72611
TL
218+
219+ if (verbose) {
220+ fprintf(stderr, "open block backend for target '%s'\n", target);
221+ }
6402d961
TL
222+ Error *local_err = NULL;
223+ int flags = BDRV_O_RDWR;
6402d961
TL
224+ BlockBackend *blk = blk_new_open(target, NULL, options, flags, &local_err);
225+ if (!blk) {
226+ fprintf(stderr, "%s\n", error_get_pretty(local_err));
227+ return -1;
228+ }
229+
c6979241 230+ CallbackData *callback_data = calloc(sizeof(CallbackData), 1);
6402d961
TL
231+
232+ callback_data->target = blk;
233+ callback_data->skip_zero = skip_zero;
234+ callback_data->last_offset = 0;
235+
236+ // blk_set_enable_write_cache(blk, !writethrough);
237+
bce72611
TL
238+ if (verbose) {
239+ fprintf(stderr, "starting to restore snapshot '%s'\n", snapshot);
fff7e250 240+ fflush(stderr); // ensure we do not get printed after the progress log
bce72611 241+ }
6402d961
TL
242+ int res = proxmox_restore_image(
243+ conn,
244+ archive_name,
245+ write_callback,
246+ callback_data,
247+ &pbs_error,
248+ verbose);
249+
250+ proxmox_restore_disconnect(conn);
251+
252+ if (res < 0) {
253+ fprintf(stderr, "restore failed: %s\n", pbs_error);
254+ return -1;
255+ }
256+
257+ return 0;
258+}