1 #define _GNU_SOURCE
2 #include <stdbool.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <time.h>
7 #include <xenctrl.h>
8 #include <xenguest.h>
9
10 #include "xenstore.h"
11
12 /* Add a string plus terminating 0 byte to buf, returning new len. */
add_to_buf(char ** buf,const char * val,int len)13 static int add_to_buf(char **buf, const char *val, int len)
14 {
15 int vallen = strlen(val) + 1;
16
17 if (len < 0)
18 return -1;
19
20 *buf = realloc(*buf, len + vallen);
21 if (!*buf)
22 return -1;
23
24 strcpy(*buf + len, val);
25
26 return len + vallen;
27 }
28
live_update_start(struct xs_handle * xsh,bool force,unsigned int to)29 static int live_update_start(struct xs_handle *xsh, bool force, unsigned int to)
30 {
31 int len = 0;
32 char *buf = NULL, *ret;
33 time_t time_start;
34
35 if (asprintf(&ret, "%u", to) < 0)
36 return 1;
37 len = add_to_buf(&buf, "-s", len);
38 len = add_to_buf(&buf, "-t", len);
39 len = add_to_buf(&buf, ret, len);
40 free(ret);
41 if (force)
42 len = add_to_buf(&buf, "-F", len);
43 if (len < 0)
44 return 1;
45
46 ret = strdup("BUSY");
47 if (!ret) {
48 free(buf);
49 return 1;
50 }
51
52 for (time_start = time(NULL); time(NULL) - time_start < to;) {
53 free(ret);
54 ret = xs_control_command(xsh, "live-update", buf, len);
55 if (!ret)
56 goto err;
57 if (strcmp(ret, "BUSY"))
58 break;
59 sleep(1);
60 }
61
62 if (strcmp(ret, "OK"))
63 goto err;
64
65 free(buf);
66 free(ret);
67
68 return 0;
69
70 err:
71 fprintf(stderr, "Starting live update failed:\n%s\n",
72 ret ? : strerror(errno));
73 free(buf);
74 free(ret);
75
76 return 3;
77 }
78
live_update_cmdline(struct xs_handle * xsh,const char * cmdline)79 static int live_update_cmdline(struct xs_handle *xsh, const char *cmdline)
80 {
81 int len = 0, rc = 0;
82 char *buf = NULL, *ret;
83
84 len = add_to_buf(&buf, "-c", len);
85 len = add_to_buf(&buf, cmdline, len);
86 if (len < 0)
87 return 1;
88
89 ret = xs_control_command(xsh, "live-update", buf, len);
90 free(buf);
91 if (!ret || strcmp(ret, "OK")) {
92 fprintf(stderr, "Setting update binary failed:\n%s\n",
93 ret ? : strerror(errno));
94 rc = 3;
95 }
96 free(ret);
97
98 return rc;
99 }
100
send_kernel_blob(struct xs_handle * xsh,const char * binary)101 static int send_kernel_blob(struct xs_handle *xsh, const char *binary)
102 {
103 int rc = 0, len = 0;
104 xc_interface *xch;
105 struct xc_dom_image *dom;
106 char *ret, *buf = NULL;
107 size_t off, sz;
108 #define BLOB_CHUNK_SZ 2048
109
110 xch = xc_interface_open(NULL, NULL, 0);
111 if (!xch) {
112 fprintf(stderr, "xc_interface_open() failed\n");
113 return 1;
114 }
115
116 dom = xc_dom_allocate(xch, NULL, NULL);
117 if (!dom) {
118 rc = 1;
119 goto out_close;
120 }
121
122 rc = xc_dom_kernel_file(dom, binary);
123 if (rc) {
124 rc = 1;
125 goto out_rel;
126 }
127
128 if (asprintf(&ret, "%zu", dom->kernel_size) < 0) {
129 rc = 1;
130 goto out_rel;
131 }
132 len = add_to_buf(&buf, "-b", len);
133 len = add_to_buf(&buf, ret, len);
134 free(ret);
135 if (len < 0) {
136 rc = 1;
137 goto out_rel;
138 }
139 ret = xs_control_command(xsh, "live-update", buf, len);
140 free(buf);
141 if (!ret || strcmp(ret, "OK")) {
142 fprintf(stderr, "Starting live update failed:\n%s\n",
143 ret ? : strerror(errno));
144 rc = 3;
145 }
146 free(ret);
147 if (rc)
148 goto out_rel;
149
150 /* buf capable to hold "-d" <1..2048> BLOB_CHUNK_SZ and a terminating 0. */
151 buf = malloc(3 + 5 + BLOB_CHUNK_SZ + 1);
152 if (!buf) {
153 rc = 1;
154 goto out_rel;
155 }
156
157 strcpy(buf, "-d");
158 sz = BLOB_CHUNK_SZ;
159 for (off = 0; off < dom->kernel_size; off += BLOB_CHUNK_SZ) {
160 if (dom->kernel_size - off < BLOB_CHUNK_SZ)
161 sz = dom->kernel_size - off;
162 sprintf(buf + 3, "%zu", sz);
163 len = 3 + strlen(buf + 3) + 1;
164 memcpy(buf + len, dom->kernel_blob + off, sz);
165 buf[len + sz] = 0;
166 len += sz + 1;
167 ret = xs_control_command(xsh, "live-update", buf, len);
168 if (!ret || strcmp(ret, "OK")) {
169 fprintf(stderr, "Transfer of new binary failed:\n%s\n",
170 ret ? : strerror(errno));
171 rc = 3;
172 free(ret);
173 break;
174 }
175 free(ret);
176 }
177
178 free(buf);
179
180 out_rel:
181 xc_dom_release(dom);
182
183 out_close:
184 xc_interface_close(xch);
185
186 return rc;
187 }
188
189 /*
190 * Live update of Xenstore stubdom
191 *
192 * Sequence of actions:
193 * 1. transfer new stubdom binary
194 * a) specify size
195 * b) transfer unpacked binary in chunks
196 * 2. transfer new cmdline (optional)
197 * 3. start update (includes flags)
198 */
live_update_stubdom(struct xs_handle * xsh,const char * binary,const char * cmdline,bool force,unsigned int to)199 static int live_update_stubdom(struct xs_handle *xsh, const char *binary,
200 const char *cmdline, bool force, unsigned int to)
201 {
202 int rc;
203
204 rc = send_kernel_blob(xsh, binary);
205 if (rc)
206 goto abort;
207
208 if (cmdline) {
209 rc = live_update_cmdline(xsh, cmdline);
210 if (rc)
211 goto abort;
212 }
213
214 rc = live_update_start(xsh, force, to);
215 if (rc)
216 goto abort;
217
218 return 0;
219
220 abort:
221 xs_control_command(xsh, "live-update", "-a", 3);
222 return rc;
223 }
224
225 /*
226 * Live update of Xenstore daemon
227 *
228 * Sequence of actions:
229 * 1. transfer new binary filename
230 * 2. transfer new cmdline (optional)
231 * 3. start update (includes flags)
232 */
live_update_daemon(struct xs_handle * xsh,const char * binary,const char * cmdline,bool force,unsigned int to)233 static int live_update_daemon(struct xs_handle *xsh, const char *binary,
234 const char *cmdline, bool force, unsigned int to)
235 {
236 int len = 0, rc;
237 char *buf = NULL, *ret;
238
239 len = add_to_buf(&buf, "-f", len);
240 len = add_to_buf(&buf, binary, len);
241 if (len < 0)
242 return 1;
243 ret = xs_control_command(xsh, "live-update", buf, len);
244 free(buf);
245 if (!ret || strcmp(ret, "OK")) {
246 fprintf(stderr, "Setting update binary failed:\n%s\n",
247 ret ? : strerror(errno));
248 free(ret);
249 return 3;
250 }
251 free(ret);
252
253 if (cmdline) {
254 rc = live_update_cmdline(xsh, cmdline);
255 if (rc)
256 goto abort;
257 }
258
259 rc = live_update_start(xsh, force, to);
260 if (rc)
261 goto abort;
262
263 return 0;
264
265 abort:
266 xs_control_command(xsh, "live-update", "-a", 3);
267 return rc;
268 }
269
live_update(struct xs_handle * xsh,int argc,char ** argv)270 static int live_update(struct xs_handle *xsh, int argc, char **argv)
271 {
272 int rc = 0;
273 unsigned int i, to = 60;
274 char *binary = NULL, *cmdline = NULL, *val;
275 bool force = false;
276
277 for (i = 0; i < argc; i++) {
278 if (!strcmp(argv[i], "-c")) {
279 i++;
280 if (i == argc) {
281 fprintf(stderr, "Missing command line value\n");
282 rc = 2;
283 goto out;
284 }
285 cmdline = argv[i];
286 } else if (!strcmp(argv[i], "-t")) {
287 i++;
288 if (i == argc) {
289 fprintf(stderr, "Missing timeout value\n");
290 rc = 2;
291 goto out;
292 }
293 to = atoi(argv[i]);
294 } else if (!strcmp(argv[i], "-F"))
295 force = true;
296 else
297 binary = argv[i];
298 }
299
300 if (!binary) {
301 fprintf(stderr, "Missing binary specification\n");
302 rc = 2;
303 goto out;
304 }
305
306 val = xs_read(xsh, XBT_NULL, "/tool/xenstored/domid", &i);
307 if (val)
308 rc = live_update_stubdom(xsh, binary, cmdline, force, to);
309 else
310 rc = live_update_daemon(xsh, binary, cmdline, force, to);
311
312 free(val);
313
314 out:
315 return rc;
316 }
317
main(int argc,char ** argv)318 int main(int argc, char **argv)
319 {
320 struct xs_handle *xsh;
321 char *par = NULL;
322 char *ret;
323 unsigned int p;
324 int rc = 0, len = 0;
325
326 if (argc < 2) {
327 fprintf(stderr, "Usage:\n"
328 "%s <command> [<arg>...]\n", argv[0]);
329 rc = 2;
330 goto out;
331 }
332
333 xsh = xs_open(0);
334 if (xsh == NULL) {
335 fprintf(stderr, "Failed to contact Xenstored.\n");
336 rc = 1;
337 goto out;
338 }
339
340 if (!strcmp(argv[1], "live-update")) {
341 rc = live_update(xsh, argc - 2, argv + 2);
342 goto out_close;
343 }
344
345 for (p = 2; p < argc; p++)
346 len = add_to_buf(&par, argv[p], len);
347 if (len < 0) {
348 fprintf(stderr, "Allocation error.\n");
349 rc = 1;
350 goto out_close;
351 }
352
353 ret = xs_control_command(xsh, argv[1], par, len);
354 if (!ret) {
355 rc = 3;
356 if (errno == EINVAL) {
357 ret = xs_control_command(xsh, "help", NULL, 0);
358 if (ret)
359 fprintf(stderr, "Command not supported. Valid commands are:\n"
360 "%s\n", ret);
361 else
362 fprintf(stderr, "Error when executing command.\n");
363 } else
364 fprintf(stderr, "Error %d when trying to execute command.\n",
365 errno);
366 } else if (strlen(ret) > 0)
367 printf("%s\n", ret);
368
369 out_close:
370 xs_close(xsh);
371
372 out:
373 free(par);
374 return rc;
375 }
376