From mboxrd@z Thu Jan 1 00:00:00 1970 From: Ian Jackson Subject: [PATCH 10/24] libxl: provide libxl__openpty_* Date: Mon, 16 Apr 2012 18:17:52 +0100 Message-ID: <1334596686-8479-11-git-send-email-ian.jackson@eu.citrix.com> References: <1334596686-8479-1-git-send-email-ian.jackson@eu.citrix.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1334596686-8479-1-git-send-email-ian.jackson@eu.citrix.com> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: xen-devel@lists.xen.org Cc: Ian Jackson List-Id: xen-devel@lists.xenproject.org General facility for ao operations to open ptys. This will be used by the bootloader machinery. Signed-off-by: Ian Jackson Acked-by: Ian Campbell --- tools/libxl/libxl_aoutils.c | 127 ++++++++++++++++++++++++++++++++++++++++++ tools/libxl/libxl_internal.h | 36 ++++++++++++ 2 files changed, 163 insertions(+), 0 deletions(-) diff --git a/tools/libxl/libxl_aoutils.c b/tools/libxl/libxl_aoutils.c index 4c60ad9..734a5dc 100644 --- a/tools/libxl/libxl_aoutils.c +++ b/tools/libxl/libxl_aoutils.c @@ -187,3 +187,130 @@ int libxl__datacopier_start(libxl__datacopier_state *dc) return rc; } +/*----- openpty -----*/ + +/* implementation */ + +static void openpty_cleanup(libxl__openpty_state *op) +{ + int i; + + for (i=0; icount; i++) { + libxl__openpty_result *res = &op->results[i]; + libxl__carefd_close(res->master); res->master = 0; + libxl__carefd_close(res->slave); res->slave = 0; + } +} + +static void openpty_exited(libxl__egc *egc, libxl__ev_child *child, + pid_t pid, int status) { + libxl__openpty_state *op = CONTAINER_OF(child, *op, child); + STATE_AO_GC(op->ao); + + if (status) { + /* Perhaps the child gave us the fds and then exited nonzero. + * Well that would be odd but we don't really care. */ + libxl_report_child_exitstatus(CTX, op->rc ? LIBXL__LOG_ERROR + : LIBXL__LOG_WARNING, + "openpty child", pid, status); + } + if (op->rc) + openpty_cleanup(op); + op->callback(egc, op); +} + +int libxl__openptys(libxl__openpty_state *op, + const struct termios *termp, + const 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; iresults[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; iresults[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; +} + diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index 20c95db..9af99ec 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -1498,6 +1498,42 @@ _hidden void libxl__datacopier_kill(libxl__datacopier_state *dc); _hidden int libxl__datacopier_start(libxl__datacopier_state *dc); +/*----- openpty -----*/ + +/* + * opens count (>0) ptys like count calls to openpty, and then + * calls back. On entry, all op[].master and op[].slave must be + * 0. On callback, either rc==0 and master and slave are non-0, + * or rc is a libxl error and they are both 0. If libxl__openpty + * returns non-0 no callback will happen and everything is left + * cleaned up. + */ + +typedef struct libxl__openpty_state libxl__openpty_state; +typedef struct libxl__openpty_result libxl__openpty_result; +typedef void libxl__openpty_callback(libxl__egc *egc, libxl__openpty_state *op); + +struct libxl__openpty_state { + /* caller must fill these in, and they must all remain valid */ + libxl__ao *ao; + libxl__openpty_callback *callback; + int count; + libxl__openpty_result *results; /* actual size is count, out parameter */ + /* public, result, caller may only read in callback */ + int rc; + /* private for implementation */ + libxl__ev_child child; +}; + +struct libxl__openpty_result { + libxl__carefd *master, *slave; +}; + +int libxl__openptys(libxl__openpty_state *op, + const struct termios *termp, + const struct winsize *winp); + + /* * Convenience macros. */ -- 1.7.2.5