From a5680759eb45ff4fde89571666dcd5ceea3b239a Mon Sep 17 00:00:00 2001 From: Wang Xu Date: Sun, 4 Oct 2015 19:28:49 +0800 Subject: [PATCH] add support of separate stderr output of container this patch add a pipe besides the pty for container, and the stderr will be sent from the stderr session if the session provided in spec. this intend to support log the stdout and stderr separately. Signed-off-by: Wang Xu --- src/event.c | 1 + src/exec.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++------- src/exec.h | 3 +++ src/parse.c | 4 +++ 4 files changed, 76 insertions(+), 10 deletions(-) diff --git a/src/event.c b/src/event.c index c075801..a6ec6a7 100644 --- a/src/event.c +++ b/src/event.c @@ -220,6 +220,7 @@ void hyper_event_hup(struct hyper_event *de, int efd) if (epoll_ctl(efd, EPOLL_CTL_DEL, de->fd, NULL) < 0) perror("epoll_ctl del epoll event failed"); close(de->fd); + de->fd = -1; hyper_reset_event(de); } diff --git a/src/exec.c b/src/exec.c index ea45fd0..72114e2 100644 --- a/src/exec.c +++ b/src/exec.c @@ -36,18 +36,25 @@ static void pts_hup(struct hyper_event *de, int efd) hyper_set_be32(buf->data + buf->get + 8, 12); buf->get += 12; + if (buf->get + 12 > buf->size) { + fprintf(stdout, "%s: tty buf full (for stderr)\n", __func__); + } else { + /* no in event, no more data, send eof in stderr */ + hyper_set_be64(buf->data + buf->get, exec->errseq); + hyper_set_be32(buf->data + buf->get + 8, 12); + buf->get += 12; + } + hyper_modify_event(ctl.efd, &ctl.tty, EPOLLIN | EPOLLOUT); hyper_release_exec(exec, pod); } -static int pts_loop(struct hyper_event *de) +static int pts_loop(struct hyper_event *de, uint64_t seq) { int size = -1; struct hyper_buf *buf = &ctl.tty.wbuf; - struct hyper_exec *exec = container_of(de, struct hyper_exec, e); - fprintf(stdout, "%s\n", __func__); while ((buf->get + 12 < buf->size) && size) { size = read(de->fd, buf->data + buf->get + 12, buf->size - buf->get - 12); fprintf(stdout, "%s: read %d data\n", __func__, size); @@ -63,11 +70,9 @@ static int pts_loop(struct hyper_event *de) break; } - hyper_set_be64(buf->data + buf->get, exec->seq); + hyper_set_be64(buf->data + buf->get, seq); hyper_set_be32(buf->data + buf->get + 8, size + 12); buf->get += size + 12; - - dprintf("%s: seq %" PRIu64" len %" PRIu32"\n", __func__, exec->seq, size); } if (hyper_modify_event(ctl.efd, &ctl.tty, EPOLLIN | EPOLLOUT) < 0) { @@ -78,14 +83,37 @@ static int pts_loop(struct hyper_event *de) return 0; } +static int stdout_loop(struct hyper_event *de) +{ + struct hyper_exec *exec = container_of(de, struct hyper_exec, e); + fprintf(stdout, "%s, seq %" PRIu64"\n", __func__, exec->seq); + + return pts_loop(de, exec->seq); +} + struct hyper_event_ops pts_ops = { - .read = pts_loop, + .read = stdout_loop, .hup = pts_hup, .write = hyper_event_write, .wbuf_size = 512, /* don't need read buff, the pts data will store in tty buffer */ }; +static int stderr_loop(struct hyper_event *de) +{ + struct hyper_exec *exec = container_of(de, struct hyper_exec, errev); + fprintf(stdout, "%s, seq %" PRIu64"\n", __func__, exec->errseq); + + return pts_loop(de, exec->errseq); +} + +struct hyper_event_ops err_ops = { + /* don't need to deal with hup, the hup will be dealed by pts*/ + .read = stderr_loop, + /* don't need read buff, the stderr data will store in tty buffer */ + /* don't need write buff, the stderr data is one way */ +}; + int hyper_setup_exec_tty(struct hyper_exec *e) { int unlock = 0; @@ -94,6 +122,16 @@ int hyper_setup_exec_tty(struct hyper_exec *e) if (e->seq == 0) return 0; + if (e->errseq > 0) { + int errpipe[2]; + if (pipe2(errpipe, O_NONBLOCK|O_CLOEXEC) < 0) { + fprintf(stderr, "creating stderr pipe failed\n"); + return -1; + } + e->errev.fd = errpipe[0]; + e->errfd = errpipe[1]; + } + if (e->id) { if (sprintf(path, "/tmp/hyper/%s/devpts/", e->id) < 0) { fprintf(stderr, "get ptmx path failed\n"); @@ -179,9 +217,16 @@ int hyper_dup_exec_tty(int to, struct hyper_exec *e) goto out; } - if (dup2(fd, STDERR_FILENO) < 0) { - perror("dup tty device to stderr failed"); - goto out; + if (e->errseq > 0) { + if (dup2(e->errfd, STDERR_FILENO) < 0) { + perror("dup err pipe to stderr failed"); + goto out; + } + } else { + if (dup2(fd, STDERR_FILENO) < 0) { + perror("dup tty device to stderr failed"); + goto out; + } } ret = 0; @@ -205,6 +250,15 @@ int hyper_watch_exec_pty(struct hyper_exec *exec, struct hyper_pod *pod) return -1; } + if (exec->errseq == 0) + return 0; + + if (hyper_init_event(&exec->errev, &err_ops, NULL) < 0 || + hyper_add_event(ctl.efd, &exec->errev, EPOLLIN) < 0) { + fprintf(stderr, "add container stderr event failed\n"); + return -1; + } + return 0; } @@ -447,8 +501,12 @@ int hyper_release_exec(struct hyper_exec *exec, /* exec has no pty or the pty user already exited */ fprintf(stdout, "last user of exec exit, release\n"); close(exec->e.fd); + close(exec->errev.fd); close(exec->ptyfd); + close(exec->errfd); + hyper_reset_event(&exec->e); + hyper_reset_event(&exec->errev); list_del_init(&exec->list); diff --git a/src/exec.h b/src/exec.h index ba2dba0..2726e08 100644 --- a/src/exec.h +++ b/src/exec.h @@ -7,14 +7,17 @@ struct hyper_exec { struct list_head list; struct hyper_event e; + struct hyper_event errev; char *id; char **argv; int argc; uint64_t seq; + uint64_t errseq; int pid; int ptyno; int init; int ptyfd; + int errfd; uint8_t code; uint8_t exit; }; diff --git a/src/parse.c b/src/parse.c index 9d5bffa..ef8cc22 100644 --- a/src/parse.c +++ b/src/parse.c @@ -228,6 +228,10 @@ static int hyper_parse_container(struct hyper_pod *pod, struct hyper_container * i++; c->exec.seq = json_token_ll(json, &toks[i]); fprintf(stdout, "container seq %" PRIu64 "\n", c->exec.seq); + } else if (json_token_streq(json, t, "stderr") && t->size == 1) { + i++; + c->exec.errseq = json_token_ll(json, &toks[i]); + fprintf(stdout, "container stderr seq %" PRIu64 "\n", c->exec.errseq); } else if (json_token_streq(json, t, "workdir") && t->size == 1) { i++; c->workdir = strdup(json_token_str(json, &toks[i]));