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,const char * override_config_file,uint8_t ** config_data_r,int * config_len_r)34 void save_domain_core_begin(uint32_t domid,
35 const char *override_config_file,
36 uint8_t **config_data_r,
37 int *config_len_r)
38 {
39 int rc;
40 libxl_domain_config d_config;
41 char *config_c = 0;
42
43 /* configuration file in optional data: */
44
45 libxl_domain_config_init(&d_config);
46
47 if (override_config_file) {
48 void *config_v = 0;
49 rc = libxl_read_file_contents(ctx, override_config_file,
50 &config_v, config_len_r);
51 if (rc) {
52 fprintf(stderr, "unable to read overridden config file\n");
53 exit(EXIT_FAILURE);
54 }
55 parse_config_data(override_config_file, config_v, *config_len_r,
56 &d_config);
57 free(config_v);
58 } else {
59 rc = libxl_retrieve_domain_configuration(ctx, domid, &d_config);
60 if (rc) {
61 fprintf(stderr, "unable to retrieve domain configuration\n");
62 exit(EXIT_FAILURE);
63 }
64 }
65
66 config_c = libxl_domain_config_to_json(ctx, &d_config);
67 if (!config_c) {
68 fprintf(stderr, "unable to convert config file to JSON\n");
69 exit(EXIT_FAILURE);
70 }
71 *config_data_r = (uint8_t *)config_c;
72 *config_len_r = strlen(config_c) + 1; /* including trailing '\0' */
73
74 libxl_domain_config_dispose(&d_config);
75 }
76
save_domain_core_writeconfig(int fd,const char * source,const uint8_t * config_data,int config_len)77 void save_domain_core_writeconfig(int fd, const char *source,
78 const uint8_t *config_data, int config_len)
79 {
80 struct save_file_header hdr;
81 uint8_t *optdata_begin;
82 union { uint32_t u32; char b[4]; } u32buf;
83
84 memset(&hdr, 0, sizeof(hdr));
85 memcpy(hdr.magic, savefileheader_magic, sizeof(hdr.magic));
86 hdr.byteorder = SAVEFILE_BYTEORDER_VALUE;
87 hdr.mandatory_flags = XL_MANDATORY_FLAG_STREAMv2;
88
89 optdata_begin= 0;
90
91 #define ADD_OPTDATA(ptr, len) ({ \
92 if ((len)) { \
93 hdr.optional_data_len += (len); \
94 optdata_begin = xrealloc(optdata_begin, hdr.optional_data_len); \
95 memcpy(optdata_begin + hdr.optional_data_len - (len), \
96 (ptr), (len)); \
97 } \
98 })
99
100 u32buf.u32 = config_len;
101 ADD_OPTDATA(u32buf.b, 4);
102 ADD_OPTDATA(config_data, config_len);
103 if (config_len)
104 hdr.mandatory_flags |= XL_MANDATORY_FLAG_JSON;
105
106 /* that's the optional data */
107
108 CHK_ERRNOVAL(libxl_write_exactly(
109 ctx, fd, &hdr, sizeof(hdr), source, "header"));
110 CHK_ERRNOVAL(libxl_write_exactly(
111 ctx, fd, optdata_begin, hdr.optional_data_len,
112 source, "header"));
113
114 free(optdata_begin);
115
116 fprintf(stderr, "Saving to %s new xl format (info"
117 " 0x%"PRIx32"/0x%"PRIx32"/%"PRIu32")\n",
118 source, hdr.mandatory_flags, hdr.optional_flags,
119 hdr.optional_data_len);
120 }
121
save_domain(uint32_t domid,const char * filename,int checkpoint,int leavepaused,const char * override_config_file)122 static int save_domain(uint32_t domid, const char *filename, int checkpoint,
123 int leavepaused, const char *override_config_file)
124 {
125 int fd;
126 uint8_t *config_data;
127 int config_len;
128
129 save_domain_core_begin(domid, override_config_file,
130 &config_data, &config_len);
131
132 if (!config_len) {
133 fputs(" Savefile will not contain xl domain config\n", stderr);
134 }
135
136 fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644);
137 if (fd < 0) {
138 fprintf(stderr, "Failed to open temp file %s for writing\n", filename);
139 exit(EXIT_FAILURE);
140 }
141
142 save_domain_core_writeconfig(fd, filename, config_data, config_len);
143
144 int rc = libxl_domain_suspend(ctx, domid, fd, 0, NULL);
145 close(fd);
146
147 if (rc < 0) {
148 fprintf(stderr, "Failed to save domain, resuming domain\n");
149 libxl_domain_resume(ctx, domid, 1, 0);
150 }
151 else if (leavepaused || checkpoint) {
152 if (leavepaused)
153 libxl_domain_pause(ctx, domid);
154 libxl_domain_resume(ctx, domid, 1, 0);
155 }
156 else
157 libxl_domain_destroy(ctx, domid, 0);
158
159 exit(rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
160 }
161
main_restore(int argc,char ** argv)162 int main_restore(int argc, char **argv)
163 {
164 const char *checkpoint_file = NULL;
165 const char *config_file = NULL;
166 struct domain_create dom_info;
167 int paused = 0, debug = 0, daemonize = 1, monitor = 1,
168 console_autoconnect = 0, vnc = 0, vncautopass = 0;
169 int opt, rc;
170 static struct option opts[] = {
171 {"vncviewer", 0, 0, 'V'},
172 {"vncviewer-autopass", 0, 0, 'A'},
173 COMMON_LONG_OPTS
174 };
175
176 SWITCH_FOREACH_OPT(opt, "FcpdeVA", opts, "restore", 1) {
177 case 'c':
178 console_autoconnect = 1;
179 break;
180 case 'p':
181 paused = 1;
182 break;
183 case 'd':
184 debug = 1;
185 break;
186 case 'F':
187 daemonize = 0;
188 break;
189 case 'e':
190 daemonize = 0;
191 monitor = 0;
192 break;
193 case 'V':
194 vnc = 1;
195 break;
196 case 'A':
197 vnc = vncautopass = 1;
198 break;
199 }
200
201 if (argc-optind == 1) {
202 checkpoint_file = argv[optind];
203 } else if (argc-optind == 2) {
204 config_file = argv[optind];
205 checkpoint_file = argv[optind + 1];
206 } else {
207 help("restore");
208 return EXIT_FAILURE;
209 }
210
211 memset(&dom_info, 0, sizeof(dom_info));
212 dom_info.debug = debug;
213 dom_info.daemonize = daemonize;
214 dom_info.monitor = monitor;
215 dom_info.paused = paused;
216 dom_info.config_file = config_file;
217 dom_info.restore_file = checkpoint_file;
218 dom_info.migrate_fd = -1;
219 dom_info.send_back_fd = -1;
220 dom_info.vnc = vnc;
221 dom_info.vncautopass = vncautopass;
222 dom_info.console_autoconnect = console_autoconnect;
223
224 rc = create_domain(&dom_info);
225 if (rc < 0)
226 return EXIT_FAILURE;
227
228 return EXIT_SUCCESS;
229 }
230
main_save(int argc,char ** argv)231 int main_save(int argc, char **argv)
232 {
233 uint32_t domid;
234 const char *filename;
235 const char *config_filename = NULL;
236 int checkpoint = 0;
237 int leavepaused = 0;
238 int opt;
239
240 SWITCH_FOREACH_OPT(opt, "cp", NULL, "save", 2) {
241 case 'c':
242 checkpoint = 1;
243 break;
244 case 'p':
245 leavepaused = 1;
246 break;
247 }
248
249 if (argc-optind > 3) {
250 help("save");
251 return EXIT_FAILURE;
252 }
253
254 domid = find_domain(argv[optind]);
255 filename = argv[optind + 1];
256 if ( argc - optind >= 3 )
257 config_filename = argv[optind + 2];
258
259 save_domain(domid, filename, checkpoint, leavepaused, config_filename);
260 return EXIT_SUCCESS;
261 }
262
263 #endif /* LIBXL_HAVE_NO_SUSPEND_RESUME */
264
265
266
267 /*
268 * Local variables:
269 * mode: C
270 * c-basic-offset: 4
271 * indent-tabs-mode: nil
272 * End:
273 */
274