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