bool libxl__async_exec_inuse(const libxl__async_exec_state *aes) { bool time_inuse = libxl__ev_time_isregistered(&aes->time); bool child_inuse = libxl__ev_child_inuse(&aes->child); assert(time_inuse == child_inuse); return child_inuse; }
static void helper_done(libxl__egc *egc, libxl__save_helper_state *shs) { STATE_AO_GC(shs->ao); libxl__ev_fd_deregister(gc, &shs->readable); libxl__carefd_close(shs->pipes[0]); shs->pipes[0] = 0; libxl__carefd_close(shs->pipes[1]); shs->pipes[1] = 0; assert(!libxl__ev_child_inuse(&shs->child)); if (shs->toolstack_data_file) fclose(shs->toolstack_data_file); shs->egc = egc; shs->completion_callback(egc, shs->caller_state, shs->rc, shs->retval, shs->errnoval); shs->egc = 0; }
/* might be called at any time, provided it's init'd */ static void bootloader_stop(libxl__egc *egc, libxl__bootloader_state *bl, int rc) { STATE_AO_GC(bl->ao); int r; libxl__datacopier_kill(&bl->keystrokes); libxl__datacopier_kill(&bl->display); if (libxl__ev_child_inuse(&bl->child)) { r = kill(bl->child.pid, SIGTERM); if (r) LOGE(WARN, "%sfailed to kill bootloader [%lu]", rc ? "after failure, " : "", (unsigned long)bl->child.pid); } if (!bl->rc) bl->rc = rc; }
static void helper_failed(libxl__egc *egc, libxl__save_helper_state *shs, int rc) { STATE_AO_GC(shs->ao); if (!shs->rc) shs->rc = rc; libxl__ev_fd_deregister(gc, &shs->readable); if (!libxl__ev_child_inuse(&shs->child)) { helper_done(egc, shs); return; } int r = kill(shs->child.pid, SIGKILL); if (r) LOGE(WARN, "failed to kill save/restore helper [%lu]", (unsigned long)shs->child.pid); }
static void async_exec_timeout(libxl__egc *egc, libxl__ev_time *ev, const struct timeval *requested_abs, int rc) { libxl__async_exec_state *aes = CONTAINER_OF(ev, *aes, time); STATE_AO_GC(aes->ao); if (!aes->rc) aes->rc = rc; libxl__ev_time_deregister(gc, &aes->time); assert(libxl__ev_child_inuse(&aes->child)); LOG(ERROR, "killing execution of %s because of timeout", aes->what); if (kill(aes->child.pid, SIGKILL)) { LOGEV(ERROR, errno, "unable to kill %s [%ld]", aes->what, (unsigned long)aes->child.pid); } return; }
int libxl__openptys(libxl__openpty_state *op, struct termios *termp, struct winsize *winp) { /* * This is completely crazy. openpty calls grantpt which the spec * says may fork, and may not be called with a SIGCHLD handler. * Now our application may have a SIGCHLD handler so that's bad. * We could perhaps block it but we'd need to block it on all * threads. This is just Too Hard. * * So instead, we run openpty in a child process. That child * process then of course has only our own thread and our own * signal handlers. We pass the fds back. * * Since our only current caller actually wants two ptys, we * support calling openpty multiple times for a single fork. */ STATE_AO_GC(op->ao); int count = op->count; int r, i, rc, sockets[2], ptyfds[count][2]; libxl__carefd *for_child = 0; pid_t pid = -1; for (i=0; i<count; i++) { ptyfds[i][0] = ptyfds[i][1] = -1; libxl__openpty_result *res = &op->results[i]; assert(!res->master); assert(!res->slave); } sockets[0] = sockets[1] = -1; /* 0 is for us, 1 for our child */ libxl__carefd_begin(); r = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets); if (r) { sockets[0] = sockets[1] = -1; } for_child = libxl__carefd_opened(CTX, sockets[1]); if (r) { LOGE(ERROR,"socketpair failed"); rc = ERROR_FAIL; goto out; } pid = libxl__ev_child_fork(gc, &op->child, openpty_exited); if (pid == -1) { rc = ERROR_FAIL; goto out; } if (!pid) { /* child */ close(sockets[0]); signal(SIGCHLD, SIG_DFL); for (i=0; i<count; i++) { r = openpty(&ptyfds[i][0], &ptyfds[i][1], NULL, termp, winp); if (r) { LOGE(ERROR,"openpty failed"); _exit(-1); } } rc = libxl__sendmsg_fds(gc, sockets[1], "",1, 2*count, &ptyfds[0][0], "ptys"); if (rc) { LOGE(ERROR,"sendmsg to parent failed"); _exit(-1); } _exit(0); } libxl__carefd_close(for_child); for_child = 0; /* this should be fast so do it synchronously */ libxl__carefd_begin(); char buf[1]; rc = libxl__recvmsg_fds(gc, sockets[0], buf,1, 2*count, &ptyfds[0][0], "ptys"); if (!rc) { for (i=0; i<count; i++) { libxl__openpty_result *res = &op->results[i]; res->master = libxl__carefd_record(CTX, ptyfds[i][0]); res->slave = libxl__carefd_record(CTX, ptyfds[i][1]); } } /* now the pty fds are in the carefds, if they were ever open */ libxl__carefd_unlock(); if (rc) goto out; rc = 0; out: if (sockets[0] >= 0) close(sockets[0]); libxl__carefd_close(for_child); if (libxl__ev_child_inuse(&op->child)) { op->rc = rc; /* we will get a callback when the child dies */ return 0; } assert(rc); openpty_cleanup(op); return rc; }