1 /*
2 * Copyright 2009-2017 Citrix Ltd and other contributors
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published
6 * by the Free Software Foundation; version 2.1 only. with the special
7 * exception on linking described in file LICENSE.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 */
14
15 #include <fcntl.h>
16 #include <inttypes.h>
17 #include <stdlib.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <sys/utsname.h>
21 #include <time.h>
22 #include <unistd.h>
23
24 #include <libxl.h>
25 #include <libxl_utils.h>
26 #include <libxlutil.h>
27
28 #include "xl.h"
29 #include "xl_utils.h"
30 #include "xl_parse.h"
31
32 #ifndef LIBXL_HAVE_NO_SUSPEND_RESUME
33
save_domain_core_begin(uint32_t domid,int preserve_domid,const char * override_config_file,uint8_t ** config_data_r,int * config_len_r)34 void save_domain_core_begin(uint32_t domid,
35 int preserve_domid,
36 const char *override_config_file,
37 uint8_t **config_data_r,
38 int *config_len_r)
39 {
40 int rc;
41 libxl_domain_config d_config;
42 char *config_c = 0;
43
44 /* configuration file in optional data: */
45
46 libxl_domain_config_init(&d_config);
47
48 if (override_config_file) {
49 void *config_v = 0;
50 rc = libxl_read_file_contents(ctx, override_config_file,
51 &config_v, config_len_r);
52 if (rc) {
53 fprintf(stderr, "unable to read overridden config file\n");
54 exit(EXIT_FAILURE);
55 }
56 parse_config_data(override_config_file, config_v, *config_len_r,
57 &d_config);
58 free(config_v);
59 } else {
60 rc = libxl_retrieve_domain_configuration(ctx, domid, &d_config,
61 NULL);
62 if (rc) {
63 fprintf(stderr, "unable to retrieve domain configuration\n");
64 exit(EXIT_FAILURE);
65 }
66
67 d_config.c_info.domid = preserve_domid ? domid : 0;
68 }
69
70 config_c = libxl_domain_config_to_json(ctx, &d_config);
71 if (!config_c) {
72 fprintf(stderr, "unable to convert config file to JSON\n");
73 exit(EXIT_FAILURE);
74 }
75 *config_data_r = (uint8_t *)config_c;
76 *config_len_r = strlen(config_c) + 1; /* including trailing '\0' */
77
78 libxl_domain_config_dispose(&d_config);
79 }
80
save_domain_core_writeconfig(int fd,const char * source,const uint8_t * config_data,int config_len)81 void save_domain_core_writeconfig(int fd, const char *source,
82 const uint8_t *config_data, int config_len)
83 {
84 struct save_file_header hdr;
85 uint8_t *optdata_begin;
86 union { uint32_t u32; char b[4]; } u32buf;
87
88 memset(&hdr, 0, sizeof(hdr));
89 memcpy(hdr.magic, savefileheader_magic, sizeof(hdr.magic));
90 hdr.byteorder = SAVEFILE_BYTEORDER_VALUE;
91 hdr.mandatory_flags = XL_MANDATORY_FLAG_STREAMv2;
92
93 optdata_begin= 0;
94
95 #define ADD_OPTDATA(ptr, len) ({ \
96 if ((len)) { \
97 hdr.optional_data_len += (len); \
98 optdata_begin = xrealloc(optdata_begin, hdr.optional_data_len); \
99 memcpy(optdata_begin + hdr.optional_data_len - (len), \
100 (ptr), (len)); \
101 } \
102 })
103
104 u32buf.u32 = config_len;
105 ADD_OPTDATA(u32buf.b, 4);
106 ADD_OPTDATA(config_data, config_len);
107 if (config_len)
108 hdr.mandatory_flags |= XL_MANDATORY_FLAG_JSON;
109
110 /* that's the optional data */
111
112 CHK_ERRNOVAL(libxl_write_exactly(
113 ctx, fd, &hdr, sizeof(hdr), source, "header"));
114 CHK_ERRNOVAL(libxl_write_exactly(
115 ctx, fd, optdata_begin, hdr.optional_data_len,
116 source, "header"));
117
118 free(optdata_begin);
119
120 fprintf(stderr, "Saving to %s new xl format (info"
121 " 0x%"PRIx32"/0x%"PRIx32"/%"PRIu32")\n",
122 source, hdr.mandatory_flags, hdr.optional_flags,
123 hdr.optional_data_len);
124 }
125
save_domain(uint32_t domid,int preserve_domid,const char * filename,int checkpoint,int leavepaused,const char * override_config_file)126 static int save_domain(uint32_t domid, int preserve_domid,
127 const char *filename, int checkpoint,
128 int leavepaused, const char *override_config_file)
129 {
130 int fd;
131 uint8_t *config_data;
132 int config_len;
133
134 save_domain_core_begin(domid, preserve_domid, override_config_file,
135 &config_data, &config_len);
136
137 if (!config_len) {
138 fputs(" Savefile will not contain xl domain config\n", stderr);
139 }
140
141 fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644);
142 if (fd < 0) {
143 fprintf(stderr, "Failed to open temp file %s for writing\n", filename);
144 exit(EXIT_FAILURE);
145 }
146
147 save_domain_core_writeconfig(fd, filename, config_data, config_len);
148
149 int rc = libxl_domain_suspend(ctx, domid, fd, 0, NULL);
150 close(fd);
151
152 if (rc < 0) {
153 fprintf(stderr, "Failed to save domain, resuming domain\n");
154 libxl_domain_resume(ctx, domid, 1, 0);
155 }
156 else if (leavepaused || checkpoint) {
157 if (leavepaused)
158 libxl_domain_pause(ctx, domid, NULL);
159 libxl_domain_resume(ctx, domid, 1, 0);
160 }
161 else
162 libxl_domain_destroy(ctx, domid, 0);
163
164 exit(rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
165 }
166
main_restore(int argc,char ** argv)167 int main_restore(int argc, char **argv)
168 {
169 const char *checkpoint_file = NULL;
170 const char *config_file = NULL;
171 struct domain_create dom_info;
172 int paused = 0, debug = 0, daemonize = 1, monitor = 1,
173 console_autoconnect = 0, vnc = 0, vncautopass = 0;
174 int opt, rc;
175 static struct option opts[] = {
176 {"vncviewer", 0, 0, 'V'},
177 {"vncviewer-autopass", 0, 0, 'A'},
178 COMMON_LONG_OPTS
179 };
180
181 SWITCH_FOREACH_OPT(opt, "FcpdeVA", opts, "restore", 1) {
182 case 'c':
183 console_autoconnect = 1;
184 break;
185 case 'p':
186 paused = 1;
187 break;
188 case 'd':
189 debug = 1;
190 break;
191 case 'F':
192 daemonize = 0;
193 break;
194 case 'e':
195 daemonize = 0;
196 monitor = 0;
197 break;
198 case 'V':
199 vnc = 1;
200 break;
201 case 'A':
202 vnc = vncautopass = 1;
203 break;
204 }
205
206 if (argc-optind == 1) {
207 checkpoint_file = argv[optind];
208 } else if (argc-optind == 2) {
209 config_file = argv[optind];
210 checkpoint_file = argv[optind + 1];
211 } else {
212 help("restore");
213 return EXIT_FAILURE;
214 }
215
216 memset(&dom_info, 0, sizeof(dom_info));
217 dom_info.debug = debug;
218 dom_info.daemonize = daemonize;
219 dom_info.monitor = monitor;
220 dom_info.paused = paused;
221 dom_info.config_file = config_file;
222 dom_info.restore_file = checkpoint_file;
223 dom_info.migrate_fd = -1;
224 dom_info.send_back_fd = -1;
225 dom_info.vnc = vnc;
226 dom_info.vncautopass = vncautopass;
227 dom_info.console_autoconnect = console_autoconnect;
228
229 rc = create_domain(&dom_info);
230 if (rc < 0)
231 return EXIT_FAILURE;
232
233 return EXIT_SUCCESS;
234 }
235
main_save(int argc,char ** argv)236 int main_save(int argc, char **argv)
237 {
238 uint32_t domid;
239 const char *filename;
240 const char *config_filename = NULL;
241 int checkpoint = 0;
242 int leavepaused = 0;
243 int preserve_domid = 0;
244 int opt;
245
246 SWITCH_FOREACH_OPT(opt, "cpD", NULL, "save", 2) {
247 case 'c':
248 checkpoint = 1;
249 break;
250 case 'p':
251 leavepaused = 1;
252 break;
253 case 'D':
254 preserve_domid = 1;
255 break;
256 }
257
258 if (argc-optind > 3) {
259 help("save");
260 return EXIT_FAILURE;
261 }
262
263 domid = find_domain(argv[optind]);
264 filename = argv[optind + 1];
265 if ( argc - optind >= 3 )
266 config_filename = argv[optind + 2];
267
268 save_domain(domid, preserve_domid, filename, checkpoint, leavepaused,
269 config_filename);
270 return EXIT_SUCCESS;
271 }
272
273 #endif /* LIBXL_HAVE_NO_SUSPEND_RESUME */
274
275
276
277 /*
278 * Local variables:
279 * mode: C
280 * c-basic-offset: 4
281 * indent-tabs-mode: nil
282 * End:
283 */
284