From 61b64be9ac4e5d46e9363bb605c7b2e14d0cd2a2 Mon Sep 17 00:00:00 2001 From: LiFeng Date: Mon, 13 Apr 2020 20:41:03 +0800 Subject: [PATCH 14/49] exec: refact attach progress Signed-off-by: LiFeng --- src/lxc/attach.c | 2 +- src/lxc/attach_options.h | 23 +++- src/lxc/conf.h | 2 + src/lxc/terminal.c | 27 ++++- src/lxc/tools/arguments.h | 1 + src/lxc/tools/lxc_attach.c | 273 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 324 insertions(+), 4 deletions(-) diff --git a/src/lxc/attach.c b/src/lxc/attach.c index 801dc27..e66ca1c 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -1420,7 +1420,7 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, } if (pid == 0) { - if (options->attach_flags & LXC_ATTACH_TERMINAL) { + if (options->attach_flags & LXC_ATTACH_TERMINAL && terminal.tty_state) { ret = pthread_sigmask(SIG_SETMASK, &terminal.tty_state->oldmask, NULL); if (ret < 0) { diff --git a/src/lxc/attach_options.h b/src/lxc/attach_options.h index 3a02ee5..7b0ea5e 100644 --- a/src/lxc/attach_options.h +++ b/src/lxc/attach_options.h @@ -116,10 +116,12 @@ typedef struct lxc_attach_options_t { #ifdef HAVE_ISULAD char *init_fifo[3]; /* isulad: default fifos for the start */ int64_t timeout;/* isulad: Seconds for waiting on a container to attach/exec before it is killed*/ + const char *suffix; #endif } lxc_attach_options_t; +#ifdef HAVE_ISULAD /*! Default attach options to use */ #define LXC_ATTACH_OPTIONS_DEFAULT \ { \ @@ -136,8 +138,27 @@ typedef struct lxc_attach_options_t { /* .stdout_fd = */ 1, \ /* .stderr_fd = */ 2, \ /* .log_fd = */ -EBADF, \ + /* .init_fifo = */ {NULL, NULL, NULL}, \ } - +#else +/*! Default attach options to use */ +#define LXC_ATTACH_OPTIONS_DEFAULT \ + { \ + /* .attach_flags = */ LXC_ATTACH_DEFAULT, \ + /* .namespaces = */ -1, \ + /* .personality = */ -1, \ + /* .initial_cwd = */ NULL, \ + /* .uid = */ (uid_t)-1, \ + /* .gid = */ (gid_t)-1, \ + /* .env_policy = */ LXC_ATTACH_KEEP_ENV, \ + /* .extra_env_vars = */ NULL, \ + /* .extra_keep_env = */ NULL, \ + /* .stdin_fd = */ 0, \ + /* .stdout_fd = */ 1, \ + /* .stderr_fd = */ 2, \ + /* .log_fd = */ -EBADF, \ + } +#endif /*! * Representation of a command to run in a container. */ diff --git a/src/lxc/conf.h b/src/lxc/conf.h index c5b70e1..52460a3 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -432,6 +432,8 @@ struct lxc_conf { char *container_info_file; int exit_fd; /* exit fifo fd*/ + + char *errmsg; /* record error messages */ #endif }; diff --git a/src/lxc/terminal.c b/src/lxc/terminal.c index c8cd83f..775743d 100644 --- a/src/lxc/terminal.c +++ b/src/lxc/terminal.c @@ -1174,8 +1174,25 @@ static int lxc_terminal_peer_default(struct lxc_terminal *terminal) if (terminal->path) path = terminal->path; - else - path = "/dev/tty"; + +#ifdef HAVE_ISULAD + /* isulad: if no console was given, try current controlling terminal, there + * won't be one if we were started as a daemon (-d) + */ + if (!path && !access("/dev/tty", F_OK)) { + int fd; + fd = open("/dev/tty", O_RDWR); + if (fd >= 0) { + close(fd); + path = "/dev/tty"; + } + } + + if (!path) { + DEBUG("Not have a controlling terminal"); + return 0; + } +#endif terminal->peer = lxc_unpriv(open(path, O_RDWR | O_CLOEXEC)); if (terminal->peer < 0) { @@ -1884,9 +1901,15 @@ int lxc_terminal_prepare_login(int fd) if (ret < 0) return -1; +#ifdef HAVE_ISULAD + ret = set_stdfds(fd); + if (ret < 0) + return -1; +#else ret = lxc_terminal_set_stdfds(fd); if (ret < 0) return -1; +#endif if (fd > STDERR_FILENO) close(fd); diff --git a/src/lxc/tools/arguments.h b/src/lxc/tools/arguments.h index ea5f938..e0866d6 100644 --- a/src/lxc/tools/arguments.h +++ b/src/lxc/tools/arguments.h @@ -44,6 +44,7 @@ struct lxc_arguments { const char *container_info; /* isulad: file used to store pid and ppid info of container */ char *terminal_fifos[3]; /* isulad add, fifos used to redirct stdin/out/err */ const char *exit_monitor_fifo; /* isulad: fifo used to monitor state of monitor process */ + const char *suffix; /* isulad add, suffix used for connect with parent of execed process*/ #endif /* for lxc-console */ diff --git a/src/lxc/tools/lxc_attach.c b/src/lxc/tools/lxc_attach.c index a8f493a..47ac2f2 100644 --- a/src/lxc/tools/lxc_attach.c +++ b/src/lxc/tools/lxc_attach.c @@ -74,6 +74,12 @@ static const struct option my_longopts[] = { {"rcfile", required_argument, 0, 'f'}, {"uid", required_argument, 0, 'u'}, {"gid", required_argument, 0, 'g'}, +#ifdef HAVE_ISULAD + {"in-fifo", required_argument, 0, OPT_INPUT_FIFO}, /* isulad add terminal fifos*/ + {"out-fifo", required_argument, 0, OPT_OUTPUT_FIFO}, + {"err-fifo", required_argument, 0, OPT_STDERR_FIFO}, + {"suffix", required_argument, 0, OPT_ATTACH_SUFFIX}, +#endif LXC_COMMON_OPTIONS }; @@ -201,6 +207,20 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg) if (lxc_safe_uint(arg, &args->gid) < 0) return -1; break; +#ifdef HAVE_ISULAD + case OPT_INPUT_FIFO: + args->terminal_fifos[0] = arg; + break; + case OPT_OUTPUT_FIFO: + args->terminal_fifos[1] = arg; + break; + case OPT_STDERR_FIFO: + args->terminal_fifos[2] = arg; + break; + case OPT_ATTACH_SUFFIX: + args->suffix = arg; + break; +#endif } return 0; @@ -264,6 +284,258 @@ static int lxc_attach_create_log_file(const char *log_file) return fd; } +#ifdef HAVE_ISULAD +// isulad: send '128 + signal' if container is killed by signal. +#define ExitSignalOffset 128 + +/*isulad: attach with terminal*/ +static int do_attach_foreground(struct lxc_container *c, lxc_attach_command_t *command, + lxc_attach_options_t *attach_options, + char **errmsg) +{ + int ret = 0; + pid_t pid; + int wexit = -1; + int signal; + + if (command->program) + ret = c->attach(c, lxc_attach_run_command, command, attach_options, &pid); + else + ret = c->attach(c, lxc_attach_run_shell, NULL, attach_options, &pid); + if (ret < 0) + goto out; + + ret = lxc_wait_for_pid_status(pid); + if (ret < 0) + goto out; + + if (WIFEXITED(ret)) + wexit = WEXITSTATUS(ret); + else + wexit = -1; + + if (WIFSIGNALED(ret)) { + signal = WTERMSIG(ret); + wexit = ExitSignalOffset + signal; + } +out: + if (c->lxc_conf->errmsg) + *errmsg = safe_strdup(c->lxc_conf->errmsg); + return wexit; +} + +static void close_msg_pipe(int *errpipe) +{ + if (errpipe[0] >= 0) { + close(errpipe[0]); + errpipe[0] = -1; + } + if (errpipe[1] >= 0) { + close(errpipe[1]); + errpipe[1] = -1; + } +} + +/*isulad: attach without terminal in background */ +static int do_attach_background(struct lxc_container *c, lxc_attach_command_t *command, + lxc_attach_options_t *attach_options, + char **errmsg) +{ + int ret = 0; + int msgpipe[2]; + pid_t pid = 0; + ssize_t size_read; + char msgbuf[BUFSIZ + 1] = {0}; + + //pipdfd for get error message of child or grandchild process. + if (pipe2(msgpipe, O_CLOEXEC) != 0) { + SYSERROR("Failed to init msgpipe"); + return -1; + } + + pid = fork(); + if (pid < 0) { + close_msg_pipe(msgpipe); + return -1; + } + + if (pid != 0) { + close(msgpipe[1]); + msgpipe[1] = -1; + size_read = read(msgpipe[0], msgbuf, BUFSIZ); + if (size_read > 0) { + *errmsg = safe_strdup(msgbuf); + ret = -1; + } + + close(msgpipe[0]); + msgpipe[0] = -1; + + return ret; + } + + /* second fork to be reparented by init */ + pid = fork(); + if (pid < 0) { + SYSERROR("Error doing dual-fork"); + close_msg_pipe(msgpipe); + exit(1); + } + if (pid != 0) { + close_msg_pipe(msgpipe); + exit(0); + } + + close(msgpipe[0]); + msgpipe[0] = -1; + + if (null_stdfds() < 0) { + ERROR("failed to close fds"); + exit(1); + } + setsid(); + + if (command->program) + ret = c->attach(c, lxc_attach_run_command, command, attach_options, &pid); + else + ret = c->attach(c, lxc_attach_run_shell, NULL, attach_options, &pid); + if (ret < 0) { + if (c->lxc_conf->errmsg) + lxc_write_error_message(msgpipe[1], "%s", c->lxc_conf->errmsg); + else + lxc_write_error_message(msgpipe[1], "Failed to attach container"); + close(msgpipe[1]); + msgpipe[1] = -1; + ret = -1; + goto out; + } + + close(msgpipe[1]); + msgpipe[1] = -1; + + ret = wait_for_pid(pid); +out: + lxc_container_put(c); + if (ret) + exit(EXIT_FAILURE); + else + exit(0); +} + +int main(int argc, char *argv[]) +{ + int ret = -1; + int wexit = 0; + struct lxc_log log; + char *errmsg = NULL; + pid_t pid; + lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT; + lxc_attach_command_t command = (lxc_attach_command_t){.program = NULL}; + + if (lxc_caps_init()) + exit(EXIT_FAILURE); + + if (lxc_arguments_parse(&my_args, argc, argv)) + exit(EXIT_FAILURE); + + log.name = my_args.name; + log.file = my_args.log_file; + log.level = my_args.log_priority; + log.prefix = my_args.progname; + log.quiet = my_args.quiet; + log.lxcpath = my_args.lxcpath[0]; + + if (lxc_log_init(&log)) + exit(EXIT_FAILURE); + + if (geteuid()) + if (access(my_args.lxcpath[0], O_RDONLY) < 0) { + ERROR("You lack access to %s", my_args.lxcpath[0]); + exit(EXIT_FAILURE); + } + + struct lxc_container *c = lxc_container_new(my_args.name, my_args.lxcpath[0]); + if (!c) + exit(EXIT_FAILURE); + + if (my_args.rcfile) { + c->clear_config(c); + if (!c->load_config(c, my_args.rcfile)) { + ERROR("Failed to load rcfile"); + lxc_container_put(c); + exit(EXIT_FAILURE); + } + + c->configfile = strdup(my_args.rcfile); + if (!c->configfile) { + ERROR("Out of memory setting new config filename"); + lxc_container_put(c); + exit(EXIT_FAILURE); + } + } + + if (!c->may_control(c)) { + ERROR("Insufficent privileges to control %s", c->name); + lxc_container_put(c); + exit(EXIT_FAILURE); + } + + if (remount_sys_proc) + attach_options.attach_flags |= LXC_ATTACH_REMOUNT_PROC_SYS; + + if (elevated_privileges) + attach_options.attach_flags &= ~(elevated_privileges); + + if (my_args.terminal_fifos[0] || my_args.terminal_fifos[1] || my_args.terminal_fifos[2]) { + attach_options.init_fifo[0] = my_args.terminal_fifos[0]; + attach_options.init_fifo[1] = my_args.terminal_fifos[1]; + attach_options.init_fifo[2] = my_args.terminal_fifos[2]; + attach_options.attach_flags |= LXC_ATTACH_TERMINAL; + } else if (stdfd_is_pty()) { + attach_options.attach_flags |= LXC_ATTACH_TERMINAL; + } + + attach_options.namespaces = namespace_flags; + attach_options.personality = new_personality; + attach_options.env_policy = env_policy; + attach_options.extra_env_vars = extra_env; + attach_options.extra_keep_env = extra_keep; + + if (my_args.argc > 0) { + command.program = my_args.argv[0]; + command.argv = (char**)my_args.argv; + } + + if (my_args.console_log) { + attach_options.log_fd = lxc_attach_create_log_file(my_args.console_log); + if (attach_options.log_fd < 0) { + ERROR("Failed to create log file for %s", c->name); + lxc_container_put(c); + exit(EXIT_FAILURE); + } + } + + attach_options.suffix = my_args.suffix; + + /* isulad: add do attach background */ + if (attach_options.attach_flags & LXC_ATTACH_TERMINAL) + wexit = do_attach_foreground(c, &command, &attach_options, &errmsg); + else + wexit = do_attach_background(c, &command, &attach_options, &errmsg); + + if (errmsg) { + fprintf(stderr, "%s:%s:%s:%d starting container process caused \"%s\"", c->name, + __FILE__, __func__, __LINE__, errmsg); + free(errmsg); + } + + lxc_container_put(c); + if (wexit >= 0) + exit(wexit); + + exit(EXIT_FAILURE); +} +#else int main(int argc, char *argv[]) { int ret = -1; @@ -377,3 +649,4 @@ out: exit(EXIT_FAILURE); } +#endif -- 1.8.3.1