From fc179b0e5abb9dfe444343e81ef50e69cbc678cd Mon Sep 17 00:00:00 2001 From: LiFeng Date: Fri, 11 Jan 2019 21:52:11 -0500 Subject: [PATCH 009/131] lxc_start: add default terminal fifos Signed-off-by: LiFeng --- src/lxc/conf.c | 4 + src/lxc/lxccontainer.c | 30 ++++++ src/lxc/lxccontainer.h | 10 ++ src/lxc/terminal.c | 194 +++++++++++++++++++++++++++++++++++++- src/lxc/terminal.h | 16 ++++ src/lxc/tools/arguments.h | 5 + src/lxc/tools/lxc_start.c | 11 +++ src/lxc/utils.c | 23 +++++ src/lxc/utils.h | 4 + 9 files changed, 294 insertions(+), 3 deletions(-) diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 37a5ff79..7b7f95b7 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -2714,6 +2714,10 @@ struct lxc_conf *lxc_conf_init(void) new->console.slave = -1; new->console.name[0] = '\0'; memset(&new->console.ringbuf, 0, sizeof(struct lxc_ringbuf)); + /* isulad init console fifos */ + new->console.init_fifo[0] = NULL; + new->console.init_fifo[1] = NULL; + lxc_list_init(&new->console.fifos); new->maincmd_fd = -1; new->nbd_idx = -1; new->rootfs.mount = strdup(default_rootfs_mount); diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index 1d7f5bea..318c71e6 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -4961,6 +4961,33 @@ out: return ret; } +/* isulad add set console fifos*/ +static bool do_lxcapi_set_terminal_default_fifos(struct lxc_container *c, const char *in, const char *out) +{ + struct lxc_conf *conf; + + if (!c || !c->lxc_conf || !in || !out) + return false; + if (container_mem_lock(c)) { + ERROR("Error getting mem lock"); + return false; + } + + conf = c->lxc_conf; + if (conf->console.init_fifo[0]) + free(conf->console.init_fifo[0]); + conf->console.init_fifo[0] = strdup(in); + + if (conf->console.init_fifo[1]) + free(conf->console.init_fifo[1]); + conf->console.init_fifo[1] = strdup(out); + + container_mem_unlock(c); + return true; +} + +WRAP_API_2(bool, lxcapi_set_terminal_default_fifos, const char *, const char *) + struct lxc_container *lxc_container_new(const char *name, const char *configpath) { struct lxc_container *c; @@ -5084,6 +5111,9 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath c->migrate = lxcapi_migrate; c->console_log = lxcapi_console_log; + /* isulad add begin */ + c->set_terminal_init_fifos = lxcapi_set_terminal_default_fifos; + /* isulad add end */ return c; err: diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h index 9e06215c..486531e5 100644 --- a/src/lxc/lxccontainer.h +++ b/src/lxc/lxccontainer.h @@ -847,6 +847,16 @@ struct lxc_container { * \return \c true if the container was rebooted successfully, else \c false. */ bool (*reboot2)(struct lxc_container *c, int timeout); + + /*! isulad add + * \brief An API call to change the path of the console default fifos + * + * \param c Container. + * \param path Value of the console path. + * + * \return \c true on success, else \c false. + */ + bool (*set_terminal_init_fifos)(struct lxc_container *c, const char *in, const char *out); }; /*! diff --git a/src/lxc/terminal.c b/src/lxc/terminal.c index 4060e7f9..c5077122 100644 --- a/src/lxc/terminal.c +++ b/src/lxc/terminal.c @@ -364,6 +364,20 @@ static int lxc_terminal_write_log_file(struct lxc_terminal *terminal, char *buf, return bytes_read; } +/* isulad: forward data to all fifos */ +static void lxc_forward_data_to_fifo(struct lxc_list *list, char *buf, int r) +{ + struct lxc_list *it,*next; + struct lxc_fifos_fd *elem = NULL; + + lxc_list_for_each_safe(it, list, next) { + elem = it->elem; + lxc_write_nointr(elem->out_fd, buf, r); + } + + return; +} + int lxc_terminal_io_cb(int fd, uint32_t events, void *data, struct lxc_epoll_descr *descr) { @@ -384,7 +398,13 @@ int lxc_terminal_io_cb(int fd, uint32_t events, void *data, terminal->tty_state = NULL; } terminal->peer = -EBADF; - } else { + close(fd); + return LXC_MAINLOOP_CONTINUE; /* isulad: do not close mainloop when peer close*/ + } else if (lxc_terminal_is_fifo(fd, &terminal->fifos)) { + /* isulad: delete fifos when the client close */ + lxc_terminal_delete_fifo(fd, &terminal->fifos); + return LXC_MAINLOOP_CONTINUE; + } else { ERROR("Handler received unexpected file descriptor"); } close(fd); @@ -392,7 +412,7 @@ int lxc_terminal_io_cb(int fd, uint32_t events, void *data, return LXC_MAINLOOP_CLOSE; } - if (fd == terminal->peer) + if (fd == terminal->peer || lxc_terminal_is_fifo(fd, &terminal->fifos)) w = lxc_write_nointr(terminal->master, buf, r); w_rbuf = w_log = 0; @@ -401,6 +421,9 @@ int lxc_terminal_io_cb(int fd, uint32_t events, void *data, if (terminal->peer >= 0) w = lxc_write_nointr(terminal->peer, buf, r); + /* isulad: forward data to fifos */ + lxc_forward_data_to_fifo(&terminal->fifos, buf, r); + /* write to terminal ringbuffer */ if (terminal->buffer_size > 0) w_rbuf = lxc_ringbuf_write(&terminal->ringbuf, buf, r); @@ -450,6 +473,27 @@ static int lxc_terminal_mainloop_add_peer(struct lxc_terminal *terminal) return 0; } +/* isulad add fifo to mainloop */ +static int lxc_console_mainloop_add_fifo(struct lxc_terminal *terminal) +{ + int ret = 0; + struct lxc_list *it,*next; + struct lxc_fifos_fd *elem = NULL; + + lxc_list_for_each_safe(it, &terminal->fifos, next) { + elem = it->elem; + if (elem->in_fd >= 0) { + ret = lxc_mainloop_add_handler(terminal->descr, elem->in_fd, + lxc_terminal_io_cb, terminal); + if (ret) { + ERROR("console fifo %s not added to mainloop", elem->in_fifo); + return -1; + } + } + } + return ret; +} + int lxc_terminal_mainloop_add(struct lxc_epoll_descr *descr, struct lxc_terminal *terminal) { @@ -473,7 +517,20 @@ int lxc_terminal_mainloop_add(struct lxc_epoll_descr *descr, */ terminal->descr = descr; - return lxc_terminal_mainloop_add_peer(terminal); + ret = lxc_terminal_mainloop_add_peer(terminal); + if (ret < 0) { + ERROR("Failed to add handler for terminal peer to mainloop"); + return -1; + } + + /* isulad add fifo to mainloop */ + ret = lxc_console_mainloop_add_fifo(terminal); + if (ret < 0) { + ERROR("Failed to add handler for terminal fifos to mainloop"); + return -1; + } + + return 0; } int lxc_setup_tios(int fd, struct termios *oldtios) @@ -812,6 +869,9 @@ void lxc_terminal_delete(struct lxc_terminal *terminal) if (terminal->log_fd >= 0) close(terminal->log_fd); terminal->log_fd = -1; + + /* isulad: delete all fifos */ + lxc_terminal_delete_fifo(-1, &terminal->fifos); } /** @@ -880,6 +940,77 @@ int lxc_terminal_create_log_file(struct lxc_terminal *terminal) return 0; } +/* isulad: open terminal fifos */ +static int terminal_fifo_open(const char *fifo_path, int flags) +{ + int fd = -1; + + fd = open(fifo_path, flags); + if (fd < 0) { + WARN("Failed to open fifo %s to send message: %s.", fifo_path, + strerror(errno)); + return -1; + } + + return fd; +} + +/* isulad: set terminal fifos */ +static int lxc_terminal_set_fifo(struct lxc_terminal *console, const char *in, const char *out) +{ + int fifofd_in = -1, fifofd_out = -1; + struct lxc_fifos_fd *fifo_elem = NULL; + + if (!in || !out) + return -1; + + if (!fifo_exists(in) || !fifo_exists(out)) { + ERROR("File %s or %s does not refer to a FIFO", in, out); + return -1; + } + + fifofd_in = terminal_fifo_open(in, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (fifofd_in < 0) { + ERROR("Failed to open FIFO: %s", in); + return -1; + } + + fifofd_out = terminal_fifo_open(out, O_WRONLY | O_NONBLOCK | O_CLOEXEC); + if (fifofd_out < 0) { + ERROR("Failed to open FIFO: %s", out); + close(fifofd_in); + return -1; + } + + fifo_elem = malloc(sizeof(*fifo_elem)); + if (!fifo_elem) { + close(fifofd_in); + close(fifofd_out); + return -1; + } + memset(fifo_elem, 0, sizeof(*fifo_elem)); + + fifo_elem->in_fifo = strdup(in); + fifo_elem->out_fifo = strdup(out); + fifo_elem->in_fd = fifofd_in; + fifo_elem->out_fd = fifofd_out; + lxc_list_add_elem(&fifo_elem->node, fifo_elem); + lxc_list_add_tail(&console->fifos, &fifo_elem->node); + + return fifofd_in; +} + +/* isulad: add default fifos */ +static int lxc_terminal_fifo_default(struct lxc_terminal *terminal) +{ + if (!terminal->init_fifo[0] || !terminal->init_fifo[1]) { + ERROR("Invalid default terminal fifos"); + return -1; + } + + return lxc_terminal_set_fifo(terminal, terminal->init_fifo[0], terminal->init_fifo[1]); +} + int lxc_terminal_create(struct lxc_terminal *terminal) { int ret; @@ -902,6 +1033,13 @@ int lxc_terminal_create(struct lxc_terminal *terminal) goto err; } + /* isulad: make master NONBLOCK */ + ret = fd_nonblock(terminal->master); + if (ret < 0) { + SYSERROR("Failed to set O_NONBLOCK flag on terminal master"); + goto err; + } + ret = fd_cloexec(terminal->slave, true); if (ret < 0) { SYSERROR("Failed to set FD_CLOEXEC flag on terminal slave"); @@ -914,6 +1052,13 @@ int lxc_terminal_create(struct lxc_terminal *terminal) goto err; } + /* isulad: open fifos */ + ret = lxc_terminal_fifo_default(terminal); + if (ret < 0) { + ERROR("Failed to allocate fifo terminal"); + goto err; + } + return 0; err: @@ -1198,12 +1343,55 @@ void lxc_terminal_init(struct lxc_terminal *terminal) lxc_terminal_info_init(&terminal->proxy); } +/* isulad: judge the fd whether is fifo */ +static bool lxc_terminal_is_fifo(int fd, struct lxc_list *list) +{ + struct lxc_list *it,*next; + struct lxc_fifos_fd *elem = NULL; + + lxc_list_for_each_safe(it, list, next) { + elem = it->elem; + if (elem->in_fd == fd) + return true; + } + + return false; +} + +/* isulad: if fd == -1, means delete all the fifos*/ +int lxc_terminal_delete_fifo(int fd, struct lxc_list *list) +{ + struct lxc_list *it,*next; + struct lxc_fifos_fd *elem = NULL; + + lxc_list_for_each_safe(it, list, next) { + elem = it->elem; + if (elem->in_fd == fd || -1 == fd) { + INFO("Delete fifo fd %d", fd); + lxc_list_del(it); + if (elem->in_fifo) + free(elem->in_fifo); + if (elem->out_fifo) + free(elem->out_fifo); + close(elem->in_fd); + close(elem->out_fd); + free(elem); + } + } + + return 0; +} + void lxc_terminal_conf_free(struct lxc_terminal *terminal) { free(terminal->log_path); free(terminal->path); if (terminal->buffer_size > 0 && terminal->ringbuf.addr) lxc_ringbuf_release(&terminal->ringbuf); + /*isulad: free console fifos */ + free(terminal->init_fifo[0]); + free(terminal->init_fifo[1]); + lxc_terminal_delete_fifo(-1, &terminal->fifos); } int lxc_terminal_map_ids(struct lxc_conf *c, struct lxc_terminal *terminal) diff --git a/src/lxc/terminal.h b/src/lxc/terminal.h index bfd271f4..d25da657 100644 --- a/src/lxc/terminal.h +++ b/src/lxc/terminal.h @@ -115,6 +115,17 @@ struct lxc_terminal { /* the in-memory ringbuffer */ struct lxc_ringbuf ringbuf; }; + char *init_fifo[2]; /* isulad: default fifos for the start */ + struct lxc_list fifos; /* isulad: fifos used to forward teminal */ +}; + +/* isulad: fifo struct */ +struct lxc_fifos_fd { + char *in_fifo; + char *out_fifo; + int in_fd; + int out_fd; + struct lxc_list node; }; /** @@ -295,4 +306,9 @@ extern void lxc_terminal_init(struct lxc_terminal *terminal); extern int lxc_terminal_map_ids(struct lxc_conf *c, struct lxc_terminal *terminal); +/* isulad: judge the fd whether is fifo*/ +static bool lxc_terminal_is_fifo(int fd, struct lxc_list *list); +/* isulad: if fd == -1, means delete all the fifos*/ +int lxc_terminal_delete_fifo(int fd, struct lxc_list *list); + #endif /* __LXC_TERMINAL_H */ diff --git a/src/lxc/tools/arguments.h b/src/lxc/tools/arguments.h index 810050ad..b7af2b51 100644 --- a/src/lxc/tools/arguments.h +++ b/src/lxc/tools/arguments.h @@ -62,6 +62,7 @@ struct lxc_arguments { /* for lxc-start */ const char *share_ns[32]; /* size must be greater than LXC_NS_MAX */ + const char *terminal_fifos[2]; /* isulad add, fifos used to redirct stdin/out/err */ /* for lxc-console */ unsigned int ttynum; @@ -172,6 +173,10 @@ struct lxc_arguments { #define OPT_SHARE_IPC OPT_USAGE - 4 #define OPT_SHARE_UTS OPT_USAGE - 5 #define OPT_SHARE_PID OPT_USAGE - 6 +/* isulad add begin */ +#define OPT_INPUT_FIFO OPT_USAGE - 7 +#define OPT_OUTPUT_FIFO OPT_USAGE - 8 +/* isulad add end*/ extern int lxc_arguments_parse(struct lxc_arguments *args, int argc, char *const argv[]); diff --git a/src/lxc/tools/lxc_start.c b/src/lxc/tools/lxc_start.c index 4553cb5c..8f03f111 100644 --- a/src/lxc/tools/lxc_start.c +++ b/src/lxc/tools/lxc_start.c @@ -69,6 +69,8 @@ static const struct option my_longopts[] = { {"share-ipc", required_argument, 0, OPT_SHARE_IPC}, {"share-uts", required_argument, 0, OPT_SHARE_UTS}, {"share-pid", required_argument, 0, OPT_SHARE_PID}, + {"in-fifo", required_argument, 0, OPT_INPUT_FIFO}, + {"out-fifo", required_argument, 0, OPT_OUTPUT_FIFO}, LXC_COMMON_OPTIONS }; @@ -140,6 +142,12 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg) case OPT_SHARE_PID: args->share_ns[LXC_NS_PID] = arg; break; + case OPT_INPUT_FIFO: + args->terminal_fifos[0] = arg; + break; + case OPT_OUTPUT_FIFO: + args->terminal_fifos[1] = arg; + break; } return 0; } @@ -322,6 +330,9 @@ int main(int argc, char *argv[]) if (my_args.close_all_fds) c->want_close_all_fds(c, true); + if (my_args.terminal_fifos[0] && my_args.terminal_fifos[1]) + c->set_terminal_init_fifos(c, my_args.terminal_fifos[0], my_args.terminal_fifos[1]); + if (args == default_args) err = c->start(c, 0, NULL) ? EXIT_SUCCESS : EXIT_FAILURE; else diff --git a/src/lxc/utils.c b/src/lxc/utils.c index 6e9165ae..67c3b3ef 100644 --- a/src/lxc/utils.c +++ b/src/lxc/utils.c @@ -611,6 +611,19 @@ bool dir_exists(const char *path) return S_ISDIR(sb.st_mode); } +bool fifo_exists(const char *path) +{ + struct stat sb; + int ret; + + ret = stat(path, &sb); + if (ret < 0) + // could be something other than eexist, just say no + return false; + return S_ISFIFO(sb.st_mode); +} + + /* Note we don't use SHA-1 here as we don't want to depend on HAVE_GNUTLS. * FNV has good anti collision properties and we're not worried * about pre-image resistance or one-way-ness, we're just trying to make @@ -1715,6 +1728,16 @@ int fd_cloexec(int fd, bool cloexec) return 0; } +/* isulad: fd_nonblock */ +int fd_nonblock(int fd) +{ + long flags; + + flags = fcntl(fd, F_GETFL); + + return fcntl(fd, F_SETFL, flags | O_NONBLOCK); +} + int recursive_destroy(char *dirname) { int ret; diff --git a/src/lxc/utils.h b/src/lxc/utils.h index 94196d09..2d38178c 100644 --- a/src/lxc/utils.h +++ b/src/lxc/utils.h @@ -147,6 +147,8 @@ extern gid_t get_ns_gid(gid_t orig); extern bool dir_exists(const char *path); +extern bool fifo_exists(const char *path); + #define FNV1A_64_INIT ((uint64_t)0xcbf29ce484222325ULL) extern uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval); @@ -242,4 +244,6 @@ extern int fd_cloexec(int fd, bool cloexec); extern int recursive_destroy(char *dirname); extern int lxc_setup_keyring(void); +extern int fd_nonblock(int fd); + #endif /* __LXC_UTILS_H */ -- 2.23.0