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