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]));