commit
7cb47aeb21
1 changed files with 279 additions and 271 deletions
550
conmon/conmon.c
550
conmon/conmon.c
|
@ -94,32 +94,32 @@ static inline void strv_cleanup(char ***strv)
|
||||||
#define CMD_SIZE 1024
|
#define CMD_SIZE 1024
|
||||||
#define MAX_EVENTS 10
|
#define MAX_EVENTS 10
|
||||||
|
|
||||||
static bool terminal = false;
|
static bool opt_terminal = false;
|
||||||
static bool opt_stdin = false;
|
static bool opt_stdin = false;
|
||||||
static char *cid = NULL;
|
static char *opt_cid = NULL;
|
||||||
static char *cuuid = NULL;
|
static char *opt_cuuid = NULL;
|
||||||
static char *runtime_path = NULL;
|
static char *opt_runtime_path = NULL;
|
||||||
static char *bundle_path = NULL;
|
static char *opt_bundle_path = NULL;
|
||||||
static char *pid_file = NULL;
|
static char *opt_pid_file = NULL;
|
||||||
static bool systemd_cgroup = false;
|
static bool opt_systemd_cgroup = false;
|
||||||
static char *exec_process_spec = NULL;
|
static char *opt_exec_process_spec = NULL;
|
||||||
static bool exec = false;
|
static bool opt_exec = false;
|
||||||
static char *log_path = NULL;
|
static char *opt_log_path = NULL;
|
||||||
static int timeout = 0;
|
static int opt_timeout = 0;
|
||||||
static GOptionEntry entries[] =
|
static GOptionEntry opt_entries[] =
|
||||||
{
|
{
|
||||||
{ "terminal", 't', 0, G_OPTION_ARG_NONE, &terminal, "Terminal", NULL },
|
{ "terminal", 't', 0, G_OPTION_ARG_NONE, &opt_terminal, "Terminal", NULL },
|
||||||
{ "stdin", 'i', 0, G_OPTION_ARG_NONE, &opt_stdin, "Stdin", NULL },
|
{ "stdin", 'i', 0, G_OPTION_ARG_NONE, &opt_stdin, "Stdin", NULL },
|
||||||
{ "cid", 'c', 0, G_OPTION_ARG_STRING, &cid, "Container ID", NULL },
|
{ "cid", 'c', 0, G_OPTION_ARG_STRING, &opt_cid, "Container ID", NULL },
|
||||||
{ "cuuid", 'u', 0, G_OPTION_ARG_STRING, &cuuid, "Container UUID", NULL },
|
{ "cuuid", 'u', 0, G_OPTION_ARG_STRING, &opt_cuuid, "Container UUID", NULL },
|
||||||
{ "runtime", 'r', 0, G_OPTION_ARG_STRING, &runtime_path, "Runtime path", NULL },
|
{ "runtime", 'r', 0, G_OPTION_ARG_STRING, &opt_runtime_path, "Runtime path", NULL },
|
||||||
{ "bundle", 'b', 0, G_OPTION_ARG_STRING, &bundle_path, "Bundle path", NULL },
|
{ "bundle", 'b', 0, G_OPTION_ARG_STRING, &opt_bundle_path, "Bundle path", NULL },
|
||||||
{ "pidfile", 'p', 0, G_OPTION_ARG_STRING, &pid_file, "PID file", NULL },
|
{ "pidfile", 'p', 0, G_OPTION_ARG_STRING, &opt_pid_file, "PID file", NULL },
|
||||||
{ "systemd-cgroup", 's', 0, G_OPTION_ARG_NONE, &systemd_cgroup, "Enable systemd cgroup manager", NULL },
|
{ "systemd-cgroup", 's', 0, G_OPTION_ARG_NONE, &opt_systemd_cgroup, "Enable systemd cgroup manager", NULL },
|
||||||
{ "exec", 'e', 0, G_OPTION_ARG_NONE, &exec, "Exec a command in a running container", NULL },
|
{ "exec", 'e', 0, G_OPTION_ARG_NONE, &opt_exec, "Exec a command in a running container", NULL },
|
||||||
{ "exec-process-spec", 0, 0, G_OPTION_ARG_STRING, &exec_process_spec, "Path to the process spec for exec", NULL },
|
{ "exec-process-spec", 0, 0, G_OPTION_ARG_STRING, &opt_exec_process_spec, "Path to the process spec for exec", NULL },
|
||||||
{ "log-path", 'l', 0, G_OPTION_ARG_STRING, &log_path, "Log file path", NULL },
|
{ "log-path", 'l', 0, G_OPTION_ARG_STRING, &opt_log_path, "Log file path", NULL },
|
||||||
{ "timeout", 'T', 0, G_OPTION_ARG_INT, &timeout, "Timeout in seconds", NULL },
|
{ "timeout", 'T', 0, G_OPTION_ARG_INT, &opt_timeout, "Timeout in seconds", NULL },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -352,14 +352,7 @@ next:
|
||||||
* Returns NULL on error.
|
* Returns NULL on error.
|
||||||
*/
|
*/
|
||||||
static char *process_cgroup_subsystem_path(int pid, const char *subsystem) {
|
static char *process_cgroup_subsystem_path(int pid, const char *subsystem) {
|
||||||
_cleanup_free_ char *cgroups_file_path = NULL;
|
_cleanup_free_ char *cgroups_file_path = g_strdup_printf("/proc/%d/cgroup", pid);
|
||||||
int rc;
|
|
||||||
rc = asprintf(&cgroups_file_path, "/proc/%d/cgroup", pid);
|
|
||||||
if (rc < 0) {
|
|
||||||
nwarn("Failed to allocate memory for cgroups file path");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
_cleanup_fclose_ FILE *fp = NULL;
|
_cleanup_fclose_ FILE *fp = NULL;
|
||||||
fp = fopen(cgroups_file_path, "re");
|
fp = fopen(cgroups_file_path, "re");
|
||||||
if (fp == NULL) {
|
if (fp == NULL) {
|
||||||
|
@ -398,12 +391,7 @@ static char *process_cgroup_subsystem_path(int pid, const char *subsystem) {
|
||||||
*subpath = 0;
|
*subpath = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = asprintf(&subsystem_path, "%s/%s%s", CGROUP_ROOT, subpath, path);
|
subsystem_path = g_strdup_printf("%s/%s%s", CGROUP_ROOT, subpath, path);
|
||||||
if (rc < 0) {
|
|
||||||
nwarn("Failed to allocate memory for subsystemd path");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
subsystem_path[strlen(subsystem_path) - 1] = '\0';
|
subsystem_path[strlen(subsystem_path) - 1] = '\0';
|
||||||
return subsystem_path;
|
return subsystem_path;
|
||||||
}
|
}
|
||||||
|
@ -440,6 +428,42 @@ static char *escape_json_string(const char *str)
|
||||||
return g_string_free (escaped, FALSE);
|
return g_string_free (escaped, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int get_pipe_fd_from_env(const char *envname)
|
||||||
|
{
|
||||||
|
char *pipe_str, *endptr;
|
||||||
|
int pipe_fd;
|
||||||
|
|
||||||
|
pipe_str = getenv(envname);
|
||||||
|
if (pipe_str == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
pipe_fd = strtol(pipe_str, &endptr, 10);
|
||||||
|
if (errno != 0 || *endptr != '\0')
|
||||||
|
pexit("unable to parse %s", envname);
|
||||||
|
if (fcntl(pipe_fd, F_SETFD, FD_CLOEXEC) == -1)
|
||||||
|
pexit("unable to make %s CLOEXEC", envname);
|
||||||
|
|
||||||
|
return pipe_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_argv(GPtrArray *argv_array, ...) G_GNUC_NULL_TERMINATED;
|
||||||
|
|
||||||
|
static void add_argv(GPtrArray *argv_array, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
char *arg;
|
||||||
|
|
||||||
|
va_start (args, argv_array);
|
||||||
|
while ((arg = va_arg (args, char *)))
|
||||||
|
g_ptr_array_add (argv_array, arg);
|
||||||
|
va_end (args);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void end_argv(GPtrArray *argv_array)
|
||||||
|
{
|
||||||
|
g_ptr_array_add(argv_array, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Global state */
|
/* Global state */
|
||||||
|
|
||||||
|
@ -455,12 +479,11 @@ static int conn_sock = -1;
|
||||||
static int conn_sock_readable;
|
static int conn_sock_readable;
|
||||||
static int conn_sock_writable;
|
static int conn_sock_writable;
|
||||||
|
|
||||||
static int logfd = -1;
|
static int log_fd = -1;
|
||||||
static int oom_efd = -1;
|
static int oom_event_fd = -1;
|
||||||
static int afd = -1;
|
static int attach_socket_fd = -1;
|
||||||
static int cfd = -1;
|
static int console_socket_fd = -1;
|
||||||
/* Used for OOM notification API */
|
static int terminal_ctrl_fd = -1;
|
||||||
static int ofd = -1;
|
|
||||||
|
|
||||||
static bool timed_out = FALSE;
|
static bool timed_out = FALSE;
|
||||||
|
|
||||||
|
@ -499,7 +522,7 @@ static gboolean stdio_cb(int fd, GIOCondition condition, gpointer user_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num_read > 0) {
|
if (num_read > 0) {
|
||||||
if (write_k8s_log(logfd, pipe, buf, num_read) < 0) {
|
if (write_k8s_log(log_fd, pipe, buf, num_read) < 0) {
|
||||||
nwarn("write_k8s_log failed");
|
nwarn("write_k8s_log failed");
|
||||||
return G_SOURCE_CONTINUE;
|
return G_SOURCE_CONTINUE;
|
||||||
}
|
}
|
||||||
|
@ -562,7 +585,7 @@ static gboolean oom_cb(int fd, GIOCondition condition, G_GNUC_UNUSED gpointer us
|
||||||
|
|
||||||
/* End of input */
|
/* End of input */
|
||||||
close (fd);
|
close (fd);
|
||||||
oom_efd = -1;
|
oom_event_fd = -1;
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -687,7 +710,7 @@ static gboolean terminal_accept_cb(int fd, G_GNUC_UNUSED GIOCondition condition,
|
||||||
int connfd = -1;
|
int connfd = -1;
|
||||||
struct termios tset;
|
struct termios tset;
|
||||||
|
|
||||||
ninfo("about to accept from csfd: %d", fd);
|
ninfo("about to accept from console_socket_fd: %d", fd);
|
||||||
connfd = accept4(fd, NULL, NULL, SOCK_CLOEXEC);
|
connfd = accept4(fd, NULL, NULL, SOCK_CLOEXEC);
|
||||||
if (connfd < 0) {
|
if (connfd < 0) {
|
||||||
nwarn("Failed to accept console-socket connection");
|
nwarn("Failed to accept console-socket connection");
|
||||||
|
@ -742,7 +765,7 @@ static void write_sync_fd(int sync_pipe_fd, int res, const char *message)
|
||||||
if (sync_pipe_fd == -1)
|
if (sync_pipe_fd == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (exec)
|
if (opt_exec)
|
||||||
res_key = "exit_code";
|
res_key = "exit_code";
|
||||||
else
|
else
|
||||||
res_key = "pid";
|
res_key = "pid";
|
||||||
|
@ -760,31 +783,166 @@ static void write_sync_fd(int sync_pipe_fd, int res, const char *message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *setup_console_socket(void)
|
||||||
|
{
|
||||||
|
struct sockaddr_un addr = {0};
|
||||||
|
char csname[PATH_MAX] = "/tmp/conmon-term.XXXXXXXX";
|
||||||
|
/*
|
||||||
|
* Generate a temporary name. Is this unsafe? Probably, but we can
|
||||||
|
* replace it with a rename(2) setup if necessary.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int unusedfd = g_mkstemp(csname);
|
||||||
|
if (unusedfd < 0)
|
||||||
|
pexit("Failed to generate random path for console-socket");
|
||||||
|
close(unusedfd);
|
||||||
|
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
strncpy(addr.sun_path, csname, sizeof(addr.sun_path)-1);
|
||||||
|
|
||||||
|
ninfo("addr{sun_family=AF_UNIX, sun_path=%s}", addr.sun_path);
|
||||||
|
|
||||||
|
/* Bind to the console socket path. */
|
||||||
|
console_socket_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
|
||||||
|
if (console_socket_fd < 0)
|
||||||
|
pexit("Failed to create console-socket");
|
||||||
|
if (fchmod(console_socket_fd, 0700))
|
||||||
|
pexit("Failed to change console-socket permissions");
|
||||||
|
/* XXX: This should be handled with a rename(2). */
|
||||||
|
if (unlink(csname) < 0)
|
||||||
|
pexit("Failed to unlink temporary ranom path");
|
||||||
|
if (bind(console_socket_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
|
||||||
|
pexit("Failed to bind to console-socket");
|
||||||
|
if (listen(console_socket_fd, 128) < 0)
|
||||||
|
pexit("Failed to listen on console-socket");
|
||||||
|
|
||||||
|
return g_strdup(csname);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *setup_attach_socket(void)
|
||||||
|
{
|
||||||
|
_cleanup_free_ char *attach_sock_path = NULL;
|
||||||
|
char *attach_symlink_dir_path;
|
||||||
|
struct sockaddr_un attach_addr = {0};
|
||||||
|
attach_addr.sun_family = AF_UNIX;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a symlink so we don't exceed unix domain socket
|
||||||
|
* path length limit.
|
||||||
|
*/
|
||||||
|
attach_symlink_dir_path = g_build_filename("/var/run/crio", opt_cuuid, NULL);
|
||||||
|
if (unlink(attach_symlink_dir_path) == -1 && errno != ENOENT)
|
||||||
|
pexit("Failed to remove existing symlink for attach socket directory");
|
||||||
|
|
||||||
|
if (symlink(opt_bundle_path, attach_symlink_dir_path) == -1)
|
||||||
|
pexit("Failed to create symlink for attach socket");
|
||||||
|
|
||||||
|
attach_sock_path = g_build_filename("/var/run/crio", opt_cuuid, "attach", NULL);
|
||||||
|
ninfo("attach sock path: %s", attach_sock_path);
|
||||||
|
|
||||||
|
strncpy(attach_addr.sun_path, attach_sock_path, sizeof(attach_addr.sun_path) - 1);
|
||||||
|
ninfo("addr{sun_family=AF_UNIX, sun_path=%s}", attach_addr.sun_path);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We make the socket non-blocking to avoid a race where client aborts connection
|
||||||
|
* before the server gets a chance to call accept. In that scenario, the server
|
||||||
|
* accept blocks till a new client connection comes in.
|
||||||
|
*/
|
||||||
|
attach_socket_fd = socket(AF_UNIX, SOCK_SEQPACKET|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
|
||||||
|
if (attach_socket_fd == -1)
|
||||||
|
pexit("Failed to create attach socket");
|
||||||
|
|
||||||
|
if (fchmod(attach_socket_fd, 0700))
|
||||||
|
pexit("Failed to change attach socket permissions");
|
||||||
|
|
||||||
|
if (bind(attach_socket_fd, (struct sockaddr *)&attach_addr, sizeof(struct sockaddr_un)) == -1)
|
||||||
|
pexit("Failed to bind attach socket: %s", attach_sock_path);
|
||||||
|
|
||||||
|
if (listen(attach_socket_fd, 10) == -1)
|
||||||
|
pexit("Failed to listen on attach socket: %s", attach_sock_path);
|
||||||
|
|
||||||
|
g_unix_fd_add (attach_socket_fd, G_IO_IN, attach_cb, NULL);
|
||||||
|
|
||||||
|
return attach_symlink_dir_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setup_terminal_control_fifo()
|
||||||
|
{
|
||||||
|
_cleanup_free_ char *ctl_fifo_path = g_build_filename(opt_bundle_path, "ctl", NULL);
|
||||||
|
ninfo("ctl fifo path: %s", ctl_fifo_path);
|
||||||
|
|
||||||
|
/* Setup fifo for reading in terminal resize and other stdio control messages */
|
||||||
|
|
||||||
|
if (mkfifo(ctl_fifo_path, 0666) == -1)
|
||||||
|
pexit("Failed to mkfifo at %s", ctl_fifo_path);
|
||||||
|
|
||||||
|
terminal_ctrl_fd = open(ctl_fifo_path, O_RDONLY|O_NONBLOCK|O_CLOEXEC);
|
||||||
|
if (terminal_ctrl_fd == -1)
|
||||||
|
pexit("Failed to open control fifo");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open a dummy writer to prevent getting flood of POLLHUPs when
|
||||||
|
* last writer closes.
|
||||||
|
*/
|
||||||
|
int dummyfd = open(ctl_fifo_path, O_WRONLY|O_CLOEXEC);
|
||||||
|
if (dummyfd == -1)
|
||||||
|
pexit("Failed to open dummy writer for fifo");
|
||||||
|
|
||||||
|
g_unix_fd_add (terminal_ctrl_fd, G_IO_IN, ctrl_cb, NULL);
|
||||||
|
|
||||||
|
ninfo("terminal_ctrl_fd: %d", terminal_ctrl_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setup_oom_handling(int cpid)
|
||||||
|
{
|
||||||
|
/* Setup OOM notification for container process */
|
||||||
|
_cleanup_free_ char *memory_cgroup_path = process_cgroup_subsystem_path(cpid, "memory");
|
||||||
|
_cleanup_close_ int cfd = -1;
|
||||||
|
int ofd = -1; /* Not closed */
|
||||||
|
if (!memory_cgroup_path) {
|
||||||
|
nexit("Failed to get memory cgroup path");
|
||||||
|
}
|
||||||
|
|
||||||
|
_cleanup_free_ char *memory_cgroup_file_path = g_build_filename(memory_cgroup_path, "cgroup.event_control", NULL);
|
||||||
|
|
||||||
|
if ((cfd = open(memory_cgroup_file_path, O_WRONLY | O_CLOEXEC)) == -1) {
|
||||||
|
nwarn("Failed to open %s", memory_cgroup_file_path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_cleanup_free_ char *memory_cgroup_file_oom_path = g_build_filename(memory_cgroup_path, "memory.oom_control", NULL);
|
||||||
|
if ((ofd = open(memory_cgroup_file_oom_path, O_RDONLY | O_CLOEXEC)) == -1)
|
||||||
|
pexit("Failed to open %s", memory_cgroup_file_oom_path);
|
||||||
|
|
||||||
|
if ((oom_event_fd = eventfd(0, EFD_CLOEXEC)) == -1)
|
||||||
|
pexit("Failed to create eventfd");
|
||||||
|
|
||||||
|
_cleanup_free_ char *data = g_strdup_printf("%d %d", oom_event_fd, ofd);
|
||||||
|
if (write_all(cfd, data, strlen(data)) < 0)
|
||||||
|
pexit("Failed to write to cgroup.event_control");
|
||||||
|
|
||||||
|
g_unix_fd_add (oom_event_fd, G_IO_IN, oom_cb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
char cwd[PATH_MAX];
|
char cwd[PATH_MAX];
|
||||||
char default_pid_file[PATH_MAX];
|
_cleanup_free_ char *default_pid_file = NULL;
|
||||||
char attach_sock_path[PATH_MAX];
|
_cleanup_free_ char *csname = NULL;
|
||||||
char ctl_fifo_path[PATH_MAX];
|
|
||||||
GError *err = NULL;
|
GError *err = NULL;
|
||||||
_cleanup_free_ char *contents;
|
_cleanup_free_ char *contents = NULL;
|
||||||
int cpid = -1;
|
int cpid = -1;
|
||||||
int status;
|
int status;
|
||||||
pid_t pid, main_pid, create_pid;
|
pid_t pid, main_pid, create_pid;
|
||||||
_cleanup_close_ int epfd = -1;
|
|
||||||
_cleanup_close_ int csfd = -1;
|
|
||||||
/* Used for !terminal cases. */
|
/* Used for !terminal cases. */
|
||||||
int slavefd_stdin = -1;
|
int slavefd_stdin = -1;
|
||||||
int slavefd_stdout = -1;
|
int slavefd_stdout = -1;
|
||||||
int slavefd_stderr = -1;
|
int slavefd_stderr = -1;
|
||||||
char csname[PATH_MAX] = "/tmp/conmon-term.XXXXXXXX";
|
|
||||||
char buf[BUF_SIZE];
|
char buf[BUF_SIZE];
|
||||||
int num_read;
|
int num_read;
|
||||||
int sync_pipe_fd = -1;
|
int sync_pipe_fd = -1;
|
||||||
int start_pipe_fd = -1;
|
int start_pipe_fd = -1;
|
||||||
char *start_pipe, *sync_pipe, *endptr;
|
|
||||||
int len;
|
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
GOptionContext *context;
|
GOptionContext *context;
|
||||||
GPtrArray *runtime_argv = NULL;
|
GPtrArray *runtime_argv = NULL;
|
||||||
|
@ -792,33 +950,30 @@ int main(int argc, char *argv[])
|
||||||
_cleanup_close_ int dev_null_w = -1;
|
_cleanup_close_ int dev_null_w = -1;
|
||||||
int fds[2];
|
int fds[2];
|
||||||
|
|
||||||
_cleanup_free_ char *memory_cgroup_path = NULL;
|
|
||||||
int wb;
|
|
||||||
|
|
||||||
main_loop = g_main_loop_new (NULL, FALSE);
|
main_loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
|
||||||
/* Command line parameters */
|
/* Command line parameters */
|
||||||
context = g_option_context_new("- conmon utility");
|
context = g_option_context_new("- conmon utility");
|
||||||
g_option_context_add_main_entries(context, entries, "conmon");
|
g_option_context_add_main_entries(context, opt_entries, "conmon");
|
||||||
if (!g_option_context_parse(context, &argc, &argv, &error)) {
|
if (!g_option_context_parse(context, &argc, &argv, &error)) {
|
||||||
g_print("option parsing failed: %s\n", error->message);
|
g_print("option parsing failed: %s\n", error->message);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cid == NULL)
|
if (opt_cid == NULL)
|
||||||
nexit("Container ID not provided. Use --cid");
|
nexit("Container ID not provided. Use --cid");
|
||||||
|
|
||||||
if (!exec && cuuid == NULL)
|
if (!opt_exec && opt_cuuid == NULL)
|
||||||
nexit("Container UUID not provided. Use --cuuid");
|
nexit("Container UUID not provided. Use --cuuid");
|
||||||
|
|
||||||
if (runtime_path == NULL)
|
if (opt_runtime_path == NULL)
|
||||||
nexit("Runtime path not provided. Use --runtime");
|
nexit("Runtime path not provided. Use --runtime");
|
||||||
|
|
||||||
if (bundle_path == NULL && !exec) {
|
if (opt_bundle_path == NULL && !opt_exec) {
|
||||||
if (getcwd(cwd, sizeof(cwd)) == NULL) {
|
if (getcwd(cwd, sizeof(cwd)) == NULL) {
|
||||||
nexit("Failed to get working directory");
|
nexit("Failed to get working directory");
|
||||||
}
|
}
|
||||||
bundle_path = cwd;
|
opt_bundle_path = cwd;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_null_r = open("/dev/null", O_RDONLY | O_CLOEXEC);
|
dev_null_r = open("/dev/null", O_RDONLY | O_CLOEXEC);
|
||||||
|
@ -829,27 +984,20 @@ int main(int argc, char *argv[])
|
||||||
if (dev_null_w < 0)
|
if (dev_null_w < 0)
|
||||||
pexit("Failed to open /dev/null");
|
pexit("Failed to open /dev/null");
|
||||||
|
|
||||||
if (exec && exec_process_spec == NULL) {
|
if (opt_exec && opt_exec_process_spec == NULL) {
|
||||||
nexit("Exec process spec path not provided. Use --exec-process-spec");
|
nexit("Exec process spec path not provided. Use --exec-process-spec");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pid_file == NULL) {
|
if (opt_pid_file == NULL) {
|
||||||
if (snprintf(default_pid_file, sizeof(default_pid_file),
|
default_pid_file = g_strdup_printf ("%s/pidfile-%s", cwd, opt_cid);
|
||||||
"%s/pidfile-%s", cwd, cid) < 0) {
|
opt_pid_file = default_pid_file;
|
||||||
nexit("Failed to generate the pidfile path");
|
|
||||||
}
|
|
||||||
pid_file = default_pid_file;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log_path == NULL)
|
if (opt_log_path == NULL)
|
||||||
nexit("Log file path not provided. Use --log-path");
|
nexit("Log file path not provided. Use --log-path");
|
||||||
|
|
||||||
start_pipe = getenv("_OCI_STARTPIPE");
|
start_pipe_fd = get_pipe_fd_from_env("_OCI_STARTPIPE");
|
||||||
if (start_pipe) {
|
if (start_pipe_fd >= 0) {
|
||||||
errno = 0;
|
|
||||||
start_pipe_fd = strtol(start_pipe, &endptr, 10);
|
|
||||||
if (errno != 0 || *endptr != '\0')
|
|
||||||
pexit("unable to parse _OCI_STARTPIPE");
|
|
||||||
/* Block for an initial write to the start pipe before
|
/* Block for an initial write to the start pipe before
|
||||||
spawning any childred or exiting, to ensure the
|
spawning any childred or exiting, to ensure the
|
||||||
parent can put us in the right cgroup. */
|
parent can put us in the right cgroup. */
|
||||||
|
@ -881,19 +1029,11 @@ int main(int argc, char *argv[])
|
||||||
setsid();
|
setsid();
|
||||||
|
|
||||||
/* Environment variables */
|
/* Environment variables */
|
||||||
sync_pipe = getenv("_OCI_SYNCPIPE");
|
sync_pipe_fd = get_pipe_fd_from_env("_OCI_SYNCPIPE");
|
||||||
if (sync_pipe) {
|
|
||||||
errno = 0;
|
|
||||||
sync_pipe_fd = strtol(sync_pipe, &endptr, 10);
|
|
||||||
if (errno != 0 || *endptr != '\0')
|
|
||||||
pexit("unable to parse _OCI_SYNCPIPE");
|
|
||||||
if (fcntl(sync_pipe_fd, F_SETFD, FD_CLOEXEC) == -1)
|
|
||||||
pexit("unable to make _OCI_SYNCPIPE CLOEXEC");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Open the log path file. */
|
/* Open the log path file. */
|
||||||
logfd = open(log_path, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, 0600);
|
log_fd = open(opt_log_path, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, 0600);
|
||||||
if (logfd < 0)
|
if (log_fd < 0)
|
||||||
pexit("Failed to open log file");
|
pexit("Failed to open log file");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -905,37 +1045,8 @@ int main(int argc, char *argv[])
|
||||||
pexit("Failed to set as subreaper");
|
pexit("Failed to set as subreaper");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (terminal) {
|
if (opt_terminal) {
|
||||||
struct sockaddr_un addr = {0};
|
csname = setup_console_socket();
|
||||||
|
|
||||||
/*
|
|
||||||
* Generate a temporary name. Is this unsafe? Probably, but we can
|
|
||||||
* replace it with a rename(2) setup if necessary.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int unusedfd = g_mkstemp(csname);
|
|
||||||
if (unusedfd < 0)
|
|
||||||
pexit("Failed to generate random path for console-socket");
|
|
||||||
close(unusedfd);
|
|
||||||
|
|
||||||
addr.sun_family = AF_UNIX;
|
|
||||||
strncpy(addr.sun_path, csname, sizeof(addr.sun_path)-1);
|
|
||||||
|
|
||||||
ninfo("addr{sun_family=AF_UNIX, sun_path=%s}", addr.sun_path);
|
|
||||||
|
|
||||||
/* Bind to the console socket path. */
|
|
||||||
csfd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
|
|
||||||
if (csfd < 0)
|
|
||||||
pexit("Failed to create console-socket");
|
|
||||||
if (fchmod(csfd, 0700))
|
|
||||||
pexit("Failed to change console-socket permissions");
|
|
||||||
/* XXX: This should be handled with a rename(2). */
|
|
||||||
if (unlink(csname) < 0)
|
|
||||||
pexit("Failed to unlink temporary ranom path");
|
|
||||||
if (bind(csfd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
|
|
||||||
pexit("Failed to bind to console-socket");
|
|
||||||
if (listen(csfd, 128) < 0)
|
|
||||||
pexit("Failed to listen on console-socket");
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -972,39 +1083,45 @@ int main(int argc, char *argv[])
|
||||||
slavefd_stderr = fds[1];
|
slavefd_stderr = fds[1];
|
||||||
|
|
||||||
runtime_argv = g_ptr_array_new();
|
runtime_argv = g_ptr_array_new();
|
||||||
g_ptr_array_add(runtime_argv, runtime_path);
|
add_argv(runtime_argv,
|
||||||
|
opt_runtime_path,
|
||||||
|
NULL);
|
||||||
|
|
||||||
/* Generate the cmdline. */
|
/* Generate the cmdline. */
|
||||||
if (!exec && systemd_cgroup)
|
if (!opt_exec && opt_systemd_cgroup)
|
||||||
g_ptr_array_add(runtime_argv, "--systemd-cgroup");
|
add_argv(runtime_argv,
|
||||||
|
"--systemd-cgroup",
|
||||||
|
NULL);
|
||||||
|
|
||||||
if (exec) {
|
if (opt_exec) {
|
||||||
g_ptr_array_add (runtime_argv, "exec");
|
add_argv(runtime_argv,
|
||||||
g_ptr_array_add (runtime_argv, "-d");
|
"exec", "-d",
|
||||||
g_ptr_array_add (runtime_argv, "--pid-file");
|
"--pid-file", opt_pid_file,
|
||||||
g_ptr_array_add (runtime_argv, pid_file);
|
NULL);
|
||||||
} else {
|
} else {
|
||||||
g_ptr_array_add (runtime_argv, "create");
|
add_argv(runtime_argv,
|
||||||
g_ptr_array_add (runtime_argv, "--bundle");
|
"create",
|
||||||
g_ptr_array_add (runtime_argv, bundle_path);
|
"--bundle", opt_bundle_path,
|
||||||
g_ptr_array_add (runtime_argv, "--pid-file");
|
"--pid-file", opt_pid_file,
|
||||||
g_ptr_array_add (runtime_argv, pid_file);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (terminal) {
|
if (csname != NULL) {
|
||||||
g_ptr_array_add(runtime_argv, "--console-socket");
|
add_argv(runtime_argv,
|
||||||
g_ptr_array_add(runtime_argv, csname);
|
"--console-socket", csname,
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the exec arguments. */
|
/* Set the exec arguments. */
|
||||||
if (exec) {
|
if (opt_exec) {
|
||||||
g_ptr_array_add(runtime_argv, "--process");
|
add_argv(runtime_argv,
|
||||||
g_ptr_array_add(runtime_argv, exec_process_spec);
|
"--process", opt_exec_process_spec,
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Container name comes last. */
|
/* Container name comes last. */
|
||||||
g_ptr_array_add(runtime_argv, cid);
|
add_argv(runtime_argv, opt_cid, NULL);
|
||||||
g_ptr_array_add(runtime_argv, NULL);
|
end_argv(runtime_argv);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have to fork here because the current runC API dups the stdio of the
|
* We have to fork here because the current runC API dups the stdio of the
|
||||||
|
@ -1047,8 +1164,8 @@ int main(int argc, char *argv[])
|
||||||
close(slavefd_stderr);
|
close(slavefd_stderr);
|
||||||
|
|
||||||
ninfo("about to waitpid: %d", create_pid);
|
ninfo("about to waitpid: %d", create_pid);
|
||||||
if (terminal) {
|
if (csname != NULL) {
|
||||||
guint terminal_watch = g_unix_fd_add (csfd, G_IO_IN, terminal_accept_cb, csname);
|
guint terminal_watch = g_unix_fd_add (console_socket_fd, G_IO_IN, terminal_accept_cb, csname);
|
||||||
g_child_watch_add (create_pid, runtime_exit_cb, NULL);
|
g_child_watch_add (create_pid, runtime_exit_cb, NULL);
|
||||||
g_main_loop_run (main_loop);
|
g_main_loop_run (main_loop);
|
||||||
g_source_remove (terminal_watch);
|
g_source_remove (terminal_watch);
|
||||||
|
@ -1058,7 +1175,7 @@ int main(int argc, char *argv[])
|
||||||
int old_errno = errno;
|
int old_errno = errno;
|
||||||
kill(create_pid, SIGKILL);
|
kill(create_pid, SIGKILL);
|
||||||
errno = old_errno;
|
errno = old_errno;
|
||||||
pexit("Failed to wait for `runtime %s`", exec ? "exec" : "create");
|
pexit("Failed to wait for `runtime %s`", opt_exec ? "exec" : "create");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1077,11 +1194,11 @@ int main(int argc, char *argv[])
|
||||||
nexit("Failed to create container: exit status %d", WEXITSTATUS(runtime_status));
|
nexit("Failed to create container: exit status %d", WEXITSTATUS(runtime_status));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (terminal && masterfd_stdout == -1)
|
if (opt_terminal && masterfd_stdout == -1)
|
||||||
nexit("Runtime did not set up terminal");
|
nexit("Runtime did not set up terminal");
|
||||||
|
|
||||||
/* Read the pid so we can wait for the process to exit */
|
/* Read the pid so we can wait for the process to exit */
|
||||||
g_file_get_contents(pid_file, &contents, NULL, &err);
|
g_file_get_contents(opt_pid_file, &contents, NULL, &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
nwarn("Failed to read pidfile: %s", err->message);
|
nwarn("Failed to read pidfile: %s", err->message);
|
||||||
g_error_free(err);
|
g_error_free(err);
|
||||||
|
@ -1092,104 +1209,21 @@ int main(int argc, char *argv[])
|
||||||
ninfo("container PID: %d", cpid);
|
ninfo("container PID: %d", cpid);
|
||||||
|
|
||||||
/* Setup endpoint for attach */
|
/* Setup endpoint for attach */
|
||||||
char attach_symlink_dir_path[PATH_MAX] = { 0 };
|
_cleanup_free_ char *attach_symlink_dir_path = NULL;
|
||||||
struct sockaddr_un attach_addr = {0};
|
if (!opt_exec) {
|
||||||
|
attach_symlink_dir_path = setup_attach_socket();
|
||||||
if (!exec) {
|
|
||||||
attach_addr.sun_family = AF_UNIX;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create a symlink so we don't exceed unix domain socket
|
|
||||||
* path length limit.
|
|
||||||
*/
|
|
||||||
snprintf(attach_symlink_dir_path, PATH_MAX, "/var/run/crio/%s", cuuid);
|
|
||||||
if (unlink(attach_symlink_dir_path) == -1 && errno != ENOENT) {
|
|
||||||
pexit("Failed to remove existing symlink for attach socket directory");
|
|
||||||
}
|
|
||||||
if (symlink(bundle_path, attach_symlink_dir_path) == -1)
|
|
||||||
pexit("Failed to create symlink for attach socket");
|
|
||||||
|
|
||||||
snprintf(attach_sock_path, PATH_MAX, "/var/run/crio/%s/attach", cuuid);
|
|
||||||
ninfo("attach sock path: %s", attach_sock_path);
|
|
||||||
|
|
||||||
strncpy(attach_addr.sun_path, attach_sock_path, sizeof(attach_addr.sun_path) - 1);
|
|
||||||
ninfo("addr{sun_family=AF_UNIX, sun_path=%s}", attach_addr.sun_path);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We make the socket non-blocking to avoid a race where client aborts connection
|
|
||||||
* before the server gets a chance to call accept. In that scenario, the server
|
|
||||||
* accept blocks till a new client connection comes in.
|
|
||||||
*/
|
|
||||||
afd = socket(AF_UNIX, SOCK_SEQPACKET|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
|
|
||||||
if (afd == -1)
|
|
||||||
pexit("Failed to create attach socket");
|
|
||||||
|
|
||||||
if (fchmod(afd, 0700))
|
|
||||||
pexit("Failed to change attach socket permissions");
|
|
||||||
|
|
||||||
if (bind(afd, (struct sockaddr *)&attach_addr, sizeof(struct sockaddr_un)) == -1)
|
|
||||||
pexit("Failed to bind attach socket: %s", attach_sock_path);
|
|
||||||
|
|
||||||
if (listen(afd, 10) == -1)
|
|
||||||
pexit("Failed to listen on attach socket: %s", attach_sock_path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup fifo for reading in terminal resize and other stdio control messages */
|
if (!opt_exec) {
|
||||||
_cleanup_close_ int ctlfd = -1;
|
setup_terminal_control_fifo();
|
||||||
_cleanup_close_ int dummyfd = -1;
|
|
||||||
if (!exec) {
|
|
||||||
snprintf(ctl_fifo_path, PATH_MAX, "%s/ctl", bundle_path);
|
|
||||||
ninfo("ctl fifo path: %s", ctl_fifo_path);
|
|
||||||
|
|
||||||
if (mkfifo(ctl_fifo_path, 0666) == -1)
|
|
||||||
pexit("Failed to mkfifo at %s", ctl_fifo_path);
|
|
||||||
|
|
||||||
ctlfd = open(ctl_fifo_path, O_RDONLY|O_NONBLOCK|O_CLOEXEC);
|
|
||||||
if (ctlfd == -1)
|
|
||||||
pexit("Failed to open control fifo");
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Open a dummy writer to prevent getting flood of POLLHUPs when
|
|
||||||
* last writer closes.
|
|
||||||
*/
|
|
||||||
dummyfd = open(ctl_fifo_path, O_WRONLY|O_CLOEXEC);
|
|
||||||
if (dummyfd == -1)
|
|
||||||
pexit("Failed to open dummy writer for fifo");
|
|
||||||
|
|
||||||
ninfo("ctlfd: %d", ctlfd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send the container pid back to parent */
|
/* Send the container pid back to parent */
|
||||||
if (!exec) {
|
if (!opt_exec) {
|
||||||
write_sync_fd(sync_pipe_fd, cpid, NULL);
|
write_sync_fd(sync_pipe_fd, cpid, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup OOM notification for container process */
|
setup_oom_handling(cpid);
|
||||||
memory_cgroup_path = process_cgroup_subsystem_path(cpid, "memory");
|
|
||||||
if (!memory_cgroup_path) {
|
|
||||||
nexit("Failed to get memory cgroup path");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool oom_handling_enabled = true;
|
|
||||||
char memory_cgroup_file_path[PATH_MAX];
|
|
||||||
snprintf(memory_cgroup_file_path, PATH_MAX, "%s/cgroup.event_control", memory_cgroup_path);
|
|
||||||
if ((cfd = open(memory_cgroup_file_path, O_WRONLY | O_CLOEXEC)) == -1) {
|
|
||||||
nwarn("Failed to open %s", memory_cgroup_file_path);
|
|
||||||
oom_handling_enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oom_handling_enabled) {
|
|
||||||
snprintf(memory_cgroup_file_path, PATH_MAX, "%s/memory.oom_control", memory_cgroup_path);
|
|
||||||
if ((ofd = open(memory_cgroup_file_path, O_RDONLY | O_CLOEXEC)) == -1)
|
|
||||||
pexit("Failed to open %s", memory_cgroup_file_path);
|
|
||||||
|
|
||||||
if ((oom_efd = eventfd(0, EFD_CLOEXEC)) == -1)
|
|
||||||
pexit("Failed to create eventfd");
|
|
||||||
|
|
||||||
wb = snprintf(buf, BUF_SIZE, "%d %d", oom_efd, ofd);
|
|
||||||
if (write_all(cfd, buf, wb) < 0)
|
|
||||||
pexit("Failed to write to cgroup.event_control");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (masterfd_stdout >= 0) {
|
if (masterfd_stdout >= 0) {
|
||||||
g_unix_fd_add (masterfd_stdout, G_IO_IN, stdio_cb, GINT_TO_POINTER(STDOUT_PIPE));
|
g_unix_fd_add (masterfd_stdout, G_IO_IN, stdio_cb, GINT_TO_POINTER(STDOUT_PIPE));
|
||||||
|
@ -1200,23 +1234,8 @@ int main(int argc, char *argv[])
|
||||||
num_stdio_fds++;
|
num_stdio_fds++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add the OOM event fd to epoll */
|
if (opt_timeout > 0) {
|
||||||
if (oom_handling_enabled) {
|
g_timeout_add_seconds (opt_timeout, timeout_cb, NULL);
|
||||||
g_unix_fd_add (oom_efd, G_IO_IN, oom_cb, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add the attach socket to epoll */
|
|
||||||
if (afd > 0) {
|
|
||||||
g_unix_fd_add (afd, G_IO_IN, attach_cb, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add control fifo fd to epoll */
|
|
||||||
if (ctlfd > 0) {
|
|
||||||
g_unix_fd_add (ctlfd, G_IO_IN, ctrl_cb, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeout > 0) {
|
|
||||||
g_timeout_add_seconds (timeout, timeout_cb, NULL);
|
|
||||||
}
|
}
|
||||||
g_main_loop_run (main_loop);
|
g_main_loop_run (main_loop);
|
||||||
|
|
||||||
|
@ -1242,28 +1261,17 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!exec) {
|
if (!opt_exec) {
|
||||||
_cleanup_free_ char *status_str = NULL;
|
_cleanup_free_ char *status_str = g_strdup_printf("%d", exit_status);
|
||||||
ret = asprintf(&status_str, "%d", exit_status);
|
if (!g_file_set_contents("exit", status_str, -1, &err))
|
||||||
if (ret < 0) {
|
nexit("Failed to write %s to exit file: %s\n",
|
||||||
pexit("Failed to allocate memory for status");
|
status_str, err->message);
|
||||||
}
|
|
||||||
g_file_set_contents("exit", status_str,
|
|
||||||
strlen(status_str), &err);
|
|
||||||
if (err) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"Failed to write %s to exit file: %s\n",
|
|
||||||
status_str, err->message);
|
|
||||||
g_error_free(err);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* Send the command exec exit code back to the parent */
|
/* Send the command exec exit code back to the parent */
|
||||||
write_sync_fd(sync_pipe_fd, exit_status, exit_message);
|
write_sync_fd(sync_pipe_fd, exit_status, exit_message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attach_symlink_dir_path[0] != 0 &&
|
if (attach_symlink_dir_path != NULL &&
|
||||||
unlink(attach_symlink_dir_path) == -1 && errno != ENOENT) {
|
unlink(attach_symlink_dir_path) == -1 && errno != ENOENT) {
|
||||||
pexit("Failed to remove symlink for attach socket directory");
|
pexit("Failed to remove symlink for attach socket directory");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue