]> git.proxmox.com Git - pve-qemu.git/blame - debian/patches/pve/0032-PVE-Backup-pbs-restore-new-command-to-restore-from-p.patch
small cleanups for pbs-restore
[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
TL
6
7---
8 Makefile | 4 +-
c6979241
TL
9 pbs-restore.c | 206 ++++++++++++++++++++++++++++++++++++++++++++++++++
10 2 files changed, 209 insertions(+), 1 deletion(-)
6402d961
TL
11 create mode 100644 pbs-restore.c
12
13diff --git a/Makefile b/Makefile
b7e851a5 14index dbd9542ae4..7c1fb58e18 100644
6402d961
TL
15--- a/Makefile
16+++ b/Makefile
83faa3fe 17@@ -479,7 +479,7 @@ dummy := $(call unnest-vars,, \
6402d961
TL
18
19 include $(SRC_PATH)/tests/Makefile.include
20
21-all: $(DOCS) $(if $(BUILD_DOCS),sphinxdocs) $(TOOLS) vma$(EXESUF) $(HELPERS-y) recurse-all modules $(vhost-user-json-y)
22+all: $(DOCS) $(if $(BUILD_DOCS),sphinxdocs) $(TOOLS) vma$(EXESUF) pbs-restore$(EXESUF) $(HELPERS-y) recurse-all modules $(vhost-user-json-y)
23
24 qemu-version.h: FORCE
25 $(call quiet-command, \
83faa3fe
TL
26@@ -610,6 +610,8 @@ qemu-io$(EXESUF): qemu-io.o $(authz-obj-y) $(block-obj-y) $(crypto-obj-y) $(io-o
27 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)
28 qemu-storage-daemon$(EXESUF): LIBS += -lproxmox_backup_qemu
6402d961
TL
29 vma$(EXESUF): vma.o vma-reader.o $(authz-obj-y) $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
30+pbs-restore$(EXESUF): pbs-restore.o $(authz-obj-y) $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
31+pbs-restore$(EXESUF): LIBS += -lproxmox_backup_qemu
32
33 qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o $(COMMON_LDADDS)
34
35diff --git a/pbs-restore.c b/pbs-restore.c
36new file mode 100644
c6979241 37index 0000000000..0b24e35403
6402d961
TL
38--- /dev/null
39+++ b/pbs-restore.c
c6979241 40@@ -0,0 +1,206 @@
6402d961
TL
41+/*
42+ * Qemu image restore helper for Proxmox Backup
43+ *
44+ * Copyright (C) 2019 Proxmox Server Solutions
45+ *
46+ * Authors:
47+ * Dietmar Maurer (dietmar@proxmox.com)
48+ *
49+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
50+ * See the COPYING file in the top-level directory.
51+ *
52+ */
53+
54+#include "qemu/osdep.h"
55+#include <glib.h>
56+#include <getopt.h>
57+#include <string.h>
58+
59+#include "qemu-common.h"
60+#include "qemu/module.h"
61+#include "qemu/error-report.h"
62+#include "qemu/main-loop.h"
63+#include "qemu/cutils.h"
64+#include "qapi/error.h"
65+#include "qapi/qmp/qdict.h"
66+#include "sysemu/block-backend.h"
67+
68+#include <proxmox-backup-qemu.h>
69+
70+static void help(void)
71+{
72+ const char *help_msg =
73+ "usage: pbs-restore [--repository <repo>] snapshot archive-name target [command options]\n"
74+ ;
75+
76+ printf("%s", help_msg);
77+ exit(1);
78+}
79+
80+typedef struct CallbackData {
81+ BlockBackend *target;
82+ uint64_t last_offset;
83+ bool skip_zero;
84+} CallbackData;
85+
86+static int write_callback(
87+ void *callback_data_ptr,
88+ uint64_t offset,
89+ const unsigned char *data,
90+ uint64_t data_len)
91+{
92+ int res = -1;
93+
94+ CallbackData *callback_data = (CallbackData *)callback_data_ptr;
95+
96+ uint64_t last_offset = callback_data->last_offset;
97+ if (offset > last_offset) callback_data->last_offset = offset;
98+
99+ if (data == NULL) {
100+ if (callback_data->skip_zero && offset > last_offset) {
101+ return 0;
102+ }
103+ res = blk_pwrite_zeroes(callback_data->target, offset, data_len, 0);
104+ } else {
105+ res = blk_pwrite(callback_data->target, offset, data, data_len, 0);
106+ }
107+
108+ if (res < 0) {
109+ fprintf(stderr, "blk_pwrite failed at offset %ld length %ld (%d) - %s\n", offset, data_len, res, strerror(-res));
110+ return res;
111+ }
112+
113+ return 0;
114+}
115+
116+int main(int argc, char **argv)
117+{
118+ Error *main_loop_err = NULL;
119+ const char *format = "raw";
120+ const char *repository = NULL;
121+ const char *keyfile = NULL;
122+ int verbose = false;
123+ bool skip_zero = false;
124+
125+ error_init(argv[0]);
126+
c6979241 127+ for (;;) {
6402d961
TL
128+ static const struct option long_options[] = {
129+ {"help", no_argument, 0, 'h'},
130+ {"skip-zero", no_argument, 0, 'S'},
131+ {"verbose", no_argument, 0, 'v'},
132+ {"format", required_argument, 0, 'f'},
133+ {"repository", required_argument, 0, 'r'},
134+ {"keyfile", required_argument, 0, 'k'},
135+ {0, 0, 0, 0}
136+ };
137+ int c = getopt_long(argc, argv, "hvf:r:k:", long_options, NULL);
138+ if (c == -1) {
139+ break;
140+ }
c6979241
TL
141+ switch (c) {
142+ case ':':
143+ fprintf(stderr, "missing argument for option '%s'\n", argv[optind - 1]);
144+ return -1;
145+ case '?':
146+ fprintf(stderr, "unrecognized option '%s'\n", argv[optind - 1]);
147+ return -1;
148+ case 'f':
149+ format = g_strdup(argv[optind - 1]);
150+ break;
151+ case 'r':
152+ repository = g_strdup(argv[optind - 1]);
153+ break;
154+ case 'k':
155+ keyfile = g_strdup(argv[optind - 1]);
156+ break;
157+ case 'v':
158+ verbose = true;
159+ break;
160+ case 'S':
161+ skip_zero = true;
162+ break;
163+ case 'h':
164+ help();
165+ return 0;
6402d961
TL
166+ }
167+ }
168+
169+ if (optind >= argc - 2) {
170+ fprintf(stderr, "missing arguments\n");
171+ help();
172+ return -1;
173+ }
174+
175+ if (repository == NULL) {
176+ repository = getenv("PBS_REPOSITORY");
177+ }
178+
179+ if (repository == NULL) {
180+ fprintf(stderr, "no repository specified\n");
181+ help();
182+ return -1;
183+ }
184+
185+ char *snapshot = argv[optind++];
186+ char *archive_name = argv[optind++];
187+ char *target = argv[optind++];
188+
189+ const char *password = getenv("PBS_PASSWORD");
190+ const char *fingerprint = getenv("PBS_FINGERPRINT");
191+ const char *key_password = getenv("PBS_ENCRYPTION_PASSWORD");
192+
193+ if (qemu_init_main_loop(&main_loop_err)) {
194+ g_error("%s", error_get_pretty(main_loop_err));
195+ }
196+
197+ bdrv_init();
198+ module_call_init(MODULE_INIT_QOM);
199+
200+ char *pbs_error = NULL;
201+ ProxmoxRestoreHandle *conn = proxmox_restore_connect(
202+ repository, snapshot, password, keyfile, key_password, fingerprint, &pbs_error);
203+ if (conn == NULL) {
204+ fprintf(stderr, "restore failed: %s\n", pbs_error);
205+ return -1;
206+ }
207+
208+ QDict *options = qdict_new();
6402d961
TL
209+
210+ if (format) {
211+ qdict_put_str(options, "driver", format);
212+ }
213+
214+ Error *local_err = NULL;
215+ int flags = BDRV_O_RDWR;
6402d961
TL
216+ BlockBackend *blk = blk_new_open(target, NULL, options, flags, &local_err);
217+ if (!blk) {
218+ fprintf(stderr, "%s\n", error_get_pretty(local_err));
219+ return -1;
220+ }
221+
c6979241 222+ CallbackData *callback_data = calloc(sizeof(CallbackData), 1);
6402d961
TL
223+
224+ callback_data->target = blk;
225+ callback_data->skip_zero = skip_zero;
226+ callback_data->last_offset = 0;
227+
228+ // blk_set_enable_write_cache(blk, !writethrough);
229+
230+ int res = proxmox_restore_image(
231+ conn,
232+ archive_name,
233+ write_callback,
234+ callback_data,
235+ &pbs_error,
236+ verbose);
237+
238+ proxmox_restore_disconnect(conn);
239+
240+ if (res < 0) {
241+ fprintf(stderr, "restore failed: %s\n", pbs_error);
242+ return -1;
243+ }
244+
245+ return 0;
246+}