From aaf1b46c66aa596ec718c11c4f4270e41e7b570e Mon Sep 17 00:00:00 2001
From: zhongtao <zhongtao17@huawei.com>
Date: Tue, 7 Nov 2023 16:39:35 +0800
Subject: [PATCH 11/14] add runc attach implement

Signed-off-by: zhongtao <zhongtao17@huawei.com>
---
 .../connect/grpc/grpc_containers_client.cc    |   9 +
 src/cmd/isula/stream/attach.c                 |  12 +-
 src/cmd/isulad-shim/common.c                  | 116 ++++-
 src/cmd/isulad-shim/common.h                  |  30 ++
 src/cmd/isulad-shim/main.c                    |  14 +
 src/cmd/isulad-shim/process.c                 | 453 ++++++++++++++++--
 src/cmd/isulad-shim/process.h                 |   7 +-
 src/cmd/isulad-shim/terminal.c                |   2 +-
 .../executor/container_cb/execution_stream.c  |   1 +
 src/daemon/modules/api/runtime_api.h          |   1 +
 .../modules/runtime/isula/isula_rt_ops.c      | 168 ++++++-
 src/utils/cutils/error.h                      |   4 +-
 12 files changed, 755 insertions(+), 62 deletions(-)

diff --git a/src/client/connect/grpc/grpc_containers_client.cc b/src/client/connect/grpc/grpc_containers_client.cc
index 2dd73100..bcb1e8da 100644
--- a/src/client/connect/grpc/grpc_containers_client.cc
+++ b/src/client/connect/grpc/grpc_containers_client.cc
@@ -1394,6 +1394,8 @@ public:
     auto run(const struct isula_attach_request *request, struct isula_attach_response *response) -> int override
     {
         ClientContext context;
+        bool detach = false;
+        std::string attach_detach_msg = "read escape sequence";
 
         if (set_custom_header_metadata(context, request) != 0) {
             ERROR("Failed to translate request to grpc");
@@ -1415,6 +1417,9 @@ public:
                     break;
                 }
                 if (!stream_response.stdout().empty()) {
+                    if (strcmp(stream_response.stdout().c_str(), attach_detach_msg.c_str()) == 0) {
+                        detach = true;
+                    }
                     std::cout << stream_response.stdout() << std::flush;
                 }
                 if (!stream_response.stderr().empty()) {
@@ -1437,6 +1442,10 @@ public:
             response->cc = ISULAD_ERR_EXEC;
         }
 
+        if (detach) {
+            response->server_errono = ISULAD_INFO_DETACH;
+        }
+
 out:
         if (request->attach_stdin) {
             pthread_cancel(writer.native_handle());
diff --git a/src/cmd/isula/stream/attach.c b/src/cmd/isula/stream/attach.c
index ff49af92..b61c9350 100644
--- a/src/cmd/isula/stream/attach.c
+++ b/src/cmd/isula/stream/attach.c
@@ -37,6 +37,7 @@
 #include "connect.h"
 #include "constants.h"
 #include "client_helpers.h"
+#include "error.h"
 #ifndef GRPC_CONNECTOR
 #include "client_console.h"
 #endif
@@ -70,8 +71,10 @@ static int check_tty(bool tty, struct termios *oldtios, bool *reset_tty)
         }
         *reset_tty = true;
     } else {
-        INFO("the input device is not a TTY");
-        return 0;
+        // if it is trying to attach to a container TTY
+        // from a non-TTY client input stream, returns -1.
+        COMMAND_ERROR("the input device is not a TTY");
+        return -1;
     }
 
     return 0;
@@ -353,6 +356,7 @@ static int client_attach(struct client_arguments *args, uint32_t *exit_code)
 #endif
 
     config = get_connect_config(args);
+    // Obtain the container's real exit code by waiting for the container to stop.
     container_wait_thread(args, exit_code, &sem_exited);
     ret = ops->container.attach(&request, response, &config);
     if (ret != 0) {
@@ -374,7 +378,9 @@ static int client_attach(struct client_arguments *args, uint32_t *exit_code)
 
     if (sem_timedwait(&sem_exited, &ts) != 0) {
         if (errno == ETIMEDOUT) {
-            COMMAND_ERROR("Wait container status timeout.");
+            if (response->server_errono != ISULAD_INFO_DETACH) {
+                INFO("Wait container stopped status timeout.");
+            }
         } else {
             CMD_SYSERROR("Failed to wait sem");
         }
diff --git a/src/cmd/isulad-shim/common.c b/src/cmd/isulad-shim/common.c
index 781dc004..48d266dc 100644
--- a/src/cmd/isulad-shim/common.c
+++ b/src/cmd/isulad-shim/common.c
@@ -33,16 +33,26 @@
 #include <isula_libutils/utils_file.h>
 
 int g_log_fd = -1;
+int g_attach_log_fd = -1;
 
 int init_shim_log(void)
 {
-    g_log_fd = open_no_inherit(SHIM_LOG_NAME, O_CREAT | O_WRONLY | O_APPEND | O_SYNC, 0640);
+    g_log_fd = open_no_inherit(SHIM_LOG_NAME, O_CREAT | O_WRONLY | O_APPEND | O_SYNC, LOG_FILE_MODE);
     if (g_log_fd < 0) {
         return SHIM_ERR;
     }
     return SHIM_OK;
 }
 
+int init_attach_log(void)
+{
+    g_attach_log_fd = open_no_inherit(ATTACH_LOG_NAME, O_CREAT | O_WRONLY | O_APPEND | O_SYNC, LOG_FILE_MODE);
+    if (g_attach_log_fd < 0) {
+        return SHIM_ERR;
+    }
+    return SHIM_OK;
+}
+
 void signal_routine(int sig)
 {
     switch (sig) {
@@ -162,11 +172,24 @@ int generate_random_str(char *id, size_t len)
     return SHIM_OK;
 }
 
-void write_message(const char *level, const char *fmt, ...)
-{
 #define MAX_MSG_JSON_TEMPLATE 32
 #define MAX_MESSAGE_CONTENT_LEN 128
 #define MAX_MESSAGE_LEN (MAX_MSG_JSON_TEMPLATE + MAX_MESSAGE_CONTENT_LEN)
+
+static void format_log_msg(const char *level, const char *buf, char *msg, int max_message_len)
+{
+    time_t current_time = time(NULL);
+    struct tm *local_time = localtime(&current_time);
+    char time_str[20];
+
+    strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", local_time);
+
+    (void)snprintf(msg, max_message_len - 1, "{\"time\": \"%s\", \"level\": \"%s\", \"msg\": \"%s\"}\n", time_str, level,
+                   buf);
+}
+
+void write_message(const char *level, const char *fmt, ...)
+{
     if (g_log_fd < 0) {
         return;
     }
@@ -183,15 +206,31 @@ void write_message(const char *level, const char *fmt, ...)
         return;
     }
 
-    nwrite = snprintf(msg, MAX_MESSAGE_LEN - 1, "{\"level\": \"%s\", \"msg\": \"%s\"}\n", level, buf);
-    if (nwrite < 0 || (size_t)nwrite >= (MAX_MESSAGE_LEN - 1)) {
+    format_log_msg(level, buf, msg, MAX_MESSAGE_CONTENT_LEN);
+
+    (void)isula_file_total_write_nointr(g_log_fd, msg, strlen(msg));
+}
+
+void write_attach_message(const char *level, const char *fmt, ...)
+{
+    char buf[MAX_MESSAGE_CONTENT_LEN] = { 0 };
+    char msg[MAX_MESSAGE_LEN] = { 0 };
+    int nwrite = -1;
+
+    if (g_attach_log_fd < 0) {
         return;
     }
-
-    nwrite = isula_file_total_write_nointr(g_log_fd, msg, strlen(msg));
-    if (nwrite < 0 || (size_t)nwrite != strlen(msg)) {
+    va_list arg_list;
+    va_start(arg_list, fmt);
+    nwrite = vsnprintf(buf, MAX_MESSAGE_CONTENT_LEN, fmt, arg_list);
+    va_end(arg_list);
+    if (nwrite < 0) {
         return;
     }
+
+    format_log_msg(level, buf, msg, MAX_MESSAGE_CONTENT_LEN);
+
+    (void)isula_file_total_write_nointr(g_attach_log_fd, msg, strlen(msg));
 }
 
 /* note: This function can only read small text file. */
@@ -272,3 +311,64 @@ int open_no_inherit(const char *path, int flag, mode_t mode)
 
     return fd;
 }
+
+/* judge the fd whether is attach fifo */
+struct isula_linked_list *get_attach_fifo_item(int fd, struct isula_linked_list *list)
+{
+    struct isula_linked_list *it = NULL;
+    struct isula_linked_list *next = NULL;
+
+    if (fd <= 0 || list == NULL || isula_linked_list_empty(list)) {
+        return it;
+    }
+
+    isula_linked_list_for_each_safe(it, list, next) {
+        struct shim_fifos_fd *elem = (struct shim_fifos_fd *)it->elem;
+        if (elem == NULL) {
+            continue;
+        }
+        if (elem->in_fd == fd) {
+            return it;
+        }
+        if (elem->out_fd == fd) {
+            return it;
+        }
+        if (elem->err_fd == fd) {
+            return it;
+        }
+    }
+
+    return it;
+}
+
+void free_shim_fifos_fd(struct shim_fifos_fd *item)
+{
+    if (item == NULL) {
+        return;
+    }
+    if (item->in_fifo != NULL) {
+        free(item->in_fifo);
+        item->in_fifo = NULL;
+    }
+    if (item->out_fifo != NULL) {
+        free(item->out_fifo);
+        item->out_fifo = NULL;
+    }
+    if (item->err_fifo != NULL) {
+        free(item->err_fifo);
+        item->err_fifo = NULL;
+    }
+    if (item->in_fd >= 0) {
+        close(item->in_fd);
+        item->in_fd = -1;
+    }
+    if (item->out_fd >= 0) {
+        close(item->out_fd);
+        item->out_fd = -1;
+    }
+    if (item->err_fd >= 0) {
+        close(item->err_fd);
+        item->err_fd = -1;
+    }
+    free(item);
+}
\ No newline at end of file
diff --git a/src/cmd/isulad-shim/common.h b/src/cmd/isulad-shim/common.h
index 55efdc28..2020a799 100644
--- a/src/cmd/isulad-shim/common.h
+++ b/src/cmd/isulad-shim/common.h
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 #include <stdint.h>
 #include <isula_libutils/utils.h>
+#include <isula_libutils/utils_linked_list.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -59,8 +60,22 @@ extern "C" {
 #define CONTAINER_ACTION_REBOOT 129
 #define CONTAINER_ACTION_SHUTDOWN 130
 
+#define ATTACH_SOCKET "attach_socket.sock"
+#define ATTACH_LOG_NAME "attach-log.json"
+#define ATTACH_DETACH_MSG "read escape sequence"
+#define MAX_ATTACH_NUM 16
+
+#define CTRL_Q 0x11  // ASCII code control character ctrl + Q
+
+#define LOG_FILE_MODE 0600
+
+#define SOCKET_DIRECTORY_MODE 0600
+#define ATTACH_FIFOPATH_MODE 0600
+
 int init_shim_log(void);
 
+int init_attach_log(void);
+
 void signal_routine(int sig);
 
 /**
@@ -90,18 +105,33 @@ void signal_routine(int sig);
         }                         \
     } while (0)
 
+struct shim_fifos_fd {
+    char *in_fifo;
+    char *out_fifo;
+    char *err_fifo;
+    int in_fd;
+    int out_fd;
+    int err_fd;
+};
+
 char *read_text_file(const char *path);
 
 int cmd_combined_output(const char *binary, const char *params[], void *output, int *output_len);
 
 void write_message(const char *level, const char *fmt, ...);
 
+void write_attach_message(const char *level, const char *fmt, ...);
+
 int generate_random_str(char *id, size_t len);
 
 void close_fd(int *pfd);
 
 int open_no_inherit(const char *path, int flag, mode_t mode);
 
+struct isula_linked_list *get_attach_fifo_item(int fd, struct isula_linked_list *list);
+
+void free_shim_fifos_fd(struct shim_fifos_fd *item);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/cmd/isulad-shim/main.c b/src/cmd/isulad-shim/main.c
index 454011d0..deb07271 100644
--- a/src/cmd/isulad-shim/main.c
+++ b/src/cmd/isulad-shim/main.c
@@ -145,6 +145,20 @@ int main(int argc, char **argv)
         }
     }
 
+    if (p->state->attach_socket != NULL) {
+        ret = prepare_attach_socket(p);
+        if (ret != SHIM_OK) {
+            write_message(ERR_MSG, "failed to prepare attach socket:%d", ret);
+            exit(EXIT_FAILURE);
+        }
+
+        ret = init_attach_log();
+        if (ret != SHIM_OK) {
+            write_message(ERR_MSG, "failed to init shim attach log");
+            exit(EXIT_FAILURE);
+        }
+    }
+
     /* start epoll for io copy */
     ret = process_io_start(p, &tid_epoll);
     if (ret != SHIM_OK) {
diff --git a/src/cmd/isulad-shim/process.c b/src/cmd/isulad-shim/process.c
index 40908102..187067d2 100644
--- a/src/cmd/isulad-shim/process.c
+++ b/src/cmd/isulad-shim/process.c
@@ -19,20 +19,22 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#include <sys/ioctl.h>
+#include <sys/eventfd.h>
+#include <sys/resource.h> // IWYU pragma: keep
+#include <sys/stat.h>
+#include <sys/wait.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <limits.h>
-#include <sys/wait.h>
 #include <semaphore.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <sys/ioctl.h>
-#include <sys/eventfd.h>
 #include <termios.h> // IWYU pragma: keep
-#include <sys/resource.h> // IWYU pragma: keep
 #include <stdint.h>
 #include <stdio.h>
+#include <stddef.h>
 
 #include <isula_libutils/json_common.h>
 #include <isula_libutils/shim_client_process_state.h>
@@ -42,6 +44,8 @@
 #include <isula_libutils/utils_mainloop.h>
 #include <isula_libutils/auto_cleanup.h>
 #include <isula_libutils/utils_buffer.h>
+#include <isula_libutils/utils_linked_list.h>
+#include <isula_libutils/utils_array.h>
 
 #include "common.h"
 #include "terminal.h"
@@ -57,7 +61,7 @@ static shim_client_process_state *load_process()
 
     p_state = shim_client_process_state_parse_file("process.json", NULL, &err);
     if (p_state == NULL) {
-        write_message(ERR_MSG, "parse process state failed");
+        write_message(ERR_MSG, "parse process state failed: %s", err);
     }
     /* "err" will definitely be allocated memory in the function above */
     free(err);
@@ -168,6 +172,99 @@ static int sync_exit_cb(int fd, uint32_t events, void *cbdata, isula_epoll_descr
     return EPOLL_LOOP_HANDLE_CLOSE;
 }
 
+static bool fifo_exists(const char *path)
+{
+    struct stat sb;
+    int ret;
+
+    ret = stat(path, &sb);
+    if (ret < 0) {
+        // could be something other than exist, just return false
+        return false;
+    }
+
+    return S_ISFIFO(sb.st_mode);
+}
+
+static int add_attach_terminal_fifos(const char *in, const char *out, const char *err, int *input_fd, process_t *p)
+{
+    __isula_auto_close int fifofd_in = -1;
+    __isula_auto_close int fifofd_out = -1;
+    __isula_auto_close int fifofd_err = -1;
+    struct shim_fifos_fd *fifos = NULL;
+    struct isula_linked_list *node = NULL;
+
+    bool invalid = (in != NULL && !fifo_exists(in)) || (out != NULL && !fifo_exists(out)) || (err != NULL &&
+                                                                                             !fifo_exists(err));
+    if (invalid) {
+        write_attach_message(ERR_MSG, "File %s or %s or %s does not refer to a FIFO", in, out, err);
+        return -1;
+    }
+
+    if (in != NULL) {
+        fifofd_in = isula_file_open(in, O_RDONLY | O_NONBLOCK | O_CLOEXEC, 0);
+        if (fifofd_in < 0) {
+            write_attach_message(ERR_MSG, "Failed to open FIFO: %s", in);
+            return -1;
+        }
+    }
+
+    if (out != NULL) {
+        fifofd_out = isula_file_open(out, O_WRONLY | O_NONBLOCK | O_CLOEXEC, 0);
+        if (fifofd_out < 0) {
+            write_attach_message(ERR_MSG, "Failed to open FIFO: %s", out);
+            return -1;
+        }
+    }
+
+    if (err != NULL) {
+        fifofd_err = isula_file_open(err, O_WRONLY | O_NONBLOCK | O_CLOEXEC, 0);
+        if (fifofd_err < 0) {
+            write_attach_message(ERR_MSG, "Failed to open FIFO: %s", err);
+            return -1;
+        }
+    }
+
+    fifos = isula_common_calloc_s(sizeof(*fifos));
+    if (fifos == NULL) {
+        write_attach_message(ERR_MSG, "Out of memory");
+        goto err_out;
+    }
+
+    fifos->in_fifo = isula_strdup_s(in);
+    fifos->out_fifo = isula_strdup_s(out);
+    fifos->err_fifo = isula_strdup_s(err);
+
+    fifos->in_fd = isula_transfer_fd(fifofd_in);
+    fifos->out_fd = isula_transfer_fd(fifofd_out);
+    fifos->err_fd = isula_transfer_fd(fifofd_err);
+    node = isula_common_calloc_s(sizeof(struct isula_linked_list));
+    if (node == NULL) {
+        write_attach_message(ERR_MSG, "Out of memory");
+        goto err_out;
+    }
+
+    node->elem = fifos;
+    isula_linked_list_add(p->attach_fifos, node);
+
+    if (input_fd != NULL) {
+        *input_fd = fifos->in_fd;
+    }
+
+    return 0;
+err_out:
+    free_shim_fifos_fd(fifos);
+    return -1;
+}
+
+static void remove_attach_terminal_fifos(isula_epoll_descr_t *descr, struct isula_linked_list *item)
+{
+    struct shim_fifos_fd *elem = (struct shim_fifos_fd *)item->elem;
+    isula_epoll_remove_handler(descr, elem->in_fd);
+    isula_linked_list_del(item);
+    free_shim_fifos_fd(elem);
+}
+
 static int stdin_cb(int fd, uint32_t events, void *cbdata, isula_epoll_descr_t *descr)
 {
     process_t *p = (process_t *)cbdata;
@@ -210,6 +307,57 @@ static int stdin_cb(int fd, uint32_t events, void *cbdata, isula_epoll_descr_t *
     return EPOLL_LOOP_HANDLE_CONTINUE;
 }
 
+static int attach_stdin_cb(int fd, uint32_t events, void *cbdata, isula_epoll_descr_t *descr)
+{
+    process_t *p = (process_t *)cbdata;
+    int r_count = 0;
+    int w_count = 0;
+    int *fd_to = NULL;
+    struct isula_linked_list *item;
+
+    if (events & EPOLLHUP) {
+        write_message(ERR_MSG, "attach stdin %d received the EPOLLHUP event", fd);
+        goto err_out;
+    }
+
+    if (!(events & EPOLLIN)) {
+        return EPOLL_LOOP_HANDLE_CONTINUE;
+    }
+
+    (void)memset(p->buf, 0, DEFAULT_IO_COPY_BUF);
+
+    r_count = isula_file_read_nointr(fd, p->buf, DEFAULT_IO_COPY_BUF);
+    if (r_count <= 0) {
+        write_message(ERR_MSG, "failed to read from attach stdin %d, error:%d", fd, SHIM_SYS_ERR(errno));
+        goto err_out;
+    }
+
+    if (p->state->terminal) {
+        fd_to = &(p->recv_fd);
+    } else {
+        fd_to = &(p->shim_io->in);
+    }
+
+    if (fd_to == NULL || *fd_to == -1) {
+        return EPOLL_LOOP_HANDLE_CONTINUE;
+    }
+    w_count = isula_file_total_write_nointr(*fd_to, p->buf, r_count);
+    if (w_count < 0) {
+        /* When any error occurs, set the write fd -1  */
+        write_message(WARN_MSG, "write in_fd %d error:%d", *fd_to, SHIM_SYS_ERR(errno));
+        close(*fd_to);
+        *fd_to = -1;
+    }
+
+    return EPOLL_LOOP_HANDLE_CONTINUE;
+err_out:
+    item = get_attach_fifo_item(fd, p->attach_fifos);
+    if (item != NULL && item->elem != NULL) {
+        remove_attach_terminal_fifos(descr, item);
+    }
+    return EPOLL_LOOP_HANDLE_CONTINUE;
+}
+
 static int stdout_cb(int fd, uint32_t events, void *cbdata, isula_epoll_descr_t *descr)
 {
     process_t *p = (process_t *)cbdata;
@@ -237,16 +385,29 @@ static int stdout_cb(int fd, uint32_t events, void *cbdata, isula_epoll_descr_t
 
     shim_write_container_log_file(p->terminal, STDID_OUT, p->buf, r_count);
 
-    if (p->isulad_io->out == -1) {
+    if (p->isulad_io->out != -1) {
+        w_count = isula_file_total_write_nointr(p->isulad_io->out, p->buf, r_count);
+        if (w_count < 0) {
+            /* When any error occurs, set the write fd -1  */
+            write_message(WARN_MSG, "write out_fd %d error:%d", p->isulad_io->out, SHIM_SYS_ERR(errno));
+            close(p->isulad_io->out);
+            p->isulad_io->out = -1;
+        }
+    }
+
+    if (isula_linked_list_empty(p->attach_fifos)) {
         return EPOLL_LOOP_HANDLE_CONTINUE;
     }
 
-    w_count = isula_file_total_write_nointr(p->isulad_io->out, p->buf, r_count);
-    if (w_count < 0) {
-        /* When any error occurs, set the write fd -1  */
-        write_message(WARN_MSG, "write out_fd %d error:%d", p->isulad_io->out, SHIM_SYS_ERR(errno));
-        close(p->isulad_io->out);
-        p->isulad_io->out = -1;
+    struct isula_linked_list *it = NULL;
+    struct isula_linked_list *next = NULL;
+
+    isula_linked_list_for_each_safe(it, p->attach_fifos, next) {
+        struct shim_fifos_fd *elem = (struct shim_fifos_fd *)it->elem;
+        w_count = isula_file_total_write_nointr(elem->out_fd, p->buf, r_count);
+        if (w_count < 0) {
+            remove_attach_terminal_fifos(descr, it);
+        }
     }
 
     return EPOLL_LOOP_HANDLE_CONTINUE;
@@ -279,16 +440,29 @@ static int stderr_cb(int fd, uint32_t events, void *cbdata, isula_epoll_descr_t
 
     shim_write_container_log_file(p->terminal, STDID_ERR, p->buf, r_count);
 
-    if (p->isulad_io->err == -1) {
+    if (p->isulad_io->err != -1) {
+        w_count = isula_file_total_write_nointr(p->isulad_io->err, p->buf, r_count);
+        if (w_count < 0) {
+            /* When any error occurs, set the write fd -1  */
+            write_message(WARN_MSG, "write err_fd %d error:%d", p->isulad_io->err, SHIM_SYS_ERR(errno));
+            close(p->isulad_io->err);
+            p->isulad_io->err = -1;
+        }
+    }
+
+    if (isula_linked_list_empty(p->attach_fifos)) {
         return EPOLL_LOOP_HANDLE_CONTINUE;
     }
 
-    w_count = isula_file_total_write_nointr(p->isulad_io->err, p->buf, r_count);
-    if (w_count < 0) {
-        /* When any error occurs, set the write fd -1  */
-        write_message(WARN_MSG, "write err_fd %d error:%d", p->isulad_io->err, SHIM_SYS_ERR(errno));
-        close(p->isulad_io->err);
-        p->isulad_io->err = -1;
+    struct isula_linked_list *it = NULL;
+    struct isula_linked_list *next = NULL;
+
+    isula_linked_list_for_each_safe(it, p->attach_fifos, next) {
+        struct shim_fifos_fd *elem = (struct shim_fifos_fd *)it->elem;
+        w_count = isula_file_total_write_nointr(elem->out_fd, p->buf, r_count);
+        if (w_count < 0) {
+            remove_attach_terminal_fifos(descr, it);
+        }
     }
 
     return EPOLL_LOOP_HANDLE_CONTINUE;
@@ -326,6 +500,159 @@ static int resize_cb(int fd, uint32_t events, void *cbdata, isula_epoll_descr_t
     return EPOLL_LOOP_HANDLE_CONTINUE;
 }
 
+static bool attach_fifopath_security_check(process_t *p, const char *fifopath)
+{
+    struct stat st = { 0 };
+    char real_path[PATH_MAX] = { 0 };
+
+    if (isula_validate_absolute_path(fifopath) != 0) {
+        write_attach_message(ERR_MSG, "attach fifo path \"%s\" must be an valid absolute path", fifopath);
+        return false;
+    }
+
+    if (realpath(fifopath, real_path) == NULL) {
+        write_attach_message(ERR_MSG, "Failed to get realpath for '%s': %s.", real_path, SHIM_SYS_ERR(errno));
+        return false;
+    }
+
+    if (!isula_has_prefix(real_path, p->workdir)) {
+        write_attach_message(ERR_MSG, "attach fifo path \"%s\" must be under the state path", real_path, p->workdir);
+        return false;
+    }
+
+    if (lstat(real_path, &st) != 0) {
+        write_attach_message(ERR_MSG, "Failed to lstat %s : %s", real_path, SHIM_SYS_ERR(errno));
+        return false;
+    }
+
+    if (!S_ISFIFO(st.st_mode)) {
+        write_attach_message(ERR_MSG, "attach fifo path \"%s\" must be an FIFO", real_path);
+        return false;
+    }
+
+    if ((st.st_mode & 0777) != ATTACH_FIFOPATH_MODE) {
+        write_attach_message(ERR_MSG, "attach fifo path \"%s\" permission invalid", real_path);
+        return false;
+    }
+
+    if (st.st_uid != 0) {
+        write_attach_message(ERR_MSG, "attach fifo path \"%s\" uid invalid", real_path);
+        return false;
+    }
+
+    return true;
+}
+
+// attach_cb needs to read the content from communication fd and parse it.
+// at the same time, it also needs to establish a connection between the attach fd and the container fd.
+// 1. if it fails, it needs to write an error message to attach log file,
+// and write -1 to connection fd to let isulad know that it has failed.
+// 2. if it succeeds, write 0 to let isulad know that it is ready.
+// attach_cb returns EPOLL_LOOP_HANDLE_CONTINUE regardless of success or failure,
+// because whether the attach operation is successful or not does not affect the first process of the container.
+static int attach_cb(int fd, uint32_t events, void *cbdata, isula_epoll_descr_t *descr)
+{
+    process_t *p = (process_t *)cbdata;
+    int r_count = 0;
+    char tmp_buf[BUFSIZ + 1] = { 0 };
+    char *in = NULL, *out = NULL, *err = NULL;
+    int fifofd_in = -1;
+    isula_string_array *tmp_str_array = NULL;
+    int ret = 0;
+    // attach execution return value
+    int status = -1;
+    bool valid = true;
+
+    // after receiving the event that isulad closes the connection,
+    // close the communication fd and remove it from epoll.
+    if (events & EPOLLHUP) {
+        close(fd);
+        isula_epoll_remove_handler(descr, fd);
+        return EPOLL_LOOP_HANDLE_CONTINUE;
+    }
+
+    if (!(events & EPOLLIN)) {
+        return EPOLL_LOOP_HANDLE_CONTINUE;
+    }
+
+    r_count = isula_file_read_nointr(fd, tmp_buf, sizeof(tmp_buf) - 1);
+    if (r_count <= 0) {
+        write_attach_message(ERR_MSG, "Failed to read msg from attach conn fd");
+        goto out;
+    }
+
+    // limit the number of attach connections to MAX_ATTACH_NUM
+    if (isula_linked_list_len(p->attach_fifos) >= MAX_ATTACH_NUM) {
+        write_attach_message(ERR_MSG, "The number of attach connections exceeds the limit:%d, and this connection is rejected.",
+                             MAX_ATTACH_NUM);
+        goto out;
+    }
+
+    tmp_str_array = isula_string_split_to_multi(tmp_buf, ' ');
+    if (tmp_str_array->len != 3) {
+        write_attach_message(ERR_MSG, "Invalid attach msg from isulad");
+        goto out;
+    }
+
+    for (int i = 0; i < tmp_str_array->len; i++) {
+        valid = valid && attach_fifopath_security_check(p, tmp_str_array->items[i]);
+    }
+
+    if (!valid) {
+        write_attach_message(ERR_MSG, "Invalid attach fifo path from isulad");
+        goto out;
+    }
+
+    in = tmp_str_array->items[0];
+    out = tmp_str_array->items[1];
+    err = tmp_str_array->items[2];
+
+    if (add_attach_terminal_fifos(in, out, err, &fifofd_in, p) < 0) {
+        write_attach_message(ERR_MSG, "Failed to add attach terminal fifos");
+        goto out;
+    }
+
+    // attach stdin --> container stdin
+    ret = isula_epoll_add_handler(descr, fifofd_in, attach_stdin_cb, p);
+    if (ret != SHIM_OK) {
+        write_attach_message(ERR_MSG, "add fifofd_in fd %d to epoll loop failed:%d", fifofd_in, SHIM_SYS_ERR(errno));
+        struct isula_linked_list *item = get_attach_fifo_item(fd, p->attach_fifos);
+        if (item != NULL && item->elem != NULL) {
+            remove_attach_terminal_fifos(descr, item);
+        }
+        goto out;
+    }
+
+    status = 0;
+out:
+    isula_string_array_free(tmp_str_array);
+    (void)isula_file_write_nointr(fd, &status, sizeof(int));
+    return EPOLL_LOOP_HANDLE_CONTINUE;
+}
+
+// do_attach_socket_accept returns EPOLL_LOOP_HANDLE_CONTINUE regardless of success or failure,
+// because whether the attach operation is successful or not does not affect the first process of the container.
+static int do_attach_socket_accept(int fd, uint32_t events, void *cbdata, isula_epoll_descr_t *descr)
+{
+    process_t *p = (process_t *)cbdata;
+    int conn_fd = -1;
+    int ret = SHIM_ERR;
+
+    conn_fd = accept(p->attach_socket_fd, NULL, NULL);
+    if (conn_fd < 0) {
+        write_attach_message(ERR_MSG, "accept from fd %d failed:%d", p->attach_socket_fd, SHIM_SYS_ERR(errno));
+        return EPOLL_LOOP_HANDLE_CONTINUE;
+    }
+
+    ret = isula_epoll_add_handler(descr, conn_fd, attach_cb, p);
+    if (ret != SHIM_OK) {
+        write_attach_message(ERR_MSG, "add recv_fd %d to epoll loop failed:%d", conn_fd, SHIM_SYS_ERR(errno));
+        close(conn_fd);
+        return EPOLL_LOOP_HANDLE_CONTINUE;
+    }
+    return EPOLL_LOOP_HANDLE_CONTINUE;
+}
+
 static int task_console_accept(int fd, uint32_t events, void *cbdata, isula_epoll_descr_t *descr)
 {
     process_t *p = (process_t *)cbdata;
@@ -399,6 +726,7 @@ static void stdio_release(int (*stdio_fd)[2])
         for (j = 0; j < 2; j++) {
             if (stdio_fd[i][j] > 0) {
                 close(stdio_fd[i][j]);
+                stdio_fd[i][j] = -1;
             }
         }
     }
@@ -568,24 +896,6 @@ static int open_generic_io(process_t *p, isula_epoll_descr_t *descr)
     return SHIM_OK;
 }
 
-static int set_non_block(int fd)
-{
-    int flag = -1;
-    int ret = SHIM_ERR;
-
-    flag = fcntl(fd, F_GETFL, 0);
-    if (flag < 0) {
-        return SHIM_ERR;
-    }
-
-    ret = fcntl(fd, F_SETFL, flag | O_NONBLOCK);
-    if (ret != 0) {
-        return SHIM_ERR;
-    }
-
-    return SHIM_OK;
-}
-
 /*
     std_id: channel type
     isulad_stdio: one side of the isulad fifo file
@@ -623,6 +933,14 @@ static void *io_epoll_loop(void *data)
         exit(EXIT_FAILURE);
     }
 
+    if (p->state->attach_socket != NULL) {
+        ret = isula_epoll_add_handler(&descr, p->attach_socket_fd, do_attach_socket_accept, p);
+        if (ret != SHIM_OK) {
+            write_message(ERR_MSG, "add attach_socket_fd %d to epoll loop failed:%d", p->attach_socket_fd, SHIM_SYS_ERR(errno));
+            exit(EXIT_FAILURE);
+        }
+    }
+
     if (p->state->terminal) {
         ret = open_terminal_io(p, &descr);
     } else {
@@ -651,7 +969,7 @@ static void *io_epoll_loop(void *data)
     }
 
     if (fd_out > 0) {
-        ret = set_non_block(fd_out);
+        ret = isula_set_non_block(fd_out);
         if (ret != SHIM_OK) {
             write_message(ERR_MSG, "set fd %d non_block failed:%d", fd_out, SHIM_SYS_ERR(errno));
             exit(EXIT_FAILURE);
@@ -666,7 +984,7 @@ static void *io_epoll_loop(void *data)
     }
 
     if (fd_err > 0) {
-        ret = set_non_block(fd_err);
+        ret = isula_set_non_block(fd_err);
         if (ret != SHIM_OK) {
             write_message(ERR_MSG, "set fd %d non_block failed:%d", fd_err, SHIM_SYS_ERR(errno));
             exit(EXIT_FAILURE);
@@ -807,15 +1125,19 @@ failure:
     if (p->isulad_io != NULL) {
         if (p->isulad_io->in > 0) {
             close(p->isulad_io->in);
+            p->isulad_io->in = -1;
         }
         if (p->isulad_io->out > 0) {
             close(p->isulad_io->out);
+            p->isulad_io->out = -1;
         }
         if (p->isulad_io->err > 0) {
             close(p->isulad_io->err);
+            p->isulad_io->err = -1;
         }
         if (p->isulad_io->resize > 0) {
             close(p->isulad_io->resize);
+            p->isulad_io->resize = -1;
         }
         free(p->isulad_io);
         p->isulad_io = NULL;
@@ -937,6 +1259,13 @@ process_t *new_process(char *id, char *bundle, char *runtime)
         goto failure;
     }
 
+    p->attach_fifos = isula_common_calloc_s(sizeof(struct isula_linked_list));
+    if (p->attach_fifos == NULL) {
+        goto failure;
+    }
+
+    isula_linked_list_init(p->attach_fifos);
+
     return p;
 
 failure:
@@ -1368,3 +1697,49 @@ int process_signal_handle_routine(process_t *p, const pthread_t tid_epoll, const
     (void)isula_file_write_nointr(STDOUT_FILENO, &status, sizeof(int));
     return SHIM_OK;
 }
+
+int prepare_attach_socket(process_t *p)
+{
+    struct sockaddr_un addr;
+    int ret = -1;
+
+    if (strlen(p->state->attach_socket) >= sizeof(addr.sun_path)) {
+        write_message(ERR_MSG, "Invalid attach socket path: %s", p->state->attach_socket);
+        return SHIM_ERR;
+    }
+
+    p->attach_socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (p->attach_socket_fd < 0) {
+        write_message(ERR_MSG, "Failed to create socket:%d", SHIM_SYS_ERR(errno));
+        return SHIM_ERR;
+    }
+
+    (void)memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    (void)strncpy(addr.sun_path, p->state->attach_socket, sizeof(addr.sun_path) - 1);
+
+    ret = bind(p->attach_socket_fd, (struct sockaddr *)&addr, sizeof(addr));
+    if (ret < 0) {
+        write_message(ERR_MSG, "bind console fd failed:%d", SHIM_SYS_ERR(errno));
+        return SHIM_ERR;
+    }
+
+    ret = chmod(p->state->attach_socket, SOCKET_DIRECTORY_MODE);
+    if (ret != 0) {
+        write_message(ERR_MSG, "Failed to chmod for socket: %s", p->state->attach_socket);
+        return SHIM_ERR;
+    }
+
+    //If the backlog argument is greater than the value in
+    // /proc/sys/net/core/somaxconn, then it is silently capped to that
+    // value.  Since Linux 5.4, the default in this file is 4096; in
+    // earlier kernels, the default value is 128.  Before Linux 2.4.25,
+    // this limit was a hard coded value, SOMAXCONN, with the value 128.
+    // The maximum number of attach we allow here is MAX_ATTACH_NUM, so just use it directly
+    ret = listen(p->attach_socket_fd, MAX_ATTACH_NUM);
+    if (ret < 0) {
+        write_message(ERR_MSG, "listen console fd failed:%d", SHIM_SYS_ERR(errno));
+        return SHIM_ERR;
+    }
+    return SHIM_OK;
+}
\ No newline at end of file
diff --git a/src/cmd/isulad-shim/process.h b/src/cmd/isulad-shim/process.h
index 280d9874..5607316c 100644
--- a/src/cmd/isulad-shim/process.h
+++ b/src/cmd/isulad-shim/process.h
@@ -19,7 +19,8 @@
 #include <pthread.h>
 #include <semaphore.h>
 #include <stdbool.h>
-#include "isula_libutils/shim_client_process_state.h"
+#include <isula_libutils/shim_client_process_state.h>
+#include "isula_libutils/utils_linked_list.h"
 #include "terminal.h"
 
 #ifdef __cplusplus
@@ -49,6 +50,7 @@ typedef struct process {
     char *root_path;
     int io_loop_fd;
     int exit_fd;
+    int attach_socket_fd; // the server socket fd that establishes a connection with isulad
     int ctr_pid;
     int sync_fd;
     int listen_fd;
@@ -58,6 +60,7 @@ typedef struct process {
     stdio_t *stdio; // shim to on runtime side, in:r out/err: w
     stdio_t *shim_io; // shim io on isulad side, in: w  out/err: r
     stdio_t *isulad_io; // isulad io, in:r out/err: w
+    struct isula_linked_list *attach_fifos; /* isulad: fifos used to attach teminal */
     shim_client_process_state *state;
     sem_t sem_mainloop;
     char *buf;
@@ -70,6 +73,8 @@ typedef struct {
 
 process_t* new_process(char *id, char *bundle, char *runtime);
 
+int prepare_attach_socket(process_t *p);
+
 int process_io_start(process_t *p, pthread_t *tid_epoll);
 int create_process(process_t *p);
 int process_signal_handle_routine(process_t *p, const pthread_t tid_epoll, const uint64_t timeout);
diff --git a/src/cmd/isulad-shim/terminal.c b/src/cmd/isulad-shim/terminal.c
index 0653dc45..1c063300 100644
--- a/src/cmd/isulad-shim/terminal.c
+++ b/src/cmd/isulad-shim/terminal.c
@@ -162,7 +162,7 @@ static int shim_json_data_write(log_terminal *terminal, const char *buf, int rea
      * shouldn't happen, otherwise, discard some last bytes.
      */
     nret = isula_file_total_write_nointr(terminal->fd, buf,
-                                 terminal->log_maxsize < read_count ? terminal->log_maxsize : read_count);
+                                         terminal->log_maxsize < read_count ? terminal->log_maxsize : read_count);
     if (nret < 0) {
         ret = -1;
         goto out;
diff --git a/src/daemon/executor/container_cb/execution_stream.c b/src/daemon/executor/container_cb/execution_stream.c
index 7db96b19..124dcfe2 100644
--- a/src/daemon/executor/container_cb/execution_stream.c
+++ b/src/daemon/executor/container_cb/execution_stream.c
@@ -346,6 +346,7 @@ static int container_attach_cb(const container_attach_request *request, containe
     }
 
     params.rootpath = cont->root_path;
+    params.state = cont->state_path;
     params.stdin = fifos[0];
     params.stdout = fifos[1];
     params.stderr = fifos[2];
diff --git a/src/daemon/modules/api/runtime_api.h b/src/daemon/modules/api/runtime_api.h
index edb33d02..3c2100f5 100644
--- a/src/daemon/modules/api/runtime_api.h
+++ b/src/daemon/modules/api/runtime_api.h
@@ -161,6 +161,7 @@ typedef struct _rt_resume_params_t {
 
 typedef struct _rt_attach_params_t {
     const char *rootpath;
+    const char *state;
     const char *stdin;
     const char *stdout;
     const char *stderr;
diff --git a/src/daemon/modules/runtime/isula/isula_rt_ops.c b/src/daemon/modules/runtime/isula/isula_rt_ops.c
index cb1ee26f..1787170b 100644
--- a/src/daemon/modules/runtime/isula/isula_rt_ops.c
+++ b/src/daemon/modules/runtime/isula/isula_rt_ops.c
@@ -18,6 +18,10 @@
 #include "isula_rt_ops.h"
 #include <unistd.h>
 #include <sys/wait.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/types.h>
 #include <limits.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -26,6 +30,7 @@
 #include <isula_libutils/isulad_daemon_configs.h>
 #include <isula_libutils/json_common.h>
 #include <isula_libutils/oci_runtime_spec.h>
+#include <isula_libutils/utils_file.h>
 #include <signal.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -52,9 +57,11 @@
 
 #define SHIM_BINARY "isulad-shim"
 #define RESIZE_FIFO_NAME "resize_fifo"
+#define ATTACH_SOCKET "attach_socket.sock"
 #define SHIM_LOG_SIZE ((BUFSIZ - 100) / 2)
 #define RESIZE_DATA_SIZE 100
 #define PID_WAIT_TIME 120
+#define ATTACH_WAIT_TIME 120
 #define SHIM_EXIT_TIMEOUT 2
 
 // file name formats of cgroup resources json
@@ -223,6 +230,19 @@ static void show_shim_runtime_errlog(const char *workdir)
     isulad_set_error_message(buf);
 }
 
+static void show_shim_attach_errlog(const char *workdir)
+{
+    char buf[SHIM_LOG_SIZE] = { 0 };
+
+    if (g_isulad_errmsg != NULL) {
+        return;
+    }
+
+    get_err_message(buf, sizeof(buf), workdir, "attach-log.json");
+    ERROR("shim-log: %s", buf);
+    isulad_set_error_message("shim-log error:\n%s\n", buf);
+}
+
 bool rt_isula_detect(const char *runtime)
 {
     if (runtime != NULL && (strcasecmp(runtime, "lcr") != 0)) {
@@ -463,8 +483,9 @@ static void runtime_exec_param_init(runtime_exec_info *rei)
     }
 }
 
-static int runtime_exec_info_init(runtime_exec_info *rei, const char *workdir, const char *root_path, const char *runtime, const char *subcmd,
-                                   const char **opts, size_t opts_len, const char *id, char **params, size_t params_num)
+static int runtime_exec_info_init(runtime_exec_info *rei, const char *workdir, const char *root_path,
+                                  const char *runtime, const char *subcmd, const char **opts, size_t opts_len, const char *id, char **params,
+                                  size_t params_num)
 {
     int ret = 0;
     rei->workdir = workdir;
@@ -1012,6 +1033,7 @@ int rt_isula_create(const char *id, const char *runtime, const rt_create_params_
     size_t runtime_args_len = 0;
     int ret = 0;
     char workdir[PATH_MAX] = { 0 };
+    char attach_socket[PATH_MAX] = { 0 };
     shim_client_process_state p = { 0 };
     int shim_exit_code = 0;
     int nret = 0;
@@ -1034,6 +1056,13 @@ int rt_isula_create(const char *id, const char *runtime, const rt_create_params_
         goto out;
     }
 
+    nret = snprintf(attach_socket, sizeof(attach_socket), "%s/%s", workdir, ATTACH_SOCKET);
+    if (nret < 0 || (size_t)nret >= sizeof(attach_socket)) {
+        INFO("Failed to get full attach socket path");
+        ret = -1;
+        goto out;
+    }
+
     p.exit_fifo = (char *)params->exit_fifo;
     p.open_tty = params->tty;
     p.open_stdin = params->open_stdin;
@@ -1042,6 +1071,7 @@ int rt_isula_create(const char *id, const char *runtime, const rt_create_params_
     p.isulad_stderr = (char *)params->stderr;
     p.runtime_args = (char **)runtime_args;
     p.runtime_args_len = runtime_args_len;
+    p.attach_socket = attach_socket;
     copy_process(&p, config->process);
     copy_annotations(&p, config->annotations);
 
@@ -1224,7 +1254,7 @@ static bool fg_exec(const rt_exec_params_t *params)
     return false;
 }
 
-static char *try_generate_exec_id()
+static char *try_generate_random_id()
 {
     char *id = NULL;
 
@@ -1324,7 +1354,7 @@ int rt_isula_exec(const char *id, const char *runtime, const rt_exec_params_t *p
     if (params->suffix != NULL) {
         exec_id = util_strdup_s(params->suffix);
     } else {
-        exec_id = try_generate_exec_id();
+        exec_id = try_generate_random_id();
     }
     if (exec_id == NULL) {
         ERROR("Out of memory or generate exec id failed");
@@ -1423,13 +1453,133 @@ out:
     return ret;
 }
 
-int rt_isula_attach(const char *id, const char *runtime, const rt_attach_params_t *params)
+static int get_container_attach_statuscode(const char *workdir, int attach_shim_fd)
 {
-    ERROR("isula attach not support on isulad-shim");
-    isulad_set_error_message("isula attach not support on isulad-shim");
+    int status_code = 0;
+    int ret = -1;
+    struct timespec beg = { 0 };
+    struct timespec end = { 0 };
+
+    if (clock_gettime(CLOCK_MONOTONIC, &beg) != 0) {
+        ERROR("Failed get time");
+        return -1;
+    }
+
+    while (true) {
+        if (clock_gettime(CLOCK_MONOTONIC, &end) != 0) {
+            ERROR("Failed get time");
+            return -1;
+        }
+        if (end.tv_sec - beg.tv_sec > ATTACH_WAIT_TIME) {
+            ERROR("Wait container attach exitcode timeout");
+            return -1;
+        }
+        ret = util_read_nointr(attach_shim_fd, &status_code, sizeof(int));
+        if (ret <= 0) {
+            if (shim_alive(workdir)) {
+                // wait 100 millisecond to read exit code
+                util_usleep_nointerupt(100000);
+                continue;
+            }
+            ERROR("Failed read pid from dead shim %s", workdir);
+            return -1;
+        }
+        return status_code; /* success */
+    }
     return -1;
 }
 
+static int get_attach_socketfd(const char *attach_socket, int *socket_fd)
+{
+    struct sockaddr_un addr = { 0 };
+    __isula_auto_close int tmp_socket = -1;
+
+    if (strlen(attach_socket) >= sizeof(addr.sun_path)) {
+        SYSERROR("Invalid attach socket path: %s", attach_socket);
+        return -1; 
+    }
+
+    tmp_socket = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (tmp_socket < 0) {
+        SYSERROR("Failed to create attach socket");
+        return -1;
+    }
+
+    if (isula_set_non_block(tmp_socket) < 0) {
+        SYSERROR("Failed to set socket non block");
+        return -1;
+    }
+
+    (void)memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    (void)strcpy(addr.sun_path, attach_socket);
+
+    if (connect(tmp_socket, (void *)&addr, sizeof(addr)) < 0) {
+        SYSERROR("Failed to connect attach socket: %s", attach_socket);
+        return -1;
+    }
+    *socket_fd = isula_transfer_fd(tmp_socket);
+    return 0;
+}
+
+int rt_isula_attach(const char *id, const char *runtime, const rt_attach_params_t *params)
+{
+    int ret = 0;
+    int len = 0;
+    int status_code = 0;
+    __isula_auto_close int socket_fd = -1;
+    char buf[BUFSIZ] = { 0 };
+    char workdir[PATH_MAX] = { 0 };
+    char attach_socket[PATH_MAX] = { 0 };
+
+    if (id == NULL || runtime == NULL || params == NULL) {
+        ERROR("Null argument");
+        return -1;
+    }
+
+    ret = snprintf(workdir, sizeof(workdir), "%s/%s", params->state, id);
+    if (ret < 0 || (size_t)ret >= sizeof(workdir)) {
+        ERROR("Failed join exec full path");
+        return -1;
+    }
+
+    // the communication format between isulad and isulad-shim attach is:
+    // stdin-path stdout-path stderr-path
+    len = snprintf(buf, sizeof(buf), "%s %s %s", params->stdin, params->stdout, params->stderr);
+    if (len < 0 || (size_t)len >= sizeof(buf)) {
+        ERROR("Failed to snprintf string");
+        return -1;
+    }
+
+    ret = snprintf(attach_socket, sizeof(attach_socket), "%s/%s", workdir, ATTACH_SOCKET);
+    if (ret < 0 || (size_t)ret >= sizeof(attach_socket)) {
+        ERROR("Failed to get full attach socket path");
+        return -1;
+    }
+
+    ret = get_attach_socketfd(attach_socket, &socket_fd);
+    if (ret < 0) {
+        ERROR("Failed to get attach socketfd");
+        return -1;
+    }
+
+    DEBUG("write %s to attach fd", buf);
+
+    ret = isula_file_write_nointr(socket_fd, buf, len);
+    if (ret < 0) {
+        SYSERROR("Failed to write attach isulad fd");
+        return -1;
+    }
+
+    status_code = get_container_attach_statuscode(workdir, socket_fd);
+    if (status_code < 0) {
+        show_shim_attach_errlog(workdir);
+        return -1;
+    }
+
+    return 0;
+}
+
 static int to_engine_resources_unified(const host_config *hostconfig, shim_client_cgroup_resources *cr)
 {
     int i;
@@ -1673,7 +1823,7 @@ static int parse_ps_data(char *stdout_msg, rt_listpids_out_t *out)
 }
 
 static int runtime_call_ps(const char *workdir, const char *runtime, const char *id,
-                               rt_listpids_out_t *out)
+                           rt_listpids_out_t *out)
 {
     __isula_auto_free char *stdout_msg = NULL;
     __isula_auto_free char *stderr_msg = NULL;
@@ -1681,7 +1831,7 @@ static int runtime_call_ps(const char *workdir, const char *runtime, const char
     int ret = 0;
     int nret = 0;
     char *params[PARAM_NUM] = { 0 };
-    const char *opts[2] = { "--format" , "json" };
+    const char *opts[2] = { "--format", "json" };
     char root_path[PATH_MAX] = { 0 };
 
     nret = snprintf(root_path, PATH_MAX, "%s/%s", workdir, runtime);
diff --git a/src/utils/cutils/error.h b/src/utils/cutils/error.h
index 088ed261..75eae760 100644
--- a/src/utils/cutils/error.h
+++ b/src/utils/cutils/error.h
@@ -44,8 +44,10 @@ extern "C" {
     /* err in runtime module */                                                              \
     XX(ERR_RUNTIME, DEF_ERR_RUNTIME_STR)                                                     \
     \
+    /* info for detach */                                                                    \
+    XX(INFO_DETACH, "Attach detach")                                                         \
     /* err max */                                                                            \
-    XX(ERR_UNKNOWN, "Unknown error")
+    XX(ERR_UNKNOWN, "Unknown error")                                                         
 
 #define ISULAD_ERRNO_GEN(n, s) ISULAD_##n,
 typedef enum { ISULAD_ERRNO_MAP(ISULAD_ERRNO_GEN) } isulad_errno_t;
-- 
2.42.0

