Grooooot 7be59a7c67 iSulad: sync openeuler at 3.6
Signed-off-by: Grooooot <isula@huawei.com>
2020-03-06 14:58:03 +08:00

1019 lines
25 KiB
C

/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved.
* iSulad licensed under the Mulan PSL v1.
* You can use this software according to the terms and conditions of the Mulan PSL v1.
* You may obtain a copy of Mulan PSL v1 at:
* http://license.coscl.org.cn/MulanPSL
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
* PURPOSE.
* See the Mulan PSL v1 for more details.
* Author: leizhongkai
* Create: 2020-1-20
* Description: process operation encapsulation
******************************************************************************/
#define _GNU_SOURCE
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <sys/wait.h>
#include <semaphore.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <termios.h>
#include "common.h"
#include "process.h"
#define MAX_EVENTS 100
#define DEFAULT_IO_COPY_BUF (16*1024)
extern int g_log_fd;
typedef int (*epoll_loop_callback_t)(int fd, uint32_t event, void *data);
struct epoll_loop_handler {
epoll_loop_callback_t cb;
int epfd;
int cbfd;
void *cbdata;
};
static shim_client_process_state* load_process()
{
parser_error err = NULL;
shim_client_process_state *p_state = NULL;
p_state = shim_client_process_state_parse_file("process.json", NULL, &err);
if (p_state == NULL) {
write_message(g_log_fd, ERR_MSG, "parse process state failed");
goto out;
}
out:
if (err != NULL) {
free(err);
}
return p_state;
}
static int open_fifo_noblock(const char *path, mode_t mode)
{
int fd = -1;
// By default, We consider that the file has been created by isulad
fd = open_no_inherit(path, mode | O_NONBLOCK, -1);
if (fd < 0) {
write_message(g_log_fd, ERR_MSG, "open fifo file failed:%d", SHIM_SYS_ERR(errno));
return -1;
}
return fd;
}
static int receive_fd(int sock)
{
u_char *pfd = NULL;
int fd = -1;
int cmsgsize = CMSG_LEN(sizeof(int));
struct cmsghdr* cmptr = (struct cmsghdr*)calloc(1, cmsgsize);
if (cmptr == NULL) {
return -1;
}
char buf[32] = { 0 };
struct iovec iov[1];
iov[0].iov_base = buf;
iov[0].iov_len = sizeof(buf);
struct msghdr msg;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_control = cmptr;
msg.msg_controllen = cmsgsize;
int ret = recvmsg(sock, &msg, 0);
if (ret == -1) {
free(cmptr);
write_message(g_log_fd, ERR_MSG, "get console fd failed:%d", SHIM_SYS_ERR(errno));
return -1;
}
pfd = CMSG_DATA(cmptr);
fd = *(int *)pfd;
free(cmptr);
return fd;
}
static bool check_fd(int fd)
{
struct termios term;
int ret = ioctl(fd, TCGETS, &term);
if (ret != 0) {
return false;
}
return true;
}
static int add_io_dispatch(int epfd, io_thread_t *io_thd, int from, int to)
{
int ret = SHIM_ERR;
if (io_thd == NULL || io_thd->ioc == NULL) {
return SHIM_ERR;
}
io_copy_t *ioc = io_thd->ioc;
fd_node_t *fn = (fd_node_t *)calloc(1, sizeof(fd_node_t));
if (fn == NULL) {
return SHIM_ERR;
}
fn->fd = to;
fn->next = NULL;
pthread_mutex_lock(&(ioc->mutex));
// add src fd
if (from != -1 && ioc->fd_from == -1) {
ioc->fd_from = from;
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.ptr = io_thd;
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, from, &ev);
if (ret != SHIM_OK) {
write_message(g_log_fd, ERR_MSG, "add fd %d to epoll loop failed:%d", from, SHIM_SYS_ERR(errno));
pthread_mutex_unlock(&(ioc->mutex));
return SHIM_ERR;
}
}
// add dest fd
if (to != -1) {
if (ioc->fd_to == NULL) {
ioc->fd_to = fn;
} else {
fd_node_t *tmp = ioc->fd_to;
while (tmp->next != NULL) {
tmp = tmp->next;
}
tmp->next = fn;
}
}
pthread_mutex_unlock(&(ioc->mutex));
return SHIM_OK;
}
static void remove_io_dispatch(io_thread_t *io_thd, int from, int to)
{
if (io_thd == NULL || io_thd->ioc == NULL) {
return;
}
io_copy_t *ioc = io_thd->ioc;
pthread_mutex_lock(&(ioc->mutex));
fd_node_t *tmp = NULL;
do {
// remove src fd
if (from != -1 && from == ioc->fd_from) {
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = ioc->fd_from;
(void)epoll_ctl(io_thd->epfd, EPOLL_CTL_DEL, ioc->fd_from, &ev);
}
// remove dest fd
if (ioc->fd_to == NULL) {
break;
}
if (ioc->fd_to->fd == to) {
tmp = ioc->fd_to;
ioc->fd_to = ioc->fd_to->next;
break;
}
fd_node_t *pre = NULL;
tmp = ioc->fd_to->next;
while (tmp != NULL && tmp->fd != to) {
pre = tmp;
tmp = tmp->next;
}
if (tmp != NULL) {
pre->next = tmp->next;
}
} while (0);
if (tmp != NULL) {
free(tmp);
}
pthread_mutex_unlock(&(ioc->mutex));
}
static void* task_io_copy(void *data)
{
io_thread_t *io_thd = (io_thread_t*)data;
if (io_thd == NULL || io_thd->ioc == NULL) {
return NULL;
}
io_copy_t *ioc = io_thd->ioc;
char *buf = calloc(1, DEFAULT_IO_COPY_BUF + 1);
if (buf == NULL) {
_exit(EXIT_FAILURE);
}
for (;;) {
memset(buf, 0, DEFAULT_IO_COPY_BUF);
sem_wait(&(io_thd->sem_thd));
if (io_thd->shutdown) {
break;
}
int r_count = read(ioc->fd_from, buf, DEFAULT_IO_COPY_BUF);
if (r_count == -1) {
// If errno == EAGAIN, that means we have read all data
if (errno == EAGAIN || errno == EINTR) {
continue;
}
break;
} else if (r_count == 0) {
// End of file. The remote has closed the connection.
break;
} else {
fd_node_t *fn = ioc->fd_to;
for (; fn != NULL; fn = fn->next) {
int w_count;
w_count = write_nointr(fn->fd, buf, r_count);
if (w_count < 0) {
// remove the write fd
remove_io_dispatch(io_thd, -1, fn->fd);
}
}
}
}
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = ioc->fd_from;
(void)epoll_ctl(io_thd->epfd, EPOLL_CTL_DEL, ioc->fd_from, &ev);
free(buf);
return NULL;
}
static void do_io_copy(int fd, uint32_t event, void *data)
{
io_thread_t *thd = (io_thread_t*)data;
if (thd->ioc == NULL || fd != thd->ioc->fd_from) {
return;
}
if (event & EPOLLIN) {
sem_post(&thd->sem_thd);
} else if (event & EPOLLHUP) {
thd->shutdown = true;
sem_post(&thd->sem_thd);
}
return;
}
static int process_io_start(process_t *p, int std_id)
{
int ret = SHIM_ERR;
io_thread_t *io_thd = NULL;
io_copy_t *ioc = NULL;
ioc = (io_copy_t *)calloc(1, sizeof(io_copy_t));
if (ioc == NULL) {
goto failure;
}
ioc->id = std_id;
ioc->fd_from = -1;
ioc->fd_to = NULL;
if (pthread_mutex_init(&(ioc->mutex), NULL) != 0) {
goto failure;
}
io_thd = (io_thread_t *)calloc(1, sizeof(io_thread_t));
if (io_thd == NULL) {
goto failure;
}
if (sem_init(&io_thd->sem_thd, 0, 0) == -1) {
write_message(g_log_fd, ERR_MSG, "sem init failed:%d", SHIM_SYS_ERR(errno));
goto failure;
}
io_thd->epfd = p->io_loop_fd;
io_thd->ioc = ioc;
io_thd->shutdown = false;
p->io_threads[std_id] = io_thd;
ret = pthread_create(&(io_thd->tid), NULL, task_io_copy, io_thd);
if (ret != SHIM_OK) {
write_message(g_log_fd, ERR_MSG, "thread io copy create failed:%d", SHIM_SYS_ERR(errno));
goto failure;
}
ret = SHIM_OK;
return ret;
failure:
if (ioc != NULL) {
pthread_mutex_destroy(&(ioc->mutex));
free(ioc);
}
if (io_thd != NULL) {
free(io_thd);
}
return SHIM_ERR;
}
static int start_io_copy_threads(process_t *p)
{
int ret = SHIM_ERR;
int i;
for (i = 0; i < 3; i++) {
ret = process_io_start(p, i);
if (ret != SHIM_OK) {
return SHIM_ERR;
}
}
return SHIM_OK;
}
static void destory_io_thread(process_t *p, int std_id)
{
io_thread_t *io_thd = p->io_threads[std_id];
if (io_thd == NULL) {
return;
}
io_thd->shutdown = true;
sem_post(&io_thd->sem_thd);
pthread_join(io_thd->tid, NULL);
if (io_thd->ioc != NULL) {
free(io_thd->ioc);
}
free(io_thd);
p->io_threads[std_id] = NULL;
}
static int connect_to_isulad(process_t *p, int std_id, const char *isulad_stdio, int fd)
{
mode_t mode;
int fd_isulad = -1;
int *fd_from = NULL;
int *fd_to = NULL;
if (std_id == stdid_in) {
mode = O_RDONLY;
fd_from = &fd_isulad;
fd_to = &fd;
} else {
mode = O_WRONLY;
fd_from = &fd;
fd_to = &fd_isulad;
}
if (isulad_stdio != NULL && file_exists(isulad_stdio)) {
fd_isulad = open_fifo_noblock(isulad_stdio, mode);
if (fd_isulad < 0) {
return SHIM_ERR;
}
}
if (*fd_from != -1) {
return add_io_dispatch(p->io_loop_fd, p->io_threads[std_id], *fd_from, *fd_to);
}
// if no I/O source is available, the I/O thread nead to be destroyed
destory_io_thread(p, std_id);
return SHIM_OK;
}
static void* task_console_accept(void *data)
{
int conn_fd = -1;
int recv_fd = -1;
int ret = SHIM_ERR;
console_accept_t *ac = (console_accept_t*)data;
conn_fd = accept(ac->listen_fd, NULL, NULL);
if (conn_fd < 0) {
write_message(g_log_fd, ERR_MSG, "accept from fd %d failed:%d", ac->listen_fd, SHIM_SYS_ERR(errno));
exit(EXIT_FAILURE);
}
recv_fd = receive_fd(conn_fd);
if (check_fd(recv_fd) != true) {
write_message(g_log_fd, ERR_MSG, "check console fd failed");
exit(EXIT_FAILURE);
}
// do console io copy
//
// p.state.stdin---->runtime.console
ret = connect_to_isulad(ac->p, stdid_in, ac->p->state->isulad_stdin, recv_fd);
if (ret != SHIM_OK) {
exit(EXIT_FAILURE);
}
// p.state.stdout<------runtime.console
ret = connect_to_isulad(ac->p, stdid_out, ac->p->state->isulad_stdout, recv_fd);
if (ret != SHIM_OK) {
exit(EXIT_FAILURE);
}
// if the terminal is used, we do not need to active the io copy of stderr pipe
destory_io_thread(ac->p, stdid_err);
// release listen socket
close_fd(&ac->listen_fd);
if (ac->p->console_sock_path != NULL) {
unlink(ac->p->console_sock_path);
free(ac->p->console_sock_path);
ac->p->console_sock_path = NULL;
}
free(ac);
return NULL;
}
static void* task_io_loop(void *data)
{
process_t *p = (process_t*)data;
int wait_fds = 0;
struct epoll_event evs[MAX_EVENTS];
int i;
p->io_loop_fd = epoll_create1(EPOLL_CLOEXEC);
if (p->io_loop_fd < 0) {
write_message(g_log_fd, ERR_MSG, "epoll create failed:%d", SHIM_SYS_ERR(errno));
exit(EXIT_FAILURE);
}
// begin wait
while (1) {
wait_fds = epoll_wait(p->io_loop_fd, evs, MAX_EVENTS, -1);
if (wait_fds < 0) {
if (errno == EINTR) {
continue;
}
_exit(EXIT_FAILURE);
}
for (i = 0; i < wait_fds; i++) {
io_thread_t *thd_io = (io_thread_t*)evs[i].data.ptr;
do_io_copy(thd_io->ioc->fd_from, evs[i].events, thd_io);
}
}
}
static int new_temp_console_path(process_t *p)
{
#define RAND_NUM_LEN 9
int ret = SHIM_ERR;
char str_rand[RAND_NUM_LEN + 1] = { 0 };
ret = generate_random_str(str_rand, RAND_NUM_LEN);
if (ret != SHIM_OK) {
return SHIM_ERR;
}
p->console_sock_path = (char *)calloc(1, MAX_CONSOLE_SOCK_LEN + 1);
if (p->console_sock_path == NULL) {
return SHIM_ERR;
}
snprintf(p->console_sock_path, MAX_CONSOLE_SOCK_LEN, "/tmp/isulad%s-pty.sock", str_rand);
return SHIM_OK;
}
static int console_init(process_t *p)
{
int ret = SHIM_ERR;
int fd = -1;
struct sockaddr_un addr;
console_accept_t* ac = NULL;
fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
return SHIM_SYS_ERR(errno);
}
(void)memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
(void)strcpy(addr.sun_path, p->console_sock_path);
// bind
ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
if (ret < 0) {
write_message(g_log_fd, ERR_MSG, "bind console fd failed:%d", SHIM_SYS_ERR(errno));
goto failure;
}
// listen
ret = listen(fd, 2);
if (ret < 0) {
write_message(g_log_fd, ERR_MSG, "listen console fd failed:%d", SHIM_SYS_ERR(errno));
goto failure;
}
ac = (console_accept_t*)calloc(1, sizeof(console_accept_t));
if (ac == NULL) {
goto failure;
}
ac->p = p;
ac->listen_fd = fd;
pthread_t tid_accept;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
ret = pthread_create(&tid_accept, &attr, task_console_accept, ac);
if (ret != SHIM_OK) {
goto failure;
}
return SHIM_OK;
failure:
close_fd(&fd);
if (ac != NULL) {
free(ac);
}
return SHIM_ERR;
}
static stdio_t* initialize_io(process_t *p)
{
int ret = SHIM_ERR;
int stdio_fd[3][2] = { {-1, -1}, {-1, -1}, {-1, -1} };
int i, j;
stdio_t *stdio = (stdio_t *)calloc(1, sizeof(stdio_t));
p->stdio = (stdio_t *)calloc(1, sizeof(stdio_t));
if (p->stdio == NULL || stdio == NULL) {
goto failure;
}
if ((pipe2(stdio_fd[0], O_CLOEXEC | O_NONBLOCK) != 0) ||
(pipe2(stdio_fd[1], O_CLOEXEC | O_NONBLOCK) != 0) ||
(pipe2(stdio_fd[2], O_CLOEXEC | O_NONBLOCK) != 0)) {
write_message(g_log_fd, ERR_MSG, "open pipe failed when init io:%d", SHIM_SYS_ERR(errno));
goto failure;
}
p->stdio->in = stdio_fd[0][0];// r
stdio->in = stdio_fd[0][1]; // w
p->stdio->out = stdio_fd[1][1];// w
stdio->out = stdio_fd[1][0];// r
p->stdio->err = stdio_fd[2][1];// w
stdio->err = stdio_fd[2][0];// r
for (i = 0; i < 3; i++) {
for (j = 0; j < 2; j++) {
ret = fchown(stdio_fd[i][j], p->state->root_uid, p->state->root_gid);
if (ret != SHIM_OK) {
goto failure;
}
}
}
return stdio;
failure:
if (stdio != NULL) {
free(stdio);
stdio = NULL;
}
if (p->stdio != NULL) {
free(p->stdio);
p->stdio = NULL;
}
for (i = 0; i < 3; i++) {
for (j = 0; j < 2; j++) {
if (stdio_fd[i][j] > 0) {
close(stdio_fd[i][j]);
}
}
}
return NULL;
}
static int open_terminal_io(process_t *p)
{
int ret = SHIM_ERR;
ret = new_temp_console_path(p);
if (ret != SHIM_OK) {
write_message(g_log_fd, ERR_MSG, "get temp console sock path failed");
return SHIM_ERR;
}
// begin listen and accept fd from p->console_sock_path
ret = console_init(p);
if (ret != SHIM_OK) {
write_message(g_log_fd, ERR_MSG, "init console failed:%d", ret);
return SHIM_ERR;
}
return SHIM_OK;
}
static int open_generic_io(process_t *p)
{
int ret = SHIM_ERR;
stdio_t *io = initialize_io(p);
if (io == NULL) {
return SHIM_ERR;
}
p->shim_io = io;
// stdin
ret = connect_to_isulad(p, stdid_in, p->state->isulad_stdin, io->in);
if (ret != SHIM_OK) {
return SHIM_ERR;
}
// stdout
ret = connect_to_isulad(p, stdid_out, p->state->isulad_stdout, io->out);
if (ret != SHIM_OK) {
return SHIM_ERR;
}
// stderr
ret = connect_to_isulad(p, stdid_err, p->state->isulad_stderr, io->err);
if (ret != SHIM_OK) {
return SHIM_ERR;
}
return SHIM_OK;
}
static void adapt_for_isulad_stdin(process_t *p)
{
// iSulad: close stdin pipe if we do not want open_stdin with container stdin just like lxc
if (!p->state->open_stdin && !file_exists(p->state->isulad_stdin)) {
if (p->shim_io != NULL && p->shim_io->in != -1) {
close(p->shim_io->in);
p->shim_io->in = -1;
}
}
}
process_t* new_process(char *id, char *bundle, char *runtime)
{
shim_client_process_state* p_state;
process_t* p = NULL;
int i;
p_state = load_process();
if (p_state == NULL) {
return NULL;
}
p = (process_t*)calloc(1, sizeof(process_t));
if (p == NULL) {
return NULL;
}
p->id = id;
p->bundle = bundle;
p->runtime = runtime;
p->state = p_state;
p->console_sock_path = NULL;
p->exit_fd = -1;
p->io_loop_fd = -1;
p->ctr_pid = -1;
p->stdio = NULL;
p->shim_io = NULL;
for (i = 0; i < 3; i ++) {
p->io_threads[i] = NULL;
}
return p;
}
int open_io(process_t *p)
{
int ret = SHIM_ERR;
ret = start_io_copy_threads(p);
if (ret != SHIM_OK) {
return SHIM_ERR;
}
if (p->state->terminal) {
return open_terminal_io(p);
}
return open_generic_io(p);
}
int process_io_init(process_t *p)
{
int ret = SHIM_ERR;
pthread_t tid_loop;
ret = pthread_create(&tid_loop, NULL, task_io_loop, p);
if (ret != SHIM_OK) {
return SHIM_SYS_ERR(errno);
}
return SHIM_OK;
}
static void get_runtime_cmd(process_t *p, const char *log_path, const char *pid_path, const char *process_desc,
const char *params[])
{
int i = 0;
int j;
params[i++] = p->runtime;
for (j = 0; j < p->state->runtime_args_len; j++) {
params[i++] = p->state->runtime_args[j];
}
params[i++] = "--log";
params[i++] = log_path;
params[i++] = "--log-format";
params[i++] = "json";
if (p->state->exec && process_desc != NULL) {
params[i++] = "exec";
params[i++] = "-d";
params[i++] = "--process";
params[i++] = process_desc;
} else {
params[i++] = "create";
params[i++] = "--bundle";
params[i++] = p->bundle;
}
params[i++] = "--pid-file";
params[i++] = pid_path;
if (p->console_sock_path != NULL) {
params[i++] = "--console-socket";
params[i++] = p->console_sock_path;
}
params[i++] = p->id;
}
static int reap_container(int ctr_pid, int *status)
{
#define EXIT_SIGNAL_OFFSET 128
int st;
struct rusage rus;
// block wait
int pid = wait4(-1, &st, 0, &rus);
if (pid <= 0) {
return SHIM_ERR_WAIT;
} else if (pid != ctr_pid) {
return SHIM_ERR;
}
if (WIFSIGNALED(st)) {
*status = EXIT_SIGNAL_OFFSET + WTERMSIG(st);
} else {
*status = WEXITSTATUS(st);
}
return SHIM_OK;
}
static void process_kill_all(process_t *p)
{
if (p->state->exec) {
return;
}
const char *params[MAX_RUNTIME_ARGS] = { NULL };
char output[BUFSIZ] = { 0 };
int output_len = BUFSIZ;
int i = 0;
int j;
params[i++] = p->runtime;
for (j = 0; j < p->state->runtime_args_len; j++) {
params[i++] = p->state->runtime_args[j];
}
params[i++] = "kill";
params[i++] = "--all";
params[i++] = p->id;
params[i++] = "SIGKILL";
(void)cmd_combined_output(p->runtime, params, output, &output_len);
return;
}
void process_delete(process_t *p)
{
if (p->state->exec) {
return;
}
const char *params[MAX_RUNTIME_ARGS] = { NULL };
char output[BUFSIZ] = { 0 };
int output_len = BUFSIZ;
int i = 0;
int j;
char log_path[PATH_MAX] = { 0 };
char *cwd;
cwd = getcwd(NULL, 0);
if (cwd == NULL) {
write_message(g_log_fd, ERR_MSG, "get cwd failed when do process delete");
return;
}
snprintf(log_path, PATH_MAX, "%s/log.json", cwd);
params[i++] = p->runtime;
for (j = 0; j < p->state->runtime_args_len; j++) {
params[i++] = p->state->runtime_args[j];
}
params[i++] = "--log";
params[i++] = log_path;
params[i++] = "--log-format";
params[i++] = "json";
params[i++] = "delete";
params[i++] = "--force";
params[i++] = p->id;
(void)cmd_combined_output(p->runtime, params, output, &output_len);
free(cwd);
return;
}
int create_process(process_t *p)
{
int ret = -1;
char *data = NULL;
int exec_fd[2] = { -1, -1 };
char exec_buff[BUFSIZ + 1] = { 0 };
int nread = -1;
if (pipe2(exec_fd, O_CLOEXEC) != 0) {
write_message(g_log_fd, ERR_MSG, "create pipe failed when create process:%d", SHIM_SYS_ERR(errno));
return SHIM_ERR;
}
pid_t pid = fork();
if (pid == (pid_t) - 1) {
write_message(g_log_fd, ERR_MSG, "fork failed when create process:%d", SHIM_SYS_ERR(errno));
return SHIM_ERR;
}
// child:runtime
if (pid == (pid_t)0) {
close_fd(&exec_fd[0]);
if (p->shim_io != NULL) {
if (p->shim_io->in != -1) {
close(p->shim_io->in);
p->shim_io->in = -1;
dup2(p->stdio->in, 0);
}
if (p->shim_io->out != -1) {
close(p->shim_io->out);
p->shim_io->out = -1;
dup2(p->stdio->out, 1);
}
if (p->shim_io->err != -1) {
close(p->shim_io->err);
p->shim_io->err = -1;
dup2(p->stdio->err, 2);
}
}
char *cwd = getcwd(NULL, 0);
char *log_path = (char *)calloc(1, PATH_MAX);
char *pid_path = (char *)calloc(1, PATH_MAX);
if (cwd == NULL || log_path == NULL || pid_path == NULL) {
(void)dprintf(exec_fd[1], "memory error: %s", strerror(errno));
_exit(EXIT_FAILURE);
}
snprintf(log_path, PATH_MAX, "%s/log.json", cwd);
snprintf(pid_path, PATH_MAX, "%s/pid", cwd);
char *process_desc = NULL;
if (p->state->exec) {
process_desc = (char *)calloc(1, PATH_MAX);
if (process_desc == NULL) {
(void)dprintf(exec_fd[1], "memory error: %s", strerror(errno));
_exit(EXIT_FAILURE);
}
snprintf(process_desc, PATH_MAX, "%s/process.json", cwd);
}
const char *params[MAX_RUNTIME_ARGS] = { 0 };
get_runtime_cmd(p, log_path, pid_path, process_desc, params);
execvp(p->runtime, (char * const *)params);
(void)dprintf(exec_fd[1], "fork/exec error: %s", strerror(errno));
_exit(EXIT_FAILURE);
}
// parent
close_fd(&exec_fd[1]);
if (p->stdio != NULL) {
close_fd(&p->stdio->in);
close_fd(&p->stdio->out);
close_fd(&p->stdio->err);
}
nread = read_nointr(exec_fd[0], exec_buff, sizeof(exec_buff));
if (nread > 0) {
write_message(g_log_fd, ERR_MSG, "runtime error");
ret = SHIM_ERR;
goto out;
}
// block to wait pid exit
ret = waitpid(pid, NULL, 0);
if (ret != pid) {
write_message(g_log_fd, ERR_MSG, "wait runtime failed:%d", SHIM_SYS_ERR(errno));
ret = SHIM_ERR;
goto out;
}
// save pid
data = read_text_file("pid");
if (data == NULL) {
write_message(g_log_fd, ERR_MSG, "read pid of runtime failed");
goto out;
}
int ctr_pid = atoi(data);
if (ctr_pid <= 0) {
goto out;
}
p->ctr_pid = ctr_pid;
adapt_for_isulad_stdin(p);
ret = SHIM_OK;
out:
close_fd(&exec_fd[0]);
if (data != NULL) {
free(data);
}
return ret;
}
int process_signal_handle_routine(process_t *p)
{
int ret = SHIM_ERR;
bool exit_shim = false;
int i;
for (;;) {
int status;
ret = reap_container(p->ctr_pid, &status);
if (ret == SHIM_OK) {
exit_shim = true;
if (status == CONTAINER_ACTION_REBOOT) {
ret = setenv("CONTAINER_ACTION", "reboot", 1);
if (ret != SHIM_OK) {
write_message(g_log_fd, WARN_MSG, "set reboot action failed:%d", SHIM_SYS_ERR(errno));
}
} else if (status == CONTAINER_ACTION_SHUTDOWN) {
ret = setenv("CONTAINER_ACTION", "shutdown", 1);
if (ret != SHIM_OK) {
write_message(g_log_fd, WARN_MSG, "set shutdown action failed:%d", SHIM_SYS_ERR(errno));
}
}
} else if (ret == SHIM_ERR_WAIT) {
// avoid thread entering the infinite loop
usleep(1000);
continue;
}
if (exit_shim) {
process_kill_all(p);
process_delete(p);
if (p->exit_fd > 0) {
(void)write_nointr(p->exit_fd, &status, sizeof(int));
}
for (i = 0; i < 3; i ++) {
destory_io_thread(p, i);
}
return status;
}
}
}