diff --git a/cmake/checker.cmake b/cmake/checker.cmake index 4aaec1b3cf7fa92c20da4e1286d40dfec6f21aab..56683c7ab5f074d8daad88f3473000acfa122a2e 100644 --- a/cmake/checker.cmake +++ b/cmake/checker.cmake @@ -65,6 +65,14 @@ find_library(LIBARCHIVE_LIBRARY archive HINTS ${PC_LIBARCHIVE_LIBDIR} ${PC_LIBARCHIVE_LIBRARY_DIRS}) _CHECK(LIBARCHIVE_LIBRARY "LIBARCHIVE_LIBRARY-NOTFOUND" "libarchive.so") +# check libtar +find_path(LIBTAR_INCLUDE_DIR libtar.h + HINTS ${PC_LIBTAR_INCLUDEDIR} ${PC_LIBTAR_INCLUDE_DIRS}) +_CHECK(LIBTAR_INCLUDE_DIR "LIBTAR_INCLUDE_DIR-NOTFOUND" "libtar.h") +find_library(LIBTAR_LIBRARY tar + HINTS ${PC_LIBTAR_LIBDIR} ${PC_LIBTAR_LIBRARY_DIRS}) +_CHECK(LIBTAR_LIBRARY "LIBTAR_LIBRARY-NOTFOUND" "libtar.so") + # check libcrypto pkg_check_modules(PC_CRYPTO REQUIRED "libcrypto") find_library(CRYPTO_LIBRARY crypto diff --git a/iSulad.spec b/iSulad.spec index be5d8ad45a95d5a628710a5852fec732a7512869..e52e577866f0a0666dc55f128fdcb6df741713a9 100644 --- a/iSulad.spec +++ b/iSulad.spec @@ -40,7 +40,7 @@ Requires: iSulad-img lcr lxc clibcni Requires: grpc protobuf Requires: libcurl Requires: sqlite http-parser libseccomp -Requires: libcap libselinux libwebsockets +Requires: libcap libselinux libwebsockets libtar Requires: systemd %description diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f2706868379a6c0b63fdb5b476d8fb34cbf282a1..5e2873b4640f6ddb877c5d0f0981073c75e988c8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -106,7 +106,7 @@ target_include_directories(libisula PUBLIC # set libisula FLAGS set_target_properties(libisula PROPERTIES PREFIX "") -target_link_libraries(libisula ${LIBYAJL_LIBRARY} ${SELINUX_LIBRARY} ${ISULA_LIBUTILS_LIBRARY} ${LIBARCHIVE_LIBRARY} ${WEBSOCKET_LIBRARY} ${CRYPTO_LIBRARY}) +target_link_libraries(libisula ${LIBYAJL_LIBRARY} ${SELINUX_LIBRARY} ${ISULA_LIBUTILS_LIBRARY} ${LIBARCHIVE_LIBRARY} ${LIBTAR_LIBRARY} ${WEBSOCKET_LIBRARY} ${CRYPTO_LIBRARY}) if (GRPC_CONNECTOR) target_link_libraries(libisula -Wl,--as-needed -lstdc++) @@ -172,7 +172,7 @@ target_include_directories(isulad PUBLIC ${WEBSOCKET_SERVICE_INCS} ) -target_link_libraries(isulad ${LIBYAJL_LIBRARY} ${SYSTEMD_LIBRARY} ${SELINUX_LIBRARY} ${LIBARCHIVE_LIBRARY} ${WEBSOCKET_LIBRARY} ${CRYPTO_LIBRARY}) +target_link_libraries(isulad ${LIBYAJL_LIBRARY} ${SYSTEMD_LIBRARY} ${SELINUX_LIBRARY} ${LIBARCHIVE_LIBRARY} ${LIBTAR_LIBRARY} ${WEBSOCKET_LIBRARY} ${CRYPTO_LIBRARY}) target_link_libraries(isulad -ldl ${ZLIB_LIBRARY} ${ISULA_LIBUTILS_LIBRARY} -lpthread libhttpclient) if (ENABLE_EMBEDDED_IMAGE) target_link_libraries(isulad ${SQLITE3_LIBRARY}) diff --git a/src/cmd/isula/extend/export.c b/src/cmd/isula/extend/export.c index 9df6f3509caa5a1238c7034b5fbba716a66324fe..741ea224cd9b11174b6f6a6d27623450b0922523 100644 --- a/src/cmd/isula/extend/export.c +++ b/src/cmd/isula/extend/export.c @@ -120,7 +120,7 @@ int cmd_export_main(int argc, const char **argv) g_cmd_export_args.name = g_cmd_export_args.argv[i]; if (client_export(&g_cmd_export_args)) { - ERROR("Container \"%s\" export failed", g_cmd_export_args.name); + COMMAND_ERROR("Container \"%s\" export failed", g_cmd_export_args.name); exit(ECOMMON); } diff --git a/src/cmd/isula/stream/cp.c b/src/cmd/isula/stream/cp.c index 0e36f58f9633880dc395aba4212b04fc25e509f3..0c721ab5e7a0000d2a9a670f212811dbb414a9b5 100644 --- a/src/cmd/isula/stream/cp.c +++ b/src/cmd/isula/stream/cp.c @@ -23,7 +23,7 @@ #include "isula_libutils/log.h" #include "path.h" #include "isula_connect.h" -#include "libtar.h" +#include "isulad_tar.h" #define FromContainer 0x01u #define ToContainer 0x10u diff --git a/src/connect/client/grpc/grpc_containers_client.cc b/src/connect/client/grpc/grpc_containers_client.cc index cb0fdca508b8faf65b65326ec28580eb0dffaffd..8533b90f91ca8a905e17ee468279c0aca1436deb 100644 --- a/src/connect/client/grpc/grpc_containers_client.cc +++ b/src/connect/client/grpc/grpc_containers_client.cc @@ -21,7 +21,7 @@ #include "isula_libutils/container_copy_to_request.h" #include "isula_libutils/container_exec_request.h" #include "utils.h" -#include "libtar.h" +#include "isulad_tar.h" #include "stoppable_thread.h" #include "container.grpc.pb.h" #include "client_base.h" diff --git a/src/image/oci/oci_export.c b/src/image/oci/oci_export.c new file mode 100644 index 0000000000000000000000000000000000000000..ec68bfa879b949d9c4e1ea9d8955cf9b60b6c6b0 --- /dev/null +++ b/src/image/oci/oci_export.c @@ -0,0 +1,61 @@ +/****************************************************************************** +* Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. +* iSulad licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* 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 v2 for more details. +* Author: wangfengtu +* Create: 2020-06-01 +* Description: isula image export operator implement +*******************************************************************************/ +#include "storage.h" +#include "oci_export.h" +#include "isula_libutils/log.h" +#include "libisulad.h" +#include "isulad_tar.h" + +int oci_do_export(char *id, char *file) +{ + int ret = 0; + int ret2 = 0; + char *mount_point = NULL; + char *errmsg = NULL; + + if (id == NULL || file == NULL) { + ERROR("Invalid NULL param"); + return -1; + } + + mount_point = storage_rootfs_mount(id); + if (mount_point == NULL) { + ERROR("mount container %s failed", id); + isulad_try_set_error_message("failed to mount rootfs"); + return -1; + } + + ret = chroot_tar(mount_point, file, &errmsg); + if (ret != 0) { + ERROR("export container %s to file %s failed", id, file); + isulad_try_set_error_message("%s", errmsg); + goto out; + } + +out: + free(mount_point); + mount_point = NULL; + free(errmsg); + errmsg = NULL; + + ret2 = storage_rootfs_umount(id); + if (ret2 != 0) { + ret = ret2; + ERROR("umount container %s failed", id); + isulad_try_set_error_message("failed to umount rootfs"); + } + + return ret; +} diff --git a/src/image/oci/oci_export.h b/src/image/oci/oci_export.h new file mode 100644 index 0000000000000000000000000000000000000000..7033cc6110b092db790cff060f043596bd537d2d --- /dev/null +++ b/src/image/oci/oci_export.h @@ -0,0 +1,28 @@ +/****************************************************************************** +* Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. +* iSulad licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* 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 v2 for more details. +* Author: wangfengtu +* Create: 2020-06-01 +* Description: isula image export operator implement +*******************************************************************************/ +#ifndef __IMAGE_OCI_EXPORT_H +#define __IMAGE_OCI_EXPORT_H + +#ifdef __cplusplus +extern "C" { +#endif + +int oci_do_export(char *id, char *file); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/image/oci/oci_image.c b/src/image/oci/oci_image.c index 8a240ddb75fd3e3e357a4172ab50d9360498303d..5e4ab8acf157046f189cef5802a97f6f9fa8bdf9 100644 --- a/src/image/oci/oci_image.c +++ b/src/image/oci/oci_image.c @@ -27,6 +27,7 @@ #include "storage.h" #include "oci_load.h" #include "oci_import.h" +#include "oci_export.h" #define IMAGE_NOT_KNOWN_ERR "image not known" @@ -434,8 +435,7 @@ int oci_export_rf(const im_export_request *request) return -1; } - // TODO call storage export load interface - //ret = isula_container_export(request->name_id, request->file, 0, 0, 0); + ret = oci_do_export(request->name_id, request->file); if (ret != 0) { ERROR("Failed to export container: %s", request->name_id); } diff --git a/src/services/execution/execute/execution_stream.c b/src/services/execution/execute/execution_stream.c index 5b3ad4e5dd3bb8273ce7a624c955f7e72a06a9e6..ba98a11300abfd70d3bbd2394a1e1981e4ee309d 100644 --- a/src/services/execution/execute/execution_stream.c +++ b/src/services/execution/execute/execution_stream.c @@ -36,7 +36,7 @@ #include "config.h" #include "image.h" #include "path.h" -#include "libtar.h" +#include "isulad_tar.h" #include "isula_libutils/container_inspect.h" #include "containers_store.h" #include "container_state.h" diff --git a/src/services/execution/log_gather.c b/src/services/execution/log_gather.c index eb23d8bb121568248cb0fb6b3cdb139dde29224a..327ce6dbe8e6d20a130be09e4cf6be878f62382b 100644 --- a/src/services/execution/log_gather.c +++ b/src/services/execution/log_gather.c @@ -26,7 +26,7 @@ #include "isula_libutils/log.h" #include "utils.h" -#include "libtar.h" +#include "isulad_tar.h" typedef int(*log_save_t)(const void *buf, size_t count); static log_save_t g_save_log_op = NULL; diff --git a/src/tar/libtar.c b/src/tar/isulad_tar.c similarity index 88% rename from src/tar/libtar.c rename to src/tar/isulad_tar.c index 8098b895e64c4afdd87afd58a4c4e190a776b511..9b67531c8cddc9a73a2adbf692b4a6aeb7b9e461 100644 --- a/src/tar/libtar.c +++ b/src/tar/isulad_tar.c @@ -25,8 +25,9 @@ #include #include #include +#include -#include "libtar.h" +#include "isulad_tar.h" #include "utils.h" #include "path.h" #include "isula_libutils/log.h" @@ -40,6 +41,8 @@ #define TAR_EXACT_OPT "-x" #define TAR_CHDIR_OPT "-C" #define TAR_GZIP_OPT "-z" +#define TAR_DEFAULT_MODE 0600 +#define TAR_DEFAULT_FLAG (O_WRONLY | O_CREAT) static void set_char_to_separator(char *p) { @@ -888,3 +891,124 @@ int tar_resource(const struct archive_copy_info *info, struct io_read_wrapper *a return tar_resource_rebase(info->path, info->rebase_name, archive_reader, err); } +static int tar_all(char *path, int fd) +{ + TAR *tar = NULL; + int ret = 0; + + ret = tar_fdopen(&tar, fd, NULL, NULL, TAR_DEFAULT_FLAG, TAR_DEFAULT_MODE, TAR_GNU); + if (ret != 0) { + ERROR("open file for exporting container rootfs failed: %s", strerror(errno)); + fprintf(stderr, "open file for exporting container rootfs failed: %s", strerror(errno)); + return -1; + } + + ret = tar_append_tree(tar, path, "."); + if (ret != 0) { + ERROR("append files tree for exporting container rootfs failed: %s", strerror(errno)); + fprintf(stderr, "append files tree for exporting container rootfs failed: %s", strerror(errno)); + goto out; + } + +out: + + tar_close(tar); + tar = NULL; + + return ret; +} + +int chroot_tar(char *path, char *file, char **errmsg) +{ + int ret = 0; + pid_t pid; + int pipe_for_read[2] = { -1, -1 }; + int keepfds[] = { -1, -1 }; + char errbuf[BUFSIZ] = {0}; + int fd = 0; + + if (pipe2(pipe_for_read, O_CLOEXEC) != 0) { + ERROR("Failed to create pipe"); + ret = -1; + goto cleanup; + } + + pid = fork(); + if (pid == (pid_t) -1) { + ERROR("Failed to fork()"); + ret = -1; + close(pipe_for_read[0]); + close(pipe_for_read[1]); + goto cleanup; + } + + if (pid == (pid_t)0) { + keepfds[0] = isula_libutils_get_log_fd(); + keepfds[1] = pipe_for_read[1]; + ret = util_check_inherited_exclude_fds(true, keepfds, 2); + if (ret != 0) { + ERROR("Failed to close fds."); + ret = -1; + goto child_out; + } + + // child process, dup2 pipe_for_read[1] to stderr, + if (dup2(pipe_for_read[1], 2) < 0) { + ERROR("Dup fd error: %s", strerror(errno)); + ret = -1; + goto child_out; + } + + fd = open(file, TAR_DEFAULT_FLAG, TAR_DEFAULT_MODE); + if (fd < 0) { + ERROR("Failed to open file %s for export: %s", file, strerror(errno)); + fprintf(stderr, "Failed to open file %s for export: %s", file, strerror(errno)); + ret = -1; + goto child_out; + } + + if (chroot(path) != 0) { + ERROR("Failed to chroot to %s", path); + fprintf(stderr, "Failed to chroot to %s", path); + ret = -1; + goto child_out; + } + + if (chdir("/") != 0) { + ERROR("Failed to chroot to /"); + fprintf(stderr, "Failed to chroot to /"); + ret = -1; + goto child_out; + } + + ret = tar_all("/", fd); + +child_out: + + if (ret != 0) { + exit(EXIT_FAILURE); + } else { + exit(EXIT_SUCCESS); + } + } + + ret = wait_for_pid(pid); + if (ret != 0) { + ERROR("tar failed"); + if (read(pipe_for_read[0], errbuf, BUFSIZ) < 0) { + ERROR("read error message from child failed"); + } + close(pipe_for_read[0]); + pipe_for_read[0] = -1; + } + + close(pipe_for_read[1]); + pipe_for_read[1] = -1; + +cleanup: + if (errmsg != NULL && strlen(errbuf) != 0) { + *errmsg = util_strdup_s(errbuf); + } + + return ret; +} diff --git a/src/tar/libtar.h b/src/tar/isulad_tar.h similarity index 97% rename from src/tar/libtar.h rename to src/tar/isulad_tar.h index 9db9aa1d0ff9de6194dc207d6a8a4c485e790a67..f60603189509f0ce2da615ca3675c4e4b9d8908d 100644 --- a/src/tar/libtar.h +++ b/src/tar/isulad_tar.h @@ -68,6 +68,8 @@ int archive_copy_to(const struct io_read_wrapper *content, bool compression, con int archive_path(const char *srcdir, const char *srcbase, const char *rebase_name, bool compression, struct io_read_wrapper *archive_reader); +int chroot_tar(char *path, char *file, char **errmsg); + #ifdef __cplusplus } #endif