From 76f7d7d1afa0b16b69adf306e6e352132971a55d Mon Sep 17 00:00:00 2001 From: Antoine Date: Sun, 19 Jul 2020 23:17:39 +0200 Subject: [PATCH] add interactive mode for /bin/sh entrypoint --- src/container.c | 6 ++-- src/data.c | 39 ++++++++++++++++++++++++ src/main.c | 1 + src/prototype.h | 8 ++++- src/system.c | 81 ++++++++++++++++++++++++++++++++++++++----------- src/type.h | 3 ++ 6 files changed, 117 insertions(+), 21 deletions(-) diff --git a/src/container.c b/src/container.c index a18c0a3..5468891 100644 --- a/src/container.c +++ b/src/container.c @@ -39,12 +39,12 @@ int container_create(void *stuff) } // run container command - if (run_subprocess_async(cloneArgs->argv) != 0) + if (run_subprocess_async(cloneArgs->argc, cloneArgs->argv) != 0) { error_handler_container(c, "failed to execvp arguments"); } - free(c); // free twice don't know why but maybe clone lost + free(c); // free twice don't know why but maybe clone lost c reference c = NULL; // we end container @@ -75,7 +75,7 @@ pid_t run_container(container_t *c) { error_handler_container(c, "failed to run_container clone"); } - // lets wait on our child process here before we, the parent, exits + // lets wait on our child process here before we, the parent, exit if (waitpid(pid, NULL, 0) == -1) { error_handler_container(c, "failed to wait pid %d", pid); diff --git a/src/data.c b/src/data.c index ed77411..4e5844f 100644 --- a/src/data.c +++ b/src/data.c @@ -68,4 +68,43 @@ char *read_infinite_fd(int fd) return stdout_buffer; } +/** + * Read stdin and write to file descriptor + */ +void write_infinite_fd(int fd) +{ + char *stdin_buffer = new_array(1024); + int x = 0; + printf("$ "); + fflush(stdout); + + while ((x = read(STDIN_FILENO, stdin_buffer, sizeof(stdin_buffer))) > 0) + { + write(fd, stdin_buffer, sizeof(stdin_buffer)); + init_array(stdin_buffer, sizeof(stdin_buffer)); + printf("$ "); + fflush(stdout); + } + free(stdin_buffer); +} + +/** + * Function use to filter char* array + * copy src char* into dst if function is true + * Return dst length + */ +int filter_char_array(int src_length, char **src, char **dst, char_predicate filter_func) +{ + int dst_size = 0; + for (int i = 0; i < src_length; i++) + { + if ((*filter_func)(src[i])) + { + dst[dst_size] = src[i]; + dst_size++; + } + } + return dst_size; +} + #endif diff --git a/src/main.c b/src/main.c index 491165d..f400f50 100644 --- a/src/main.c +++ b/src/main.c @@ -12,6 +12,7 @@ int main(int argc, char *const argv[]) } struct clone_args cloneArgs; + cloneArgs.argc = argc - 1; cloneArgs.argv = &argv[1]; cloneArgs.hostname = "container-hostname"; diff --git a/src/prototype.h b/src/prototype.h index be1a0c3..b4099f3 100644 --- a/src/prototype.h +++ b/src/prototype.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "./type.h" @@ -19,15 +20,20 @@ void error(const char *sys_msg, ...); void last_error(const char *sys_msg, ...); // system.c -int run_subprocess_async(char *const *argv); +int run_subprocess_async(int argc, char *const *argv); int run_subprocess(char *const *argv); int pivot_root(char *mount_dir); int clean_pivot_root(char *a); void remount(); +bool is_interactive(char *str); +bool is_not_interactive(char *str); +bool contain_interactive(int argc, char *const *argv); // data.c char *new_array(size_t size); void init_array(char *arr, size_t size); char *read_infinite_fd(int fd); +void write_infinite_fd(int fd); +int filter_char_array(int src_length, char **src, char **dst, char_predicate filter_func); #endif diff --git a/src/system.c b/src/system.c index d095f0b..c22bfe4 100644 --- a/src/system.c +++ b/src/system.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -111,13 +112,21 @@ int run_subprocess(char *const *argv) /** * Run external binary into new sub process */ -int run_subprocess_async(char *const *argv) +int run_subprocess_async(int argc, char *const *argv) { pid_t pid; + bool run_interactive = contain_interactive(argc, argv); + // if container is running in interactive mode remove "-i" from argv + if (run_interactive) + { + char **dst_argv = (char **)malloc(sizeof(char *) * argc); + argc = filter_char_array(argc, (char **)argv, dst_argv, is_not_interactive); + argv = dst_argv; + } - // pipe to permit child => parent comunication - int pipefd[2]; - pipe(pipefd); + // pipe to permit parent => child comunication + int pipe_parent_to_child_fd[2]; + pipe(pipe_parent_to_child_fd); if ((pid = fork()) == -1) { @@ -125,13 +134,10 @@ int run_subprocess_async(char *const *argv) } else if (pid == 0) { - close(pipefd[0]); // close reading end in the child + close(pipe_parent_to_child_fd[1]); // close writing end in the child printf("[CHILD] : running\n"); - dup2(pipefd[1], 1); // send stdout to the pipe - dup2(pipefd[1], 2); // send stderr to the pipe - - close(pipefd[1]); // this descriptor is no longer needed + dup2(pipe_parent_to_child_fd[0], STDIN_FILENO); // send pipe to the stdin errno = execvp(argv[0], argv); return errno; @@ -140,20 +146,23 @@ int run_subprocess_async(char *const *argv) { int child_status; - close(pipefd[1]); // close the write end of the pipe in the parent + close(pipe_parent_to_child_fd[0]); // close the read end of the pipe in the parent + // if container is running in interactive mode + if (run_interactive) + { + // read stdin write infinity + write_infinite_fd(pipe_parent_to_child_fd[1]); + } + + close(pipe_parent_to_child_fd[1]); // this descriptor is no longer needed + + // wait child if long task is in progress waitpid(pid, &child_status, 0); if (WIFEXITED(child_status)) { - char *stdout_buffer = read_infinite_fd(pipefd[0]); - printf("[PARENT] child stdout : \n%s\n", stdout_buffer); - free(stdout_buffer); - - close(pipefd[0]); // close the descriptor is no longer needed - int es = WEXITSTATUS(child_status); printf("[PARENT] Exit status was %d\n", es); - return es; } } @@ -161,4 +170,42 @@ int run_subprocess_async(char *const *argv) return EXIT_FAILURE; } +/** + * Return true if char* str is equal to "-i" + */ +bool is_interactive(char *str) +{ + if (strcmp(str, "-i") == 0) + { + return true; + } + return false; +} + +/** + * Return true if char* str is not equal to "-i" + * opposite of is_interactive + */ +bool is_not_interactive(char *str) +{ + return !is_interactive(str); +} + +/** + * Return true if argv char* array contain "-i" + */ +bool contain_interactive(int argc, char *const *argv) +{ + bool res = false; + for (int i = 0; i < argc; i++) + { + if (is_interactive(argv[i])) + { + res = true; + break; + } + } + return res; +} + #endif diff --git a/src/type.h b/src/type.h index c07897c..65bd736 100644 --- a/src/type.h +++ b/src/type.h @@ -6,6 +6,7 @@ */ struct clone_args { + int argc; char *const *argv; const char *hostname; }; @@ -19,4 +20,6 @@ typedef struct container_t struct clone_args cloneArgs; } container_t; +typedef bool (*char_predicate)(char *); + #endif