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