1 /*
2 * Copyright (C) 2014 Citrix Ltd.
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 "libxl_osdeps.h"
16
17 #include "libxl_internal.h"
18
19 /*
20 * Infrastructure for converting a legacy migration stream into a
21 * libxl v2 stream.
22 *
23 * This is done by fork()ing the python conversion script, which takes
24 * in a legacy stream, and puts out a suitably-formatted v2 stream.
25 */
26
27 static void helper_exited(libxl__egc *egc, libxl__ev_child *ch,
28 pid_t pid, int status);
29 static void helper_stop(libxl__egc *egc, libxl__ao_abortable *abrt, int rc);
30 static void helper_done(libxl__egc *egc,
31 libxl__conversion_helper_state *chs);
32
33 /*----- Entrypoints -----*/
34
libxl__conversion_helper_init(libxl__conversion_helper_state * chs)35 void libxl__conversion_helper_init(libxl__conversion_helper_state *chs)
36 {
37 assert(chs->ao);
38
39 chs->v2_carefd = NULL;
40 chs->rc = 0;
41 libxl__ao_abortable_init(&chs->abrt);
42 libxl__ev_child_init(&chs->child);
43 }
44
libxl__convert_legacy_stream(libxl__egc * egc,libxl__conversion_helper_state * chs)45 int libxl__convert_legacy_stream(libxl__egc *egc,
46 libxl__conversion_helper_state *chs)
47 {
48 STATE_AO_GC(chs->ao);
49 libxl__carefd *child_in = NULL, *child_out = NULL;
50 int rc = 0;
51
52 chs->abrt.ao = chs->ao;
53 chs->abrt.callback = helper_stop;
54 rc = libxl__ao_abortable_register(&chs->abrt);
55 if (rc) goto err;
56
57 libxl__carefd_begin();
58 int fds[2];
59 if (libxl_pipe(CTX, fds)) {
60 rc = ERROR_FAIL;
61 libxl__carefd_unlock();
62 goto err;
63 }
64 child_out = libxl__carefd_record(CTX, fds[0]);
65 child_in = libxl__carefd_record(CTX, fds[1]);
66 libxl__carefd_unlock();
67
68 pid_t pid = libxl__ev_child_fork(gc, &chs->child, helper_exited);
69 if (!pid) {
70 char * const args[] =
71 {
72 getenv("LIBXL_CONVERT_HELPER") ?:
73 LIBEXEC_BIN "/convert-legacy-stream",
74 "--in", GCSPRINTF("%d", chs->legacy_fd),
75 "--out", GCSPRINTF("%d", fds[1]),
76 /*
77 * The width calculation is an assumption for the common
78 * case. The conversion script needs to know the width of
79 * the toolstack which saved the legacy stream.
80 *
81 * In the overwhelming majority of cases, the width of the
82 * saving toolstack will be the same as our current
83 * width. To avoid extending the libxl API with a
84 * parameter intended to disappear shortly, this option
85 * has not been exposed to the caller.
86 *
87 * If more complicated conversion is required, the
88 * conversion script can be instantiated manually, which
89 * will bypass all of this conversion logic.
90 */
91 "--width", sizeof(unsigned long) == 8 ? "64" : "32",
92
93 "--guest", chs->hvm ? "hvm" : "pv",
94 "--format", "libxl",
95 /* "--verbose", */
96 NULL,
97 };
98
99 libxl_fd_set_cloexec(CTX, chs->legacy_fd, 0);
100 libxl_fd_set_cloexec(CTX, libxl__carefd_fd(child_in), 0);
101
102 libxl__exec(gc,
103 -1, -1, -1,
104 args[0], args, NULL);
105 }
106
107 libxl__carefd_close(child_in);
108 chs->v2_carefd = child_out;
109
110 assert(!rc);
111 return rc;
112
113 err:
114 libxl__ao_abortable_deregister(&chs->abrt);
115 assert(rc);
116 return rc;
117 }
118
libxl__conversion_helper_abort(libxl__egc * egc,libxl__conversion_helper_state * chs,int rc)119 void libxl__conversion_helper_abort(libxl__egc *egc,
120 libxl__conversion_helper_state *chs,
121 int rc)
122 {
123 STATE_AO_GC(chs->ao);
124 assert(rc);
125
126 if (libxl__conversion_helper_inuse(chs)) {
127
128 if (!chs->rc)
129 chs->rc = rc;
130
131 libxl__kill(gc, chs->child.pid, SIGTERM, "conversion helper");
132 }
133 }
134
135 /*----- State handling -----*/
136
helper_stop(libxl__egc * egc,libxl__ao_abortable * abrt,int rc)137 static void helper_stop(libxl__egc *egc, libxl__ao_abortable *abrt, int rc)
138 {
139 libxl__conversion_helper_state *chs = CONTAINER_OF(abrt, *chs, abrt);
140 STATE_AO_GC(chs->ao);
141
142 libxl__conversion_helper_abort(egc, chs, rc);
143 }
144
helper_exited(libxl__egc * egc,libxl__ev_child * ch,pid_t pid,int status)145 static void helper_exited(libxl__egc *egc, libxl__ev_child *ch,
146 pid_t pid, int status)
147 {
148 libxl__conversion_helper_state *chs = CONTAINER_OF(ch, *chs, child);
149 STATE_AO_GC(chs->ao);
150
151 if (status) {
152 libxl_report_child_exitstatus(
153 CTX, chs->rc ? XTL_DEBUG : XTL_ERROR,
154 "conversion helper", pid, status);
155
156 if (!chs->rc)
157 chs->rc = ERROR_FAIL;
158 }
159
160 helper_done(egc, chs);
161 }
162
helper_done(libxl__egc * egc,libxl__conversion_helper_state * chs)163 static void helper_done(libxl__egc *egc,
164 libxl__conversion_helper_state *chs)
165 {
166 STATE_AO_GC(chs->ao);
167
168 assert(!libxl__conversion_helper_inuse(chs));
169
170 libxl__ao_abortable_deregister(&chs->abrt);
171
172 chs->completion_callback(egc, chs, chs->rc);
173 }
174