1 /*
2 * Copyright (C) 2010 Citrix Ltd.
3 * Author Ian Campbell <ian.campbell@citrix.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published
7 * by the Free Software Foundation; version 2.1 only.
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" /* must come before any other headers */
16
17 #include <termios.h>
18 #ifdef HAVE_UTMP_H
19 #include <utmp.h>
20 #endif
21
22 #ifdef INCLUDE_LIBUTIL_H
23 #include INCLUDE_LIBUTIL_H
24 #endif
25
26 #include "libxl_internal.h"
27
28 #define BOOTLOADER_BUF_OUT 65536
29 #define BOOTLOADER_BUF_IN 4096
30
31 static void bootloader_gotptys(libxl__egc *egc, libxl__openpty_state *op);
32 static void bootloader_keystrokes_copyfail(libxl__egc *egc,
33 libxl__datacopier_state *dc, int rc, int onwrite, int errnoval);
34 static void bootloader_display_copyfail(libxl__egc *egc,
35 libxl__datacopier_state *dc, int rc, int onwrite, int errnoval);
36 static void bootloader_domaindeath(libxl__egc*, libxl__domaindeathcheck *dc,
37 int rc);
38 static void bootloader_finished(libxl__egc *egc, libxl__ev_child *child,
39 pid_t pid, int status);
40
41 /*----- bootloader arguments -----*/
42
bootloader_arg(libxl__bootloader_state * bl,const char * arg)43 static void bootloader_arg(libxl__bootloader_state *bl, const char *arg)
44 {
45 assert(bl->nargs < bl->argsspace);
46 bl->args[bl->nargs++] = arg;
47 }
48
make_bootloader_args(libxl__gc * gc,libxl__bootloader_state * bl,const char * bootloader_path)49 static void make_bootloader_args(libxl__gc *gc, libxl__bootloader_state *bl,
50 const char *bootloader_path)
51 {
52 const libxl_domain_build_info *info = bl->info;
53
54 bl->argsspace = 9 + libxl_string_list_length(&info->bootloader_args);
55
56 GCNEW_ARRAY(bl->args, bl->argsspace);
57
58 #define ARG(arg) bootloader_arg(bl, (arg))
59
60 ARG(bootloader_path);
61
62 if (info->kernel)
63 ARG(GCSPRINTF("--kernel=%s", info->kernel));
64 if (info->ramdisk)
65 ARG(GCSPRINTF("--ramdisk=%s", info->ramdisk));
66 if (info->cmdline && *info->cmdline != '\0')
67 ARG(GCSPRINTF("--args=%s", info->cmdline));
68
69 ARG(GCSPRINTF("--output=%s", bl->outputpath));
70 ARG("--output-format=simple0");
71 ARG(GCSPRINTF("--output-directory=%s", bl->outputdir));
72
73 if (info->bootloader_args) {
74 char **p = info->bootloader_args;
75 while (*p) {
76 ARG(*p);
77 p++;
78 }
79 }
80
81 ARG(bl->dls.diskpath);
82
83 /* Sentinel for execv */
84 ARG(NULL);
85
86 #undef ARG
87 }
88
89 /*----- synchronous subroutines -----*/
90
setup_xenconsoled_pty(libxl__egc * egc,libxl__bootloader_state * bl,char * slave_path,size_t slave_path_len)91 static int setup_xenconsoled_pty(libxl__egc *egc, libxl__bootloader_state *bl,
92 char *slave_path, size_t slave_path_len)
93 {
94 STATE_AO_GC(bl->ao);
95 struct termios termattr;
96 int r, rc;
97 int slave = libxl__carefd_fd(bl->ptys[1].slave);
98 int master = libxl__carefd_fd(bl->ptys[1].master);
99
100 r = ttyname_r(slave, slave_path, slave_path_len);
101 if (r == -1) {
102 LOGED(ERROR, bl->domid, "ttyname_r failed");
103 rc = ERROR_FAIL;
104 goto out;
105 }
106
107 /*
108 * On Solaris, the pty master side will get cranky if we try
109 * to write to it while there is no slave. To work around this,
110 * keep the slave descriptor open until we're done. Set it
111 * to raw terminal parameters, otherwise it will echo back
112 * characters, which will confuse the I/O loop below.
113 * Furthermore, a raw master pty device has no terminal
114 * semantics on Solaris, so don't try to set any attributes
115 * for it.
116 */
117 tcgetattr(master, &termattr);
118 cfmakeraw(&termattr);
119 tcsetattr(master, TCSANOW, &termattr);
120
121 return 0;
122
123 out:
124 return rc;
125 }
126
bootloader_result_command(libxl__gc * gc,const char * buf,const char * prefix,size_t prefixlen,uint32_t domid)127 static const char *bootloader_result_command(libxl__gc *gc, const char *buf,
128 const char *prefix, size_t prefixlen, uint32_t domid) {
129 if (strncmp(buf, prefix, prefixlen))
130 return 0;
131
132 const char *rhs = buf + prefixlen;
133 if (!CTYPE(isspace,*rhs))
134 return 0;
135
136 while (CTYPE(isspace,*rhs))
137 rhs++;
138
139 LOGD(DEBUG, domid, "bootloader output contained %s %s", prefix, rhs);
140
141 return rhs;
142 }
143
parse_bootloader_result(libxl__egc * egc,libxl__bootloader_state * bl)144 static int parse_bootloader_result(libxl__egc *egc,
145 libxl__bootloader_state *bl)
146 {
147 STATE_AO_GC(bl->ao);
148 char buf[PATH_MAX*2];
149 FILE *f = 0;
150 int rc = ERROR_FAIL;
151
152 f = fopen(bl->outputpath, "r");
153 if (!f) {
154 LOGED(ERROR, bl->domid, "open bootloader output file %s",
155 bl->outputpath);
156 goto out;
157 }
158
159 for (;;) {
160 /* Read a nul-terminated "line" and put the result in
161 * buf, and its length (not including the nul) in l */
162 int l = 0, c;
163 while ((c = getc(f)) != EOF && c != '\0') {
164 if (l < sizeof(buf)-1)
165 buf[l] = c;
166 l++;
167 }
168 if (c == EOF) {
169 if (ferror(f)) {
170 LOGED(ERROR, bl->domid, "read bootloader output file %s",
171 bl->outputpath);
172 goto out;
173 }
174 if (!l)
175 break;
176 }
177 if (l >= sizeof(buf)) {
178 LOGD(WARN, bl->domid, "bootloader output contained"
179 " overly long item `%.150s...'", buf);
180 continue;
181 }
182 buf[l] = 0;
183
184 const char *rhs;
185 #define COMMAND(s) ((rhs = bootloader_result_command(gc, buf, s, sizeof(s)-1, bl->domid)))
186
187 if (COMMAND("kernel")) {
188 bl->kernel->path = libxl__strdup(gc, rhs);
189 libxl__file_reference_map(bl->kernel);
190 unlink(bl->kernel->path);
191 } else if (COMMAND("ramdisk")) {
192 bl->ramdisk->path = libxl__strdup(gc, rhs);
193 libxl__file_reference_map(bl->ramdisk);
194 unlink(bl->ramdisk->path);
195 } else if (COMMAND("args")) {
196 bl->cmdline = libxl__strdup(gc, rhs);
197 } else if (l) {
198 LOGD(WARN, bl->domid,
199 "unexpected output from bootloader: `%s'", buf);
200 }
201 }
202 rc = 0;
203
204 out:
205 if (f) fclose(f);
206 return rc;
207 }
208
209
210 /*----- init and cleanup -----*/
211
libxl__bootloader_init(libxl__bootloader_state * bl)212 void libxl__bootloader_init(libxl__bootloader_state *bl)
213 {
214 assert(bl->ao);
215 bl->rc = 0;
216 bl->dls.diskpath = NULL;
217 bl->openpty.ao = bl->ao;
218 bl->dls.ao = bl->ao;
219 bl->ptys[0].master = bl->ptys[0].slave = 0;
220 bl->ptys[1].master = bl->ptys[1].slave = 0;
221 libxl__ev_child_init(&bl->child);
222 libxl__domaindeathcheck_init(&bl->deathcheck);
223 bl->keystrokes.ao = bl->ao; libxl__datacopier_init(&bl->keystrokes);
224 bl->display.ao = bl->ao; libxl__datacopier_init(&bl->display);
225 bl->got_pollhup = 0;
226 }
227
bootloader_cleanup(libxl__egc * egc,libxl__bootloader_state * bl)228 static void bootloader_cleanup(libxl__egc *egc, libxl__bootloader_state *bl)
229 {
230 STATE_AO_GC(bl->ao);
231 int i;
232
233 if (bl->outputpath) libxl__remove_file(gc, bl->outputpath);
234 if (bl->outputdir) libxl__remove_directory(gc, bl->outputdir);
235
236 libxl__domaindeathcheck_stop(gc,&bl->deathcheck);
237 libxl__datacopier_kill(&bl->keystrokes);
238 libxl__datacopier_kill(&bl->display);
239 for (i=0; i<2; i++) {
240 libxl__carefd_close(bl->ptys[i].master);
241 libxl__carefd_close(bl->ptys[i].slave);
242 }
243 if (bl->display.log) {
244 fclose(bl->display.log);
245 bl->display.log = NULL;
246 }
247 }
248
bootloader_setpaths(libxl__gc * gc,libxl__bootloader_state * bl)249 static void bootloader_setpaths(libxl__gc *gc, libxl__bootloader_state *bl)
250 {
251 uint32_t domid = bl->domid;
252 bl->outputdir = GCSPRINTF(XEN_RUN_DIR "/bootloader.%"PRIu32".d", domid);
253 bl->outputpath = GCSPRINTF(XEN_RUN_DIR "/bootloader.%"PRIu32".out", domid);
254 }
255
256 /* Callbacks */
257
258 static void bootloader_local_detached_cb(libxl__egc *egc,
259 libxl__disk_local_state *dls,
260 int rc);
261
bootloader_callback(libxl__egc * egc,libxl__bootloader_state * bl,int rc)262 static void bootloader_callback(libxl__egc *egc, libxl__bootloader_state *bl,
263 int rc)
264 {
265 if (!bl->rc)
266 bl->rc = rc;
267
268 bootloader_cleanup(egc, bl);
269
270 bl->dls.callback = bootloader_local_detached_cb;
271 libxl__device_disk_local_initiate_detach(egc, &bl->dls);
272 }
273
bootloader_local_detached_cb(libxl__egc * egc,libxl__disk_local_state * dls,int rc)274 static void bootloader_local_detached_cb(libxl__egc *egc,
275 libxl__disk_local_state *dls,
276 int rc)
277 {
278 STATE_AO_GC(dls->ao);
279 libxl__bootloader_state *bl = CONTAINER_OF(dls, *bl, dls);
280
281 if (rc) {
282 LOGD(ERROR, bl->domid,
283 "unable to detach locally attached disk");
284 if (!bl->rc)
285 bl->rc = rc;
286 }
287
288 bl->callback(egc, bl, bl->rc);
289 }
290
291 /* might be called at any time, provided it's init'd */
bootloader_stop(libxl__egc * egc,libxl__bootloader_state * bl,int rc)292 static void bootloader_stop(libxl__egc *egc,
293 libxl__bootloader_state *bl, int rc)
294 {
295 STATE_AO_GC(bl->ao);
296 int r;
297
298 libxl__datacopier_kill(&bl->keystrokes);
299 libxl__datacopier_kill(&bl->display);
300 if (libxl__ev_child_inuse(&bl->child)) {
301 r = kill(bl->child.pid, SIGTERM);
302 if (r) LOGED(WARN, bl->domid, "%sfailed to kill bootloader [%lu]",
303 rc ? "after failure, " : "", (unsigned long)bl->child.pid);
304 }
305 if (!bl->rc)
306 bl->rc = rc;
307 }
308
309 /*----- main flow of control -----*/
310
311 /* Callbacks */
312
313 static void bootloader_disk_attached_cb(libxl__egc *egc,
314 libxl__disk_local_state *dls,
315 int rc);
316
libxl__bootloader_run(libxl__egc * egc,libxl__bootloader_state * bl)317 void libxl__bootloader_run(libxl__egc *egc, libxl__bootloader_state *bl)
318 {
319 STATE_AO_GC(bl->ao);
320 const libxl_domain_build_info *info = bl->info;
321 uint32_t domid = bl->domid;
322 char *logfile_tmp = NULL;
323 int rc, r;
324
325 libxl__bootloader_init(bl);
326
327 if (info->type == LIBXL_DOMAIN_TYPE_HVM) {
328 LOGD(DEBUG, domid, "not a PV/PVH domain, skipping bootloader");
329 rc = 0;
330 goto out_ok;
331 }
332
333 if (!info->bootloader) {
334 LOGD(DEBUG, domid,
335 "no bootloader configured, using user supplied kernel");
336 bl->kernel->path = bl->info->kernel;
337 bl->ramdisk->path = bl->info->ramdisk;
338 bl->cmdline = bl->info->cmdline;
339 rc = 0;
340 goto out_ok;
341 }
342
343 if (!bl->disk) {
344 LOGD(ERROR, domid, "cannot run bootloader with no boot disk");
345 rc = ERROR_FAIL;
346 goto out;
347 }
348
349 bootloader_setpaths(gc, bl);
350
351 const char *logfile_leaf = GCSPRINTF("bootloader.%"PRIu32, domid);
352 rc = libxl_create_logfile(CTX, logfile_leaf, &logfile_tmp);
353 if (rc) goto out;
354
355 /* Transfer ownership of log filename to bl and the gc */
356 bl->logfile = logfile_tmp;
357 libxl__ptr_add(gc, logfile_tmp);
358 logfile_tmp = NULL;
359
360 bl->display.log = fopen(bl->logfile, "a");
361 if (!bl->display.log) {
362 LOGED(ERROR, domid,
363 "failed to create bootloader logfile %s", bl->logfile);
364 rc = ERROR_FAIL;
365 goto out;
366 }
367
368 for (;;) {
369 r = mkdir(bl->outputdir, 0600);
370 if (!r) break;
371 if (errno == EINTR) continue;
372 if (errno == EEXIST) break;
373 LOGED(ERROR, domid,
374 "failed to create bootloader dir %s", bl->outputdir);
375 rc = ERROR_FAIL;
376 goto out;
377 }
378
379 for (;;) {
380 r = open(bl->outputpath, O_WRONLY|O_CREAT|O_TRUNC, 0600);
381 if (r>=0) { close(r); break; }
382 if (errno == EINTR) continue;
383 LOGED(ERROR, domid,
384 "failed to precreate bootloader output %s", bl->outputpath);
385 rc = ERROR_FAIL;
386 goto out;
387 }
388
389
390 /* This sets the state of the dls struct from Undefined to Idle */
391 libxl__device_disk_local_init(&bl->dls);
392 bl->dls.ao = ao;
393 bl->dls.in_disk = bl->disk;
394 bl->dls.blkdev_start = info->blkdev_start;
395 bl->dls.callback = bootloader_disk_attached_cb;
396 libxl__device_disk_local_initiate_attach(egc, &bl->dls);
397 return;
398
399 out:
400 assert(rc);
401 out_ok:
402 free(logfile_tmp);
403 bootloader_callback(egc, bl, rc);
404 }
405
bootloader_disk_attached_cb(libxl__egc * egc,libxl__disk_local_state * dls,int rc)406 static void bootloader_disk_attached_cb(libxl__egc *egc,
407 libxl__disk_local_state *dls,
408 int rc)
409 {
410 STATE_AO_GC(dls->ao);
411 libxl__bootloader_state *bl = CONTAINER_OF(dls, *bl, dls);
412 const libxl_domain_build_info *info = bl->info;
413 const char *bootloader;
414
415 if (rc) {
416 LOGD(ERROR, bl->domid,
417 "failed to attach local disk for bootloader execution");
418 goto out;
419 }
420
421 LOGD(DEBUG, bl->domid,
422 "Config bootloader value: %s", info->bootloader);
423
424 if ( !strcmp(info->bootloader, "/usr/bin/pygrub") )
425 LOGD(WARN, bl->domid,
426 "bootloader='/usr/bin/pygrub' is deprecated; use " \
427 "bootloader='pygrub' instead");
428
429 bootloader = info->bootloader;
430
431 /* If the full path is not specified, check in the libexec path */
432 if ( bootloader[0] != '/' ) {
433 const char *bltmp;
434 struct stat st;
435
436 bltmp = libxl__abs_path(gc, bootloader, libxl__private_bindir_path());
437 /* Check to see if the file exists in this location; if not,
438 * fall back to checking the path */
439 LOGD(DEBUG, bl->domid,
440 "Checking for bootloader in libexec path: %s", bltmp);
441
442 if ( lstat(bltmp, &st) )
443 LOGD(DEBUG, bl->domid,
444 "%s doesn't exist, falling back to config path",
445 bltmp);
446 else
447 bootloader = bltmp;
448 }
449
450 make_bootloader_args(gc, bl, bootloader);
451
452 bl->openpty.ao = ao;
453 bl->openpty.callback = bootloader_gotptys;
454 bl->openpty.count = 2;
455 bl->openpty.results = bl->ptys;
456 rc = libxl__openptys(&bl->openpty, 0,0);
457 if (rc) goto out;
458
459 return;
460
461 out:
462 assert(rc);
463 bootloader_callback(egc, bl, rc);
464 }
465
bootloader_gotptys(libxl__egc * egc,libxl__openpty_state * op)466 static void bootloader_gotptys(libxl__egc *egc, libxl__openpty_state *op)
467 {
468 libxl__bootloader_state *bl = CONTAINER_OF(op, *bl, openpty);
469 STATE_AO_GC(bl->ao);
470 int rc, r;
471 char *const env[] = { "TERM", "vt100", NULL };
472
473 if (bl->openpty.rc) {
474 rc = bl->openpty.rc;
475 goto out;
476 }
477
478 /*
479 * We need to present the bootloader's tty as a pty slave that xenconsole
480 * can access. Since the bootloader itself needs a pty slave,
481 * we end up with a connection like this:
482 *
483 * xenconsole -- (slave pty1 master) <-> (master pty2 slave) -- bootloader
484 *
485 * where we copy characters between the two master fds, as well as
486 * listening on the bootloader's fifo for the results.
487 */
488
489 char *dom_console_xs_path;
490 char dom_console_slave_tty_path[PATH_MAX];
491 rc = setup_xenconsoled_pty(egc, bl,
492 &dom_console_slave_tty_path[0],
493 sizeof(dom_console_slave_tty_path));
494 if (rc) goto out;
495
496 char *dompath = libxl__xs_get_dompath(gc, bl->domid);
497 if (!dompath) { rc = ERROR_FAIL; goto out; }
498
499 dom_console_xs_path = GCSPRINTF("%s/console/tty", dompath);
500
501 rc = libxl__xs_printf(gc, XBT_NULL, dom_console_xs_path, "%s",
502 dom_console_slave_tty_path);
503 if (rc) {
504 LOGED(ERROR, bl->domid, "xs write console path %s := %s failed",
505 dom_console_xs_path, dom_console_slave_tty_path);
506 rc = ERROR_FAIL;
507 goto out;
508 }
509
510 bl->deathcheck.what = "stopping bootloader";
511 bl->deathcheck.domid = bl->domid;
512 bl->deathcheck.callback = bootloader_domaindeath;
513 rc = libxl__domaindeathcheck_start(ao, &bl->deathcheck);
514 if (rc) goto out;
515
516 if (bl->console_available)
517 bl->console_available(egc, bl);
518
519 int bootloader_master = libxl__carefd_fd(bl->ptys[0].master);
520 int xenconsole_master = libxl__carefd_fd(bl->ptys[1].master);
521
522 libxl_fd_set_nonblock(CTX, bootloader_master, 1);
523 libxl_fd_set_nonblock(CTX, xenconsole_master, 1);
524
525 bl->keystrokes.writefd = bl->display.readfd = bootloader_master;
526 bl->keystrokes.writewhat = bl->display.readwhat = "bootloader pty";
527
528 bl->keystrokes.readfd = bl->display.writefd = xenconsole_master;
529 bl->keystrokes.readwhat = bl->display.writewhat = "xenconsole client pty";
530
531 bl->keystrokes.ao = ao;
532 bl->keystrokes.maxsz = BOOTLOADER_BUF_OUT;
533 bl->keystrokes.bytes_to_read = -1;
534 bl->keystrokes.copywhat =
535 GCSPRINTF("bootloader input for domain %"PRIu32, bl->domid);
536 bl->keystrokes.callback = bootloader_keystrokes_copyfail;
537 bl->keystrokes.callback_pollhup = bootloader_keystrokes_copyfail;
538 /* pollhup gets called with errnoval==-1 which is not otherwise
539 * possible since errnos are nonnegative, so it's unambiguous */
540 rc = libxl__datacopier_start(&bl->keystrokes);
541 if (rc) goto out;
542
543 bl->display.ao = ao;
544 bl->display.maxsz = BOOTLOADER_BUF_IN;
545 bl->display.bytes_to_read = -1;
546 bl->display.copywhat =
547 GCSPRINTF("bootloader output for domain %"PRIu32, bl->domid);
548 bl->display.callback = bootloader_display_copyfail;
549 bl->display.callback_pollhup = bootloader_display_copyfail;
550 rc = libxl__datacopier_start(&bl->display);
551 if (rc) goto out;
552
553 LOGD(DEBUG, bl->domid, "executing bootloader: %s", bl->args[0]);
554 for (const char **blarg = bl->args;
555 *blarg;
556 blarg++)
557 LOGD(DEBUG, bl->domid, " bootloader arg: %s", *blarg);
558
559 struct termios termattr;
560
561 pid_t pid = libxl__ev_child_fork(gc, &bl->child, bootloader_finished);
562 if (pid == -1) {
563 rc = ERROR_FAIL;
564 goto out;
565 }
566
567 if (!pid) {
568 /* child */
569 r = login_tty(libxl__carefd_fd(bl->ptys[0].slave));
570 if (r) { LOGED(ERROR, bl->domid, "login_tty failed"); exit(-1); }
571 libxl__exec(gc, -1, -1, -1, bl->args[0], (char **) bl->args, env);
572 }
573
574 /* parent */
575
576 /*
577 * On Solaris, the master pty side does not have terminal semantics,
578 * so don't try to set any attributes, as it will fail.
579 */
580 #if !defined(__sun__)
581 tcgetattr(bootloader_master, &termattr);
582 cfmakeraw(&termattr);
583 tcsetattr(bootloader_master, TCSANOW, &termattr);
584 #endif
585
586 return;
587
588 out:
589 bootloader_callback(egc, bl, rc);
590 }
591
592 /* perhaps one of these will be called, but perhaps not */
bootloader_copyfail(libxl__egc * egc,const char * which,libxl__bootloader_state * bl,int ondisplay,int rc,int onwrite,int errnoval)593 static void bootloader_copyfail(libxl__egc *egc, const char *which,
594 libxl__bootloader_state *bl, int ondisplay,
595 int rc, int onwrite, int errnoval)
596 {
597 STATE_AO_GC(bl->ao);
598
599 if (errnoval==-1) {
600 /* POLLHUP */
601 if (!!ondisplay != !!onwrite) {
602 rc = 0;
603 bl->got_pollhup = 1;
604 } else {
605 LOGD(ERROR, bl->domid, "unexpected POLLHUP on %s", which);
606 }
607 } else if (!rc) {
608 LOGD(ERROR, bl->domid, "unexpected eof copying %s", which);
609 rc = ERROR_FAIL;
610 }
611
612 bootloader_stop(egc, bl, rc);
613 }
bootloader_keystrokes_copyfail(libxl__egc * egc,libxl__datacopier_state * dc,int rc,int onwrite,int errnoval)614 static void bootloader_keystrokes_copyfail(libxl__egc *egc,
615 libxl__datacopier_state *dc, int rc, int onwrite, int errnoval)
616 {
617 libxl__bootloader_state *bl = CONTAINER_OF(dc, *bl, keystrokes);
618 bootloader_copyfail(egc, "bootloader input", bl, 0, rc,onwrite,errnoval);
619 }
bootloader_display_copyfail(libxl__egc * egc,libxl__datacopier_state * dc,int rc,int onwrite,int errnoval)620 static void bootloader_display_copyfail(libxl__egc *egc,
621 libxl__datacopier_state *dc, int rc, int onwrite, int errnoval)
622 {
623 libxl__bootloader_state *bl = CONTAINER_OF(dc, *bl, display);
624 bootloader_copyfail(egc, "bootloader output", bl, 1, rc,onwrite,errnoval);
625 }
626
bootloader_domaindeath(libxl__egc * egc,libxl__domaindeathcheck * dc,int rc)627 static void bootloader_domaindeath(libxl__egc *egc,
628 libxl__domaindeathcheck *dc,
629 int rc)
630 {
631 libxl__bootloader_state *bl = CONTAINER_OF(dc, *bl, deathcheck);
632 bootloader_stop(egc, bl, rc);
633 }
634
bootloader_finished(libxl__egc * egc,libxl__ev_child * child,pid_t pid,int status)635 static void bootloader_finished(libxl__egc *egc, libxl__ev_child *child,
636 pid_t pid, int status)
637 {
638 libxl__bootloader_state *bl = CONTAINER_OF(child, *bl, child);
639 STATE_AO_GC(bl->ao);
640 int rc;
641
642 libxl__datacopier_kill(&bl->keystrokes);
643 libxl__datacopier_kill(&bl->display);
644
645 if (status) {
646 if (bl->got_pollhup && WIFSIGNALED(status) && WTERMSIG(status)==SIGTERM)
647 LOGD(ERROR, bl->domid, "got POLLHUP, sent SIGTERM");
648 LOGD(ERROR, bl->domid,
649 "bootloader failed - consult logfile %s", bl->logfile);
650 libxl_report_child_exitstatus(CTX, XTL_ERROR, "bootloader",
651 pid, status);
652 rc = ERROR_FAIL;
653 goto out;
654 } else {
655 LOGD(DEBUG, bl->domid, "bootloader completed");
656 }
657
658 if (bl->rc) {
659 /* datacopier went wrong */
660 rc = bl->rc;
661 goto out;
662 }
663
664 rc = parse_bootloader_result(egc, bl);
665 if (rc) goto out;
666
667 rc = 0;
668 LOGD(DEBUG, bl->domid, "bootloader execution successful");
669
670 out:
671 bootloader_callback(egc, bl, rc);
672 }
673
674 /*
675 * Local variables:
676 * mode: C
677 * c-basic-offset: 4
678 * indent-tabs-mode: nil
679 * End:
680 */
681