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