From 96694e419d45d4d6c87d179b6cc6e488c0ca2109 Mon Sep 17 00:00:00 2001 From: lifeng68 Date: Wed, 25 Nov 2020 17:07:31 +0800 Subject: [PATCH] iSulad: sync with upstream and add chrpath Signed-off-by: lifeng68 --- ...h => 0000-update-from-2.0.5-to-2.0.7.patch | 37539 +++++++++++++++- 0000-update-from-v2.0.5-to-v2.0.6.patch | 21385 --------- ...Add-a-solution-to-the-gpgkey-problem.patch | 45 + ...iSulad-modify-defattr-to-755-in-spec.patch | 26 - ...e-dockerfile-to-isulad-v2.0.6-use-mu.patch | 254 - ...mp-directory-from-var-tmp-to-var-lib.patch | 606 + ...start-should-read-the-isulad-shim-pi.patch | 92 - ...roto-to-v1.19.3-according-to-kubelet.patch | 102 + ...-get-realpath-for-root-and-state-dir.patch | 240 - 0004-adapt-CI-ISULAD_TMPDIR-testcases.patch | 50 + ...stcase-for-root-and-run-dir-realpath.patch | 318 - ...0.1-port-in-cri-stream-websocket-ser.patch | 75 + 0006-info-fix-typo-driverr-to-driver.patch | 26 - ...que-token-in-CRI-websockets-server-R.patch | 50 + ...t_use_decrypted_key_flag-and-setup-a.patch | 56 + 0007-create-fix-wrong-ret-code.patch | 48 - ...-add-iSulad-s-build-guide-for-RISC-V.patch | 319 - 0009-add-non-root-group.patch | 190 - 0010-add-nonroot-execute-CI.patch | 90 - ...-support-extension-data-transmission.patch | 91 - ...add-remove-target-file-in-handle-.wh.patch | 386 - 0013-iSulad-internal-change.patch | 476 - 0014-unlink-etc-dir-when-link-exists.patch | 26 - ...-support-variable-extension-cni-args.patch | 182 - ...-support-variable-extension-cni-args.patch | 112 - 0017-add-unlink-dir-comments.patch | 26 - ...Sulad-add-ISULAD_TMPDIR-env-variable.patch | 398 - 0020-add-ISULAD_TMPDIR-env-CI.patch | 120 - ...-memory-leak-in-inspect-grpc-service.patch | 41 - ...n-code-remove-unused-code-in-connect.patch | 1424 - ...character-at-end-of-iSulad.sysconfig.patch | 24 - 0024-clean-code-remove-unused-in-code.patch | 46 - ...-fdatasync-when-do-atomic-write-file.patch | 66 - 0026-network-support-mutlnetworks.patch | 975 - 0027-add-testcases-for-mutl-networks.patch | 159 - ...r-to-get-only-non-sandbox-containers.patch | 43 - iSulad.spec | 54 +- 37 files changed, 38492 insertions(+), 27668 deletions(-) rename 0019-CI-remove-test-data-from-iSulad-repo.patch => 0000-update-from-2.0.5-to-2.0.7.patch (96%) delete mode 100644 0000-update-from-v2.0.5-to-v2.0.6.patch create mode 100644 0001-Add-a-solution-to-the-gpgkey-problem.patch delete mode 100644 0001-iSulad-modify-defattr-to-755-in-spec.patch delete mode 100644 0002-Dockerfile-update-dockerfile-to-isulad-v2.0.6-use-mu.patch create mode 100644 0002-change-default-tmp-directory-from-var-tmp-to-var-lib.patch delete mode 100644 0003-isulad-rt_isula_start-should-read-the-isulad-shim-pi.patch create mode 100644 0003-update-api.proto-to-v1.19.3-according-to-kubelet.patch delete mode 100644 0004-Realpath-add-get-realpath-for-root-and-state-dir.patch create mode 100644 0004-adapt-CI-ISULAD_TMPDIR-testcases.patch delete mode 100644 0005-CI-add-testcase-for-root-and-run-dir-realpath.patch create mode 100644 0005-listening-127.0.0.1-port-in-cri-stream-websocket-ser.patch delete mode 100644 0006-info-fix-typo-driverr-to-driver.patch create mode 100644 0006-using-64-bit-unique-token-in-CRI-websockets-server-R.patch create mode 100644 0007-add-mock-conf_get_use_decrypted_key_flag-and-setup-a.patch delete mode 100644 0007-create-fix-wrong-ret-code.patch delete mode 100644 0008-add-iSulad-s-build-guide-for-RISC-V.patch delete mode 100644 0009-add-non-root-group.patch delete mode 100644 0010-add-nonroot-execute-CI.patch delete mode 100644 0011-cni-support-extension-data-transmission.patch delete mode 100644 0012-unpack-add-remove-target-file-in-handle-.wh.patch delete mode 100644 0013-iSulad-internal-change.patch delete mode 100644 0014-unlink-etc-dir-when-link-exists.patch delete mode 100644 0015-support-variable-extension-cni-args.patch delete mode 100644 0016-CI-for-support-variable-extension-cni-args.patch delete mode 100644 0017-add-unlink-dir-comments.patch delete mode 100644 0018-iSulad-add-ISULAD_TMPDIR-env-variable.patch delete mode 100644 0020-add-ISULAD_TMPDIR-env-CI.patch delete mode 100644 0021-iSulad-fix-memory-leak-in-inspect-grpc-service.patch delete mode 100644 0022-clean-code-remove-unused-code-in-connect.patch delete mode 100644 0023-add-newline-character-at-end-of-iSulad.sysconfig.patch delete mode 100644 0024-clean-code-remove-unused-in-code.patch delete mode 100644 0025-utils-add-fdatasync-when-do-atomic-write-file.patch delete mode 100644 0026-network-support-mutlnetworks.patch delete mode 100644 0027-add-testcases-for-mutl-networks.patch delete mode 100644 0028-add-filter-to-get-only-non-sandbox-containers.patch diff --git a/0019-CI-remove-test-data-from-iSulad-repo.patch b/0000-update-from-2.0.5-to-2.0.7.patch similarity index 96% rename from 0019-CI-remove-test-data-from-iSulad-repo.patch rename to 0000-update-from-2.0.5-to-2.0.7.patch index 5e99eb1..4abcb78 100644 --- a/0019-CI-remove-test-data-from-iSulad-repo.patch +++ b/0000-update-from-2.0.5-to-2.0.7.patch @@ -1,28 +1,1476 @@ -From b1f0e1de825bb252b577df085f0a063b3cece480 Mon Sep 17 00:00:00 2001 +From 41dc79ec6179e527681884635739930264c2c704 Mon Sep 17 00:00:00 2001 From: lifeng68 -Date: Thu, 5 Nov 2020 14:58:25 +0800 -Subject: [PATCH 19/28] CI: remove test data from iSulad repo +Date: Wed, 25 Nov 2020 16:56:28 +0800 +Subject: [PATCH] update from 2.0.5 to 2.0.7 Signed-off-by: lifeng68 --- - .../container_cases/test_data/pause.tar | Bin 765440 -> 0 bytes - CI/test_cases/image_cases/busybox.tar | Bin 1446400 -> 0 bytes - CI/test_cases/image_cases/empty.gz | Bin 26 -> 0 bytes - CI/test_cases/image_cases/file.gz | Bin 30 -> 0 bytes - CI/test_cases/image_cases/mult_image.tar | Bin 77709824 -> 0 bytes - .../image_cases/multiplex_busybox.tar | Bin 20480 -> 0 bytes - CI/test_cases/image_cases/rootfs.tar | Bin 1443840 -> 0 bytes - CI/test_cases/image_cases/rootfs.tar.xz | Bin 634980 -> 0 bytes - 8 files changed, 0 insertions(+), 0 deletions(-) + CI/Dockerfile | 2 +- + CI/install_depends.sh | 8 +- + CI/make-and-install.sh | 4 +- + CI/test.sh | 2 +- + CI/test_cases/container_cases/blkio_iops.sh | 74 + + CI/test_cases/container_cases/blkio_weight.sh | 76 + + CI/test_cases/container_cases/cni_test.sh | 86 +- + .../container_cases/criconfigs/bridge.json | 17 +- + .../container_cases/criconfigs/mock.json | 9 + + .../criconfigs/mutlnet_pod.json | 17 + + .../criconfigs/sandbox-config.json | 5 + + .../container_cases/dev_cgroup_rule.sh | 98 + + .../container_cases/graph_root_test.sh | 284 +++ + CI/test_cases/container_cases/nano_cpus.sh | 113 ++ + CI/test_cases/container_cases/nonroot.sh | 70 + + CI/test_cases/container_cases/run.sh | 2 +- + .../container_cases/storage_opts_dm.sh | 2 +- + .../container_cases/test_data/pause.tar | Bin 765440 -> 0 bytes + CI/test_cases/container_cases/volume.sh | 434 +++++ + .../volume_mount_propagation.sh | 297 ++++ + .../container_cases/volume_v_propagation.sh | 297 ++++ + CI/test_cases/image_cases/busybox.tar | Bin 1446400 -> 0 bytes + CI/test_cases/image_cases/empty.gz | Bin 26 -> 0 bytes + CI/test_cases/image_cases/file.gz | Bin 30 -> 0 bytes + .../image_cases/image_load_multiplex.sh | 83 + + CI/test_cases/image_cases/image_tag.sh | 2 + + CI/test_cases/image_cases/isulad_tmpdir.sh | 100 ++ + CI/test_cases/image_cases/mult_image.tar | Bin 77709824 -> 0 bytes + CI/test_cases/image_cases/registry.sh | 22 +- + CI/test_cases/image_cases/rootfs.tar | Bin 1443840 -> 0 bytes + CI/test_cases/image_cases/rootfs.tar.xz | Bin 634980 -> 0 bytes + CMakeLists.txt | 18 +- + Dockerfile | 136 +- + README.md | 85 +- + cmake/checker.cmake | 16 +- + cmake/options.cmake | 9 +- + cmake/protoc.cmake | 34 +- + docs/build_guide.md | 6 +- + docs/build_guide_riscv.md | 296 ++++ + iSulad.spec | 28 +- + release_notes | 105 ++ + src/CMakeLists.txt | 4 +- + src/api/services/cri/api.proto | 9 + + src/api/services/health/health.proto | 54 - + src/api/services/images/images.proto | 88 +- + src/api/services/volumes/volumes.proto | 59 + + src/api/types/descriptor.proto | 49 - + src/client/connect/CMakeLists.txt | 8 +- + src/client/connect/grpc/CMakeLists.txt | 1 + + src/client/connect/grpc/grpc_client.cc | 8 +- + .../connect/grpc/grpc_containers_client.cc | 95 +- + .../connect/grpc/grpc_volumes_client.cc | 197 +++ + src/client/connect/grpc/grpc_volumes_client.h | 31 + + src/client/connect/isula_connect.h | 14 +- + .../{libisula.c => connect/protocol_type.c} | 281 +-- + .../{libisula.h => connect/protocol_type.h} | 249 +-- + .../connect/rest/rest_containers_client.c | 96 +- + src/client/connect/rest/rest_images_client.c | 2 +- + src/cmd/CMakeLists.txt | 10 +- + src/cmd/command_parser.c | 70 +- + src/cmd/command_parser.h | 10 +- + src/cmd/isula/CMakeLists.txt | 3 + + src/cmd/isula/base/create.c | 1009 +++++------ + src/cmd/isula/base/create.h | 829 +++++---- + src/cmd/isula/base/kill.c | 4 +- + src/cmd/isula/base/rename.c | 1 - + src/cmd/isula/base/restart.c | 3 +- + src/cmd/isula/base/rm.c | 5 +- + src/cmd/isula/base/run.c | 61 +- + src/cmd/isula/base/start.c | 3 +- + src/cmd/isula/base/start.h | 2 +- + src/cmd/isula/base/stop.c | 1 - + src/cmd/isula/client_arguments.c | 18 + + src/cmd/isula/client_arguments.h | 28 +- + src/cmd/isula/client_console.c | 319 ++++ + src/cmd/isula/client_console.h | 52 + + src/cmd/isula/extend/events.c | 12 +- + src/cmd/isula/extend/export.c | 1 - + src/cmd/isula/extend/pause.c | 1 - + src/cmd/isula/extend/resume.c | 1 - + src/cmd/isula/extend/stats.c | 11 +- + src/cmd/isula/extend/update.c | 92 +- + src/cmd/isula/extend/update.h | 34 +- + src/cmd/isula/images/images.c | 2 +- + src/cmd/isula/images/import.c | 2 +- + src/cmd/isula/images/load.c | 1 - + src/cmd/isula/images/login.c | 3 +- + src/cmd/isula/images/login.h | 4 +- + src/cmd/isula/images/logout.c | 1 - + src/cmd/isula/images/pull.c | 1 - + src/cmd/isula/images/rmi.c | 1 - + src/cmd/isula/images/tag.c | 2 +- + src/cmd/isula/information/health.c | 108 -- + src/cmd/isula/information/info.c | 3 +- + src/cmd/isula/information/inspect.c | 1 - + src/cmd/isula/information/logs.c | 8 +- + src/cmd/isula/information/logs.h | 16 +- + src/cmd/isula/information/ps.c | 27 +- + src/cmd/isula/information/top.c | 1 - + src/cmd/isula/information/version.c | 1 - + src/cmd/isula/information/wait.c | 4 +- + src/cmd/isula/isula_commands.c | 334 +--- + src/cmd/isula/isula_commands.h | 32 +- + src/cmd/isula/isula_container_spec.c | 450 +++++ + src/cmd/isula/isula_container_spec.h | 89 + + .../isula/isula_host_spec.c} | 1366 +++++--------- + src/cmd/isula/isula_host_spec.h | 163 ++ + src/cmd/isula/main.c | 74 +- + src/cmd/isula/stream/attach.c | 3 +- + src/cmd/isula/stream/cp.c | 8 +- + src/cmd/isula/stream/exec.c | 148 +- + src/cmd/isula/volume/CMakeLists.txt | 7 + + src/cmd/isula/volume/list.c | 170 ++ + src/cmd/isula/volume/list.h | 33 + + src/cmd/isula/volume/prune.c | 134 ++ + src/cmd/isula/volume/prune.h | 37 + + src/cmd/isula/volume/remove.c | 124 ++ + src/cmd/isula/volume/remove.h | 37 + + src/cmd/isula/volume/volume.c | 67 + + src/cmd/isula/volume/volume.h | 29 + + src/cmd/isulad-shim/common.c | 12 +- + src/cmd/isulad-shim/main.c | 22 +- + src/cmd/isulad-shim/process.c | 293 +-- + src/cmd/isulad-shim/terminal.c | 10 +- + src/cmd/isulad/isulad_commands.c | 198 +-- + src/cmd/isulad/isulad_commands.h | 4 +- + src/cmd/isulad/main.c | 39 +- + src/cmd/options/CMakeLists.txt | 5 + + src/cmd/options/opt_ulimit.c | 190 ++ + .../options/opt_ulimit.h} | 23 +- + src/common/constants.h | 7 +- + src/contrib/config/config.json | 2 +- + src/contrib/config/daemon.json | 2 +- + src/contrib/config/iSulad.sysconfig | 4 + + .../config/systemcontainer_config.json | 2 +- + src/daemon/common/CMakeLists.txt | 11 +- + src/daemon/common/selinux_label.c | 2 +- + src/daemon/common/sysinfo.c | 11 +- + src/daemon/common/sysinfo.h | 2 +- + src/daemon/config/daemon_arguments.c | 4 +- + src/daemon/config/isulad_config.c | 247 +-- + src/daemon/config/isulad_config.h | 4 +- + src/daemon/entry/connect/CMakeLists.txt | 6 +- + .../connect/grpc/grpc_containers_service.cc | 264 +-- + .../connect/grpc/grpc_containers_service.h | 42 +- + .../grpc/grpc_containers_service_private.cc | 117 +- + .../entry/connect/grpc/grpc_images_service.cc | 104 +- + .../entry/connect/grpc/grpc_images_service.h | 20 +- + .../connect/grpc/grpc_server_tls_auth.cc | 4 +- + src/daemon/entry/connect/grpc/grpc_service.cc | 3 + + .../connect/grpc/grpc_volumes_service.cc | 218 +++ + .../entry/connect/grpc/grpc_volumes_service.h | 71 + + .../connect/rest/rest_containers_service.c | 2 +- + .../entry/connect/rest/rest_images_service.c | 2 +- + .../entry/connect/rest/rest_service_common.c | 2 +- + src/daemon/entry/cri/cni_network_plugin.cc | 378 +++- + src/daemon/entry/cri/cni_network_plugin.h | 14 +- + src/daemon/entry/cri/cri_container.cc | 49 +- + src/daemon/entry/cri/cri_helpers.cc | 50 +- + src/daemon/entry/cri/cri_helpers.h | 5 +- + src/daemon/entry/cri/cri_runtime_service.h | 13 +- + src/daemon/entry/cri/cri_sandbox.cc | 260 ++- + src/daemon/entry/cri/cri_security_context.cc | 5 +- + src/daemon/entry/cri/network_plugin.cc | 120 +- + src/daemon/entry/cri/network_plugin.h | 10 +- + src/daemon/entry/cri/sysctl_tools.c | 2 +- + src/daemon/executor/CMakeLists.txt | 4 + + src/daemon/executor/callback.c | 2 + + src/daemon/executor/callback.h | 15 + + src/daemon/executor/container_cb/execution.c | 6 +- + .../executor/container_cb/execution_create.c | 230 ++- + .../executor/container_cb/execution_extend.c | 50 +- + .../container_cb/execution_information.c | 31 +- + .../executor/container_cb/execution_network.c | 243 +-- + .../executor/container_cb/execution_stream.c | 26 +- + src/daemon/executor/container_cb/list.c | 6 +- + src/daemon/executor/image_cb/image_cb.c | 7 +- + src/daemon/executor/volume_cb/CMakeLists.txt | 12 + + src/daemon/executor/volume_cb/volume_cb.c | 207 +++ + src/daemon/executor/volume_cb/volume_cb.h | 32 + + src/daemon/modules/CMakeLists.txt | 3 + + .../modules/api/service_container_api.h | 3 + + src/daemon/modules/api/volume_api.h | 93 + + .../container/container_events_handler.c | 4 +- + .../container/container_gc/containers_gc.c | 8 +- + .../modules/container/container_state.c | 10 +- + src/daemon/modules/container/container_unix.c | 55 +- + .../container/health_check/health_check.c | 24 +- + .../modules/container/restore/restore.c | 5 +- + .../modules/container/supervisor/supervisor.c | 4 +- + src/daemon/modules/events/collector.c | 24 +- + src/daemon/modules/events/monitord.c | 47 +- + src/daemon/modules/events/monitord.h | 6 +- + .../modules/events_sender/event_sender.c | 2 +- + src/daemon/modules/image/CMakeLists.txt | 2 + + src/daemon/modules/image/embedded/db/db_all.c | 10 +- + src/daemon/modules/image/embedded/db/db_all.h | 3 + + .../modules/image/embedded/db/sqlite_common.c | 14 +- + .../image/embedded/embedded_config_merge.c | 57 +- + .../image/embedded/embedded_config_merge.h | 3 +- + .../modules/image/embedded/embedded_image.c | 2 +- + src/daemon/modules/image/embedded/lim.c | 16 +- + src/daemon/modules/image/embedded/lim.h | 2 +- + src/daemon/modules/image/external/ext_image.c | 2 +- + src/daemon/modules/image/image.c | 24 +- + .../modules/image/image_rootfs_handler.c | 45 +- + src/daemon/modules/image/image_spec_merge.c | 84 + + src/daemon/modules/image/image_spec_merge.h | 30 + + .../modules/image/oci/oci_common_operators.c | 10 +- + .../modules/image/oci/oci_config_merge.c | 79 +- + src/daemon/modules/image/oci/oci_export.c | 2 +- + src/daemon/modules/image/oci/oci_image.c | 25 +- + src/daemon/modules/image/oci/oci_import.c | 39 +- + src/daemon/modules/image/oci/oci_load.c | 389 ++-- + src/daemon/modules/image/oci/oci_load.h | 5 +- + src/daemon/modules/image/oci/oci_pull.c | 5 +- + src/daemon/modules/image/oci/registry/aes.c | 2 +- + src/daemon/modules/image/oci/registry/auths.c | 38 +- + src/daemon/modules/image/oci/registry/auths.h | 2 +- + src/daemon/modules/image/oci/registry/certs.c | 6 +- + .../modules/image/oci/registry/http_request.c | 4 +- + .../modules/image/oci/registry/registry.c | 99 +- + .../image/oci/registry/registry_apiv2.c | 34 +- + src/daemon/modules/image/oci/registry_type.c | 8 +- + src/daemon/modules/image/oci/registry_type.h | 3 +- + .../oci/storage/image_store/image_store.c | 326 ++-- + .../graphdriver/devmapper/deviceset.c | 56 +- + .../graphdriver/devmapper/driver_devmapper.c | 46 +- + .../graphdriver/devmapper/driver_devmapper.h | 1 + + .../graphdriver/devmapper/metadata_store.c | 3 +- + .../graphdriver/devmapper/wrapper_devmapper.c | 2 +- + .../storage/layer_store/graphdriver/driver.c | 4 +- + .../storage/layer_store/graphdriver/driver.h | 7 +- + .../graphdriver/overlay2/driver_overlay2.c | 40 +- + .../graphdriver/overlay2/driver_overlay2.h | 2 +- + .../graphdriver/quota/project_quota.c | 4 +- + .../graphdriver/quota/project_quota.h | 56 +- + .../image/oci/storage/layer_store/layer.h | 2 +- + .../oci/storage/layer_store/layer_store.c | 84 +- + .../oci/storage/layer_store/layer_store.h | 5 +- + .../oci/storage/rootfs_store/rootfs_store.c | 326 ++-- + .../oci/storage/rootfs_store/rootfs_store.h | 3 - + .../modules/image/oci/storage/storage.c | 80 +- + .../modules/image/oci/storage/storage.h | 7 +- + src/daemon/modules/image/oci/utils_images.c | 65 +- + src/daemon/modules/image/oci/utils_images.h | 7 +- + src/daemon/modules/plugin/plugin.c | 8 +- + src/daemon/modules/plugin/pspec.c | 3 +- + src/daemon/modules/runtime/engines/engine.h | 2 + + .../modules/runtime/engines/lcr/lcr_engine.c | 2 + + .../modules/runtime/engines/lcr/lcr_rt_ops.c | 12 + + .../modules/runtime/isula/isula_rt_ops.c | 46 +- + .../modules/service/service_container.c | 102 +- + src/daemon/modules/spec/parse_volume.c | 413 +++++ + src/daemon/modules/spec/parse_volume.h | 33 + + src/daemon/modules/spec/specs.c | 136 +- + src/daemon/modules/spec/specs_extend.c | 52 +- + src/daemon/modules/spec/specs_mount.c | 1574 ++++++++++++----- + src/daemon/modules/spec/specs_mount.h | 9 - + src/daemon/modules/spec/specs_namespace.c | 10 +- + src/daemon/modules/spec/specs_security.c | 57 +- + src/daemon/modules/spec/specs_security.h | 4 +- + src/daemon/modules/spec/verify.c | 149 +- + src/daemon/modules/volume/CMakeLists.txt | 12 + + src/daemon/modules/volume/local.c | 633 +++++++ + src/daemon/modules/volume/local.h | 44 + + src/daemon/modules/volume/volume.c | 655 +++++++ + src/utils/console/console.c | 2 +- + src/utils/cutils/mainloop.c | 2 +- + src/utils/cutils/map/map.c | 2 +- + src/utils/cutils/map/rb_tree.c | 8 +- + src/utils/cutils/namespace.c | 6 +- + src/utils/cutils/namespace.h | 12 +- + src/utils/cutils/path.c | 58 +- + src/utils/cutils/path.h | 25 +- + src/utils/cutils/utils.c | 474 +---- + src/utils/cutils/utils.h | 67 +- + src/utils/cutils/utils_aes.c | 2 +- + src/utils/cutils/utils_base64.c | 2 +- + src/utils/cutils/utils_convert.c | 52 + + src/utils/cutils/utils_convert.h | 4 +- + src/utils/cutils/utils_file.c | 526 +++++- + src/utils/cutils/utils_file.h | 21 +- + src/utils/cutils/utils_fs.c | 41 +- + src/utils/cutils/utils_fs.h | 3 +- + src/utils/cutils/utils_mount_spec.c | 456 +++++ + .../cutils/utils_mount_spec.h} | 32 +- + src/utils/cutils/utils_regex.c | 7 +- + src/utils/cutils/utils_string.c | 61 +- + src/utils/cutils/utils_string.h | 22 +- + src/utils/cutils/utils_timestamp.c | 156 +- + src/utils/cutils/utils_timestamp.h | 47 +- + src/utils/cutils/utils_verify.c | 126 +- + src/utils/cutils/utils_verify.h | 22 + + src/utils/http/http.c | 2 +- + src/utils/http/parser.c | 4 +- + src/utils/http/rest_common.c | 5 +- + src/utils/sha256/sha256.c | 4 +- + src/utils/sha256/sha256.h | 2 +- + src/utils/tar/isulad_tar.c | 30 +- + src/utils/tar/util_archive.c | 178 +- + src/utils/tar/util_archive.h | 6 +- + src/utils/tar/util_gzip.c | 2 +- + src/utils/tar/util_gzip.h | 3 + + test/cmd/isula/CMakeLists.txt | 2 +- + test/cmd/isula/extend/pause/CMakeLists.txt | 2 +- + test/cmd/isula/extend/pause/pause_ut.cc | 2 +- + test/cmd/isula/extend/resume/CMakeLists.txt | 2 +- + test/cmd/isula/extend/resume/resume_ut.cc | 2 +- + .../CMakeLists.txt | 0 + .../info/CMakeLists.txt | 2 +- + .../info/info_ut.cc | 2 +- + .../ps/CMakeLists.txt | 2 +- + .../{infomation => information}/ps/ps_ut.cc | 2 +- + test/cutils/utils_string/utils_string_ut.cc | 136 +- + test/fuzz/CMakeLists.txt | 52 + + test/fuzz/dict/volume_fuzz.dict | 34 + + test/fuzz/fuzz.sh | 24 + + test/fuzz/test_volume_mount_spec_fuzz.cc | 31 + + test/fuzz/test_volume_parse_volume_fuzz.cc | 31 + + .../image/oci/oci_config_merge/CMakeLists.txt | 12 +- + test/image/oci/registry/data/v2/ping_head | 5 +- + test/image/oci/registry/registry_ut.cc | 15 +- + .../oci/storage/images/storage_images_ut.cc | 10 +- + .../oci/storage/layers/storage_driver_ut.cc | 4 +- + .../oci/storage/layers/storage_layers_ut.cc | 8 +- + .../oci/storage/rootfs/storage_rootfs_ut.cc | 22 +- + test/mocks/image_mock.cc | 16 + + test/mocks/image_mock.h | 4 + + test/mocks/namespace_mock.cc | 2 +- + test/mocks/storage_mock.cc | 36 +- + test/mocks/storage_mock.h | 6 +- + test/path/path_ut.cc | 102 +- + test/runtime/isula/CMakeLists.txt | 1 + + test/runtime/lcr/CMakeLists.txt | 1 + + test/specs/specs/CMakeLists.txt | 16 +- + test/specs/specs_extend/CMakeLists.txt | 16 +- + 337 files changed, 16057 insertions(+), 7310 deletions(-) + create mode 100644 CI/test_cases/container_cases/blkio_iops.sh + create mode 100644 CI/test_cases/container_cases/blkio_weight.sh + create mode 100644 CI/test_cases/container_cases/criconfigs/mock.json + create mode 100644 CI/test_cases/container_cases/criconfigs/mutlnet_pod.json + create mode 100644 CI/test_cases/container_cases/dev_cgroup_rule.sh + create mode 100644 CI/test_cases/container_cases/graph_root_test.sh + create mode 100644 CI/test_cases/container_cases/nano_cpus.sh + create mode 100755 CI/test_cases/container_cases/nonroot.sh delete mode 100644 CI/test_cases/container_cases/test_data/pause.tar + create mode 100755 CI/test_cases/container_cases/volume.sh + create mode 100755 CI/test_cases/container_cases/volume_mount_propagation.sh + create mode 100755 CI/test_cases/container_cases/volume_v_propagation.sh delete mode 100644 CI/test_cases/image_cases/busybox.tar delete mode 100644 CI/test_cases/image_cases/empty.gz delete mode 100644 CI/test_cases/image_cases/file.gz + create mode 100755 CI/test_cases/image_cases/image_load_multiplex.sh + create mode 100644 CI/test_cases/image_cases/isulad_tmpdir.sh delete mode 100644 CI/test_cases/image_cases/mult_image.tar - delete mode 100644 CI/test_cases/image_cases/multiplex_busybox.tar delete mode 100644 CI/test_cases/image_cases/rootfs.tar delete mode 100644 CI/test_cases/image_cases/rootfs.tar.xz + create mode 100644 docs/build_guide_riscv.md + delete mode 100644 src/api/services/health/health.proto + create mode 100644 src/api/services/volumes/volumes.proto + delete mode 100644 src/api/types/descriptor.proto + create mode 100644 src/client/connect/grpc/grpc_volumes_client.cc + create mode 100644 src/client/connect/grpc/grpc_volumes_client.h + rename src/client/{libisula.c => connect/protocol_type.c} (85%) + rename src/client/{libisula.h => connect/protocol_type.h} (81%) + create mode 100644 src/cmd/isula/client_console.c + create mode 100644 src/cmd/isula/client_console.h + delete mode 100644 src/cmd/isula/information/health.c + create mode 100644 src/cmd/isula/isula_container_spec.c + create mode 100644 src/cmd/isula/isula_container_spec.h + rename src/{client/connect/pack_config.c => cmd/isula/isula_host_spec.c} (52%) + create mode 100644 src/cmd/isula/isula_host_spec.h + create mode 100644 src/cmd/isula/volume/CMakeLists.txt + create mode 100644 src/cmd/isula/volume/list.c + create mode 100644 src/cmd/isula/volume/list.h + create mode 100644 src/cmd/isula/volume/prune.c + create mode 100644 src/cmd/isula/volume/prune.h + create mode 100644 src/cmd/isula/volume/remove.c + create mode 100644 src/cmd/isula/volume/remove.h + create mode 100644 src/cmd/isula/volume/volume.c + create mode 100644 src/cmd/isula/volume/volume.h + create mode 100644 src/cmd/options/CMakeLists.txt + create mode 100644 src/cmd/options/opt_ulimit.c + rename src/{client/connect/pack_config.h => cmd/options/opt_ulimit.h} (65%) + create mode 100644 src/daemon/entry/connect/grpc/grpc_volumes_service.cc + create mode 100644 src/daemon/entry/connect/grpc/grpc_volumes_service.h + create mode 100644 src/daemon/executor/volume_cb/CMakeLists.txt + create mode 100644 src/daemon/executor/volume_cb/volume_cb.c + create mode 100644 src/daemon/executor/volume_cb/volume_cb.h + create mode 100644 src/daemon/modules/api/volume_api.h + create mode 100644 src/daemon/modules/image/image_spec_merge.c + create mode 100644 src/daemon/modules/image/image_spec_merge.h + create mode 100644 src/daemon/modules/spec/parse_volume.c + create mode 100644 src/daemon/modules/spec/parse_volume.h + create mode 100644 src/daemon/modules/volume/CMakeLists.txt + create mode 100644 src/daemon/modules/volume/local.c + create mode 100644 src/daemon/modules/volume/local.h + create mode 100644 src/daemon/modules/volume/volume.c + create mode 100644 src/utils/cutils/utils_mount_spec.c + rename src/{cmd/isula/information/health.h => utils/cutils/utils_mount_spec.h} (51%) + rename test/cmd/isula/{infomation => information}/CMakeLists.txt (100%) + rename test/cmd/isula/{infomation => information}/info/CMakeLists.txt (97%) + rename test/cmd/isula/{infomation => information}/info/info_ut.cc (98%) + rename test/cmd/isula/{infomation => information}/ps/CMakeLists.txt (97%) + rename test/cmd/isula/{infomation => information}/ps/ps_ut.cc (99%) + create mode 100644 test/fuzz/dict/volume_fuzz.dict + create mode 100644 test/fuzz/test_volume_mount_spec_fuzz.cc + create mode 100644 test/fuzz/test_volume_parse_volume_fuzz.cc +diff --git a/CI/Dockerfile b/CI/Dockerfile +index d953da9..b6f2e2c 100644 +--- a/CI/Dockerfile ++++ b/CI/Dockerfile +@@ -8,7 +8,7 @@ + # - IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + # - PURPOSE. + # - See the Mulan PSL v2 for more details. +-##- @Description: prepare compile container envrionment ++##- @Description: prepare compile container environment + ##- @Author: lifeng + ##- @Create: 2020-01-10 + ####################################################################### +diff --git a/CI/install_depends.sh b/CI/install_depends.sh +index 97fefa7..5dd2543 100755 +--- a/CI/install_depends.sh ++++ b/CI/install_depends.sh +@@ -38,10 +38,13 @@ mkdir -p ${builddir}/systemd/system + function make_crictl() + { + cd ~ +- git clone -b release-1.14 https://gitee.com/duguhaotian/cri-tools.git ++ git clone https://gitee.com/duguhaotian/cri-tools.git ++ go version + cd cri-tools ++ git checkout v1.18.0 + make -j $nproc +- cp ./_output/bin/crictl ${builddir}/bin/ ++ echo "make cri-tools: $?" ++ cp ./_output/crictl ${builddir}/bin/ + } + + #install cni plugins +@@ -113,6 +116,7 @@ if [ -d ./runc ];then + fi + git clone https://gitee.com/src-openeuler/runc.git + cd runc ++git checkout -q origin/openEuler-20.03-LTS + ./apply-patch + mkdir -p .gopath/src/github.com/opencontainers + export GOPATH=`pwd`/.gopath +diff --git a/CI/make-and-install.sh b/CI/make-and-install.sh +index a3d4888..c53cdc6 100755 +--- a/CI/make-and-install.sh ++++ b/CI/make-and-install.sh +@@ -89,7 +89,7 @@ cmake -DLIB_INSTALL_DIR=${restbuilddir}/lib -DCMAKE_INSTALL_PREFIX=${restbuilddi + make -j $(nproc) + make install + sed -i 's/"log-driver": "stdout"/"log-driver": "file"/g' ${restbuilddir}/etc/isulad/daemon.json +-sed -i "/registry-mirrors/a\ \"https://hub-mirror.c.163.com\"" ${restbuilddir}/etc/isulad/daemon.json ++sed -i "/registry-mirrors/a\ \"https://3laho3y3.mirror.aliyuncs.com\"" ${restbuilddir}/etc/isulad/daemon.json + + #build grpc version + cd $ISULAD_COPY_PATH +@@ -104,4 +104,4 @@ fi + make -j $(nproc) + make install + sed -i 's/"log-driver": "stdout"/"log-driver": "file"/g' ${builddir}/etc/isulad/daemon.json +-sed -i "/registry-mirrors/a\ \"https://hub-mirror.c.163.com\"" ${builddir}/etc/isulad/daemon.json ++sed -i "/registry-mirrors/a\ \"https://3laho3y3.mirror.aliyuncs.com\"" ${builddir}/etc/isulad/daemon.json +diff --git a/CI/test.sh b/CI/test.sh +index d21ca89..36427b9 100755 +--- a/CI/test.sh ++++ b/CI/test.sh +@@ -42,6 +42,6 @@ elif [ "x$subcmd" == "xget" ];then + sleep 2 + done + else +- echo "unknwon subcmd $subcmd" ++ echo "unknown subcmd $subcmd" + exit 1 + fi +diff --git a/CI/test_cases/container_cases/blkio_iops.sh b/CI/test_cases/container_cases/blkio_iops.sh +new file mode 100644 +index 0000000..58d3d7f +--- /dev/null ++++ b/CI/test_cases/container_cases/blkio_iops.sh +@@ -0,0 +1,74 @@ ++#!/bin/bash ++# ++# attributes: isulad basic blkio iops ++# concurrent: NA ++# spend time: 5 ++ ++####################################################################### ++##- @Copyright (C) Huawei Technologies., 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. ++##- @Description:CI ++##- @Author: lifeng ++##- @Create: 2020-09-03 ++####################################################################### ++ ++declare -r curr_path=$(dirname $(readlink -f "$0")) ++source ../helpers.sh ++ ++function test_blkio_iops_spec() ++{ ++ local ret=0 ++ local image="busybox" ++ local test="container blkio iops test => (${FUNCNAME[@]})" ++ ++ msg_info "${test} starting..." ++ ++ isula pull ${image} ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to pull image: ${image}" && return ${FAILURE} ++ ++ isula images | grep busybox ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - missing list image: ${image}" && ((ret++)) ++ ++ isula run -itd --device-read-iops /dev/loop0:-1 $image /bin/sh 2>&1 | grep "Number must be unsigned 64 bytes integer" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check Number must be unsigned 64 bytes integer" && ((ret++)) ++ ++ isula run -itd --device-write-iops /dev/loop0:-1 $image /bin/sh 2>&1 | grep "Number must be unsigned 64 bytes integer" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check Number must be unsigned 64 bytes integer" && ((ret++)) ++ ++ isula run -itd --device-write-iops /dev/loop0:2b $image /bin/sh 2>&1 | grep "Number must be unsigned 64 bytes integer" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check Number must be unsigned 64 bytes integer" && ((ret++)) ++ ++ c_id=`isula run -itd --device-read-iops /dev/loop0:123 --device-read-iops /dev/zero:111 --device-write-iops /dev/loop0:567 --device-write-iops /dev/zero:321 busybox sh` ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run container with image: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/blkio/blkio.throttle.read_iops_device" | grep "7:0 123" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check container with image: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/blkio/blkio.throttle.read_iops_device" | grep "1:5 111" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check container with image: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/blkio/blkio.throttle.write_iops_device" | grep "7:0 567" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check container with image: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/blkio/blkio.throttle.write_iops_device" | grep "1:5 321" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check container with image: ${image}" && ((ret++)) ++ ++ isula rm -f $c_id ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to rm container ${c_id}" && ((ret++)) ++ ++ msg_info "${test} finished with return ${ret}..." ++ return ${ret} ++} ++ ++declare -i ans=0 ++ ++test_blkio_iops_spec || ((ans++)) ++ ++show_result ${ans} "${curr_path}/${0}" +diff --git a/CI/test_cases/container_cases/blkio_weight.sh b/CI/test_cases/container_cases/blkio_weight.sh +new file mode 100644 +index 0000000..6d69960 +--- /dev/null ++++ b/CI/test_cases/container_cases/blkio_weight.sh +@@ -0,0 +1,76 @@ ++#!/bin/bash ++# ++# attributes: isulad basic blkio weight ++# concurrent: NA ++# spend time: 5 ++ ++####################################################################### ++##- @Copyright (C) Huawei Technologies., 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. ++##- @Description:CI ++##- @Author: lifeng ++##- @Create: 2020-09-03 ++####################################################################### ++ ++declare -r curr_path=$(dirname $(readlink -f "$0")) ++source ../helpers.sh ++ ++function test_blkio_weight_spec() ++{ ++ local ret=0 ++ local image="busybox" ++ local test="container blkio weight test => (${FUNCNAME[@]})" ++ ++ msg_info "${test} starting..." ++ ++ isula pull ${image} ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to pull image: ${image}" && return ${FAILURE} ++ ++ isula images | grep busybox ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - missing list image: ${image}" && ((ret++)) ++ ++ isula run -itd --blkio-weight 1001 $image /bin/sh 2>&1 | grep "Range of blkio weight is from 10 to 1000" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check Range of blkio weight is from 10 to 1000" && ((ret++)) ++ ++ isula run -itd --blkio-weight -1 $image /bin/sh 2>&1 | grep "Numerical result out of range" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check Range of blkio weight is from 10 to 1000" && ((ret++)) ++ ++ isula run -itd --blkio-weight-device /dev/zero:1001 $image /bin/sh 2>&1 | grep "Invalid weight for device" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Invalid weight for device" && ((ret++)) ++ ++ isula run -itd --blkio-weight-device /dev/zero:-1 $image /bin/sh 2>&1 | grep "Invalid weight for device" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Invalid weight for device" && ((ret++)) ++ ++ c_id=`isula run -itd --blkio-weight 200 ${image} sh` ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run container with image: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/blkio/blkio.weight" | grep "200" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check container blkio.weight: 200" && ((ret++)) ++ ++ isula update --blkio-weight 300 $c_id ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to update container blkio.weight" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/blkio/blkio.weight" | grep "300" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check container blkio.weight: 300" && ((ret++)) ++ ++ isula rm -f $c_id ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to rm container ${c_id}" && ((ret++)) ++ ++ msg_info "${test} finished with return ${ret}..." ++ return ${ret} ++} ++ ++declare -i ans=0 ++ ++if [ -f "/sys/fs/cgroup/blkio/blkio.weight" ];then ++ test_blkio_weight_spec || ((ans++)) ++fi ++ ++show_result ${ans} "${curr_path}/${0}" +diff --git a/CI/test_cases/container_cases/cni_test.sh b/CI/test_cases/container_cases/cni_test.sh +index 115e031..c9e1e1a 100644 +--- a/CI/test_cases/container_cases/cni_test.sh ++++ b/CI/test_cases/container_cases/cni_test.sh +@@ -53,7 +53,7 @@ function do_test_help() + TC_RET_T=$(($TC_RET_T+1)) + fi + +- sid=`crictl runp ${data_path}/sandbox-config.json` ++ sid=`crictl runp ${data_path}/$1` + if [ $? -ne 0 ]; then + msg_err "Failed to run sandbox" + TC_RET_T=$(($TC_RET_T+1)) +@@ -66,7 +66,7 @@ function do_test_help() + TC_RET_T=$(($TC_RET_T+1)) + fi + +- cid=`crictl create $sid ${data_path}/container-config.json ${data_path}/sandbox-config.json` ++ cid=`crictl create $sid ${data_path}/container-config.json ${data_path}/$1` + if [ $? -ne 0 ];then + msg_err "create container failed" + TC_RET_T=$(($TC_RET_T+1)) +@@ -96,12 +96,33 @@ function do_test_help() + nsenter -t $con_pid -n ifconfig eth0 + TC_RET_T=$(($TC_RET_T+1)) + fi +- nsenter -t $pod_pid -n ifconfig eth0 | grep "$1" ++ nsenter -t $pod_pid -n ifconfig eth0 | grep "$2" + if [ $? -ne 0 ];then + msg_err "expect ip: $1, get: " + nsenter -t $pod_pid -n ifconfig eth0 + TC_RET_T=$(($TC_RET_T+1)) + fi ++ crictl inspectp $sid | grep "$2" ++ if [ $? -ne 0 ];then ++ msg_err "inspectp: expect ip: $1, get: " ++ crictl inspectp $sid ++ TC_RET_T=$(($TC_RET_T+1)) ++ fi ++ ++ if [ "x$3" != "x" ];then ++ nsenter -t $pod_pid -n ifconfig eth1 | grep "$3" ++ if [ $? -ne 0 ];then ++ msg_err "expect ip: $2, get: " ++ nsenter -t $pod_pid -n ifconfig eth1 ++ TC_RET_T=$(($TC_RET_T+1)) ++ fi ++ crictl inspectp $sid | grep "$3" ++ if [ $? -ne 0 ];then ++ msg_err "inspectp expect ip: $2, get: " ++ crictl inspectp $sid ++ TC_RET_T=$(($TC_RET_T+1)) ++ fi ++ fi + + crictl stop $cid + if [ $? -ne 0 ];then +@@ -132,7 +153,7 @@ function do_test_help() + + function default_cni_config() + { +- do_test_help "10\.1\." ++ do_test_help "sandbox-config.json" "10\.1\." + } + + function new_cni_config() +@@ -151,7 +172,62 @@ function new_cni_config() + fi + done + tail $ISUALD_LOG +- do_test_help "10\.2\." ++ do_test_help "mutlnet_pod.json" "10\.2\." "10\.1\." ++} ++ ++function check_annotation() ++{ ++ cp ${data_path}/mock.json /etc/cni/net.d/bridge.json ++ sync;sync; ++ tail $ISUALD_LOG ++ # wait cni updated ++ s=`date "+%s"` ++ for ((i=0;i<30;i++)); do ++ sleep 1 ++ cur=`date "+%s"` ++ let "t=cur-s" ++ if [ $t -gt 6 ];then ++ break ++ fi ++ done ++ tail $ISUALD_LOG ++ ++ sid=`crictl runp ${data_path}/sandbox-config.json` ++ if [ $? -ne 0 ]; then ++ msg_err "Failed to run sandbox" ++ TC_RET_T=$(($TC_RET_T+1)) ++ fi ++ ++ basepath=/tmp/cnilogs/ ++ cat ${basepath}/${sid}.env | grep CNI_MUTLINET_EXTENSION ++ if [ $? -ne 0 ];then ++ msg_err "lost extension for mutl network args" ++ TC_RET_T=$(($TC_RET_T+1)) ++ fi ++ cat ${basepath}/${sid}.env | grep "extension=first" ++ if [ $? -ne 0 ];then ++ msg_err "lost extension for first cni args" ++ TC_RET_T=$(($TC_RET_T+1)) ++ fi ++ cat ${basepath}/${sid}.env | grep "extension=second" ++ if [ $? -ne 0 ];then ++ msg_err "lost extension for second cni args" ++ TC_RET_T=$(($TC_RET_T+1)) ++ fi ++ ++ crictl stopp $sid ++ if [ $? -ne 0 ];then ++ msg_err "stop sandbox failed" ++ TC_RET_T=$(($TC_RET_T+1)) ++ fi ++ ++ crictl rmp $sid ++ if [ $? -ne 0 ];then ++ msg_err "rm sandbox failed" ++ TC_RET_T=$(($TC_RET_T+1)) ++ fi ++ ++ return $TC_RET_T + } + + ret=0 +diff --git a/CI/test_cases/container_cases/criconfigs/bridge.json b/CI/test_cases/container_cases/criconfigs/bridge.json +index 4d19fa7..7686e26 100644 +--- a/CI/test_cases/container_cases/criconfigs/bridge.json ++++ b/CI/test_cases/container_cases/criconfigs/bridge.json +@@ -1,10 +1,11 @@ + { +- "cniVersion": "0.3.0", +- "name": "ok", +- "type": "bridge", +- "bridge": "cni0", +- "ipam": { +- "type": "host-local", +- "subnet": "10.2.0.0/16" +- } ++ "cniVersion": "0.3.0", ++ "name": "ok", ++ "type": "bridge", ++ "bridge": "cni0", ++ "isGateway": true, ++ "ipam": { ++ "type": "host-local", ++ "subnet": "10.2.0.0/16" ++ } + } +diff --git a/CI/test_cases/container_cases/criconfigs/mock.json b/CI/test_cases/container_cases/criconfigs/mock.json +new file mode 100644 +index 0000000..85bb91e +--- /dev/null ++++ b/CI/test_cases/container_cases/criconfigs/mock.json +@@ -0,0 +1,9 @@ ++{ ++ "cniVersion": "0.3.1", ++ "name": "mock", ++ "type": "isulad-cni", ++ "ipam": { ++ "type": "isulad-cni", ++ "subnet": "10.3.0.0/16" ++ } ++} +diff --git a/CI/test_cases/container_cases/criconfigs/mutlnet_pod.json b/CI/test_cases/container_cases/criconfigs/mutlnet_pod.json +new file mode 100644 +index 0000000..f860620 +--- /dev/null ++++ b/CI/test_cases/container_cases/criconfigs/mutlnet_pod.json +@@ -0,0 +1,17 @@ ++{ ++ "port_mappings":[{"protocol": 1, "container_port": 80, "host_port": 8080}], ++ "metadata": { ++ "name": "test", ++ "namespace": "default", ++ "attempt": 1, ++ "uid": "hdishd83djaidwnduwk28bcsb" ++ }, ++ "linux": { ++ }, ++ "annotations": { ++ "network.alpha.kubernetes.io/network": "[{\"name\":\"good\",\"interface\":\"eth1\"}]", ++ "extension.network.kubernetes.io/cni": "[multinetwork]", ++ "extension.network.kubernetes.io/cniargs/first": "extension=first", ++ "extension.network.kubernetes.io/cniargs/second": "extension=second" ++ } ++} +diff --git a/CI/test_cases/container_cases/criconfigs/sandbox-config.json b/CI/test_cases/container_cases/criconfigs/sandbox-config.json +index c63dc0e..e9151e8 100644 +--- a/CI/test_cases/container_cases/criconfigs/sandbox-config.json ++++ b/CI/test_cases/container_cases/criconfigs/sandbox-config.json +@@ -7,5 +7,10 @@ + "uid": "hdishd83djaidwnduwk28bcsb" + }, + "linux": { ++ }, ++ "annotations": { ++ "extension.network.kubernetes.io/cni": "[multinetwork]", ++ "extension.network.kubernetes.io/cniargs/first": "extension=first", ++ "extension.network.kubernetes.io/cniargs/second": "extension=second" + } + } +diff --git a/CI/test_cases/container_cases/dev_cgroup_rule.sh b/CI/test_cases/container_cases/dev_cgroup_rule.sh +new file mode 100644 +index 0000000..46f0a2a +--- /dev/null ++++ b/CI/test_cases/container_cases/dev_cgroup_rule.sh +@@ -0,0 +1,98 @@ ++#!/bin/bash ++# ++# attributes: isulad basic device cgroup rule ++# concurrent: NA ++# spend time: 5 ++ ++####################################################################### ++##- @Copyright (C) Huawei Technologies., 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. ++##- @Description:CI ++##- @Author: lifeng ++##- @Create: 2020-09-03 ++####################################################################### ++ ++declare -r curr_path=$(dirname $(readlink -f "$0")) ++source ../helpers.sh ++ ++function test_cpu_dev_cgoup_rule_spec() ++{ ++ local ret=0 ++ local image="busybox" ++ local test="container device cgroup rule test => (${FUNCNAME[@]})" ++ ++ msg_info "${test} starting..." ++ ++ isula pull ${image} ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to pull image: ${image}" && return ${FAILURE} ++ ++ isula images | grep busybox ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - missing list image: ${image}" && ((ret++)) ++ ++ isula run -itd --device-cgroup-rule='b *:*' busybox 2>&1 | grep "Invalid value" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Invalid value" && ((ret++)) ++ ++ isula run -itd --device-cgroup-rule='d *:*' busybox 2>&1 | grep "Invalid value" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Invalid value" && ((ret++)) ++ ++ isula run -itd --device-cgroup-rule='d *:* xxx' busybox 2>&1 | grep "Invalid value" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Invalid value" && ((ret++)) ++ ++ c_id=`isula run -itd --device-cgroup-rule='b 11:22 rmw' --device-cgroup-rule='c *:23 rmw' --device-cgroup-rule='c 33:* rm' busybox sh` ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run container with image: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/devices/devices.list" | grep "b 11:22 rwm" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check b 11:22 rmw: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/devices/devices.list" | grep "c \*:23 rwm" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check c *:23 rmw: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/devices/devices.list" | grep "c 33:\* rm" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check c 33:* rm: ${image}" && ((ret++)) ++ ++ isula restart -t 0 $c_id ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to restart container: $c_id" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/devices/devices.list" | grep "b 11:22 rwm" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check b 11:22 rmw: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/devices/devices.list" | grep "c \*:23 rwm" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check c *:23 rmw: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/devices/devices.list" | grep "c 33:\* rm" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check c 33:* rm: ${image}" && ((ret++)) ++ ++ isula rm -f $c_id ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to rm container ${c_id}" && ((ret++)) ++ ++ c_id=`isula run -itd --device-cgroup-rule='a 11:22 rmw' busybox sh` ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run container with image: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/devices/devices.list" | grep "a \*:\* rwm" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check a *:* rwm: ${image}" && ((ret++)) ++ ++ isula restart -t 0 $c_id ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to restart container: $c_id" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/devices/devices.list" | grep "a \*:\* rwm" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check a *:* rwm: ${image}" && ((ret++)) ++ ++ isula rm -f $c_id ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to rm container ${c_id}" && ((ret++)) ++ ++ msg_info "${test} finished with return ${ret}..." ++ return ${ret} ++} ++ ++declare -i ans=0 ++ ++test_cpu_dev_cgoup_rule_spec || ((ans++)) ++ ++show_result ${ans} "${curr_path}/${0}" +diff --git a/CI/test_cases/container_cases/graph_root_test.sh b/CI/test_cases/container_cases/graph_root_test.sh +new file mode 100644 +index 0000000..678d176 +--- /dev/null ++++ b/CI/test_cases/container_cases/graph_root_test.sh +@@ -0,0 +1,284 @@ ++#!/bin/bash ++# ++# attributes: isulad root and run dir realpath test ++# concurrent: NA ++# spend time: 5 ++ ++####################################################################### ++##- @Copyright (C) Huawei Technologies., 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. ++##- @Description:CI ++##- @Author: lifeng ++##- @Create: 2020-09-03 ++####################################################################### ++ ++declare -r curr_path=$(dirname $(readlink -f "$0")) ++source ../helpers.sh ++ ++function reinstall_thinpool() ++{ ++ local ret=0 ++ ++ cat /etc/isulad/daemon.json | grep driver | grep devicemapper ++ if [[ $? -ne 0 ]]; then ++ return ${ret} ++ fi ++ ++ dev_disk=`pvs | grep isulad | awk '{print$1}'` ++ rm -rf /var/lib/isulad/* ++ dmsetup remove_all ++ lvremove -f isulad/thinpool ++ lvremove -f isulad/thinpoolmeta ++ vgremove -f isulad ++ pvremove -f $dev_disk ++ mount | grep $dev_disk | grep /var/lib/isulad ++ if [ x"$?" == x"0" ]; then ++ umount /var/lib/isulad ++ fi ++ touch /etc/lvm/profile/isulad-thinpool.profile ++ cat > /etc/lvm/profile/isulad-thinpool.profile <&1 | grep "Nano CPUs and CPU Period cannot both be set" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Nano CPUs and CPU Period cannot both be set" && ((ret++)) ++ ++ isula update --cpus 1.3 --cpu-quota 20000 $c_id 2>&1 | grep "Nano CPUs and CPU Quota cannot both be set" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Nano CPUs and CPU Quota cannot both be set" && ((ret++)) ++ ++ isula update --cpu-period 20000 $c_id 2>&1 | grep "CPU Period cannot be updated as NanoCPUs has already been set" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - CPU Period cannot be updated as NanoCPUs has already been set" && ((ret++)) ++ ++ isula update --cpu-quota 20000 $c_id 2>&1 | grep "CPU Quota cannot be updated as NanoCPUs has already been set" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - CPU Quota cannot be updated as NanoCPUs has already been set" && ((ret++)) ++ ++ isula update --cpus 1.3 $c_id ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Failed to update cpus" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us" | grep "130000" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_quota_us: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us" | grep "100000" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_period_us: ${image}" && ((ret++)) ++ ++ isula restart -t 0 $c_id ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to restart container: $c_id" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us" | grep "130000" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_quota_us: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us" | grep "100000" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_period_us: ${image}" && ((ret++)) ++ ++ isula rm -f $c_id ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to rm container ${c_id}" && ((ret++)) ++ ++ check_valgrind_log ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - stop isulad failed" && ((ret++)) ++ ++ cp -f /etc/isulad/daemon.bak /etc/isulad/daemon.json ++ ++ rm -rf /var/lib/isulad/opt/test_root ++ rm -rf /opt/test_run ++ rm -rf /var/lib/isulad_test ++ rm -rf /var/run/isulad_test ++ ++ reinstall_thinpool ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - fail to reconfig isulad-thinpool" && ((ret++)) ++ ++ start_isulad_with_valgrind ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - start isulad failed" && ((ret++)) ++ ++ msg_info "${test} finished with return ${ret}..." ++ return ${ret} ++} ++ ++function test_run_root_dir_bind_realpath() ++{ ++ local ret=0 ++ local image="busybox" ++ local test="isulad root and run dir realpath test => (${FUNCNAME[@]})" ++ ++ msg_info "${test} starting..." ++ ++ check_valgrind_log ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - stop isulad failed" && ((ret++)) ++ ++ reinstall_thinpool ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - fail to reconfig isulad-thinpool" && ((ret++)) ++ ++ mkdir -p /var/lib/isulad/opt/bind_root ++ mkdir -p /opt/bind_run ++ ++ cp -f /etc/isulad/daemon.json /etc/isulad/daemon.bak ++ ++ sed -i 's#"graph": "/var/lib/isulad",#"graph": "/var/lib/isulad/bind/isulad_test",#g' /etc/isulad/daemon.json ++ sed -i 's#"state": "/var/run/isulad",#"state": "/var/run/isulad_test",#g' /etc/isulad/daemon.json ++ ++ mkdir -p /var/lib/isulad/bind/isulad_test ++ mount --bind /var/lib/isulad/opt/bind_root /var/lib/isulad/bind/isulad_test ++ ++ mkdir -p /var/run/isulad_test ++ mount --bind /opt/bind_run /var/run/isulad_test ++ ++ start_isulad_with_valgrind ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - start isulad failed" && ((ret++)) ++ ++ isula pull ${image} ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to pull image: ${image}" && ((ret++)) ++ ++ isula images | grep busybox ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - missing list image: ${image}" && ((ret++)) ++ ++ c_id=`isula run -itd --cpus 1.5 busybox sh` ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run container with image: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us" | grep "150000" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_quota_us: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us" | grep "100000" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_period_us: ${image}" && ((ret++)) ++ ++ isula restart -t 0 $c_id ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to restart container: $c_id" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us" | grep "150000" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_quota_us: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us" | grep "100000" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_period_us: ${image}" && ((ret++)) ++ ++ isula update --cpus 1.3 --cpu-period 20000 $c_id 2>&1 | grep "Nano CPUs and CPU Period cannot both be set" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Nano CPUs and CPU Period cannot both be set" && ((ret++)) ++ ++ isula update --cpus 1.3 --cpu-quota 20000 $c_id 2>&1 | grep "Nano CPUs and CPU Quota cannot both be set" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Nano CPUs and CPU Quota cannot both be set" && ((ret++)) ++ ++ isula update --cpu-period 20000 $c_id 2>&1 | grep "CPU Period cannot be updated as NanoCPUs has already been set" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - CPU Period cannot be updated as NanoCPUs has already been set" && ((ret++)) ++ ++ isula update --cpu-quota 20000 $c_id 2>&1 | grep "CPU Quota cannot be updated as NanoCPUs has already been set" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - CPU Quota cannot be updated as NanoCPUs has already been set" && ((ret++)) ++ ++ isula update --cpus 1.3 $c_id ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Failed to update cpus" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us" | grep "130000" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_quota_us: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us" | grep "100000" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_period_us: ${image}" && ((ret++)) ++ ++ isula restart -t 0 $c_id ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to restart container: $c_id" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us" | grep "130000" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_quota_us: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us" | grep "100000" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_period_us: ${image}" && ((ret++)) ++ ++ isula rm -f $c_id ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to rm container ${c_id}" && ((ret++)) ++ ++ check_valgrind_log ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - stop isulad failed" && ((ret++)) ++ ++ cp -f /etc/isulad/daemon.bak /etc/isulad/daemon.json ++ ++ umount /var/lib/isulad/bind/isulad_test ++ umount /var/run/isulad_test ++ ++ rm -rf /var/lib/isulad/opt/bind_root ++ rm -rf /opt/bind_run ++ rm -rf /var/lib/isulad/bind/isulad_test ++ rm -rf /var/run/isulad_test ++ ++ reinstall_thinpool ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - fail to reconfig isulad-thinpool" && ((ret++)) ++ ++ start_isulad_with_valgrind ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - start isulad failed" && ((ret++)) ++ ++ msg_info "${test} finished with return ${ret}..." ++ return ${ret} ++} ++ ++declare -i ans=0 ++ ++test_run_root_dir_realpath || ((ans++)) ++test_run_root_dir_bind_realpath || ((ans++)) ++ ++show_result ${ans} "${curr_path}/${0}" +diff --git a/CI/test_cases/container_cases/nano_cpus.sh b/CI/test_cases/container_cases/nano_cpus.sh +new file mode 100644 +index 0000000..fd69c5d +--- /dev/null ++++ b/CI/test_cases/container_cases/nano_cpus.sh +@@ -0,0 +1,113 @@ ++#!/bin/bash ++# ++# attributes: isulad basic nano iops ++# concurrent: NA ++# spend time: 5 ++ ++####################################################################### ++##- @Copyright (C) Huawei Technologies., 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. ++##- @Description:CI ++##- @Author: lifeng ++##- @Create: 2020-09-03 ++####################################################################### ++ ++declare -r curr_path=$(dirname $(readlink -f "$0")) ++source ../helpers.sh ++ ++function test_cpu_nano_spec() ++{ ++ local ret=0 ++ local image="busybox" ++ local test="container blkio nano test => (${FUNCNAME[@]})" ++ ++ msg_info "${test} starting..." ++ ++ isula pull ${image} ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to pull image: ${image}" && return ${FAILURE} ++ ++ isula images | grep busybox ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - missing list image: ${image}" && ((ret++)) ++ ++ isula run -itd --cpus 1.5 --cpu-period 20000 $image /bin/sh 2>&1 | grep "Nano CPUs and CPU Period cannot both be set" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Nano CPUs and CPU Period cannot both be set" && ((ret++)) ++ ++ isula run -itd --cpus 1.5 --cpu-quota 20000 $image /bin/sh 2>&1 | grep "Nano CPUs and CPU Quota cannot both be set" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Nano CPUs and CPU Quota cannot both be set" && ((ret++)) ++ ++ c_id=`isula run -itd --cpus 1.5 busybox sh` ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run container with image: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us" | grep "150000" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_quota_us: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us" | grep "100000" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_period_us: ${image}" && ((ret++)) ++ ++ isula restart -t 0 $c_id ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to restart container: $c_id" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us" | grep "150000" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_quota_us: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us" | grep "100000" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_period_us: ${image}" && ((ret++)) ++ ++ isula update --cpus 1.3 --cpu-period 20000 $c_id 2>&1 | grep "Nano CPUs and CPU Period cannot both be set" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Nano CPUs and CPU Period cannot both be set" && ((ret++)) ++ ++ isula update --cpus 1.3 --cpu-quota 20000 $c_id 2>&1 | grep "Nano CPUs and CPU Quota cannot both be set" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Nano CPUs and CPU Quota cannot both be set" && ((ret++)) ++ ++ isula update --cpu-period 20000 $c_id 2>&1 | grep "CPU Period cannot be updated as NanoCPUs has already been set" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - CPU Period cannot be updated as NanoCPUs has already been set" && ((ret++)) ++ ++ isula update --cpu-quota 20000 $c_id 2>&1 | grep "CPU Quota cannot be updated as NanoCPUs has already been set" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - CPU Quota cannot be updated as NanoCPUs has already been set" && ((ret++)) ++ ++ isula update --cpus 1.3 $c_id ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Failed to update cpus" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us" | grep "130000" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_quota_us: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us" | grep "100000" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_period_us: ${image}" && ((ret++)) ++ ++ isula restart -t 0 $c_id ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to restart container: $c_id" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us" | grep "130000" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_quota_us: ${image}" && ((ret++)) ++ ++ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us" | grep "100000" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_period_us: ${image}" && ((ret++)) ++ ++ isula rm -f $c_id ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to rm container ${c_id}" && ((ret++)) ++ ++ c_id=`isula run -itd --cpu-period 20000 --cpu-quota 10000 busybox sh` ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run container with image: ${image}" && ((ret++)) ++ ++ isula update --cpus 1.4 $c_id 2>&1 | grep "Nano CPUs cannot be updated as CPU Period has already been set" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Nano CPUs cannot be updated as CPU Period has already been set" && ((ret++)) ++ ++ isula rm -f $c_id ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to rm container ${c_id}" && ((ret++)) ++ ++ msg_info "${test} finished with return ${ret}..." ++ return ${ret} ++} ++ ++declare -i ans=0 ++ ++test_cpu_nano_spec || ((ans++)) ++ ++show_result ${ans} "${curr_path}/${0}" +diff --git a/CI/test_cases/container_cases/nonroot.sh b/CI/test_cases/container_cases/nonroot.sh +new file mode 100755 +index 0000000..b123d70 +--- /dev/null ++++ b/CI/test_cases/container_cases/nonroot.sh +@@ -0,0 +1,70 @@ ++#!/bin/bash ++# ++# attributes: isulad inheritance start ++# concurrent: YES ++# spend time: 11 ++ ++####################################################################### ++##- @Copyright (C) Huawei Technologies., 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. ++##- @Description:CI ++##- @Author: gaohuatao ++##- @Create: 2020-10-19 ++####################################################################### ++ ++curr_path=$(dirname $(readlink -f "$0")) ++data_path=$(realpath $curr_path/../data) ++source ../helpers.sh ++group="isula" ++user="nonroot_test" ++container="test_nonroot_user" ++ ++function do_test_t() ++{ ++ local ret=0 ++ local test="isula execute with non root => (${FUNCNAME[@]})" ++ ++ msg_info "${test} starting..." ++ ++ userdel $user ++ useradd -g $group $user ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - add user $user and add to group $group failed" && ((ret++)) ++ ++ su - $user -c "isula run -tid --name $container busybox /bin/bash" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container failed" && ((ret++)) ++ ++ su - $user -c "isula inspect $container" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - inspect container failed" && ((ret++)) ++ ++ su - $user -c "isula restart $container" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - restart container failed" && ((ret++)) ++ ++ su - $user -c "isula exec $container pwd" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - exec container failed" && ((ret++)) ++ ++ su - $user -c "isula stop $container" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - stop container failed" && ((ret++)) ++ ++ su - $user -c "isula rm $container" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - rm container failed" && ((ret++)) ++ ++ userdel $user ++ ++ return $TC_RET_T ++} ++ ++ret=0 ++ ++do_test_t ++if [ $? -ne 0 ];then ++ let "ret=$ret + 1" ++fi ++ ++show_result $ret "basic start" +diff --git a/CI/test_cases/container_cases/run.sh b/CI/test_cases/container_cases/run.sh +index 85f6e55..357fcd0 100755 +--- a/CI/test_cases/container_cases/run.sh ++++ b/CI/test_cases/container_cases/run.sh +@@ -50,7 +50,7 @@ function do_test_t() + + echo AA > /tmp/test_run_env + +- isula run --name $containername -itd -e AAA=BB -e BAA --env-file /tmp/test_run_env busybox ++ isula run --name $containername -itd --user 100:100 -e AAA=BB -e BAA --env-file /tmp/test_run_env busybox + fn_check_eq "$?" "0" "run failed" + testcontainer $containername running + +diff --git a/CI/test_cases/container_cases/storage_opts_dm.sh b/CI/test_cases/container_cases/storage_opts_dm.sh +index 705eaad..e0f476f 100755 +--- a/CI/test_cases/container_cases/storage_opts_dm.sh ++++ b/CI/test_cases/container_cases/storage_opts_dm.sh +@@ -84,7 +84,7 @@ function do_test() + { + local ret=0 + +- local test="devicemapper dm.mkfsarg adn dm.mountopt params test => (${FUNCNAME[@]})" ++ local test="devicemapper dm.mkfsarg and dm.mountopt params test => (${FUNCNAME[@]})" + msg_info "${test} starting..." + + isula pull $image_busybox diff --git a/CI/test_cases/container_cases/test_data/pause.tar b/CI/test_cases/container_cases/test_data/pause.tar deleted file mode 100644 index 2300176655e854dbbebe7222879e7ad9027d5b9c..0000000000000000000000000000000000000000 @@ -6536,6 +7984,1052 @@ zVhKIy_4>3#%P23v{CgOoOq6>%AxJlTaLwoqj;?3mN^7H19SL4ZiCYLnWaWcyv z1I{>VGXJ9mJf^uIR{sP3*7)ze$ch@72NqF7X^cjdbkmZ{zw6MU_d}tt(L#&R(m+cC LEe-tYY2g0>N|2;1 +diff --git a/CI/test_cases/container_cases/volume.sh b/CI/test_cases/container_cases/volume.sh +new file mode 100755 +index 0000000..f37a0e1 +--- /dev/null ++++ b/CI/test_cases/container_cases/volume.sh +@@ -0,0 +1,434 @@ ++#!/bin/bash ++# ++# attributes: isulad volume ++# concurrent: YES ++# spend time: 15 ++ ++####################################################################### ++##- @Copyright (C) Huawei Technologies., 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. ++##- @Description:CI ++##- @Author: wangfengtu ++##- @Create: 2020-08-31 ++####################################################################### ++ ++declare -r curr_path=$(dirname $(readlink -f "$0")) ++source ../helpers.sh ++test="volume test => test_volume" ++ ++function cleanup_containers_and_volumes() ++{ ++ isula rm -f `isula ps -a -q` ++ isula volume prune -f ++} ++ ++function test_volume_help() ++{ ++ local ret=0 ++ ++ isula --help | grep volume ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - isula --help failed" && ((ret++)) ++ ++ isula volume --help | grep "isula volume" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - isula volume --help failed" && ((ret++)) ++ ++ isula volume rm --help | grep "isula volume rm" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - isula volume rm --help failed" && ((ret++)) ++ ++ isula volume nonexist ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - isula volume noexist should failed" && ((ret++)) ++ ++ return ${ret} ++} ++ ++function test_volume_ls() ++{ ++ local ret=0 ++ ++ cleanup_containers_and_volumes ++ ++ isula run -tid busybox sh ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run container without volume" && ((ret++)) ++ ++ isula run -tid -v vol:/vol:ro busybox sh ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run container with volume" && ((ret++)) ++ ++ n=`isula volume ls | wc -l` ++ [[ $n -ne 2 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to list volume" && ((ret++)) ++ ++ return ${ret} ++} ++ ++# test prune can remove all volumes unused ++function test_volume_prune_remove() ++{ ++ local ret=0 ++ ++ cleanup_containers_and_volumes ++ ++ isula run -tid --name vol --mount src=vol,dst=/vol,readonly=true busybox sh ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run container with volume" && ((ret++)) ++ ++ isula rm -f vol ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to remove container with volume" && ((ret++)) ++ ++ echo y | isula volume prune ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to prune volumes" && ((ret++)) ++ ++ n=`isula volume ls | wc -l` ++ [[ $n -ne 1 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - volume not all removed after prune" && ((ret++)) ++ ++ return ${ret} ++} ++ ++# test prune can not remove used volume ++function test_volume_prune_cannot_remove() ++{ ++ local ret=0 ++ ++ cleanup_containers_and_volumes ++ ++ isula run -ti --name vol -v vol:/vol:z vol echo vol ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run image with volume failed" && ((ret++)) ++ ++ isula volume prune -f ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to prune volumes" && ((ret++)) ++ ++ n=`isula volume ls -q | wc -l` ++ [[ $n -ne 2 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - volume number not right after prune" && ((ret++)) ++ ++ return ${ret} ++} ++ ++# test --rm can remove anonymous volume but not non-anonymous ++function test_volume_auto_rm() ++{ ++ local ret=0 ++ ++ cleanup_containers_and_volumes ++ ++ isula run --rm -ti --name autorm -v vol:/vol vol echo vol ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run image with non-anonymous failed" && ((ret++)) ++ ++ isula inspect autorm ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - container still exist after container stopped" && ((ret++)) ++ ++ n=`isula volume ls -q | wc -l` ++ [[ $n -ne 1 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - volume still exist after container stopped" && ((ret++)) ++ ++ return ${ret} ++} ++ ++function test_volume_rm() ++{ ++ local ret=0 ++ ++ cleanup_containers_and_volumes ++ ++ isula run -ti --name vol -v vol:/vol vol echo vol ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run image with non-anonymous failed" && ((ret++)) ++ ++ isula rm -f vol ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to remove container with volume" && ((ret++)) ++ ++ isula volume rm vol ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to remove specified volume" && ((ret++)) ++ ++ return ${ret} ++} ++ ++function test_volume_volumes_from() ++{ ++ local ret=0 ++ ++ cleanup_containers_and_volumes ++ ++ isula run -tid --name vol1 -v volumes_from:/volumes_from --mount type=bind,source=/home,target=/vol3,bind-selinux-opts=z,bind-propagation=rprivate vol sh ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container for volumes-from failed" && ((ret++)) ++ ++ isula run -tid --name vol2 --volumes-from vol1 busybox sh ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container with --volumes-from failed" && ((ret++)) ++ ++ isula exec -ti vol2 stat /vol/dir/dir ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - --volumes-from anonymous volume failed" && ((ret++)) ++ ++ isula exec -ti vol2 stat /volumes_from ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - --volumes-from named volume failed" && ((ret++)) ++ ++ isula run -tid --name vol3 --volumes-from vol1:ro busybox sh ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container with --volumes-from readonly failed" && ((ret++)) ++ ++ isula exec -ti vol3 touch /volumes_from/fail ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - --volumes-from readonly failed" && ((ret++)) ++ ++ isula run -tid --name vol4 --volumes-from vol3 busybox sh ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container with --volumes-from readonly failed" && ((ret++)) ++ ++ isula exec -ti vol4 touch /volumes_from/fail ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - --volumes-from default readonly failed" && ((ret++)) ++ ++ isula run -tid --name vol5 --volumes-from vol3:rw busybox sh ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container with --volumes-from readonly failed" && ((ret++)) ++ ++ isula exec -ti vol5 touch /volumes_from/fail ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - --volumes-from readwrite failed" && ((ret++)) ++ ++ return ${ret} ++} ++ ++function test_volume_anonymous() ++{ ++ local ret=0 ++ ++ cleanup_containers_and_volumes ++ ++ isula run -tid --name vol vol sh ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run image with volume" && ((ret++)) ++ ++ isula exec -ti vol stat /vol ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - vol1 not found" && ((ret++)) ++ ++ isula exec -ti vol stat /vol2 ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - vol2 not found" && ((ret++)) ++ ++ return ${ret} ++} ++ ++function test_volume_volume() ++{ ++ local ret=0 ++ ++ cleanup_containers_and_volumes ++ ++ isula run -tid --name vol1 -v /vol1 busybox touch /vol1/test ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run first container" && ((ret++)) ++ ++ isula run -tid --name vol2 -v vol2:/vol2 busybox touch /vol2/test ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run second container" && ((ret++)) ++ ++ return ${ret} ++} ++ ++function test_volume_mount() ++{ ++ local ret=0 ++ ++ cleanup_containers_and_volumes ++ ++ isula run -tid --name vol1 --mount dst=/vol1 busybox touch /vol1/test ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run first container" && ((ret++)) ++ ++ isula run -tid --name vol2 --mount src=vol2,dst=/vol2,ro=false busybox touch /vol2/test ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run second container" && ((ret++)) ++ ++ isula run -tid --name vol3 --mount type=bind,source=/home,target=/vol3,bind-selinux-opts=z,bind-propagation=rprivate busybox touch /vol3/test ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run third container" && ((ret++)) ++ ++ return ${ret} ++} ++ ++function test_volume_restore() ++{ ++ local ret=0 ++ ++ cleanup_containers_and_volumes ++ ++ isula run -tid --name restore -v vol_restore:/vol busybox sh ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run container for restore volume" && ((ret++)) ++ ++ isula exec -ti restore touch /vol/restore.txt ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to create file for restore volume" && ((ret++)) ++ ++ check_valgrind_log ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - stop isulad failed" && ((ret++)) ++ ++ start_isulad_with_valgrind ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - start isulad failed" && ((ret++)) ++ ++ isula exec -ti restore cat /vol/restore.txt ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to restore volume" && ((ret++)) ++ ++ return ${ret} ++} ++ ++function test_volume_reuse() ++{ ++ local ret=0 ++ ++ cleanup_containers_and_volumes ++ ++ isula run -tid -v reuse:/vol vol touch /vol/reuse.txt ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container for volume reuse failed" && ((ret++)) ++ ++ isula run -ti -v reuse:/vol vol cat /vol/reuse.txt ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - reuse container volume failed" && ((ret++)) ++ ++ return ${ret} ++} ++ ++function test_volume_copy() ++{ ++ local ret=0 ++ ++ cleanup_containers_and_volumes ++ ++ isula run -ti --rm --mount target=/usr vol stat /usr/sbin ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - test default copy failed" && ((ret++)) ++ ++ isula run -tid --name vol -ti vol sh ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run vol failed" && ((ret++)) ++ ++ isula exec -ti vol cat /vol/hello | grep world ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - test volume copy regular failed" && ((ret++)) ++ ++ isula exec -ti vol stat /vol/link | grep "Links: 2" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - test volume copy hard link failed" && ((ret++)) ++ ++ isula exec -ti vol readlink /vol/softlink | grep hello ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - test volume copy soft link failed" && ((ret++)) ++ ++ isula exec -ti vol stat /vol/dev | grep "character special file" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - test volume copy char device failed" && ((ret++)) ++ ++ isula exec -ti vol stat /vol/dir/dir ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - test volume copy recursive failed" && ((ret++)) ++ ++ isula run -ti --rm --mount target=/usr,volume-nocopy=true vol echo hello ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - nocopy parameter of --mount start container failed" && ((ret++)) ++ ++ isula run -ti --rm --mount target=/usr,volume-nocopy=true,bind-selinux-opts=z vol stat /usr/sbin ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - nocopy parameter of --mount take no effect" && ((ret++)) ++ ++ isula run -ti --rm -v test:/usr:nocopy vol echo hello ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - nocopy parameter of -v start container failed" && ((ret++)) ++ ++ isula run -ti --rm -v test:/usr:nocopy vol stat /usr/sbin ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - nocopy parameter of -v take no effect" && ((ret++)) ++ ++ return ${ret} ++} ++ ++function test_volume_conflict() ++{ ++ local ret=0 ++ ++ cleanup_containers_and_volumes ++ ++ isula run -tid --name vol -v vol3:/vol vol sh ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run image with conflict destination should fail condition 1" && ((ret++)) ++ ++ nums=`isula inspect -f "{{.Mounts}}" vol | grep _data | wc -l` ++ [[ $nums -ne 2 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run image with volume" && ((ret++)) ++ ++ isula inspect -f "{{.Mounts}}" vol | grep vol3 ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run image with volume" && ((ret++)) ++ ++ isula rm -f vol ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to remove container" && ((ret++)) ++ ++ isula run -tid -v /vol --mount type=volume,destination=/vol busybox sh ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run image with conflict destination should fail condition 2" && ((ret++)) ++ ++ isula run -tid -v vol5:/vol5 -v /home:/vol5 busybox sh ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run image with conflict destination should fail condition 3" && ((ret++)) ++ ++ return ${ret} ++} ++ ++function test_volume_invalid_modes() ++{ ++ local ret=0 ++ ++ cleanup_containers_and_volumes ++ ++ # test invalid modes ++ isula run -tid --rm -v aaa:/aaa:rslave busybox echo hello ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container -v with volume and propagation should fail" && ((ret++)) ++ ++ isula run -tid --rm -v /home:/aaa:nocopy busybox echo hello ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container -v with bind and nocopy should fail" && ((ret++)) ++ ++ isula run -tid --rm --mount src=aaa,dst=/aaa,bind-propagation=rslave busybox echo hello ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container --mount with volume and propagation should fail" && ((ret++)) ++ ++ isula run -tid --rm --mount src=/home,dst=/aaa:nocopy busybox echo hello ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container --mount with bind and nocopy should fail" && ((ret++)) ++ ++ return ${ret} ++} ++ ++function test_volume_init_fail() ++{ ++ local ret=0 ++ ++ cleanup_containers_and_volumes ++ ++ check_valgrind_log ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - stop isulad failed" && ((ret++)) ++ ++ rm -rf /var/lib/isulad/volumes ++ touch /var/lib/isulad/volumes ++ ++ start_isulad_with_valgrind ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - start isulad should fail" && ((ret++)) ++ ++ rm -f /var/lib/isulad/volumes ++ ++ start_isulad_with_valgrind ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - start isulad failed" && ((ret++)) ++ ++ return ${ret} ++} ++ ++function prepare_test_volume() ++{ ++ local ret=0 ++ ++ isula load -i test_data/vol.tar ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - load volume image failed" && ((ret++)) ++ ++ return ${ret} ++} ++ ++function post_test_volume() ++{ ++ cleanup_containers_and_volumes ++ isula rmi vol ++} ++ ++declare -i ans=0 ++ ++msg_info "${test} starting..." ++[[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - start isulad failed" && ((ret++)) ++ ++prepare_test_volume || ((ans++)) ++ ++test_volume_help || ((ans++)) ++test_volume_init_fail || ((ans++)) ++test_volume_ls || ((ans++)) ++test_volume_prune_remove || ((ans++)) ++test_volume_prune_cannot_remove || ((ans++)) ++test_volume_auto_rm || ((ans++)) ++test_volume_rm || ((ans++)) ++test_volume_volumes_from || ((ans++)) ++test_volume_anonymous || ((ans++)) ++test_volume_volume || ((ans++)) ++test_volume_mount || ((ans++)) ++test_volume_restore || ((ans++)) ++test_volume_reuse || ((ans++)) ++test_volume_copy || ((ans++)) ++test_volume_conflict || ((ans++)) ++test_volume_invalid_modes || ((ans++)) ++ ++post_test_volume ++ ++msg_info "${test} finished with return ${ans}..." ++ ++show_result ${ans} "${curr_path}/${0}" +diff --git a/CI/test_cases/container_cases/volume_mount_propagation.sh b/CI/test_cases/container_cases/volume_mount_propagation.sh +new file mode 100755 +index 0000000..6ffb92b +--- /dev/null ++++ b/CI/test_cases/container_cases/volume_mount_propagation.sh +@@ -0,0 +1,297 @@ ++#!/bin/bash ++# ++# attributes: isulad volume ++# concurrent: YES ++# spend time: 25 ++ ++####################################################################### ++##- @Copyright (C) Huawei Technologies., 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. ++##- @Description:CI ++##- @Author: lifeng ++##- @Create: 2020-08-31 ++####################################################################### ++ ++declare -r curr_path=$(dirname $(readlink -f "$0")) ++source ../helpers.sh ++test="volume mount progagation test => test_volume" ++image="busybox" ++ ++function cleanup_containers_and_volumes() ++{ ++ isula rm -f `isula ps -a -q` ++ isula volume prune -f ++} ++ ++function test_volume_mount_default() ++{ ++ local ret=0 ++ ++ mkdir -p /tmp/src ++ ++ #run with slave property volume in container ++ CONT=$(isula run --mount type=bind,src=/tmp/src,dst=/tmp/dst -dit --privileged "${image}" /bin/sh) ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container by image $image failed" && ((ret++)) ++ ++ #check the property from host to container ++ mkdir -p /tmp/src_private ++ mkdir -p /tmp/src/src_testCE_volume_default ++ mount --bind /tmp/src_private /tmp/src/src_testCE_volume_default ++ touch /tmp/src_private/src_privatefile ++ isula exec -it "$CONT" /bin/sh -c 'ls /tmp/dst/src_testCE_volume_default/src_privatefile || echo -n "host_pass"' > /tmp/host_property_log ++ cat /tmp/host_property_log | grep "host_pass" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from host to container ""$CONT"" success ,but expect fail!" && ((ret++)) ++ ++ #check the property from container to host ++ umount /tmp/src/src_testCE_volume_default ++ isula exec -it "$CONT" /bin/sh -c 'mkdir /tmp/dst_private;mkdir /tmp/dst/dst_testCE_volume_default;mount --bind /tmp/dst_private /tmp/dst/dst_testCE_volume_default;touch /tmp/dst_private/dst_privatefile' ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - exec volume in container ""$CONT"" fail!" && ((ret++)) ++ ls /tmp/src/dst_testCE_volume_default/dst_privatefile ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from container to host success ,but expect fail!" && ((ret++)) ++ ++ #cleanup ++ isula rm -f "$CONT" ++ rm -rf /tmp/host_property_log ++ umount /tmp/dst ++ umount /tmp/src ++ rm -rf /tmp/src ++ rm -rf /tmp/dst ++ rm -rf /tmp/src_private ++ ++ return ${ret} ++} ++ ++function test_volume_mount_private() { ++ ++ mkdir -p /tmp/src ++ ++ #run with slave property volume in container ++ CONT=$(isula run --mount type=bind,src=/tmp/src,dst=/tmp/dst,bind-propagation=private -dit --privileged "${image}" /bin/sh) ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container by image $image failed" && ((ret++)) ++ ++ #check the property from host to container ++ mkdir -p /tmp/src_private ++ mkdir -p /tmp/src/src_testCE_volume_private ++ mount --bind /tmp/src_private /tmp/src/src_testCE_volume_private ++ touch /tmp/src_private/src_privatefile ++ isula exec -it "$CONT" /bin/sh -c 'ls /tmp/dst/src_testCE_volume_private/src_privatefile || echo -n "host_pass"' > /tmp/host_property_log ++ cat /tmp/host_property_log | grep "host_pass" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from host to container ""$CONT"" success ,but expect fail!" && ((ret++)) ++ ++ #check the property from container to host ++ umount /tmp/src/src_testCE_volume_private ++ isula exec -it "$CONT" /bin/sh -c 'mkdir /tmp/dst_private;mkdir /tmp/dst/dst_testCE_volume_private;mount --bind /tmp/dst_private /tmp/dst/dst_testCE_volume_private;touch /tmp/dst_private/dst_privatefile' ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - exec volume in container ""$CONT"" fail!" && ((ret++)) ++ ls /tmp/src/dst_testCE_volume_private/dst_privatefile ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from container to host success ,but expect fail!" && ((ret++)) ++ ++ #cleanup ++ isula rm -f "$CONT" ++ rm -rf /tmp/host_property_log ++ umount /tmp/dst ++ umount /tmp/src ++ rm -rf /tmp/src ++ rm -rf /tmp/dst ++ rm -rf /tmp/src_private ++} ++ ++function test_volume_mount_rprivate() { ++ ++ mkdir -p /tmp/src ++ ++ #run with slave property volume in container ++ CONT=$(isula run --mount type=bind,src=/tmp/src,dst=/tmp/dst,bind-propagation=rprivate -dit --privileged "${image}" /bin/sh) ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container by image $image failed" && ((ret++)) ++ ++ #check the property from host to container ++ mkdir -p /tmp/src_rprivate ++ mkdir -p /tmp/src/src_testCE_mount_rprivate ++ mount --bind /tmp/src_rprivate /tmp/src/src_testCE_mount_rprivate ++ touch /tmp/src_rprivate/src_rprivatefile ++ isula exec -it "$CONT" /bin/sh -c 'ls /tmp/dst/src_testCE_mount_rprivate/src_rprivatefile || echo -n "host_pass"' > /tmp/host_property_log ++ cat /tmp/host_property_log | grep "host_pass" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from host to container ""$CONT"" success ,but expect fail!" && ((ret++)) ++ ++ #check the property from container to host ++ umount /tmp/src/src_testCE_mount_rprivate ++ isula exec -it "$CONT" /bin/sh -c 'mkdir /tmp/dst_rprivate;mkdir /tmp/dst/dst_testCE_mount_rprivate;mount --bind /tmp/dst_rprivate /tmp/dst/dst_testCE_mount_rprivate;touch /tmp/dst_rprivate/dst_rprivatefile' ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - exec volume in container ""$CONT"" fail!" && ((ret++)) ++ ls /tmp/src/dst_testCE_mount_rprivate/dst_rprivatefile ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from container to host success ,but expect fail!" && ((ret++)) ++ ++ #cleanup ++ rm -rf /tmp/host_property_log ++ umount /tmp/dst ++ umount /tmp/src ++ rm -rf /tmp/src ++ rm -rf /tmp/dst ++ rm -rf /tmp/src_rprivate ++} ++ ++function test_volume_mount_rshared() { ++ ++ mkdir -p /tmp/src ++ ++ #run with slave property volume in container ++ CONT=$(isula run --mount type=bind,src=/tmp/src,dst=/tmp/dst,bind-propagation=rshared -dit --privileged "${image}" /bin/sh) ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} -run container by image $image failed" && ((ret++)) ++ ++ #check the property from host to container ++ mkdir -p /tmp/src_rshared ++ mkdir -p /tmp/src/src_testCE_mount_rshared ++ mount --bind /tmp/src_rshared /tmp/src/src_testCE_mount_rshared ++ touch /tmp/src_rshared/src_rsharedfile ++ isula exec -it "$CONT" /bin/sh -c 'ls /tmp/dst/src_testCE_mount_rshared/src_rsharedfile && echo -n "host_pass"' > /tmp/host_property_log ++ cat /tmp/host_property_log | grep "host_pass" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from host to container ""$CONT"" fail!" && ((ret++)) ++ ++ #check the property from container to host ++ umount /tmp/src/src_testCE_mount_rshared ++ isula exec -it "$CONT" /bin/sh -c 'mkdir /tmp/dst_rshared;mkdir /tmp/dst/dst_testCE_mount_rshared;mount --bind /tmp/dst_rshared /tmp/dst/dst_testCE_mount_rshared;touch /tmp/dst_rshared/dst_rsharedfile' ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - exec volume in container ""$CONT"" fail!" && ((ret++)) ++ ls /tmp/src/dst_testCE_mount_rshared/dst_rsharedfile ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from container to host fail!" && ((ret++)) ++ ++ #cleanup ++ rm -rf /tmp/host_property_log ++ umount /tmp/dst ++ umount /tmp/src ++ umount /tmp/src/dst_testCE_mount_rshared ++ rm -rf /tmp/src ++ rm -rf /tmp/dst ++ rm -rf /tmp/src_rshared ++} ++ ++function test_volume_mount_rslave() { ++ ++ mkdir -p /tmp/src ++ ++ #run with slave property volume in container ++ CONT=$(isula run --mount type=bind,src=/tmp/src,dst=/tmp/dst,bind-propagation=rslave -dit --privileged "${image}" /bin/sh) ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container by image $image failed" && ((ret++)) ++ ++ #check the property from host to container ++ mkdir -p /tmp/src_rslave ++ mkdir -p /tmp/src/src_testCE_mount_rslave ++ mount --bind /tmp/src_rslave /tmp/src/src_testCE_mount_rslave ++ touch /tmp/src_rslave/src_rslavefile ++ isula exec -it "$CONT" /bin/sh -c 'ls /tmp/dst/src_testCE_mount_rslave/src_rslavefile && echo -n "host_pass"' > /tmp/host_property_log ++ cat /tmp/host_property_log | grep "host_pass" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from host to container ""$CONT"" fail!" && ((ret++)) ++ ++ #check the property from container to host ++ umount /tmp/src/src_testCE_mount_rslave ++ isula exec -it "$CONT" /bin/sh -c 'mkdir /tmp/dst_rslave;mkdir /tmp/dst/dst_testCE_mount_rslave;mount --bind /tmp/dst_rslave /tmp/dst/dst_testCE_mount_rslave;touch /tmp/dst_rslave/dst_rslavefile' ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - exec volume in container ""$CONT"" fail!" && ((ret++)) ++ ls /tmp/src/dst_testCE_mount_rslave/dst_rslavefile ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from container to host success ,but expect fail!" && ((ret++)) ++ ++ #cleanup ++ rm -rf /tmp/host_property_log ++ umount /tmp/dst ++ umount /tmp/src ++ rm -rf /tmp/src ++ rm -rf /tmp/dst ++ rm -rf /tmp/src_rslave ++} ++ ++function test_volume_mount_shared() { ++ ++ mkdir -p /tmp/src ++ #run with shared property volume in container ++ CONT=$(isula run --mount type=bind,src=/tmp/src,dst=/tmp/dst,bind-propagation=shared -dit --privileged "$image" /bin/sh) ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container by image $image failed" && ((ret++)) ++ ++ #check the property from host to container ++ mkdir -p /tmp/src_shared ++ mkdir -p /tmp/src/src_testCE_v_shared_check ++ mount --bind /tmp/src_shared /tmp/src/src_testCE_v_shared_check ++ touch /tmp/src_shared/src_sharedfile ++ isula exec -it "$CONT" /bin/sh -c 'ls /tmp/dst/src_testCE_v_shared_check/src_sharedfile && echo -n "host_pass"' > /tmp/host_property_log ++ cat /tmp/host_property_log | grep "host_pass" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from host to container ""$CONT"" fail!" && ((ret++)) ++ ++ #check the property from container to host ++ umount /tmp/src/src_testCE_v_shared_check ++ isula exec -it "$CONT" /bin/sh -c 'mkdir /tmp/dst_shared;mkdir /tmp/dst/dst_testCE_mount_shared_check;mount --bind /tmp/dst_shared /tmp/dst/dst_testCE_mount_shared_check;touch /tmp/dst_shared/dst_sharedfile' ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - exec volume in container ""$CONT"" fail!" && ((ret++)) ++ ls /tmp/src/dst_testCE_mount_shared_check/dst_sharedfile ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from container to host fail!" && ((ret++)) ++ ++ #cleanup ++ isula rm -f "$CONT" ++ rm -rf /tmp/host_property_log ++ umount /tmp/dst ++ umount /tmp/src ++ umount /tmp/src/dst_testCE_mount_shared_check ++ rm -rf /tmp/src ++ rm -rf /tmp/dst ++ rm -rf /tmp/src_shared ++} ++ ++function test_volume_mount_slave() { ++ ++ mkdir -p /tmp/src ++ ++ #run with slave property volume in container ++ CONT=$(isula run --mount type=bind,src=/tmp/src,dst=/tmp/dst,bind-propagation=slave -dit --privileged "${image}" /bin/sh) ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container by image $image failed" && ((ret++)) ++ ++ #check the property from host to container ++ mkdir -p /tmp/src_slave ++ mkdir -p /tmp/src/src_testCE_volume_slave ++ mount --bind /tmp/src_slave /tmp/src/src_testCE_volume_slave ++ touch /tmp/src_slave/src_slavefile ++ isula exec -it "$CONT" /bin/sh -c 'ls /tmp/dst/src_testCE_volume_slave/src_slavefile && echo -n "host_pass"' > /tmp/host_property_log ++ cat /tmp/host_property_log | grep "host_pass" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from host to container ""$CONT"" fail!" && ((ret++)) ++ ++ #check the property from container to host ++ umount /tmp/src/src_testCE_volume_slave ++ isula exec -it "$CONT" /bin/sh -c 'mkdir /tmp/dst_slave;mkdir /tmp/dst/dst_testCE_volume_slave;mount --bind /tmp/dst_slave /tmp/dst/dst_testCE_volume_slave;touch /tmp/dst_slave/dst_slavefile' ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - exec volume in container ""$CONT"" fail!" && ((ret++)) ++ ls /tmp/src/dst_testCE_volume_slave/dst_slavefile ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from container to host success ,but expect fail!" && ((ret++)) ++ ++ #cleanup ++ isula rm -f "$CONT" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to remove container ""$CONT"" fail!" && ((ret++)) ++ rm -rf /tmp/host_property_log ++ umount /tmp/dst ++ umount /tmp/src ++ rm -rf /tmp/src ++ rm -rf /tmp/dst ++ rm -rf /tmp/src_slave ++} ++ ++declare -i ans=0 ++ ++msg_info "${test} starting..." ++[[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - start isulad failed" && ((ret++)) ++ ++cleanup_containers_and_volumes ++test_volume_mount_default || ((ans++)) ++cleanup_containers_and_volumes ++test_volume_mount_private || ((ans++)) ++cleanup_containers_and_volumes ++test_volume_mount_rprivate || ((ans++)) ++cleanup_containers_and_volumes ++test_volume_mount_rshared || ((ans++)) ++cleanup_containers_and_volumes ++test_volume_mount_rslave || ((ans++)) ++cleanup_containers_and_volumes ++test_volume_mount_shared || ((ans++)) ++cleanup_containers_and_volumes ++test_volume_mount_slave || ((ans++)) ++cleanup_containers_and_volumes ++ ++msg_info "${test} finished with return ${ans}..." ++ ++show_result ${ans} "${curr_path}/${0}" +diff --git a/CI/test_cases/container_cases/volume_v_propagation.sh b/CI/test_cases/container_cases/volume_v_propagation.sh +new file mode 100755 +index 0000000..ce03d4c +--- /dev/null ++++ b/CI/test_cases/container_cases/volume_v_propagation.sh +@@ -0,0 +1,297 @@ ++#!/bin/bash ++# ++# attributes: isulad volume ++# concurrent: YES ++# spend time: 25 ++ ++####################################################################### ++##- @Copyright (C) Huawei Technologies., 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. ++##- @Description:CI ++##- @Author: lifeng ++##- @Create: 2020-08-31 ++####################################################################### ++ ++declare -r curr_path=$(dirname $(readlink -f "$0")) ++source ../helpers.sh ++test="volume mount progagation test => test_volume" ++image="busybox" ++ ++function cleanup_containers_and_volumes() ++{ ++ isula rm -f `isula ps -a -q` ++ isula volume prune -f ++} ++ ++function test_volume_mount_default() ++{ ++ local ret=0 ++ ++ mkdir -p /tmp/src ++ ++ #run with slave property volume in container ++ CONT=$(isula run -v /tmp/src:/tmp/dst -dit --privileged "${image}" /bin/sh) ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container by image $image failed" && ((ret++)) ++ ++ #check the property from host to container ++ mkdir -p /tmp/src_private ++ mkdir -p /tmp/src/src_testCE_volume_default ++ mount --bind /tmp/src_private /tmp/src/src_testCE_volume_default ++ touch /tmp/src_private/src_privatefile ++ isula exec -it "$CONT" /bin/sh -c 'ls /tmp/dst/src_testCE_volume_default/src_privatefile || echo -n "host_pass"' > /tmp/host_property_log ++ cat /tmp/host_property_log | grep "host_pass" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from host to container ""$CONT"" success ,but expect fail!" && ((ret++)) ++ ++ #check the property from container to host ++ umount /tmp/src/src_testCE_volume_default ++ isula exec -it "$CONT" /bin/sh -c 'mkdir /tmp/dst_private;mkdir /tmp/dst/dst_testCE_volume_default;mount --bind /tmp/dst_private /tmp/dst/dst_testCE_volume_default;touch /tmp/dst_private/dst_privatefile' ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - exec volume in container ""$CONT"" fail!" && ((ret++)) ++ ls /tmp/src/dst_testCE_volume_default/dst_privatefile ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from container to host success ,but expect fail!" && ((ret++)) ++ ++ #cleanup ++ isula rm -f "$CONT" ++ rm -rf /tmp/host_property_log ++ umount /tmp/dst ++ umount /tmp/src ++ rm -rf /tmp/src ++ rm -rf /tmp/dst ++ rm -rf /tmp/src_private ++ ++ return ${ret} ++} ++ ++function test_volume_mount_private() { ++ ++ mkdir -p /tmp/src ++ ++ #run with slave property volume in container ++ CONT=$(isula run -v /tmp/src:/tmp/dst:private -dit --privileged "${image}" /bin/sh) ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container by image $image failed" && ((ret++)) ++ ++ #check the property from host to container ++ mkdir -p /tmp/src_private ++ mkdir -p /tmp/src/src_testCE_volume_private ++ mount --bind /tmp/src_private /tmp/src/src_testCE_volume_private ++ touch /tmp/src_private/src_privatefile ++ isula exec -it "$CONT" /bin/sh -c 'ls /tmp/dst/src_testCE_volume_private/src_privatefile || echo -n "host_pass"' > /tmp/host_property_log ++ cat /tmp/host_property_log | grep "host_pass" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from host to container ""$CONT"" success ,but expect fail!" && ((ret++)) ++ ++ #check the property from container to host ++ umount /tmp/src/src_testCE_volume_private ++ isula exec -it "$CONT" /bin/sh -c 'mkdir /tmp/dst_private;mkdir /tmp/dst/dst_testCE_volume_private;mount --bind /tmp/dst_private /tmp/dst/dst_testCE_volume_private;touch /tmp/dst_private/dst_privatefile' ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - exec volume in container ""$CONT"" fail!" && ((ret++)) ++ ls /tmp/src/dst_testCE_volume_private/dst_privatefile ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from container to host success ,but expect fail!" && ((ret++)) ++ ++ #cleanup ++ isula rm -f "$CONT" ++ rm -rf /tmp/host_property_log ++ umount /tmp/dst ++ umount /tmp/src ++ rm -rf /tmp/src ++ rm -rf /tmp/dst ++ rm -rf /tmp/src_private ++} ++ ++function test_volume_mount_rprivate() { ++ ++ mkdir -p /tmp/src ++ ++ #run with slave property volume in container ++ CONT=$(isula run -v /tmp/src:/tmp/dst:rprivate -dit --privileged "${image}" /bin/sh) ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container by image $image failed" && ((ret++)) ++ ++ #check the property from host to container ++ mkdir -p /tmp/src_rprivate ++ mkdir -p /tmp/src/src_testCE_mount_rprivate ++ mount --bind /tmp/src_rprivate /tmp/src/src_testCE_mount_rprivate ++ touch /tmp/src_rprivate/src_rprivatefile ++ isula exec -it "$CONT" /bin/sh -c 'ls /tmp/dst/src_testCE_mount_rprivate/src_rprivatefile || echo -n "host_pass"' > /tmp/host_property_log ++ cat /tmp/host_property_log | grep "host_pass" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from host to container ""$CONT"" success ,but expect fail!" && ((ret++)) ++ ++ #check the property from container to host ++ umount /tmp/src/src_testCE_mount_rprivate ++ isula exec -it "$CONT" /bin/sh -c 'mkdir /tmp/dst_rprivate;mkdir /tmp/dst/dst_testCE_mount_rprivate;mount --bind /tmp/dst_rprivate /tmp/dst/dst_testCE_mount_rprivate;touch /tmp/dst_rprivate/dst_rprivatefile' ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - exec volume in container ""$CONT"" fail!" && ((ret++)) ++ ls /tmp/src/dst_testCE_mount_rprivate/dst_rprivatefile ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from container to host success ,but expect fail!" && ((ret++)) ++ ++ #cleanup ++ rm -rf /tmp/host_property_log ++ umount /tmp/dst ++ umount /tmp/src ++ rm -rf /tmp/src ++ rm -rf /tmp/dst ++ rm -rf /tmp/src_rprivate ++} ++ ++function test_volume_mount_rshared() { ++ ++ mkdir -p /tmp/src ++ ++ #run with slave property volume in container ++ CONT=$(isula run -v /tmp/src:/tmp/dst:rshared -dit --privileged "${image}" /bin/sh) ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} -run container by image $image failed" && ((ret++)) ++ ++ #check the property from host to container ++ mkdir -p /tmp/src_rshared ++ mkdir -p /tmp/src/src_testCE_mount_rshared ++ mount --bind /tmp/src_rshared /tmp/src/src_testCE_mount_rshared ++ touch /tmp/src_rshared/src_rsharedfile ++ isula exec -it "$CONT" /bin/sh -c 'ls /tmp/dst/src_testCE_mount_rshared/src_rsharedfile && echo -n "host_pass"' > /tmp/host_property_log ++ cat /tmp/host_property_log | grep "host_pass" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from host to container ""$CONT"" fail!" && ((ret++)) ++ ++ #check the property from container to host ++ umount /tmp/src/src_testCE_mount_rshared ++ isula exec -it "$CONT" /bin/sh -c 'mkdir /tmp/dst_rshared;mkdir /tmp/dst/dst_testCE_mount_rshared;mount --bind /tmp/dst_rshared /tmp/dst/dst_testCE_mount_rshared;touch /tmp/dst_rshared/dst_rsharedfile' ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - exec volume in container ""$CONT"" fail!" && ((ret++)) ++ ls /tmp/src/dst_testCE_mount_rshared/dst_rsharedfile ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from container to host fail!" && ((ret++)) ++ ++ #cleanup ++ rm -rf /tmp/host_property_log ++ umount /tmp/dst ++ umount /tmp/src ++ umount /tmp/src/dst_testCE_mount_rshared ++ rm -rf /tmp/src ++ rm -rf /tmp/dst ++ rm -rf /tmp/src_rshared ++} ++ ++function test_volume_mount_rslave() { ++ ++ mkdir -p /tmp/src ++ ++ #run with slave property volume in container ++ CONT=$(isula run -v /tmp/src:/tmp/dst:rslave -dit --privileged "${image}" /bin/sh) ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container by image $image failed" && ((ret++)) ++ ++ #check the property from host to container ++ mkdir -p /tmp/src_rslave ++ mkdir -p /tmp/src/src_testCE_mount_rslave ++ mount --bind /tmp/src_rslave /tmp/src/src_testCE_mount_rslave ++ touch /tmp/src_rslave/src_rslavefile ++ isula exec -it "$CONT" /bin/sh -c 'ls /tmp/dst/src_testCE_mount_rslave/src_rslavefile && echo -n "host_pass"' > /tmp/host_property_log ++ cat /tmp/host_property_log | grep "host_pass" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from host to container ""$CONT"" fail!" && ((ret++)) ++ ++ #check the property from container to host ++ umount /tmp/src/src_testCE_mount_rslave ++ isula exec -it "$CONT" /bin/sh -c 'mkdir /tmp/dst_rslave;mkdir /tmp/dst/dst_testCE_mount_rslave;mount --bind /tmp/dst_rslave /tmp/dst/dst_testCE_mount_rslave;touch /tmp/dst_rslave/dst_rslavefile' ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - exec volume in container ""$CONT"" fail!" && ((ret++)) ++ ls /tmp/src/dst_testCE_mount_rslave/dst_rslavefile ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from container to host success ,but expect fail!" && ((ret++)) ++ ++ #cleanup ++ rm -rf /tmp/host_property_log ++ umount /tmp/dst ++ umount /tmp/src ++ rm -rf /tmp/src ++ rm -rf /tmp/dst ++ rm -rf /tmp/src_rslave ++} ++ ++function test_volume_mount_shared() { ++ ++ mkdir -p /tmp/src ++ #run with shared property volume in container ++ CONT=$(isula run -v /tmp/src:/tmp/dst:shared -dit --privileged "$image" /bin/sh) ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container by image $image failed" && ((ret++)) ++ ++ #check the property from host to container ++ mkdir -p /tmp/src_shared ++ mkdir -p /tmp/src/src_testCE_v_shared_check ++ mount --bind /tmp/src_shared /tmp/src/src_testCE_v_shared_check ++ touch /tmp/src_shared/src_sharedfile ++ isula exec -it "$CONT" /bin/sh -c 'ls /tmp/dst/src_testCE_v_shared_check/src_sharedfile && echo -n "host_pass"' > /tmp/host_property_log ++ cat /tmp/host_property_log | grep "host_pass" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from host to container ""$CONT"" fail!" && ((ret++)) ++ ++ #check the property from container to host ++ umount /tmp/src/src_testCE_v_shared_check ++ isula exec -it "$CONT" /bin/sh -c 'mkdir /tmp/dst_shared;mkdir /tmp/dst/dst_testCE_mount_shared_check;mount --bind /tmp/dst_shared /tmp/dst/dst_testCE_mount_shared_check;touch /tmp/dst_shared/dst_sharedfile' ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - exec volume in container ""$CONT"" fail!" && ((ret++)) ++ ls /tmp/src/dst_testCE_mount_shared_check/dst_sharedfile ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from container to host fail!" && ((ret++)) ++ ++ #cleanup ++ isula rm -f "$CONT" ++ rm -rf /tmp/host_property_log ++ umount /tmp/dst ++ umount /tmp/src ++ umount /tmp/src/dst_testCE_mount_shared_check ++ rm -rf /tmp/src ++ rm -rf /tmp/dst ++ rm -rf /tmp/src_shared ++} ++ ++function test_volume_mount_slave() { ++ ++ mkdir -p /tmp/src ++ ++ #run with slave property volume in container ++ CONT=$(isula run -v /tmp/src:/tmp/dst:slave -dit --privileged "${image}" /bin/sh) ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container by image $image failed" && ((ret++)) ++ ++ #check the property from host to container ++ mkdir -p /tmp/src_slave ++ mkdir -p /tmp/src/src_testCE_volume_slave ++ mount --bind /tmp/src_slave /tmp/src/src_testCE_volume_slave ++ touch /tmp/src_slave/src_slavefile ++ isula exec -it "$CONT" /bin/sh -c 'ls /tmp/dst/src_testCE_volume_slave/src_slavefile && echo -n "host_pass"' > /tmp/host_property_log ++ cat /tmp/host_property_log | grep "host_pass" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from host to container ""$CONT"" fail!" && ((ret++)) ++ ++ #check the property from container to host ++ umount /tmp/src/src_testCE_volume_slave ++ isula exec -it "$CONT" /bin/sh -c 'mkdir /tmp/dst_slave;mkdir /tmp/dst/dst_testCE_volume_slave;mount --bind /tmp/dst_slave /tmp/dst/dst_testCE_volume_slave;touch /tmp/dst_slave/dst_slavefile' ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - exec volume in container ""$CONT"" fail!" && ((ret++)) ++ ls /tmp/src/dst_testCE_volume_slave/dst_slavefile ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Property from container to host success ,but expect fail!" && ((ret++)) ++ ++ #cleanup ++ isula rm -f "$CONT" ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to remove container ""$CONT"" fail!" && ((ret++)) ++ rm -rf /tmp/host_property_log ++ umount /tmp/dst ++ umount /tmp/src ++ rm -rf /tmp/src ++ rm -rf /tmp/dst ++ rm -rf /tmp/src_slave ++} ++ ++declare -i ans=0 ++ ++msg_info "${test} starting..." ++[[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - start isulad failed" && ((ret++)) ++ ++cleanup_containers_and_volumes ++test_volume_mount_default || ((ans++)) ++cleanup_containers_and_volumes ++test_volume_mount_private || ((ans++)) ++cleanup_containers_and_volumes ++test_volume_mount_rprivate || ((ans++)) ++cleanup_containers_and_volumes ++test_volume_mount_rshared || ((ans++)) ++cleanup_containers_and_volumes ++test_volume_mount_rslave || ((ans++)) ++cleanup_containers_and_volumes ++test_volume_mount_shared || ((ans++)) ++cleanup_containers_and_volumes ++test_volume_mount_slave || ((ans++)) ++cleanup_containers_and_volumes ++ ++msg_info "${test} finished with return ${ans}..." ++ ++show_result ${ans} "${curr_path}/${0}" diff --git a/CI/test_cases/image_cases/busybox.tar b/CI/test_cases/image_cases/busybox.tar deleted file mode 100644 index dafbf56bd7e7449ff9c613a0c158156e02874b18..0000000000000000000000000000000000000000 @@ -21358,6 +23852,214 @@ HcmV?d00001 literal 30 lcmb2|=HPg~K|G#;IW03Ml|kE6SMMPc!!gsH)~pN+3;>A42oV4P +diff --git a/CI/test_cases/image_cases/image_load_multiplex.sh b/CI/test_cases/image_cases/image_load_multiplex.sh +new file mode 100755 +index 0000000..719d8e7 +--- /dev/null ++++ b/CI/test_cases/image_cases/image_load_multiplex.sh +@@ -0,0 +1,83 @@ ++#!/bin/bash ++# ++# attributes: isulad basic image ++# concurrent: NA ++# spend time: 22 ++ ++####################################################################### ++##- @Copyright (C) Huawei Technologies., 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. ++##- @Description:CI ++##- @Author: gaohuatao ++##- @Create: 2020-10-12 ++####################################################################### ++ ++declare -r curr_path=$(dirname $(readlink -f "$0")) ++source ../helpers.sh ++base_image="${curr_path}/busybox.tar" ++multiplex_image="${curr_path}/multiplex_busybox.tar" ++ ++function test_multiplex_layers_image_load() ++{ ++ local ret=0 ++ local test="isula load image with multiplex layers test => (${FUNCNAME[@]})" ++ ++ msg_info "${test} starting..." ++ ++ # remove all images related to busybox ++ isula rmi `isula images | grep busybox | awk '{print $3}'` ++ ++ # load image lacking layers ++ isula load -i $multiplex_image ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - load image success, expect fail: ${multiplex_image}" && ((ret++)) ++ ++ isula images | grep "multiplex_busybox" ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - get image: multiplex_busybox, expect no such image" && ((ret++)) ++ ++ # load base image ++ isula load -i $base_image ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - load image failed: ${base_image} with" && ((ret++)) ++ ++ isula images | grep busybox ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - missing list base image: busybox" && ((ret++)) ++ ++ # load image with base image loaded ++ isula load -i $multiplex_image ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - load image failed: ${multiplex_image}" && ((ret++)) ++ ++ container_name=multiplex_container ++ isula run -tid --name $container_name multiplex_busybox:latest /bin/sh ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - isula run failed" && ((ret++)) ++ ++ isula exec $container_name sh -c 'ls /gao' ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - no such file /gao" && ((ret++)) ++ ++ isula rm -f $container_name ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - rm container failed" && ((ret++)) ++ ++ base_id=`isula inspect -f '{{.image.id}}' busybox:latest` ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - fail to inspect image: busybox:latest" && ((ret++)) ++ ++ mult_id=`isula inspect -f '{{.image.id}}' multiplex_busybox:latest` ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - fail to inspect image: multiplex_busybox:latest" && ((ret++)) ++ ++ isula rmi $base_id $mult_id ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to remove image ${base_id} and ${mult_id}" && ((ret++)) ++ ++ msg_info "${test} finished with return ${ret}..." ++ return ${ret} ++} ++ ++declare -i ans=0 ++ ++test_multiplex_layers_image_load || ((ans++)) ++ ++show_result ${ans} "${curr_path}/${0}" ++ +diff --git a/CI/test_cases/image_cases/image_tag.sh b/CI/test_cases/image_cases/image_tag.sh +index ab04560..63d2687 100755 +--- a/CI/test_cases/image_cases/image_tag.sh ++++ b/CI/test_cases/image_cases/image_tag.sh +@@ -32,6 +32,8 @@ function test_tag_image() + + msg_info "${test} starting..." + ++ isula rm -f `isula ps -aq` ++ + isula pull $image_busybox + [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to pull image: ${image_busybox}" && ((ret++)) + +diff --git a/CI/test_cases/image_cases/isulad_tmpdir.sh b/CI/test_cases/image_cases/isulad_tmpdir.sh +new file mode 100644 +index 0000000..22a6ad4 +--- /dev/null ++++ b/CI/test_cases/image_cases/isulad_tmpdir.sh +@@ -0,0 +1,100 @@ ++#!/bin/bash ++# ++# attributes: isulad basic container hook ++# concurrent: NA ++# spend time: 4 ++ ++####################################################################### ++##- @Copyright (C) Huawei Technologies., 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. ++##- @Description:CI ++##- @Author: gaohuatao ++##- @Create: 2020-11-05 ++####################################################################### ++ ++declare -r curr_path=$(dirname $(readlink -f "$0")) ++source ../helpers.sh ++busybox_image="${curr_path}/busybox.tar" ++image_name="busybox:latest" ++ ++function restart_isulad() ++{ ++ check_valgrind_log ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - stop isulad failed" && ((ret++)) ++ ++ start_isulad_with_valgrind ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - start isulad failed" && ((ret++)) ++ ++} ++ ++function load_pull_test() ++{ ++ isula load -i $busybox_image ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - load image failed: ${busybox_image} with" && ((ret++)) ++ ++ isula rmi $image_name ++ ++ isula pull ${image_name} ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to pull image: ${image_name}" && return ${FAILURE} ++} ++ ++function test_isulad_tmpdir() ++{ ++ local ret=0 ++ local test="ISULAD_TMPDIR env test => (${FUNCNAME[@]})" ++ ++ msg_info "${test} starting..." ++ isula rm -f `isula ps -qa` ++ isula rmi `isula images | awk '{if (NR>1){print $3}}'` ++ ++ # The scene of ISULAD_TMPDIR dir is not exists ++ export ISULAD_TMPDIR="/var/isula/tmp" ++ restart_isulad ++ load_pull_test ++ test -d /var/isula/tmp/isula-image ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - isula-image not exist in ISULAD_TMPDIR" && ((ret++)) ++ ++ # The scene of ISULAD_TMPDIR dir is symbol link that it refers to dir exists ++ rm -rf /var/isula/tmp ++ mkdir -p /var/tmpdir ++ ln -sf /var/tmpdir /var/isula/tmpdir ++ unset ISULAD_TMPDIR ++ export ISULAD_TMPDIR="/var/isula/tmpdir" ++ restart_isulad ++ load_pull_test ++ test -d /var/isula/tmpdir/isula-image ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - isula-image not exist in ISULAD_TMPDIR" && ((ret++)) ++ ++ # rm dest dir of symbol link ++ rm -rf /var/tmpdir ++ check_valgrind_log ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - stop isulad failed" && ((ret++)) ++ ++ start_isulad_with_valgrind ++ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - start isulad failed" && ((ret++)) ++ ++ # default no ISULAD_TMPDIR env ++ unset ISULAD_TMPDIR ++ start_isulad_with_valgrind ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - start isulad failed" && ((ret++)) ++ ++ load_pull_test ++ test -d /var/tmp/isula-image ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - isula-image not exist in /var/tmp" && ((ret++)) ++ ++ msg_info "${test} finished with return ${ret}..." ++ return ${ret} ++} ++ ++declare -i ans=0 ++ ++test_isulad_tmpdir || ((ans++)) ++ ++show_result ${ans} "${curr_path}/${0}" diff --git a/CI/test_cases/image_cases/mult_image.tar b/CI/test_cases/image_cases/mult_image.tar deleted file mode 100644 index 5e71e8d06e6a20a22c6de80c6959d2f5246035dd..0000000000000000000000000000000000000000 @@ -615134,43 +617836,64 @@ z&RvYDOHDb4Ja(ZNt9UttA^-H*ub!Tx^s}eG?NERE^=IeE|Hf&5+fexQ>#qqL Q_gjyj5kLTeA1?6!0WvH;h5!Hn -diff --git a/CI/test_cases/image_cases/multiplex_busybox.tar b/CI/test_cases/image_cases/multiplex_busybox.tar -deleted file mode 100644 -index e55144cc2ffecb6996937acbce41172e5412733a..0000000000000000000000000000000000000000 -GIT binary patch -literal 0 -HcmV?d00001 - -literal 20480 -zcmeI2TTdHD6vuh)r?93ktz_)EUo7>30#YI+B}!BZm*6unALjLYOYa2od -z*hw%b5wk{k=RW&8GqZF4c+EwkXOJ7y?J5C!6jn0fAB6ETT&PmWJ5~HcXgajd^1H(k;G!aI)kYxe$ -zz_G#7a&45rYW)D}4E&|`r;2W23Llc}{}{t&1NMKr|N71IgFo)>ZD)VU`OSHM8HQB0 -zbvgeR_9v9X{Kt1!xw(`lKL5$!Q7CWDUa6*y64=1}|F@~im3>+>|0%=j=KO~pK$`z6 -zp>8Pg0_6dX(0w-nsE;PLj%5pVNy()NGEya(WyS<%jp5XCqnV=IDl1(GGSdQ!Kp~5a -zo;Z(%VgmLV7V7eKv~BD<)@=p03H;GRtVdXlC>>CxmC%N(f4Zzy+1k8}^$FZ%`6(J* -zpl4OnmUbMWJmlD`#*pDt_|GQRib!H4Ydx(AeabRcqg29++&43 -z1`|XpDT~aL5PWdlf#r<0+6O2Jd%|8`_J+N#!JYcF*>Aj^bXIBWDUf_9&G}nIF*5{Kd??%}o$3gk~G%uh>i{K0EVzDef>!VQl_b@I##Jb5V -zurMNKfZ0GoOHXjDz%cni?PzO%mbcNj)4CgPb{r%J8&+UxROIFKBbse!HGF#2Y~cN0 -z*z;Hqz>B_%-kSG6gY+Bke{la~djH?WbCdC>w%TNMx7LM0*jerWUD=;;*b9R4AQ*d0 -z`-3aGPTyIV-VJiNE}hz2L8Qn;AQ4Cez9RyIAuP7kSy-PVaf)Yf1D=?SBzU7E+&OMD -z!bPU3^Tsh9tfM+3*hfnx)_!nb|DRF*ng7p022T3lBaD*^bjR*Gc}PEyr<+8OB!b)_ -zf_#OPwn8sC%bT{ULGL=cxGBzIxsB-|B_m=+LJeTA59_&>d@jx{bi5M>B`?LQ-nQ>8 -zg{qysy`@g2xrgINnngje3Pd?U2#zGim}S^H5tO%@k)Sw;#W-3=qE^AfnK2wxayGmv|( -zX(WBrxiA@sCKsqZpL9yf{8<`!w2)`nNgg2W=t|CW5nv1ES-=?_1jG5TWZDX91dB2Q -z!4|Z>C>&7)8%lyR(Nk+duT>O|jSbYg6b1w3hIo;|2OFZ5RiF$Tsci&(m_#T~trRY5 -z?S!SCN~SQ$6q6E8nWdoUc$V~?huR7ZhIO1&O%Ag=kIloh()q=!{D1Q4YSMP+6ma~~bcZ?jJ{X$KetMWum1^Atfx&QW%RB>P -zulM7=wY_!opTmzmx;)DZ^gjwOp5*_1EAOu<2m86*<+&-^h!Ozr{nzkDIkczq-Na|B -z%V@c@z~Ac7;nf)gG=JYE>sn>Uv*WaSea&!6c@u#|AQ4Ce5`jb@5l93Q -zfkYq?NCXmrL?97J1QLNnAQ4Ce5`jb@5l93QfkYq?NCXmrL?97J1QLNnAQ4Ce9*Mwz -DD^Trr - +diff --git a/CI/test_cases/image_cases/registry.sh b/CI/test_cases/image_cases/registry.sh +index 7507d22..042b1f4 100755 +--- a/CI/test_cases/image_cases/registry.sh ++++ b/CI/test_cases/image_cases/registry.sh +@@ -39,8 +39,8 @@ function isula_pull() + isula inspect busybox + fn_check_eq "$?" "0" "isula inspect busybox" + +- isula pull hub-mirror.c.163.com/library/busybox +- fn_check_eq "$?" "0" "isula pull hub-mirror.c.163.com/library/busybox" ++ isula pull 3laho3y3.mirror.aliyuncs.com/library/busybox ++ fn_check_eq "$?" "0" "isula pull 3laho3y3.mirror.aliyuncs.com/library/busybox" + + rm -f /etc/isulad/daemon.json.bak + cp /etc/isulad/daemon.json /etc/isulad/daemon.json.bak +@@ -59,7 +59,7 @@ function isula_pull() + cp /etc/isulad/daemon.json.bak /etc/isulad/daemon.json + rm -f /etc/isulad/daemon.json.bak + +- isula rmi hub-mirror.c.163.com/library/busybox ++ isula rmi 3laho3y3.mirror.aliyuncs.com/library/busybox + + check_valgrind_log + fn_check_eq "$?" "0" "stop isulad with check valgrind" +@@ -70,12 +70,12 @@ function isula_pull() + + function isula_login() + { +- isula login -u test -p test hub-mirror.c.163.com +- fn_check_eq "$?" "0" "isula login -u test -p test hub-mirror.c.163.com" ++ isula login -u test -p test 3laho3y3.mirror.aliyuncs.com ++ fn_check_eq "$?" "0" "isula login -u test -p test 3laho3y3.mirror.aliyuncs.com" + + # double login for memory leak check +- isula login -u test -p test hub-mirror.c.163.com +- fn_check_eq "$?" "0" "isula login -u test -p test hub-mirror.c.163.com" ++ isula login -u test -p test 3laho3y3.mirror.aliyuncs.com ++ fn_check_eq "$?" "0" "isula login -u test -p test 3laho3y3.mirror.aliyuncs.com" + + # use username/password to pull busybox for memmory leak check + isula pull busybox +@@ -84,12 +84,12 @@ function isula_login() + + function isula_logout() + { +- isula logout hub-mirror.c.163.com +- fn_check_eq "$?" "0" "isula logout hub-mirror.c.163.com" ++ isula logout 3laho3y3.mirror.aliyuncs.com ++ fn_check_eq "$?" "0" "isula logout 3laho3y3.mirror.aliyuncs.com" + + # double logout for memory leak check +- isula logout hub-mirror.c.163.com +- fn_check_eq "$?" "0" "isula logout hub-mirror.c.163.com" ++ isula logout 3laho3y3.mirror.aliyuncs.com ++ fn_check_eq "$?" "0" "isula logout 3laho3y3.mirror.aliyuncs.com" + } + + function do_test_t() diff --git a/CI/test_cases/image_cases/rootfs.tar b/CI/test_cases/image_cases/rootfs.tar deleted file mode 100644 index 1d39464c011ac1c2fe1e325502de2b470b26fc3e..0000000000000000000000000000000000000000 @@ -642205,6 +644928,34720 @@ z6Y|C@{&J=k1{%hnjTHaVsnkH1XVm&^ + + RUN echo "nameserver 8.8.8.8" > /etc/resolv.conf && \ +@@ -60,18 +60,12 @@ RUN yum clean all && yum makecache && yum install -y epel-release && yum swap -y + unzip \ + tar \ + wget \ +- gtest \ +- gtest-devel \ +- gmock \ +- gmock-devel \ + cppcheck \ + python3 \ + python3-pip \ + python \ + python-pip \ + device-mapper-devel \ +- libarchive \ +- libarchive-devel \ + libtar \ + libtar-devel \ + libcurl-devel \ +@@ -118,7 +112,7 @@ RUN set -x && \ + cd ~ && \ + git clone https://gitee.com/src-openeuler/cmake.git && \ + cd cmake && \ +- git checkout openEuler-20.03-LTS-tag && \ ++ git checkout -b openEuler-20.03-LTS-tag openEuler-20.03-LTS-tag && \ + tar -xzvf cmake-3.12.1.tar.gz && \ + cd cmake-3.12.1 && \ + ./bootstrap && make && make install && \ +@@ -131,7 +125,7 @@ RUN set -x && \ + cd ~ && \ + git clone https://gitee.com/src-openeuler/protobuf.git && \ + cd protobuf && \ +- git checkout openEuler-20.03-LTS-tag && \ ++ git checkout -b openEuler-20.03-LTS-tag openEuler-20.03-LTS-tag && \ + tar -xzvf protobuf-all-3.9.0.tar.gz && \ + cd protobuf-3.9.0 && \ + ./autogen.sh && \ +@@ -146,7 +140,7 @@ RUN export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \ + cd ~ && \ + git clone https://gitee.com/src-openeuler/c-ares.git && \ + cd c-ares && \ +- git checkout openEuler-20.03-LTS-tag && \ ++ git checkout -b openEuler-20.03-LTS-tag openEuler-20.03-LTS-tag && \ + tar -xzvf c-ares-1.15.0.tar.gz && \ + cd c-ares-1.15.0 && \ + autoreconf -if && \ +@@ -161,7 +155,7 @@ RUN export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \ + cd ~ && \ + git clone https://gitee.com/src-openeuler/grpc.git && \ + cd grpc && \ +- git checkout openEuler-20.03-LTS-tag && \ ++ git checkout -b openEuler-20.03-LTS-tag openEuler-20.03-LTS-tag && \ + tar -xzvf grpc-1.22.0.tar.gz && \ + cd grpc-1.22.0 && \ + make -j $(nproc) && \ +@@ -174,7 +168,7 @@ RUN export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \ + cd ~ && \ + git clone https://gitee.com/src-openeuler/libevent.git && \ + cd libevent && \ +- git checkout openEuler-20.03-LTS-tag && \ ++ git checkout -b openEuler-20.03-LTS-tag openEuler-20.03-LTS-tag && \ + tar -xzvf libevent-2.1.11-stable.tar.gz && \ + cd libevent-2.1.11-stable && \ + ./autogen.sh && \ +@@ -189,13 +183,11 @@ RUN export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \ + cd ~ && \ + git clone https://gitee.com/src-openeuler/libevhtp.git && \ + cd libevhtp && \ +- git checkout openEuler-20.03-LTS-tag && \ +- tar -xzvf libevhtp-1.2.18.tar.gz && \ +- cd libevhtp-1.2.18 && \ +- patch -p1 -F1 -s < ../0001-decrease-numbers-of-fd-for-shared-pipe-mode.patch && \ +- patch -p1 -F1 -s < ../0002-evhtp-enable-dynamic-thread-pool.patch && \ +- patch -p1 -F1 -s < ../0003-close-open-ssl.-we-do-NOT-use-it-in-lcrd.patch && \ +- patch -p1 -F1 -s < ../0004-Use-shared-library-instead-static-one.patch && \ ++ git checkout -b openEuler-20.03-LTS-tag openEuler-20.03-LTS-tag && \ ++ tar -xzvf libevhtp-1.2.16.tar.gz && \ ++ cd libevhtp-1.2.16 && \ ++ patch -p1 -F1 -s < ../0001-support-dynamic-threads.patch && \ ++ patch -p1 -F1 -s < ../0002-close-openssl.patch && \ + rm -rf build && \ + mkdir build && \ + cd build && \ +@@ -210,7 +202,7 @@ RUN export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \ + cd ~ && \ + git clone https://gitee.com/src-openeuler/http-parser.git && \ + cd http-parser && \ +- git checkout openEuler-20.03-LTS-tag && \ ++ git checkout -b openEuler-20.03-LTS-tag openEuler-20.03-LTS-tag && \ + tar -xzvf http-parser-2.9.2.tar.gz && \ + cd http-parser-2.9.2 && \ + make -j CFLAGS="-Wno-error" && \ +@@ -223,7 +215,7 @@ RUN export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \ + cd ~ && \ + git clone https://gitee.com/src-openeuler/libwebsockets.git && \ + cd libwebsockets && \ +- git checkout openEuler-20.03-LTS-tag && \ ++ git checkout -b openEuler-20.03-LTS-tag openEuler-20.03-LTS-tag && \ + tar -xzvf libwebsockets-2.4.2.tar.gz && \ + cd libwebsockets-2.4.2 && \ + patch -p1 -F1 -s < ../libwebsockets-fix-coredump.patch && \ +@@ -234,56 +226,74 @@ RUN export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \ + make install && \ + ldconfig + +-# install lxc ++# install gtest/gmock + RUN export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \ + set -x && \ + cd ~ && \ +- git clone https://gitee.com/src-openeuler/lxc.git && \ +- cd lxc && \ +- ./apply-patches && \ +- cd lxc-4.0.3 && \ +- ./autogen.sh && \ +- ./configure && \ +- make -j $(nproc) && \ +- make install && \ +- ldconfig +- +-# install lcr +-RUN export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \ +- set -x && \ +- cd ~ && \ +- git clone https://gitee.com/openeuler/lcr.git && \ +- cd lcr && \ +- mkdir build && \ ++ git clone https://gitee.com/src-openeuler/gtest.git && \ ++ cd gtest && \ ++ git checkout -b openEuler-20.03-LTS-tag openEuler-20.03-LTS-tag && \ ++ tar xf release-1.8.1.tar.gz && \ ++ cd googletest-release-1.8.1 && \ ++ patch -p1 -F1 -s < ../gtest-1.8.1-null-pointer.patch && \ ++ patch -p1 -F1 -s < ../gtest-PR1839-Fix-Python3-support.patch && \ ++ patch -p1 -F1 -s < ../gtest-1.8.1-libversion.patch && \ ++ patch -p1 -F1 -s < ../gtest-1.8.1-add-missing-pkgconfig-requires.patch && \ ++ mkdir -p build && \ + cd build && \ +- cmake ../ && \ ++ cmake -DBUILD_SHARED_LIBS=ON ../ && \ + make -j $(nproc) && \ + make install && \ + ldconfig + +-# install clibcni ++# install libarchive + RUN export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \ +- set -x && \ +- cd ~ && \ +- git clone https://gitee.com/openeuler/clibcni.git && \ +- cd clibcni && \ +- mkdir build && \ +- cd build && \ +- cmake ../ && \ +- make -j $(nproc) && \ +- make install && \ +- ldconfig ++ set -x && \ ++ cd ~ && \ ++ git clone https://gitee.com/src-openeuler/libarchive.git && \ ++ cd libarchive && \ ++ git checkout -b openEuler-20.03-LTS-tag openEuler-20.03-LTS-tag && \ ++ tar -zxvf libarchive-3.4.1.tar.gz && \ ++ cd libarchive-3.4.1 && \ ++ patch -p1 -F1 -s < ../libarchive-uninitialized-value.patch && \ ++ cd build && \ ++ cmake -DCMAKE_USE_SYSTEM_LIBRARIES=ON ../ && \ ++ make -j $(nproc) && \ ++ make install && \ ++ ldconfig + +-# install iSulad-img + RUN export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \ +- set -x && \ +- cd ~ && \ +- git clone https://gitee.com/openeuler/iSulad-img.git && \ +- cd iSulad-img && \ +- ./apply-patch && \ +- make -j $(nproc) && \ +- make install && \ +- ldconfig +- ++ set -x && \ ++ cd ~ && \ ++ git clone https://gitee.com/openeuler/iSulad/ &&\ ++ cd iSulad &&\ ++ # git checkout 756c0bdc308c2845971ad9ca0c58760a84288bc0 &&\ ++ git checkout v2.0.6 &&\ ++ cd CI &&\ ++ ./install_depends.sh &&\ ++ cd .. &&\ ++ mkdir build &&\ ++ cd build &&\ ++ cmake .. &&\ ++ make -j $(nproc) && \ ++ make install && \ ++ ldconfig ++ ++FROM centos:7.6.1810 ++ ++COPY --from=build /usr/local/bin /usr/local/bin ++COPY --from=build /usr/local/lib /usr/local/lib ++COPY --from=build /usr/local/lib64 /usr/local/lib64 ++COPY --from=build /usr/lib64 /usr/lib64 ++COPY --from=build /etc/default/isulad/ /etc/default/isulad/ ++COPY --from=build /etc/isulad /etc/isulad ++ ++ ++ ++RUN echo "/usr/lib" >> /etc/ld.so.conf && \ ++ echo "/usr/local/lib" >> /etc/ld.so.conf &&\ ++ ldconfig ++ ++ + VOLUME [ "/sys/fs/cgroup" ] +-CMD ["/usr/sbin/init"] ++CMD ["/usr/local/bin/isulad"] +\ No newline at end of file +diff --git a/README.md b/README.md +index 934f6ee..08467dd 100644 +--- a/README.md ++++ b/README.md +@@ -9,13 +9,24 @@ + ### Installing + To install iSulad, you can use `rpm` or `yum` package manager command with `openEuler` repository. + +-Install iSulad with yum ++Or write repository file by hand: ++ ++```sh ++cat << EOF > /etc/yum.repos.d/openEuler.repo ++[openEuler] ++baseurl=https://repo.openeuler.org/openEuler-20.03-LTS/OS/\$basearch ++enabled=1 ++EOF ++``` ++ ++Install iSulad with yum: ++ + ```sh + yum install -y iSulad + ``` + + ### Run +-We provide `systemd` service to start `iSulad` ++We provide `systemd` service to start `iSulad`: + ```sh + systemctl start isulad # run the server with systemd command + ``` +@@ -25,43 +36,51 @@ You can use direct command to start `iSulad` server: + $ sudo isulad # run the server with default socket name and default log level and images manage function + ``` + ### Operations on containers: +-`iSulad` provides command line `isulad` to talk with server. +-Here are some sample commands to manager containers. + +-List all containers in your own environment: +-```sh +-# list containers +-$ sudo isula ps -a +-``` ++For more informations on how to use `iSulad`, please refer to the [guide](https://openeuler.org/en/docs/20.03_LTS/docs/Container/isulad-container-engine.html) + +-Create a container with busybox named `test` +-```sh +-# create a container 'test' with image busybox +-$ sudo isula create -t -n test busybox +-``` ++`iSulad` provides two operate interfaces to manager images and containers. ++ ++- CLI, `iSulad` provides `isula` as client CLI ++ ++ Here are some sample commands to manager containers. ++ ++ List all containers in your own environment: ++ ```sh ++ # list containers ++ $ sudo isula ps -a ++ ``` ++ ++ Create a container with busybox named `test`: ++ ```sh ++ # create a container 'test' with image busybox ++ $ sudo isula create -t -n test busybox ++ ``` ++ ++ Start this container `test`: ++ ```sh ++ # start the container 'test' ++ $ sudo isula start test ++ ``` ++ Kill the container `test`: ++ ```sh ++ # kill the container 'test': ++ $ sudo isula kill test ++ ``` ++ Remove the container `test`: ++ ```sh ++ # remove the container 'test' ++ $ sudo isula rm test ++ ``` ++ ++- CRI interface, `iSulad` can be integrated with `kubernetes` through CRI interface ++ ++ How to integrate with `kubernetes` please refer to [integration.md](./docs/integration.md) + +-Start this container `test` +-```sh +-# start the container 'test' +-$ sudo isula start test +-``` +-Kill the container `test` +-```sh +-# kill the container 'test' +-$ sudo isula kill test +-``` +-Remove the container `test` +-```sh +-# remove the container 'test' +-$ sudo isula rm test +-``` + + ### Build from source + Build requirements for developers are listed in [build_guide](./docs/build_guide.md) + +-### Integration +-Integrate with `kubernetes` are listed in [integration.md](./docs/integration.md) +- + ## Performance + + #### Machine configuration +@@ -79,7 +98,7 @@ ARM machine: + + | Configuration | Information | + | ------------- | ------------- | +-| OS | Euleros | ++| OS | openEuler | + | Kernel | linux 4.19.90 | + | CPU | 64 cores | + | Memory | 196 GB | +diff --git a/cmake/checker.cmake b/cmake/checker.cmake +index 112fb17..5ba4c63 100644 +--- a/cmake/checker.cmake ++++ b/cmake/checker.cmake +@@ -90,13 +90,15 @@ find_library(CURL_LIBRARY curl + HINTS ${PC_CURL_LIBDIR} ${PC_CURL_LIBRARY_DIRS}) + _CHECK(CURL_LIBRARY "CURL_LIBRARY-NOTFOUND" "libcurl.so") + +-pkg_check_modules(PC_SELINUX "libselinux>=2.0") +-find_path(SELINUX_INCLUDE_DIR "selinux/selinux.h" +- HINTS ${PC_SELINUX_INCLUDEDIR} ${PC_SELINUX_INCLUDE_DIRS}) +-_CHECK(SELINUX_INCLUDE_DIR "SELINUX_INCLUDE_DIR-NOTFOUND" "selinux/selinux.h") +-find_library(SELINUX_LIBRARY selinux +- HINTS ${PC_SELINUX_LIBDIR} ${PC_SELINUX_LIBRARY_DIRS}) +-_CHECK(SELINUX_LIBRARY "SELINUX_LIBRARY-NOTFOUND" "libselinux.so") ++if (ENABLE_SELINUX) ++ pkg_check_modules(PC_SELINUX "libselinux>=2.0") ++ find_path(SELINUX_INCLUDE_DIR "selinux/selinux.h" ++ HINTS ${PC_SELINUX_INCLUDEDIR} ${PC_SELINUX_INCLUDE_DIRS}) ++ _CHECK(SELINUX_INCLUDE_DIR "SELINUX_INCLUDE_DIR-NOTFOUND" "selinux/selinux.h") ++ find_library(SELINUX_LIBRARY selinux ++ HINTS ${PC_SELINUX_LIBDIR} ${PC_SELINUX_LIBRARY_DIRS}) ++ _CHECK(SELINUX_LIBRARY "SELINUX_LIBRARY-NOTFOUND" "libselinux.so") ++endif() + + # check iSula libutils + pkg_check_modules(PC_ISULA_LIBUTILS REQUIRED "lcr") +diff --git a/cmake/options.cmake b/cmake/options.cmake +index d8f5824..bb51893 100644 +--- a/cmake/options.cmake ++++ b/cmake/options.cmake +@@ -33,7 +33,7 @@ endif() + + option(VERSION "set isulad version" ON) + if (VERSION STREQUAL "ON") +- set(ISULAD_VERSION "2.0.5") ++ set(ISULAD_VERSION "2.0.7") + endif() + + option(DEBUG "set isulad gcc option" ON) +@@ -60,3 +60,10 @@ if (ENABLE_EMBEDDED STREQUAL "ON") + add_definitions(-DENABLE_EMBEDDED_IMAGE=1) + set(ENABLE_EMBEDDED_IMAGE 1) + endif() ++ ++option(ENABLE_SELINUX "enable isulad daemon selinux option" ON) ++if (ENABLE_SELINUX STREQUAL "ON") ++ add_definitions(-DENABLE_SELINUX=1) ++ set(ENABLE_SELINUX 1) ++endif() ++ +diff --git a/cmake/protoc.cmake b/cmake/protoc.cmake +index 352c0db..fa4422a 100644 +--- a/cmake/protoc.cmake ++++ b/cmake/protoc.cmake +@@ -1,26 +1,17 @@ + set(PROTOS_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/api/services) +-set(TYPES_PROTOS_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/api/types) + + set(GRPC_OUT_PRE_PATH ${CMAKE_BINARY_DIR}/grpc) +-set(TYPES_PROTOS_OUT_PATH ${GRPC_OUT_PRE_PATH}/src/api/types) + set(CONTAINER_PROTOS_OUT_PATH ${GRPC_OUT_PRE_PATH}/src/api/services/containers) + set(IMAGE_PROTOS_OUT_PATH ${GRPC_OUT_PRE_PATH}/src/api/services/images) ++set(VOLUME_PROTOS_OUT_PATH ${GRPC_OUT_PRE_PATH}/src/api/services/volumes) + set(CRI_PROTOS_OUT_PATH ${GRPC_OUT_PRE_PATH}/src/api/services/cri) + set(IMAGE_SERVICE_PROTOS_OUT_PATH ${GRPC_OUT_PRE_PATH}/src/api/image_client) + +-execute_process(COMMAND mkdir -p ${TYPES_PROTOS_OUT_PATH}) +- +-execute_process(COMMAND ${CMD_PROTOC} -I ${TYPES_PROTOS_PATH} --cpp_out=${TYPES_PROTOS_OUT_PATH} +- ${TYPES_PROTOS_PATH}/descriptor.proto ERROR_VARIABLE types_err) +-if (types_err) +- message("Parse types.proto failed: ") +- message(FATAL_ERROR ${types_err}) +-endif() +- + if (GRPC_CONNECTOR) + message("---------------Generate GRPC proto-----------------------") + execute_process(COMMAND mkdir -p ${CONTAINER_PROTOS_OUT_PATH}) + execute_process(COMMAND mkdir -p ${IMAGE_PROTOS_OUT_PATH}) ++ execute_process(COMMAND mkdir -p ${VOLUME_PROTOS_OUT_PATH}) + execute_process(COMMAND mkdir -p ${CRI_PROTOS_OUT_PATH}) + execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/containers --cpp_out=${CONTAINER_PROTOS_OUT_PATH} + ${PROTOS_PATH}/containers/container.proto ERROR_VARIABLE containers_err) +@@ -29,27 +20,36 @@ if (GRPC_CONNECTOR) + message(FATAL_ERROR ${containers_err}) + endif() + +- execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/containers --grpc_out=${CONTAINER_PROTOS_OUT_PATH} +- --plugin=protoc-gen-grpc=${CMD_GRPC_CPP_PLUGIN} ${PROTOS_PATH}/containers/container.proto ERROR_VARIABLE containers_err) ++ execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/containers --grpc_out=${CONTAINER_PROTOS_OUT_PATH} --plugin=protoc-gen-grpc=${CMD_GRPC_CPP_PLUGIN} ${PROTOS_PATH}/containers/container.proto ERROR_VARIABLE containers_err) + if (containers_err) + message("Parse containers.proto plugin failed: ") + message(FATAL_ERROR ${containers_err}) + endif() + +- execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/images -I ${TYPES_PROTOS_PATH} +- --cpp_out=${IMAGE_PROTOS_OUT_PATH} ${PROTOS_PATH}/images/images.proto ERROR_VARIABLE images_err) ++ execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/images --cpp_out=${IMAGE_PROTOS_OUT_PATH} ${PROTOS_PATH}/images/images.proto ERROR_VARIABLE images_err) + if (images_err) + message("Parse images.proto failed: ") + message(FATAL_ERROR ${images_err}) + endif() + +- execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/images -I ${TYPES_PROTOS_PATH} --grpc_out=${IMAGE_PROTOS_OUT_PATH} +- --plugin=protoc-gen-grpc=${CMD_GRPC_CPP_PLUGIN} ${PROTOS_PATH}/images/images.proto ERROR_VARIABLE images_err) ++ execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/images --grpc_out=${IMAGE_PROTOS_OUT_PATH} --plugin=protoc-gen-grpc=${CMD_GRPC_CPP_PLUGIN} ${PROTOS_PATH}/images/images.proto ERROR_VARIABLE images_err) + if (images_err) + message("Parse images.proto plugin failed: ") + message(FATAL_ERROR ${images_err}) + endif() + ++ execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/volumes --cpp_out=${VOLUME_PROTOS_OUT_PATH} ${PROTOS_PATH}/volumes/volumes.proto ERROR_VARIABLE volumes_err) ++ if (volumes_err) ++ message("Parse volumes.proto failed: ") ++ message(FATAL_ERROR ${volumes_err}) ++ endif() ++ ++ execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/volumes --grpc_out=${VOLUME_PROTOS_OUT_PATH} --plugin=protoc-gen-grpc=${CMD_GRPC_CPP_PLUGIN} ${PROTOS_PATH}/volumes/volumes.proto ERROR_VARIABLE volumes_err) ++ if (volumes_err) ++ message("Parse volumes.proto plugin failed: ") ++ message(FATAL_ERROR ${volumes_err}) ++ endif() ++ + execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/cri --cpp_out=${CRI_PROTOS_OUT_PATH} ${PROTOS_PATH}/cri/api.proto + ERROR_VARIABLE cri_err) + if (cri_err) +diff --git a/docs/build_guide.md b/docs/build_guide.md +index b401bb5..912139f 100644 +--- a/docs/build_guide.md ++++ b/docs/build_guide.md +@@ -19,6 +19,10 @@ $ sudo apt install -y libtool automake autoconf cmake make pkg-config libyajl-de + ## Build and install other dependencies from source + These dependencies may not be provided by your package manager. So you need to build them from source. + ++Please use the protobuf and grpc came with your distribution, if not exists then need to build them from source. ++ ++Note: grpc-1.22 can not support GCC 9+. ++ + ### set ldconfig and pkgconfig + ``` + $ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH +@@ -93,7 +97,7 @@ $ sudo -E make install + $ sudo -E ldconfig + ``` + +-## Build and install specific versions dependencies from source ++## Build and install specific versions dependencies from source + iSulad depend on some specific versions dependencies. + + ### build and install lxc +diff --git a/docs/build_guide_riscv.md b/docs/build_guide_riscv.md +new file mode 100644 +index 0000000..76f97c9 +--- /dev/null ++++ b/docs/build_guide_riscv.md +@@ -0,0 +1,296 @@ ++ ++# ISulad在RISC-V构架的openEuler的支持工作 ++ ++ ++--- ++ ++## RISC-V虚拟环境的搭建 ++>RISC-V的环境我们是通过在host上使用QEMU虚拟机实现的,我们要做的是使用任意一Linux发行版作为host安装QEMU虚拟机,在虚拟机中启动RISC-V的openEuler镜像,在虚拟机镜像中完成iSulad的安装。 ++### 1. 安装虚拟机 ++ ++首先是在host上安装QEMU,打开终端,依次输入以下命令: ++```shell ++wget https://download.qemu.org/qemu-5.1.0.tar.xz ++tar xvJf qemu-5.1.0.tar.xz ++cd qemu-5.1.0 ++./configure --target-list=riscv64-softmmu ++make ++make install ++``` ++### 2. 启动文件准备 ++安装好支持RISC-V的QEMU之后,就可以使用它来启动虚拟机的镜像,镜像的下载和安装可以参考[openEuler RISC-V 移植版的获取和运行](https://gitee.com/openeuler/RISC-V/blob/master/documents/Installing.md),启动QEMU的虚拟机Linux环境,应该有以下几个文件: ++ ++1. [oe-rv-rv64g-30G.qcow2](https://isrc.iscas.ac.cn/mirror/openeuler-sig-riscv/images/oe-rv-rv64g-30G.qcow2) ++ ++2. [fw_payload_oe.elf](https://isrc.iscas.ac.cn/mirror/openeuler-sig-riscv/images/fw_payload_oe.elf) ++ ++3. run_oe1_rv64.sh(可选) ++ ++ ++可以创建一个shell文件,内容来自[installing.md](https://gitee.com/openeuler/RISC-V/blob/master/documents/Installing.md),如下: ++ ++ ++```shell ++#!/bin/sh ++ ++qemu-system-riscv64 \ ++ -machine virt \ ++ -nographic \ ++ -smp 8 \ ++ -m 124G \ ++ -drive file=oe-rv-base-expand.qcow2,format=qcow2,id=hd0 \ ++ -object rng-random,filename=/dev/urandom,id=rng0 \ ++ -device virtio-rng-device,rng=rng0 \ ++ -device virtio-blk-device,drive=hd0 \ ++ -netdev user,id=usernet,hostfwd=tcp::12055-:22 \ ++ -device virtio-net-device,netdev=usernet \ ++ -append 'root=/dev/vda1 systemd.default_timeout_start_sec=600 selinux=0 rw highres=off console=ttyS0 mem=4096M earlycon' \ ++ -kernel fw_payload.elf \ ++``` ++ ++里面是一些参数的设定,可以查看QEMU的参数说明根据本地计算机配置进行调整。 ++### 3.启动虚拟机 ++可以采用两种方式: ++1. 在终端直接输入shell文件中的内容 ++2. 如果创建了shell文件,只需要在终端里输入 `sh run_oe1_rv64.sh` ++ ++默认的登陆用户名/密码是:root/openEuler12#$ ++ ++## 依赖安装 ++ ++正式编译项目之前,要在系统上安装编译工具、代码版本控制等用途的软件包。 ++这个过程会使用yum工具来对rpm软件包进行安装,如果刚刚使用`oe-rv-rv64g-30G.qcow2`,里面并没有提供yum工具,可以使用下面的命令进行yum的安装: ++ ++```shell ++wget https://isrc.iscas.ac.cn/mirror/openeuler-sig-riscv/oe-RISCV-repo/noarch/yum-4.2.15-8.noarch.rpm --no-check-certificate ++rpm -ivh yum-4.2.15-8.noarch.rpm ++``` ++之后,可以使用yum工具进行所需软件包的安装: ++```shell ++sudo yum --enablerepo='*' install -y automake autoconf libtool cmake make libcap libcap-devel libselinux libselinux-devel libseccomp libseccomp-devel yajl-devel git libcgroup tar python3 python3-pip device-mapper-devel libarchive libarchive-devel libcurl-devel zlib-devel glibc-headers openssl-devel gcc gcc-c++ systemd-devel systemd-libs libtar libtar-devel vim ++``` ++软件包的所需依赖参考了[build_guide](https://gitee.com/openeuler/iSulad/blob/master/docs/build_guide.md),和参考文档相比,去掉了golang(iSulad转为全C开发,不再使用GO语言),增加了vim(镜像没有文本编辑工具)。 ++要修改yum源的配置,在 /etc/yum.repos.d/下打开`oe-rv.repo`文件,一般使用[Index of /oe-RISCV-repo/](https://isrc.iscas.ac.cn/mirror/openeuler-sig-riscv/oe-RISCV-repo/)为yum源的地址。 ++ ++## 源码编译及安装 ++> 整个过程参考了[build_guide](https://gitee.com/openeuler/iSulad/blob/master/docs/build_guide.md),编译过程中出现了一些错误,做了修改,整理成下面的编译指南。 ++### 正式编译之前的准备工作及提示 ++##### 1.设置 ldconfig and pkgconfig(若编译中断,再次进入系统时在源码编译之前都必须运行一次!) ++ ++```javascript ++$ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH ++$ export LD_LIBRARY_PATH=/usr/local/lib:/usr/lib:$LD_LIBRARY_PATH ++$ sudo -E echo "/usr/local/lib" >> /etc/ld.so.conf ++``` ++##### 2.调整虚拟机时间为本地时间(否则编译的过程中会输出`Clock skew detected`的警告。这或许不是最好的方法,但却很简单有效,大家也可以自己找其他的方法消除警告) ++时间调整命令的格式如下: date -s 2020-09-28 ++ ++##### 3.建议创建一个合适的目录,如:build_isulad(后面编译的源码都将放在这个目录下面,每次`git clone`的时候,请先切换到此目录) ++##### 4.protobuf、grpc需要匹配所用系统的编译器版本,如:grpc-1.22 不支持GCC 9+。由于目前使用的虚拟机下编译器版本都一致,这一点不需要考虑 ++ ++### 源码编译安装protobuf(这部分的编译安装相对于参考的[build_guide](https://gitee.com/openeuler/iSulad/blob/master/docs/build_guide.md),做了比较大的调整,以满足后面的grpc能够顺利编译) ++```javascript ++$ pkg-config --cflags protobuf ++$ pkg-config --libs protobuf ++$ pkg-config --cflags --libs protobuf ++ ++ ++$ git clone https://gitee.com/src-openeuler/protobuf.git ++$ cd protobuf ++$ git checkout openEuler-20.03-LTS-tag ++$ tar -xzvf protobuf-all-3.9.0.tar.gz ++$ cd protobuf-3.9.0 ++``` ++> 此过程参考了[stack overflow](https://stackoverflow.com/questions/53586540/c-terminate-called-after-throwing-an-instance-of-stdsystem-error),如果按照[build_guide](https://gitee.com/openeuler/iSulad/blob/master/docs/build_guide.md)编译,在编译grpc时,会报` 'std::system_error'`这样的问题。 ++在编译之前要对文件做一些修改,使用如下命令打开protobuf源文件下的src/google/protobuf/stubs/common.cc文件: ++``` ++vi src/google/protobuf/stubs/common.cc ++``` ++在这个文件中,把有关 _WIN32 的所有代码都注释掉,如下: ++``` ++// updated by Aimer on linux platform ++ ++//#ifdef _WIN32 ++//#define WIN32_LEAN_AND_MEAN // We only need minimal includes ++//#include ++//#define snprintf _snprintf // see comment in strutil.cc ++//#elif defined(HAVE_PTHREAD) ++#include ++//#else ++//#error "No suitable threading library available." ++//#endif ++``` ++>此处参考了[protobuf 安装流程](http://blog.chinaunix.net/uid-28595538-id-5082366.html) ++``` shell ++$ sudo -E ./autogen.sh ++$ sudo -E ./configure CXXFLAGS="$(pkg-config --cflags protobuf)" LIBS="$(pkg-config --libs protobuf)" ++$ sudo -E make -j $(nproc) ++$ sudo -E make install ++$ sudo -E ldconfig ++``` ++ ++#### 编译成功验证 ++``` ++protoc --version ++``` ++输出:libprotoc 3.9.0(或其他的版本号) ++#### 第二种安装方法 ++由protobuf和grpc的安装的依赖关系,我们可以将它们视为一个组合,除了顺次编译外,还可以先编译grpc,再在third_party文件夹下的protobuf目录下安装protobuf,相关的编译方法网上能查到一些(可以搜protobuf+grpc编译),之前试了一下但编译成功率很低。 ++ ++### 源码编译安装c-cares ++ ++```shell ++$ git clone https://gitee.com/src-openeuler/c-ares.git ++$ cd c-ares ++$ git checkout openEuler-20.03-LTS-tag ++$ tar -xzvf c-ares-1.15.0.tar.gz ++$ cd c-ares-1.15.0 ++$ sudo -E autoreconf -if ++$ sudo -E ./configure --enable-shared --disable-dependency-tracking ++$ sudo -E make -j $(nproc) ++$ sudo -E make install ++$ sudo -E ldconfig ++``` ++### 源码编译安装grpc ++ ++```shell ++$ git clone https://gitee.com/src-openeuler/grpc.git ++$ cd grpc ++$ git checkout openEuler-20.03-LTS-tag ++$ tar -xzvf grpc-1.22.0.tar.gz ++$ cd grpc-1.22.0 ++``` ++修改源码: ++ ++* 在`include/grpcpp/impl/codegen/call_op_set.h` line 90添加 ++ ++```shell ++ /// Default assignment operator ++ WriteOptions& operator=(const WriteOptions& other) = default; ++``` ++ ++* 将`src/core/lib/gpr/log_linux.cc`、`src/core/lib/gpr/log_posix.cc`、`src/core/lib/iomgr/ev_epollex_linux.cc`这几个文件中的 ++ `gettid()`改为`sys_gettid()` ++ ++>参考[protobuf+grpc源码编译安装过程](https://blog.csdn.net/Sindweller5530/article/details/104414856) ++ ++```shell ++$ sudo -E make -j $(nproc) ++$ sudo -E make install ++$ sudo -E ldconfig ++``` ++之后会遇到'cannot find -latomic'的问题,按[链接中的](https://www.cnblogs.com/mafy/p/13380332.html)处理即可: ++ ++ ++grpc测试用例 ++``` ++cd examples/cpp/helloworld/ ++make //编译 ++./greeter_server //服务器 ++./greeter_client //客户端(重新开一个服务器连接) ++``` ++### 源码编译安装http-parser ++ ++```javascript ++$ git clone https://gitee.com/src-openeuler/http-parser.git ++$ cd http-parser ++$ git checkout openEuler-20.03-LTS-tag ++$ tar -xzvf http-parser-2.9.2.tar.gz ++$ cd http-parser-2.9.2 ++$ sudo -E make -j CFLAGS="-Wno-error" ++$ sudo -E make CFLAGS="-Wno-error" install ++$ sudo -E ldconfig ++``` ++ ++ ++### 源码编译安装libwebsockets ++```shell ++$ git clone https://gitee.com/src-openeuler/libwebsockets.git ++$ cd libwebsockets ++$ git checkout openEuler-20.03-LTS-tag ++$ tar -xzvf libwebsockets-2.4.2.tar.gz ++$ cd libwebsockets-2.4.2 ++$ patch -p1 -F1 -s < ../libwebsockets-fix-coredump.patch ++$ mkdir build ++$ cd build ++$ sudo -E cmake -DLWS_WITH_SSL=0 -DLWS_MAX_SMP=32 -DCMAKE_BUILD_TYPE=Debug ../ ++$ sudo -E make -j $(nproc) ++$ sudo -E make install ++$ sudo -E ldconfig ++``` ++ ++### 源码编译安装lxc ++```shell ++$ git clone https://gitee.com/src-openeuler/lxc.git ++$ cd lxc ++$ tar -zxf lxc-4.0.3.tar.gz ++$ ./apply-patches ++$ cd lxc-4.0.3 ++$ sudo -E ./autogen.sh ++$ sudo -E ./configure ++$ sudo -E make -j ++$ sudo -E make install ++$ sudo -E ldconfig ++``` ++在编译的过程中会遇到两个问题: ++1. 关于`__NR_signalfd` ++解决方案:[lxc的issue](https://github.com/lxc/lxc/pull/3501/files) ++2. 再次遇到'cannot find -latomic'的问题 ++这次不能使用上次的方法,这次是缺少静态链接库,使用find命令搜到libatomic.a复制到/usr/lib下,编译通过。 ++### 源码编译安装lcr ++```shell ++$ git clone https://gitee.com/openeuler/lcr.git ++$ cd lcr ++$ mkdir build ++$ cd build ++$ sudo -E cmake .. ++$ sudo -E make -j ++$ sudo -E make install ++$ sudo -E ldconfig ++``` ++### 源码编译安装clibcni ++```shell ++$ git clone https://gitee.com/openeuler/clibcni.git ++$ cd clibcni ++$ mkdir build ++$ cd build ++$ sudo -E cmake .. ++$ sudo -E make -j ++$ sudo -E make install ++$ sudo -E ldconfig ++``` ++### 源码编译安装iSulad ++```shell ++$ git clone https://gitee.com/openeuler/iSulad.git ++$ cd iSulad ++$ mkdir build ++$ cd build ++$ sudo -E cmake .. ++$ sudo -E make ++$ sudo -E make install ++$ sudo -E ldconfig ++``` ++## 内核编译及内核模块的编译 ++在完成上述工作之后,iSulad的启动还需要一个`overlay`的内核模块。虚拟机镜像默认没有提供,需要我们开启此模块和编译封装。 ++1. 下载与当前镜像系统一致的版本的内核源码(内核版本可以使用`uname -a`命令来查看) ++```shell ++git clone https://gitee.com/openeuler/kernel.git ++git checkout 某一分支 ++``` ++2. 在内核源码的目录下,执行make menuconfig,在配置界面找到File systems ---> 在Overlay filesystem support前配置成[M]或[*](单击空格键切换),之后保存并退出; ++3. 使用make Image命令,在/内核源码路径/arch/riscv/boot/ 下生成Image文件; ++4. 下载内核封装工具opensbi: ++```shell ++git clone https://gitee.com/src-openeuler/opensbi.git ++cd opensbi ++unzip v0.6.zip ++cd opensbi-0.6 ++make O=build-oe/qemu-virt PLATFORM=qemu/virt FW_PAYLOAD=y FW_PAYLOAD_PATH=/生成的Image路径/Image ++``` ++这一步会生成elf文件,编译结束会提示elf文件所在位置。 ++5. 将elf文件拷贝至host,拷贝可以使用`scp`工具进行。将.qcow2文件、.elf文件、.sh文件放在同一路径下,修改run_oe1-rv64.sh中的kernel 参数处的elf文件名为新添加的elf文件名。 ++6. 执行sh run_oe1-rv64.sh ++### 参考链接: ++* https://arkingc.github.io/2018/09/05/2018-09-05-linux-kernel/ ++* https://gitee.com/src-openeuler/risc-v-kernel/blob/master/kernel.spec ++* https://gitee.com/src-openeuler/opensbi/blob/master/opensbi.spec +diff --git a/iSulad.spec b/iSulad.spec +index 25baadc..e596b7a 100644 +--- a/iSulad.spec ++++ b/iSulad.spec +@@ -1,5 +1,5 @@ +-%global _version 2.0.5 +-%global _release 20200903.171615.gitf8400084 ++%global _version 2.0.7 ++%global _release 20201123.145029.gitb2a75048 + %global is_systemd 1 + + Name: iSulad +@@ -74,13 +74,11 @@ install -d $RPM_BUILD_ROOT/%{_bindir} + install -m 0755 ./src/isula %{buildroot}/%{_bindir}/isula + install -m 0755 ./src/isulad-shim %{buildroot}/%{_bindir}/isulad-shim + install -m 0755 ./src/isulad %{buildroot}/%{_bindir}/isulad ++chrpath -d ./src/isula ++chrpath -d ./src/isulad-shim ++chrpath -d ./src/isulad + + install -d $RPM_BUILD_ROOT/%{_includedir}/isulad +-install -m 0644 ../src/client/libisula.h %{buildroot}/%{_includedir}/isulad/libisula.h +-install -m 0644 ../src/client/connect/isula_connect.h %{buildroot}/%{_includedir}/isulad/isula_connect.h +-install -m 0644 ../src/utils/cutils/utils_timestamp.h %{buildroot}/%{_includedir}/isulad/utils_timestamp.h +-install -m 0644 ../src/utils/cutils/error.h %{buildroot}/%{_includedir}/isulad/error.h +-install -m 0644 ../src/daemon/modules/runtime/engines/engine.h %{buildroot}/%{_includedir}/isulad/engine.h + install -m 0644 ../src/daemon/modules/api/image_api.h %{buildroot}/%{_includedir}/isulad/image_api.h + + install -d $RPM_BUILD_ROOT/%{_sysconfdir}/isulad +@@ -127,8 +125,8 @@ fi + fi + + %post +-if ! getent group isulad > /dev/null; then +- groupadd --system isulad ++if ! getent group isula > /dev/null; then ++ groupadd --system isula + fi + + if [ "$1" = "1" ]; then +@@ -159,8 +157,8 @@ fi + %endif + fi + +-if ! getent group isulad > /dev/null; then +- groupadd --system isulad ++if ! getent group isula > /dev/null; then ++ groupadd --system isula + fi + + %preun +@@ -200,7 +198,7 @@ fi + %{_includedir}/isulad/* + %attr(0755,root,root) %{_libdir}/pkgconfig + %attr(0640,root,root) %{_libdir}/pkgconfig/isulad.pc +-%defattr(0550,root,root,0750) ++%defattr(0755,root,root,0755) + %{_bindir}/* + %{_libdir}/* + %attr(0640,root,root) %{_sysconfdir}/sysconfig/iSulad +@@ -215,6 +213,12 @@ fi + %endif + + %changelog ++* Tue Sep 10 2020 openEuler Buildteam - 2.0.5-20200910.140350.git72990229 ++- Type:enhancement ++- ID:NA ++- SUG:NA ++- DESC: add chrpath ++ + * Mon Aug 03 2020 openEuler Buildteam - 2.0.3-20200803.130854.git0c7dc28a + - Type:enhancement + - ID:NA +diff --git a/release_notes b/release_notes +index 2913d63..2154b3a 100644 +--- a/release_notes ++++ b/release_notes +@@ -1,3 +1,108 @@ ++2020-11-23 lifeng release 2.0.7 ++ - !834 refactor subcommand help implementation From: @wangfengtu Reviewed-by: @zh_xiaoyu,@lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !833 network: add filter with invalid resolv.conf content From: @lifeng2221dd1 Reviewed-by: @jingwoo,@duguhaotian Signed-off-by: @duguhaotian ++ - !831 mask pin memory dev From: @duguhaotian Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !828 coding standards for volume From: @jingwoo Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !827 fix segmentfault From: @wangfengtu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !826 Fix the container cannot be run under the device mapper storage driver From: @jingwoo Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !825 time: use the same timebuffer size macro From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !824 CI: add mount options check From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !823 strip body when pass response to http-parser From: @wangfengtu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !822 print more detail error message From: @wangfengtu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !821 clean code: remove unused health.c/h and move head files From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !818 erase space in human size From: @gaohuatao Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !817 sync support local volume feature from branch volume to master From: @wangfengtu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !816 wait: add check whether had beed deleted when wait rm From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: ++ - !810 add filter to get only non-sandbox containers From: @gaohuatao Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !796 network: support dualstack for cni ipstatus From: @duguhaotian Reviewed-by: Signed-off-by: ++ - !808 utils: add fdatasync when do atomic write file From: @lifeng2221dd1 Reviewed-by: @duguhaotian,@duguhaotian,@duguhaotian Signed-off-by: @duguhaotian,@duguhaotian,@duguhaotian ++ - !806 clean code: remove unused ";" in code From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !805 add newline character at end of iSulad.sysconfig From: @gaohuatao Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !804 clean code: remove unused code in connect From: @lifeng2221dd1 Reviewed-by: @jingwoo,@duguhaotian Signed-off-by: @duguhaotian ++ - !803 iSulad: fix memory leak in inspect grpc service From: @zh_xiaoyu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !801 add ISULAD_TMPDIR env CI From: @gaohuatao Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !800 CI: remove test data from iSulad repo From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !794 add ISULAD_TMPDIR env variable and unlink dir comments From: @gaohuatao Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !793 support variable extension cni args From: @duguhaotian Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !790 unlink etc dir when link exists From: @gaohuatao Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !789 iSulad: internal change From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !781 unpack: add remove target file in handle .wh From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !779 support extension data transmission to cni plugin From: @duguhaotian Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !770 iSulad: modify isula fifo mode to execute non-root From: @gaohuatao Reviewed-by: @lifeng2221dd1,@lifeng2221dd1,@lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !758 为iSulad在RISC-V架构提供构建文档 From: @shentalon Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !776 create:fix wrong ret code From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !775 info: fix typo driverr to driver From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !774 Realpath: add get realpath for root and state dir From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !773 isulad: rt_isula_start should read the isulad-shim pidinfo From: @holyfei Reviewed-by: @duguhaotian,@lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !769 Dockerfile: bugfix and update dockerfile to isulad v2.0.6; use multi-stage to decrease the size of image From: @Les1ie_1 Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !767 iSulad: modify defattr to 755 in spec From: @gaohuatao Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ ++ dev stats: ++ - 210 files changed, 9537 insertions(+), 2097 deletions(-) ++ - contributors: WangFengTu, lifeng68, gaohuatao, haozi007, wujing, Les1ie, holyfei, shentalon, zhangxiaoyu ++ ++2020-10-14 lifeng release 2.0.6 ++ - !764 add CI for image load multiplex From: @gaohuatao Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !765 clean code: refact utils and add prefix util_ From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !756 iSulad: isula load support layer reusing From: @gaohuatao Reviewed-by: Signed-off-by: ++ - !762 resize: refact client resize From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !759 clean code: reduce redundant code in isula_host_spec.c From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !760 fix load only part of certs error From: @wangfengtu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !757 layer: fix memory leak errors From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !755 avoid using HEAD_ONLY option when pulling image From: @wangfengtu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !754 use reference count to avoid flag be cleared by mistake From: @wangfengtu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !749 refact: refact client pack config progress From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !750 modify default group value "isulad" to "isula" From: @gaohuatao Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !725 iSulad: add isula group From: @gaohuatao Reviewed-by: @jingxiaolu,@lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !746 umount: skip umount if rootfs not exist From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !743 remove dir of rw layer while create failed From: @duguhaotian Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !742 fix macro defination conflict with sqlite3.h in openeuler From: @wangfengtu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !741 iSulad: bugfix, convert size_t type to int From: @zh_xiaoyu Reviewed-by: @duguhaotian,@lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !740 fix coredump when load image with uid From: @jingwoo Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !739 iSulad: fix memeory out From: @zh_xiaoyu Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !737 Docs/build_guide.md: comment gcc version From: @long-dai Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !724 Fix spell issue From: @long-dai Reviewed-by: Signed-off-by: ++ - !738 Readme: remove useless description From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !736 Docs: clean up white noise From: @long-dai Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !735 pass context to uitls scan subdir From: @duguhaotian Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !734 isulad-shim: fix code review issues From: @leizhongkai Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !733 improve code From: @duguhaotian Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !726 CI: fix spell issue From: @long-dai Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !723 README: unify punctuation From: @long-dai Reviewed-by: @lifeng2221dd1,@lifeng2221dd1 Signed-off-by: @lifeng2221dd1,@lifeng2221dd1 ++ - !731 CI: update registry from 163 to ali From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !730 fix bugs From: @wangfengtu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !722 README: add openEuler repository From: @long-dai Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !721 readme: add refer to openeuler guide From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !720 clean code: add more log for invalid input From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !719 fix bad formatting placeholder in http parse module From: @jingwoo Reviewed-by: @duguhaotian,@lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !718 fix coredump when pull image with lock ${driver}-image dir From: @jingwoo Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !716 fix layer remain caused by hold flag not clean From: @wangfengtu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !717 clear invalid data From: @duguhaotian Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !715 add compilation macro isolation for selinux related code From: @jingwoo Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !714 fix pull failure caused by link conflict From: @wangfengtu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !713 readme: fix readme From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !712 config: remove unused config From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian ++ - !711 fix code review From: @wangfengtu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !710 fix: delete rootfs dir when rootfs load failed From: @jingwoo Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !708 fix: security-opt parsing access out of bounds From: @jingwoo Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !709 fix memory leak From: @wangfengtu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 ++ - !707 dev_cgroup_rule: add support device cgroup rule Merge pull request !707 from lifeng_isula/blk ++ - !706 iSulad : logs command add option timestamps Merge pull request !706 from YoungJQ/logs ++ - !705 add chrpath Merge pull request !705 from YoungJQ/logs ++ - !704 CI: add testcases for nano CPUs Merge pull request !704 from lifeng_isula/blk ++ - !702 cpus: add support nano cpus Merge pull request !702 from lifeng_isula/blk ++ - !700 cpu_rt: add support cpurt runtime period Merge pull request !700 from lifeng_isula/blk ++ - !701 iSulad: add LIB_ISULAD_IMG_SO for libisulad_img.so to avoid func do_integration_of_images_check() Merge pull request !701 from zhangxiaoyu/master ++ - !699 update readme Merge pull request !699 from haozi007/master ++ - !698 blkio: add support blk read/write iops Merge pull request !698 from lifeng_isula/blk ++ - !697 add testcase for --user option Merge pull request !697 from JingWoo/master ++ - !696 iSulad: initialization buf before readlink() Merge pull request !696 from zhangxiaoyu/master ++ - !695 overlay: fix magic define error Merge pull request !695 from lifeng_isula/master ++ ++ dev stats: ++ - 228 files changed, 6526 insertions(+), 5324 deletions(-) ++ - contributors: lifeng68, WangFengTu, wujing, Long Dai, haozi007, gaohuatao, zhangxiaoyu, YoungJQ, leizhongkai ++ + 2020-09-03 lifeng release 2.0.5 + - !693 Set mount rootfs highest mode Merge pull request !693 from gaohuatao/update + - !692 log: fix log level to warn Merge pull request !692 from lifeng_isula/master +diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt +index 2158658..4127e5a 100644 +--- a/src/CMakeLists.txt ++++ b/src/CMakeLists.txt +@@ -145,9 +145,9 @@ endif() + + # ------ install binary -------- + install(TARGETS libisula +- LIBRARY DESTINATION ${LIB_INSTALL_DIR_DEFAULT} PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE) ++ LIBRARY DESTINATION ${LIB_INSTALL_DIR_DEFAULT} PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) + install(TARGETS isula +- RUNTIME DESTINATION bin PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE) ++ RUNTIME DESTINATION bin PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) + install(TARGETS isulad-shim + RUNTIME DESTINATION bin PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE) + install(TARGETS isulad +diff --git a/src/api/services/cri/api.proto b/src/api/services/cri/api.proto +index 022fa51..67e5527 100644 +--- a/src/api/services/cri/api.proto ++++ b/src/api/services/cri/api.proto +@@ -1,5 +1,8 @@ + /* + Copyright 2018 The Kubernetes Authors. ++Copyright (C) Huawei Technologies., Ltd. 2019. All rights reserved. ++ modify descripe: remove unused options for example: ++ remove import "github.com/gogo/protobuf/gogoproto/gogo.proto" + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. +@@ -396,10 +399,16 @@ message PodSandboxStatusRequest { + bool verbose = 2; + } + ++// PodIP represents an ip of a Pod ++message PodIP { ++ // an ip is a string representation of an IPV4 or an IPV6 ++ string ip = 1; ++} + // PodSandboxNetworkStatus is the status of the network for a PodSandbox. + message PodSandboxNetworkStatus { + // IP address of the PodSandbox. + string ip = 1; ++ repeated PodIP additional_ips = 2; + } + + // Namespace contains paths to the namespaces. +diff --git a/src/api/services/health/health.proto b/src/api/services/health/health.proto +deleted file mode 100644 +index a3d3537..0000000 +--- a/src/api/services/health/health.proto ++++ /dev/null +@@ -1,54 +0,0 @@ +-// ####################################################################### +-// ##- @Copyright (C) Huawei Technologies., Ltd. 2019-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. +-// ##- @Description: generate grpc +-// ##- @Author: tanyifeng +-// ##- @Create: 2020-01-16 +-// ####################################################################### +-// +-// Since some of this code is derived from grpc, their copyright +-// is retained here.... +-// +-// Copyright 2015 The gRPC Authors +-// +-// Licensed under the Apache License, Version 2.0 (the "License"); +-// you may not use this file except in compliance with the License. +-// You may obtain a copy of the License at +-// +-// http://www.apache.org/licenses/LICENSE-2.0 +-// +-// Unless required by applicable law or agreed to in writing, software +-// distributed under the License is distributed on an "AS IS" BASIS, +-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-// See the License for the specific language governing permissions and +-// limitations under the License. +- +-// The canonical version of this proto can be found at +-// https://github.com/grpc/grpc-proto/blob/master/grpc/health/v1/health.proto +- +-syntax = "proto3"; +-option optimize_for = CODE_SIZE; +- +-message HealthCheckRequest { +- string service = 1; +-} +- +-message HealthCheckResponse { +- enum ServingStatus { +- UNKNOWN = 0; +- SERVING = 1; +- NOT_SERVING = 2; +- } +- ServingStatus status = 1; +-} +- +-service HealthService{ +- rpc Check(HealthCheckRequest) returns (HealthCheckResponse); +-} +diff --git a/src/api/services/images/images.proto b/src/api/services/images/images.proto +index bdec2f8..71cce22 100644 +--- a/src/api/services/images/images.proto ++++ b/src/api/services/images/images.proto +@@ -9,109 +9,43 @@ + // # - PURPOSE. + // # - See the Mulan PSL v2 for more details. + // ##- @Description: generate grpc +-// ##- @Author: wujing +-// ##- @Create: 2020-01-16 ++// ##- @Author: lifeng ++// ##- @Create: 2019-04-25 + // ####################################################################### + +- +-/* +-Since some of this code is derived from containerd, their copyright +-is retained here.... +- +-Copyright 2013-2016 Docker, Inc. +- +-Licensed under the Apache License, Version 2.0 (the "License"); +-you may not use this file except in compliance with the License. +-You may obtain a copy of the License at +- +- http://www.apache.org/licenses/LICENSE-2.0 +- +-Unless required by applicable law or agreed to in writing, software +-distributed under the License is distributed on an "AS IS" BASIS, +-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-See the License for the specific language governing permissions and +-limitations under the License. +-*/ +- + syntax = "proto3"; + option optimize_for = CODE_SIZE; + + import "google/protobuf/timestamp.proto"; +-import "descriptor.proto"; + + package images; + +-// Images is a service that allows one to register images with containerd. +-// +-// In containerd, an image is merely the mapping of a name to a content root, +-// described by a descriptor. The behavior and state of image is purely +-// dictated by the type of the descriptor. +-// +-// From the perspective of this service, these references are mostly shallow, +-// in that the existence of the required content won't be validated until +-// required by consuming services. +-// +-// As such, this can really be considered a "metadata service". + service ImagesService { +- // List returns a list of all images known to containerd. + rpc List(ListImagesRequest) returns (ListImagesResponse); +- +- // Delete deletes the image by name. + rpc Delete(DeleteImageRequest) returns (DeleteImageResponse); +- +- // load image from archive. + rpc Load(LoadImageRequest) returns (LoadImageResponse); +- +- //inspect image + rpc Inspect(InspectImageRequest) returns (InspectImageResponse); +- +- // Login to a Docker registry + rpc Login(LoginRequest) returns (LoginResponse); +- +- // Logout from a Docker registry + rpc Logout(LogoutRequest) returns (LogoutResponse); +- +- // Add a tag to the image + rpc Tag(TagImageRequest) returns (TagImageResponse); +- +- // Import rootfs to be image + rpc Import(ImportRequest) returns (ImportResponse); + } + ++message Descriptor { ++ string media_type = 1; ++ string digest = 2; ++ int64 size = 3; ++} ++ + message Image { +- // Name provides a unique name for the image. +- // +- // Containerd treats this as the primary identifier. + string name = 1; +- +- // Labels provides free form labels for the image. These are runtime only +- // and do not get inherited into the package image in any way. +- // +- // Labels may be updated using the field mask. +- // The combined size of a key/value pair cannot exceed 4096 bytes. + map labels = 2; +- +- // Target describes the content entry point of the image. +- containerd.types.Descriptor target = 3; +- +- // CreatedAt is the time the image was first created. +- google.protobuf.Timestamp created_at = 7; +- +- // UpdatedAt is the last time the image was mutated. +- google.protobuf.Timestamp updated_at = 8; ++ Descriptor target = 3; ++ google.protobuf.Timestamp created_at = 4; ++ google.protobuf.Timestamp updated_at = 5; + } + + message ListImagesRequest { +- // Filters contains one or more filters using the syntax defined in the +- // containerd filter package. +- // +- // The returned result will be those that match any of the provided +- // filters. Expanded, images that match the following will be +- // returned: +- // +- // filters[0] or filters[1] or ... or filters[n-1] or filters[n] +- // +- // If filters is zero-length or nil, all items will be returned. + map filters = 1; + } + +diff --git a/src/api/services/volumes/volumes.proto b/src/api/services/volumes/volumes.proto +new file mode 100644 +index 0000000..7f1ed0e +--- /dev/null ++++ b/src/api/services/volumes/volumes.proto +@@ -0,0 +1,59 @@ ++// ####################################################################### ++// ##- @Copyright (C) Huawei Technologies., 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. ++// ##- @Description: generate grpc ++// ##- @Author: wangfengtu ++// ##- @Create: 2020-09-02 ++// ####################################################################### ++ ++syntax = "proto3"; ++option optimize_for = CODE_SIZE; ++ ++package volume; ++ ++service VolumeService { ++ rpc List(ListVolumeRequest) returns (ListVolumeResponse); ++ ++ rpc Remove(RemoveVolumeRequest) returns (RemoveVolumeResponse); ++ ++ rpc Prune(PruneVolumeRequest) returns (PruneVolumeResponse); ++} ++ ++message Volume { ++ string driver = 1; ++ string name = 2; ++} ++ ++message ListVolumeRequest { ++} ++ ++message ListVolumeResponse { ++ repeated Volume volumes = 1; ++ uint32 cc = 2; ++ string errmsg = 3; ++} ++ ++message RemoveVolumeRequest { ++ string name = 1; ++} ++ ++message RemoveVolumeResponse { ++ uint32 cc = 1; ++ string errmsg = 2; ++} ++ ++message PruneVolumeRequest { ++} ++ ++message PruneVolumeResponse { ++ repeated string volumes = 2; ++ uint32 cc = 3; ++ string errmsg = 4; ++} +diff --git a/src/api/types/descriptor.proto b/src/api/types/descriptor.proto +deleted file mode 100644 +index 38b9d19..0000000 +--- a/src/api/types/descriptor.proto ++++ /dev/null +@@ -1,49 +0,0 @@ +-// ####################################################################### +-// ##- @Copyright (C) Huawei Technologies., Ltd. 2019-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. +-// ##- @Description: generate grpc +-// ##- @Author: wujing +-// ##- @Create: 2019-01-16 +-// ####################################################################### +- +-/* +-Since some of this code is derived from containerd, their copyright +-is retained here.... +- +-Copyright 2013-2016 Docker, Inc. +- +-Licensed under the Apache License, Version 2.0 (the "License"); +-you may not use this file except in compliance with the License. +-You may obtain a copy of the License at +- +- http://www.apache.org/licenses/LICENSE-2.0 +- +-Unless required by applicable law or agreed to in writing, software +-distributed under the License is distributed on an "AS IS" BASIS, +-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-See the License for the specific language governing permissions and +-limitations under the License. +-*/ +- +-syntax = "proto3"; +-option optimize_for = CODE_SIZE; +- +-package containerd.types; +- +-// Descriptor describes a blob in a content store. +-// +-// This descriptor can be used to reference content from an +-// oci descriptor found in a manifest. +-// See https://godoc.org/github.com/opencontainers/image-spec/specs-go/v1#Descriptor +-message Descriptor { +- string media_type = 1; +- string digest = 2; +- int64 size = 3; +-} +diff --git a/src/client/connect/CMakeLists.txt b/src/client/connect/CMakeLists.txt +index 5289f5b..e9b0cc4 100644 +--- a/src/client/connect/CMakeLists.txt ++++ b/src/client/connect/CMakeLists.txt +@@ -1,6 +1,6 @@ + set(local_client_connect_srcs + ${CMAKE_CURRENT_SOURCE_DIR}/isula_connect.c +- ${CMAKE_CURRENT_SOURCE_DIR}/pack_config.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/protocol_type.c + ) + + set(local_client_connect_incs ${CMAKE_CURRENT_SOURCE_DIR}) +@@ -9,18 +9,18 @@ add_subdirectory(grpc) + + if (GRPC_CONNECTOR) + list(APPEND local_client_connect_srcs ${CLIENT_GRPC_SRCS}) +- aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/types CONNECT_API_TYPES) + aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/containers CONNECT_API_CONTAINERS) + aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/images CONNECT_API_IMAGES) ++ aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/volumes CONNECT_API_VOLUMES) + aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/cri CONNECT_API_CRI) +- set(CONNECT_API ${CONNECT_API_TYPES} ${CONNECT_API_CONTAINERS} ${CONNECT_API_IMAGES} ${CONNECT_API_CRI}) ++ set(CONNECT_API ${CONNECT_API_CONTAINERS} ${CONNECT_API_IMAGES} ${CONNECT_API_VOLUMES} ${CONNECT_API_CRI}) + list(APPEND local_client_connect_srcs ${CONNECT_API}) + + list(APPEND local_client_connect_incs ${CMAKE_CURRENT_SOURCE_DIR}/grpc) + list(APPEND local_client_connect_incs +- ${CMAKE_BINARY_DIR}/grpc/src/api/types + ${CMAKE_BINARY_DIR}/grpc/src/api/services/containers + ${CMAKE_BINARY_DIR}/grpc/src/api/services/images ++ ${CMAKE_BINARY_DIR}/grpc/src/api/services/volumes + ${CMAKE_BINARY_DIR}/grpc/src/api/services/cri + ) + +diff --git a/src/client/connect/grpc/CMakeLists.txt b/src/client/connect/grpc/CMakeLists.txt +index 630b8d7..5be0664 100644 +--- a/src/client/connect/grpc/CMakeLists.txt ++++ b/src/client/connect/grpc/CMakeLists.txt +@@ -3,6 +3,7 @@ if (GRPC_CONNECTOR) + ${CMAKE_CURRENT_SOURCE_DIR}/grpc_client.cc + ${CMAKE_CURRENT_SOURCE_DIR}/grpc_containers_client.cc + ${CMAKE_CURRENT_SOURCE_DIR}/grpc_images_client.cc ++ ${CMAKE_CURRENT_SOURCE_DIR}/grpc_volumes_client.cc + PARENT_SCOPE + ) + endif() +diff --git a/src/client/connect/grpc/grpc_client.cc b/src/client/connect/grpc/grpc_client.cc +index 93f341c..18a849c 100644 +--- a/src/client/connect/grpc/grpc_client.cc ++++ b/src/client/connect/grpc/grpc_client.cc +@@ -16,6 +16,7 @@ + #include "grpc_client.h" + #include "grpc_containers_client.h" + #include "grpc_images_client.h" ++#include "grpc_volumes_client.h" + + int grpc_ops_init(isula_connect_ops *ops) + { +@@ -23,10 +24,13 @@ int grpc_ops_init(isula_connect_ops *ops) + return -1; + } + +- if (grpc_containers_client_ops_init(ops)) { ++ if (grpc_containers_client_ops_init(ops) != 0) { + return -1; + } +- if (grpc_images_client_ops_init(ops)) { ++ if (grpc_images_client_ops_init(ops) != 0) { ++ return -1; ++ } ++ if (grpc_volumes_client_ops_init(ops) != 0) { + return -1; + } + +diff --git a/src/client/connect/grpc/grpc_containers_client.cc b/src/client/connect/grpc/grpc_containers_client.cc +index fa0d7e4..e511a6a 100644 +--- a/src/client/connect/grpc/grpc_containers_client.cc ++++ b/src/client/connect/grpc/grpc_containers_client.cc +@@ -18,7 +18,6 @@ + #include "isula_libutils/container_copy_to_request.h" + #include "isula_libutils/container_exec_request.h" + #include "isulad_tar.h" +-#include "pack_config.h" + #include "stoppable_thread.h" + #include "utils.h" + #include +@@ -173,10 +172,6 @@ public: + + auto request_to_grpc(const isula_create_request *request, CreateRequest *grequest) -> int override + { +- int ret = 0; +- char *host_json = nullptr; +- char *config_json = nullptr; +- + if (request == nullptr) { + return -1; + } +@@ -193,23 +188,14 @@ public: + if (request->runtime != nullptr) { + grequest->set_runtime(request->runtime); + } +- ret = generate_hostconfig(request->hostconfig, &host_json); +- if (ret != 0) { +- ERROR("Failed to pack host config"); +- return EINVALIDARGS; +- } +- grequest->set_hostconfig(host_json); + +- free(host_json); +- +- ret = generate_container_config(request->config, &config_json); +- if (ret != 0) { +- ERROR("Failed to pack custom config"); +- return EINVALIDARGS; ++ if (request->container_spec_json != NULL) { ++ grequest->set_customconfig(request->container_spec_json); + } +- grequest->set_customconfig(config_json); + +- free(config_json); ++ if (request->host_spec_json != NULL) { ++ grequest->set_hostconfig(request->host_spec_json); ++ } + + return 0; + } +@@ -697,7 +683,6 @@ public: + } + }; + +- + class ContainerRestart : public ClientBase { + public: +@@ -1082,8 +1067,8 @@ public: + return 0; + } + +- auto grpc_call(ClientContext *context, const InspectContainerRequest &req, +- InspectContainerResponse *reply) -> Status override ++ auto grpc_call(ClientContext *context, const InspectContainerRequest &req, InspectContainerResponse *reply) ++ -> Status override + { + return stub_->Inspect(context, req, reply); + } +@@ -1186,8 +1171,8 @@ public: + ERROR("Too many summary info!"); + return -1; + } +- response->container_summary = static_cast(util_common_calloc_s( +- sizeof(struct isula_container_summary_info *) * static_cast(num))); ++ response->container_summary = static_cast( ++ util_common_calloc_s(sizeof(struct isula_container_summary_info *) * static_cast(num))); + if (response->container_summary == nullptr) { + ERROR("out of memory"); + response->cc = ISULAD_ERR_MEMOUT; +@@ -1209,10 +1194,11 @@ public: + } + + private: +- static auto get_container_summary_from_grpc(isula_list_response *response, ListResponse *gresponse, int index) -> int ++ static auto get_container_summary_from_grpc(isula_list_response *response, ListResponse *gresponse, int index) ++ -> int + { +- response->container_summary[index] = +- static_cast(util_common_calloc_s(sizeof(struct isula_container_summary_info))); ++ response->container_summary[index] = static_cast( ++ util_common_calloc_s(sizeof(struct isula_container_summary_info))); + if (response->container_summary[index] == nullptr) { + ERROR("out of memory"); + response->cc = ISULAD_ERR_MEMOUT; +@@ -1224,15 +1210,15 @@ private: + response->container_summary[index]->id = util_strdup_s(id); + const char *name = !in.name().empty() ? in.name().c_str() : "-"; + response->container_summary[index]->name = util_strdup_s(name); +- response->container_summary[index]->runtime = !in.runtime().empty() ? util_strdup_s(in.runtime().c_str()) +- : nullptr; ++ response->container_summary[index]->runtime = !in.runtime().empty() ? util_strdup_s(in.runtime().c_str()) : ++ nullptr; + response->container_summary[index]->has_pid = static_cast(static_cast(in.pid()) != 0); + response->container_summary[index]->pid = static_cast(in.pid()); + response->container_summary[index]->status = static_cast(in.status()); +- response->container_summary[index]->image = !in.image().empty() ? util_strdup_s(in.image().c_str()) +- : util_strdup_s("none"); +- response->container_summary[index]->command = !in.command().empty() ? util_strdup_s(in.command().c_str()) +- : util_strdup_s("-"); ++ response->container_summary[index]->image = !in.image().empty() ? util_strdup_s(in.image().c_str()) : ++ util_strdup_s("none"); ++ response->container_summary[index]->command = !in.command().empty() ? util_strdup_s(in.command().c_str()) : ++ util_strdup_s("-"); + const char *starttime = !in.startat().empty() ? in.startat().c_str() : "-"; + response->container_summary[index]->startat = util_strdup_s(starttime); + +@@ -1246,8 +1232,8 @@ private: + if (!in.health_state().empty()) { + healthState = "(" + in.health_state() + ")"; + } +- response->container_summary[index]->health_state = !healthState.empty() ? util_strdup_s(healthState.c_str()) +- : nullptr; ++ response->container_summary[index]->health_state = !healthState.empty() ? util_strdup_s(healthState.c_str()) : ++ nullptr; + response->container_num++; + + return 0; +@@ -1604,33 +1590,18 @@ public: + auto request_to_grpc(const isula_update_request *request, UpdateRequest *grequest) -> int override + { + int ret = 0; +- char *json = nullptr; + + if (request == nullptr) { + return -1; + } + +- isula_host_config_t hostconfig; +- (void)memset(&hostconfig, 0, sizeof(hostconfig)); +- +- if (request->updateconfig != nullptr) { +- hostconfig.restart_policy = request->updateconfig->restart_policy; +- hostconfig.cr = request->updateconfig->cr; +- } +- ret = generate_hostconfig(&hostconfig, &json); +- if (ret != 0) { +- ERROR("Failed to generate hostconfig json"); +- ret = -1; +- goto cleanup; ++ if (request->host_spec_json != NULL) { ++ grequest->set_hostconfig(request->host_spec_json); + } +- +- grequest->set_hostconfig(json); + if (request->name != nullptr) { + grequest->set_id(request->name); + } + +-cleanup: +- free(json); + return ret; + } + +@@ -1688,8 +1659,8 @@ public: + { + int size = gresponse->containers_size(); + if (size > 0) { +- response->container_stats = +- static_cast(util_common_calloc_s(size * sizeof(struct isula_container_info))); ++ response->container_stats = static_cast( ++ util_common_calloc_s(size * sizeof(struct isula_container_info))); + if (response->container_stats == nullptr) { + ERROR("Out of memory"); + return -1; +@@ -1771,7 +1742,8 @@ public: + + std::unique_ptr> reader(stub_->Events(&context, req)); + while (reader->Read(&event)) { +- isula_event = static_cast(util_common_calloc_s(sizeof(container_events_format_t))); ++ isula_event = ++ static_cast(util_common_calloc_s(sizeof(container_events_format_t))); + if (isula_event == nullptr) { + ERROR("Out of memory"); + response->server_errono = ISULAD_ERR_EXEC; +@@ -1863,7 +1835,7 @@ private: + struct CopyFromContainerContext { + CopyFromContainerRequest request; + ClientContext context; +- ClientReader *reader{}; ++ ClientReader *reader {}; + }; + + // Note: len of buf can not smaller than ARCHIVE_BLOCK_SIZE +@@ -2008,7 +1980,8 @@ public: + explicit CopyToContainerWriteToServerTask( + const struct io_read_wrapper *reader, + std::shared_ptr> stream) +- : m_reader(reader), m_stream(std::move(std::move(stream))) ++ : m_reader(reader) ++ , m_stream(std::move(std::move(stream))) + { + } + ~CopyToContainerWriteToServerTask() = default; +@@ -2026,7 +1999,7 @@ public: + while (!stopRequested()) { + ssize_t have_read_len = m_reader->read(m_reader->context, buf, len); + CopyToContainerRequest request; +- request.set_data((const void*)buf, static_cast(have_read_len)); ++ request.set_data((const void *)buf, static_cast(have_read_len)); + if (!m_stream->Write(request)) { + DEBUG("Server may be exited, stop send data"); + break; +@@ -2095,9 +2068,8 @@ out: + return ret; + } + +- auto run(const struct isula_copy_to_container_request *request, +- struct isula_copy_to_container_response *response) -> int +- override ++ auto run(const struct isula_copy_to_container_request *request, struct isula_copy_to_container_response *response) ++ -> int override + { + ClientContext context; + if (set_custom_header_metadata(context, request, response) != 0) { +@@ -2262,4 +2234,3 @@ auto grpc_containers_client_ops_init(isula_connect_ops *ops) -> int + + return 0; + } +- +diff --git a/src/client/connect/grpc/grpc_volumes_client.cc b/src/client/connect/grpc/grpc_volumes_client.cc +new file mode 100644 +index 0000000..d8eb74b +--- /dev/null ++++ b/src/client/connect/grpc/grpc_volumes_client.cc +@@ -0,0 +1,197 @@ ++/****************************************************************************** ++ * 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-09-04 ++ * Description: provide grpc volume service functions ++ ******************************************************************************/ ++#include "grpc_volumes_client.h" ++ ++#include ++ ++#include "api.grpc.pb.h" ++#include "client_base.h" ++#include "volumes.grpc.pb.h" ++#include "utils.h" ++ ++using namespace volume; ++ ++using grpc::ClientContext; ++using grpc::Status; ++ ++class VolumeList : public ClientBase { ++public: ++ explicit VolumeList(void *args) ++ : ClientBase(args) ++ { ++ } ++ ~VolumeList() = default; ++ VolumeList(const VolumeList &) = delete; ++ VolumeList &operator=(const VolumeList &) = delete; ++ ++ auto response_from_grpc(ListVolumeResponse *gresponse, isula_list_volume_response *response) -> int override ++ { ++ int num = gresponse->volumes_size(); ++ if (num <= 0) { ++ response->volumes = nullptr; ++ response->volumes_len = 0; ++ response->server_errono = gresponse->cc(); ++ if (!gresponse->errmsg().empty()) { ++ response->errmsg = util_strdup_s(gresponse->errmsg().c_str()); ++ } ++ return 0; ++ } ++ ++ response->volumes_len = 0; ++ ++ if (static_cast(num) > SIZE_MAX / sizeof(struct isula_volume_info)) { ++ ERROR("Too many volume"); ++ response->cc = ISULAD_ERR_MEMOUT; ++ return -1; ++ } ++ auto volumes = static_cast( ++ util_common_calloc_s(sizeof(struct isula_volume_info) * static_cast(num))); ++ if (volumes == nullptr) { ++ ERROR("out of memory"); ++ response->cc = ISULAD_ERR_MEMOUT; ++ return -1; ++ } ++ ++ for (int i {}; i < num; i++) { ++ const Volume &volume = gresponse->volumes(i); ++ const char *driver = !volume.driver().empty() ? volume.driver().c_str() : "-"; ++ volumes[i].driver = util_strdup_s(driver); ++ const char *name = !volume.name().empty() ? volume.name().c_str() : "-"; ++ volumes[i].name = util_strdup_s(name); ++ } ++ ++ response->volumes = volumes; ++ response->volumes_len = static_cast(num); ++ response->server_errono = gresponse->cc(); ++ if (!gresponse->errmsg().empty()) { ++ response->errmsg = util_strdup_s(gresponse->errmsg().c_str()); ++ } ++ ++ return 0; ++ } ++ ++ auto grpc_call(ClientContext *context, const ListVolumeRequest &req, ListVolumeResponse *reply) -> Status override ++ { ++ return stub_->List(context, req, reply); ++ } ++}; ++ ++class VolumeRemove : public ++ ClientBase { ++public: ++ explicit VolumeRemove(void *args) ++ : ClientBase(args) ++ { ++ } ++ ~VolumeRemove() = default; ++ VolumeRemove(const VolumeRemove &) = delete; ++ VolumeRemove &operator=(const VolumeRemove &) = delete; ++ ++ auto request_to_grpc(const isula_remove_volume_request *request, RemoveVolumeRequest *grequest) -> int override ++ { ++ if (request == nullptr) { ++ return -1; ++ } ++ ++ if (request->name != nullptr) { ++ grequest->set_name(request->name); ++ } ++ ++ return 0; ++ } ++ ++ auto response_from_grpc(RemoveVolumeResponse *gresponse, isula_remove_volume_response *response) -> int override ++ { ++ response->server_errono = static_cast(gresponse->cc()); ++ ++ if (!gresponse->errmsg().empty()) { ++ response->errmsg = util_strdup_s(gresponse->errmsg().c_str()); ++ } ++ ++ return 0; ++ } ++ ++ auto check_parameter(const RemoveVolumeRequest &req) -> int override ++ { ++ if (req.name().empty()) { ++ ERROR("Missing volume name in the request"); ++ return -1; ++ } ++ ++ return 0; ++ } ++ ++ auto grpc_call(ClientContext *context, const RemoveVolumeRequest &req, RemoveVolumeResponse *reply) -> Status override ++ { ++ return stub_->Remove(context, req, reply); ++ } ++}; ++ ++class VolumePrune : public ++ ClientBase { ++public: ++ explicit VolumePrune(void *args) ++ : ClientBase(args) ++ { ++ } ++ ~VolumePrune() = default; ++ VolumePrune(const VolumePrune &) = delete; ++ VolumePrune &operator=(const VolumePrune &) = delete; ++ ++ auto response_from_grpc(PruneVolumeResponse *gresponse, isula_prune_volume_response *response) -> int override ++ { ++ auto size = gresponse->volumes_size(); ++ if (size != 0) { ++ response->volumes = static_cast(util_common_calloc_s(sizeof(char *) * size)); ++ if (response->volumes == NULL) { ++ return -1; ++ } ++ ++ for (int i {}; i < size; i++) { ++ response->volumes[i] = util_strdup_s(gresponse->volumes(i).c_str()); ++ response->volumes_len++; ++ } ++ } ++ ++ response->server_errono = static_cast(gresponse->cc()); ++ ++ if (!gresponse->errmsg().empty()) { ++ response->errmsg = util_strdup_s(gresponse->errmsg().c_str()); ++ } ++ ++ return 0; ++ } ++ ++ auto grpc_call(ClientContext *context, const PruneVolumeRequest &req, PruneVolumeResponse *reply) -> Status override ++ { ++ return stub_->Prune(context, req, reply); ++ } ++}; ++ ++auto grpc_volumes_client_ops_init(isula_connect_ops *ops) -> int ++{ ++ if (ops == nullptr) { ++ return -1; ++ } ++ ++ ops->volume.list = container_func; ++ ops->volume.remove = container_func; ++ ops->volume.prune = container_func; ++ ++ return 0; ++} +diff --git a/src/client/connect/grpc/grpc_volumes_client.h b/src/client/connect/grpc/grpc_volumes_client.h +new file mode 100644 +index 0000000..748b059 +--- /dev/null ++++ b/src/client/connect/grpc/grpc_volumes_client.h +@@ -0,0 +1,31 @@ ++/****************************************************************************** ++ * 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-09-04 ++ * Description: provide grpc volume client definition ++ ******************************************************************************/ ++#ifndef CLIENT_CONNECT_GRPC_GRPC_VOLUMES_CLIENT_H ++#define CLIENT_CONNECT_GRPC_GRPC_VOLUMES_CLIENT_H ++ ++#include "isula_connect.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++int grpc_volumes_client_ops_init(isula_connect_ops *ops); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif ++ +diff --git a/src/client/connect/isula_connect.h b/src/client/connect/isula_connect.h +index 8e9fed5..d433d72 100644 +--- a/src/client/connect/isula_connect.h ++++ b/src/client/connect/isula_connect.h +@@ -15,8 +15,8 @@ + #ifndef CLIENT_CONNECT_ISULA_CONNECT_H + #define CLIENT_CONNECT_ISULA_CONNECT_H + +-#include "libisula.h" + #include "connect.h" ++#include "protocol_type.h" + + #ifdef __cplusplus + extern "C" { +@@ -93,6 +93,17 @@ typedef struct { + int (*import)(const struct isula_import_request *request, struct isula_import_response *response, void *arg); + } image_ops; + ++typedef struct { ++ int (*list)(const struct isula_list_volume_request *request, struct isula_list_volume_response *response, ++ void *arg); ++ ++ int (*remove)(const struct isula_remove_volume_request *request, struct isula_remove_volume_response *response, ++ void *arg); ++ ++ int (*prune)(const struct isula_prune_volume_request *request, struct isula_prune_volume_response *response, ++ void *arg); ++} volume_ops; ++ + typedef struct { + int (*check)(const struct isula_health_check_request *request, struct isula_health_check_response *response, + void *arg); +@@ -101,6 +112,7 @@ typedef struct { + typedef struct { + container_ops container; + image_ops image; ++ volume_ops volume; + health_ops health; + } isula_connect_ops; + +diff --git a/src/client/libisula.c b/src/client/connect/protocol_type.c +similarity index 85% +rename from src/client/libisula.c +rename to src/client/connect/protocol_type.c +index 12b7ac5..94f682a 100644 +--- a/src/client/libisula.c ++++ b/src/client/connect/protocol_type.c +@@ -8,17 +8,16 @@ + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. +- * Author: tanyifeng +- * Create: 2018-11-08 ++ * Author: lifeng ++ * Create: 2020-10-12 + * Description: provide container isula library functions + ******************************************************************************/ ++#include "protocol_type.h" + #include + #include +-#include + #include + #include + +-#include "libisula.h" + #include "isula_libutils/log.h" + #include "utils.h" + #include "utils_array.h" +@@ -93,7 +92,7 @@ struct isula_filters *isula_filters_parse_args(const char **array, size_t len) + } + *valuepos++ = '\0'; + filters->values[filters->len] = util_strdup_s(util_trim_space(valuepos)); +- lowerkey = strings_to_lower(util_trim_space(copy)); ++ lowerkey = util_strings_to_lower(util_trim_space(copy)); + free(copy); + if (lowerkey == NULL) { + free(filters->values[filters->len]); +@@ -227,157 +226,6 @@ void isula_info_response_free(struct isula_info_response *response) + free(response); + } + +-void isula_ns_change_files_free(isula_host_config_t *hostconfig) +-{ +- if (hostconfig == NULL) { +- return; +- } +- +- util_free_array_by_len(hostconfig->ns_change_files, hostconfig->ns_change_files_len); +- hostconfig->ns_change_files = NULL; +- hostconfig->ns_change_files_len = 0; +-} +- +-void isula_host_config_storage_opts_free(isula_host_config_t *hostconfig) +-{ +- if (hostconfig == NULL) { +- return; +- } +- +- free_json_map_string_string(hostconfig->storage_opts); +- hostconfig->storage_opts = NULL; +-} +- +-void isula_host_config_sysctl_free(isula_host_config_t *hostconfig) +-{ +- if (hostconfig == NULL) { +- return; +- } +- +- free_json_map_string_string(hostconfig->sysctls); +- hostconfig->sysctls = NULL; +-} +- +-/* isula host config free */ +-void isula_host_config_free(isula_host_config_t *hostconfig) +-{ +- if (hostconfig == NULL) { +- return; +- } +- +- util_free_array_by_len(hostconfig->cap_add, hostconfig->cap_add_len); +- hostconfig->cap_add = NULL; +- hostconfig->cap_add_len = 0; +- +- util_free_array_by_len(hostconfig->cap_drop, hostconfig->cap_drop_len); +- hostconfig->cap_drop = NULL; +- hostconfig->cap_drop_len = 0; +- +- free_json_map_string_string(hostconfig->storage_opts); +- hostconfig->storage_opts = NULL; +- +- free_json_map_string_string(hostconfig->sysctls); +- hostconfig->sysctls = NULL; +- +- util_free_array_by_len(hostconfig->devices, hostconfig->devices_len); +- hostconfig->devices = NULL; +- hostconfig->devices_len = 0; +- +- util_free_array_by_len(hostconfig->hugetlbs, hostconfig->hugetlbs_len); +- hostconfig->hugetlbs = NULL; +- hostconfig->hugetlbs_len = 0; +- +- free(hostconfig->network_mode); +- hostconfig->network_mode = NULL; +- +- free(hostconfig->ipc_mode); +- hostconfig->ipc_mode = NULL; +- +- free(hostconfig->pid_mode); +- hostconfig->pid_mode = NULL; +- +- free(hostconfig->uts_mode); +- hostconfig->uts_mode = NULL; +- +- free(hostconfig->userns_mode); +- hostconfig->userns_mode = NULL; +- +- free(hostconfig->user_remap); +- hostconfig->user_remap = NULL; +- +- util_free_array_by_len(hostconfig->ulimits, hostconfig->ulimits_len); +- hostconfig->ulimits = NULL; +- hostconfig->ulimits_len = 0; +- +- free(hostconfig->restart_policy); +- hostconfig->restart_policy = NULL; +- +- free(hostconfig->host_channel); +- hostconfig->host_channel = NULL; +- +- free(hostconfig->hook_spec); +- hostconfig->hook_spec = NULL; +- +- free(hostconfig->env_target_file); +- hostconfig->env_target_file = NULL; +- +- free(hostconfig->cgroup_parent); +- hostconfig->cgroup_parent = NULL; +- +- util_free_array_by_len(hostconfig->binds, hostconfig->binds_len); +- hostconfig->binds = NULL; +- hostconfig->binds_len = 0; +- +- util_free_array_by_len(hostconfig->blkio_weight_device, hostconfig->blkio_weight_device_len); +- hostconfig->blkio_weight_device = NULL; +- hostconfig->blkio_weight_device_len = 0; +- +- container_cgroup_resources_free(hostconfig->cr); +- hostconfig->cr = NULL; +- +- free(hostconfig); +-} +- +-/* isula container config free */ +-void isula_container_config_free(isula_container_config_t *config) +-{ +- if (config == NULL) { +- return; +- } +- +- util_free_array_by_len(config->env, config->env_len); +- config->env = NULL; +- config->env_len = 0; +- +- free(config->hostname); +- config->hostname = NULL; +- +- free(config->user); +- config->user = NULL; +- +- util_free_array_by_len(config->mounts, config->mounts_len); +- config->mounts = NULL; +- config->mounts_len = 0; +- +- util_free_array_by_len(config->cmd, config->cmd_len); +- config->cmd = NULL; +- config->cmd_len = 0; +- +- free(config->entrypoint); +- config->entrypoint = NULL; +- +- free(config->log_driver); +- config->log_driver = NULL; +- +- free_json_map_string_string(config->annotations); +- config->annotations = NULL; +- +- free(config->workdir); +- config->workdir = NULL; +- +- free(config); +-} +- + /* isula create request free */ + void isula_create_request_free(struct isula_create_request *request) + { +@@ -397,11 +245,12 @@ void isula_create_request_free(struct isula_create_request *request) + free(request->runtime); + request->runtime = NULL; + +- isula_host_config_free(request->hostconfig); +- request->hostconfig = NULL; ++ free(request->container_spec_json); ++ request->container_spec_json = NULL; ++ ++ free(request->host_spec_json); ++ request->host_spec_json = NULL; + +- isula_container_config_free(request->config); +- request->config = NULL; + free(request); + } + +@@ -489,6 +338,9 @@ void isula_top_response_free(struct isula_top_response *response) + free(response->titles); + response->titles = NULL; + ++ free(response->errmsg); ++ response->errmsg = NULL; ++ + if (response->processes_len && response->processes != NULL) { + size_t i; + for (i = 0; i < response->processes_len; i++) { +@@ -806,22 +658,6 @@ void isula_kill_response_free(struct isula_kill_response *response) + free(response); + } + +-/* isula update config free */ +-void isula_update_config_free(isula_update_config_t *config) +-{ +- if (config == NULL) { +- return; +- } +- +- free(config->restart_policy); +- config->restart_policy = NULL; +- +- container_cgroup_resources_free(config->cr); +- config->cr = NULL; +- +- free(config); +-} +- + /* isula update request free */ + void isula_update_request_free(struct isula_update_request *request) + { +@@ -832,8 +668,8 @@ void isula_update_request_free(struct isula_update_request *request) + free(request->name); + request->name = NULL; + +- isula_update_config_free(request->updateconfig); +- request->updateconfig = NULL; ++ free(request->host_spec_json); ++ request->host_spec_json = NULL; + + free(request); + } +@@ -1453,21 +1289,6 @@ void isula_logs_response_free(struct isula_logs_response *response) + free(response); + } + +-/* container cgroup resources free */ +-void container_cgroup_resources_free(container_cgroup_resources_t *cr) +-{ +- if (cr == NULL) { +- return; +- } +- free(cr->cpuset_cpus); +- cr->cpuset_cpus = NULL; +- +- free(cr->cpuset_mems); +- cr->cpuset_mems = NULL; +- +- free(cr); +-} +- + void container_events_format_free(container_events_format_t *value) + { + size_t i; +@@ -1491,4 +1312,76 @@ void container_events_format_free(container_events_format_t *value) + value->annotations = NULL; + + free(value); +-} +\ No newline at end of file ++} ++ ++void isula_volume_list_free(size_t volumes_len, struct isula_volume_info *volumes) ++{ ++ size_t i = 0; ++ struct isula_volume_info *volume = NULL; ++ ++ if (volumes == NULL) { ++ return; ++ } ++ ++ for (i = 0, volume = volumes; i < volumes_len; i++, volume++) { ++ free(volume->driver); ++ free(volume->name); ++ } ++ free(volumes); ++ ++ return; ++} ++ ++void isula_list_volume_response_free(struct isula_list_volume_response *response) ++{ ++ if (response == NULL) { ++ return; ++ } ++ ++ isula_volume_list_free(response->volumes_len, response->volumes); ++ response->volumes = NULL; ++ response->volumes_len = 0; ++ ++ free(response->errmsg); ++ response->errmsg = NULL; ++ ++ free(response); ++ return; ++} ++ ++void isula_remove_volume_response_free(struct isula_remove_volume_response *response) ++{ ++ if (response == NULL) { ++ return; ++ } ++ ++ free(response->errmsg); ++ response->errmsg = NULL; ++ ++ free(response); ++ return; ++} ++ ++void isula_prune_volume_response_free(struct isula_prune_volume_response *response) ++{ ++ size_t i = 0; ++ ++ if (response == NULL) { ++ return; ++ } ++ ++ for (i = 0; i < response->volumes_len; i++) { ++ free(response->volumes[i]); ++ response->volumes[i] = NULL; ++ } ++ response->volumes_len = 0; ++ ++ free(response->volumes); ++ response->volumes = NULL; ++ ++ free(response->errmsg); ++ response->errmsg = NULL; ++ ++ free(response); ++ return; ++} +diff --git a/src/client/libisula.h b/src/client/connect/protocol_type.h +similarity index 81% +rename from src/client/libisula.h +rename to src/client/connect/protocol_type.h +index 62954f9..fb5ecef 100644 +--- a/src/client/libisula.h ++++ b/src/client/connect/protocol_type.h +@@ -8,12 +8,12 @@ + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. +- * Author: tanyifeng +- * Create: 2018-11-08 +- * Description: provide container isula library definition ++ * Author: lifeng ++ * Create: 2020-10-12 ++ * Description: provide container isula protocol definition + ******************************************************************************/ +-#ifndef CLIENT_LIBISULA_H +-#define CLIENT_LIBISULA_H ++#ifndef CLIENT_CONNECT_PROTOCOL_H ++#define CLIENT_CONNECT_PROTOCOL_H + + #include + #include +@@ -23,6 +23,7 @@ + #include "io_wrapper.h" + #include "isula_libutils/container_path_stat.h" + #include "isula_libutils/json_common.h" ++#include "isula_libutils/mount_spec.h" + #include "utils_timestamp.h" + + #ifdef __cplusplus +@@ -35,179 +36,13 @@ struct isula_filters { + size_t len; + }; + +-typedef struct isula_container_config { +- char **env; +- size_t env_len; +- +- char **label; +- size_t label_len; +- +- char *hostname; +- +- char *user; +- +- bool attach_stdin; +- +- bool attach_stdout; +- +- bool attach_stderr; +- +- bool open_stdin; +- +- bool tty; +- +- bool readonly; +- +- bool all_devices; +- +- bool system_container; +- char *ns_change_opt; +- +- char **mounts; +- size_t mounts_len; +- +- char *entrypoint; +- +- char **cmd; +- size_t cmd_len; +- +- char *log_driver; +- +- json_map_string_string *annotations; +- +- char *workdir; +- +- char *health_cmd; +- +- int64_t health_interval; +- +- int health_retries; +- +- int64_t health_timeout; +- +- int64_t health_start_period; +- +- bool no_healthcheck; +- +- bool exit_on_unhealthy; +- +- char **accel; +- size_t accel_len; +-} isula_container_config_t; +- +-typedef struct container_cgroup_resources { +- uint16_t blkio_weight; +- int64_t cpu_shares; +- int64_t cpu_period; +- int64_t cpu_quota; +- int64_t cpu_realtime_period; +- int64_t cpu_realtime_runtime; +- char *cpuset_cpus; +- char *cpuset_mems; +- int64_t memory; +- int64_t memory_swap; +- int64_t memory_reservation; +- int64_t kernel_memory; +- int64_t pids_limit; +- int64_t files_limit; +- int64_t oom_score_adj; +- int64_t swappiness; +-} container_cgroup_resources_t; +- +-typedef struct isula_host_config { +- char **devices; +- size_t devices_len; +- +- char **hugetlbs; +- size_t hugetlbs_len; +- +- char **group_add; +- size_t group_add_len; +- +- char *network_mode; +- +- char *ipc_mode; +- +- char *pid_mode; +- +- char *uts_mode; +- +- char *userns_mode; +- +- char *user_remap; +- +- char **ulimits; +- size_t ulimits_len; +- +- char *restart_policy; +- +- char *host_channel; +- +- char **cap_add; +- size_t cap_add_len; +- +- char **cap_drop; +- size_t cap_drop_len; +- +- json_map_string_string *storage_opts; +- +- json_map_string_string *sysctls; +- +- char **dns; +- size_t dns_len; +- +- char **dns_options; +- size_t dns_options_len; +- +- char **dns_search; +- size_t dns_search_len; +- +- char **extra_hosts; +- size_t extra_hosts_len; +- +- char *hook_spec; +- +- char **binds; +- size_t binds_len; +- +- char **blkio_weight_device; +- size_t blkio_weight_device_len; +- +- char **blkio_throttle_read_bps_device; +- size_t blkio_throttle_read_bps_device_len; +- +- char **blkio_throttle_write_bps_device; +- size_t blkio_throttle_write_bps_device_len; +- +- bool privileged; +- bool system_container; +- char **ns_change_files; +- size_t ns_change_files_len; +- bool auto_remove; +- +- bool oom_kill_disable; +- +- int64_t shm_size; +- +- bool readonly_rootfs; +- +- char *env_target_file; +- +- char *cgroup_parent; +- +- container_cgroup_resources_t *cr; +- +- char **security; +- size_t security_len; +-} isula_host_config_t; +- + struct isula_create_request { + char *name; + char *rootfs; + char *image; + char *runtime; +- isula_host_config_t *hostconfig; +- isula_container_config_t *config; ++ char *host_spec_json; ++ char *container_spec_json; + }; + + struct isula_create_response { +@@ -576,14 +411,9 @@ struct isula_info_response { + char *errmsg; + }; + +-typedef struct isula_update_config { +- char *restart_policy; +- container_cgroup_resources_t *cr; +-} isula_update_config_t; +- + struct isula_update_request { + char *name; +- isula_update_config_t *updateconfig; ++ char *host_spec_json; + }; + + struct isula_update_response { +@@ -747,11 +577,46 @@ struct isula_resize_response { + char *errmsg; + }; + +-void container_cgroup_resources_free(container_cgroup_resources_t *cr); ++struct isula_list_volume_request { ++ char unuseful; ++}; + +-void container_events_format_free(container_events_format_t *value); ++struct isula_volume_info { ++ char *driver; ++ char *name; ++}; + +-Container_Status isulastastr2sta(const char *state); ++struct isula_list_volume_response { ++ size_t volumes_len; ++ struct isula_volume_info *volumes; ++ uint32_t cc; ++ uint32_t server_errono; ++ char *errmsg; ++}; ++ ++struct isula_remove_volume_request { ++ char *name; ++}; ++ ++struct isula_remove_volume_response { ++ uint32_t cc; ++ uint32_t server_errono; ++ char *errmsg; ++}; ++ ++struct isula_prune_volume_request { ++ char unuseful; ++}; ++ ++struct isula_prune_volume_response { ++ size_t volumes_len; ++ char **volumes; ++ uint32_t cc; ++ uint32_t server_errono; ++ char *errmsg; ++}; ++ ++void container_events_format_free(container_events_format_t *value); + + struct isula_filters *isula_filters_parse_args(const char **array, size_t len); + +@@ -767,16 +632,6 @@ void isula_info_request_free(struct isula_info_request *request); + + void isula_info_response_free(struct isula_info_response *response); + +-void isula_ns_change_files_free(isula_host_config_t *hostconfig); +- +-void isula_host_config_storage_opts_free(isula_host_config_t *hostconfig); +- +-void isula_host_config_sysctl_free(isula_host_config_t *hostconfig); +- +-void isula_host_config_free(isula_host_config_t *hostconfig); +- +-void isula_container_config_free(isula_container_config_t *config); +- + void isula_create_request_free(struct isula_create_request *request); + + void isula_create_response_free(struct isula_create_response *response); +@@ -825,8 +680,6 @@ void isula_kill_request_free(struct isula_kill_request *request); + + void isula_kill_response_free(struct isula_kill_response *response); + +-void isula_update_config_free(isula_update_config_t *config); +- + void isula_update_request_free(struct isula_update_request *request); + + void isula_update_response_free(struct isula_update_response *response); +@@ -907,6 +760,14 @@ void isula_resize_response_free(struct isula_resize_response *response); + void isula_logs_request_free(struct isula_logs_request *request); + void isula_logs_response_free(struct isula_logs_response *response); + ++void isula_volume_list_free(size_t volumes_num, struct isula_volume_info *volumes); ++ ++void isula_list_volume_response_free(struct isula_list_volume_response *response); ++ ++void isula_remove_volume_response_free(struct isula_remove_volume_response *response); ++ ++void isula_prune_volume_response_free(struct isula_prune_volume_response *response); ++ + #ifdef __cplusplus + } + #endif +diff --git a/src/client/connect/rest/rest_containers_client.c b/src/client/connect/rest/rest_containers_client.c +index e697861..236e6e8 100644 +--- a/src/client/connect/rest/rest_containers_client.c ++++ b/src/client/connect/rest/rest_containers_client.c +@@ -12,15 +12,14 @@ + * Create: 2018-11-08 + * Description: provide container restful functions + ******************************************************************************/ ++#include "rest_containers_client.h" + #include + #include "error.h" + + #include "isula_libutils/log.h" + #include "isula_connect.h" + #include "container.rest.h" +-#include "pack_config.h" + #include "rest_common.h" +-#include "rest_containers_client.h" + + /* create request to rest */ + static int create_request_to_rest(const struct isula_create_request *lc_request, char **body, size_t *body_len) +@@ -37,18 +36,12 @@ static int create_request_to_rest(const struct isula_create_request *lc_request, + goto out; + } + +- ret = generate_hostconfig(lc_request->hostconfig, &crequest->hostconfig); +- if (ret != 0) { +- ERROR("Failed to pack host config"); +- ret = EINVALIDARGS; +- goto out; ++ if (lc_request->host_spec_json != NULL) { ++ crequest->hostconfig = util_strdup_s(lc_request->host_spec_json); + } + +- ret = generate_container_config(lc_request->config, &crequest->customconfig); +- if (ret != 0) { +- ERROR("Failed to pack custom config"); +- ret = EINVALIDARGS; +- goto out; ++ if (lc_request->container_spec_json != NULL) { ++ crequest->customconfig = util_strdup_s(lc_request->container_spec_json); + } + + if (lc_request->name != NULL) { +@@ -402,29 +395,33 @@ static int unpack_container_info_for_list_response(container_list_response *cres + response->container_num = num; + response->container_summary = summary_info; + for (i = 0; i < num; i++) { +- summary_info[i] = +- (struct isula_container_summary_info *)util_common_calloc_s(sizeof(struct isula_container_summary_info)); ++ summary_info[i] = (struct isula_container_summary_info *)util_common_calloc_s( ++ sizeof(struct isula_container_summary_info)); + if (summary_info[i] == NULL) { + ERROR("Out of memory"); + return -1; + } +- summary_info[i]->id = cresponse->containers[i]->id ? util_strdup_s(cresponse->containers[i]->id) +- : util_strdup_s("-"); +- summary_info[i]->name = cresponse->containers[i]->name ? util_strdup_s(cresponse->containers[i]->name) +- : util_strdup_s("-"); +- summary_info[i]->runtime = cresponse->containers[i]->runtime ? util_strdup_s(cresponse->containers[i]->runtime) +- : util_strdup_s("-"); ++ summary_info[i]->id = cresponse->containers[i]->id ? util_strdup_s(cresponse->containers[i]->id) : ++ util_strdup_s("-"); ++ summary_info[i]->name = cresponse->containers[i]->name ? util_strdup_s(cresponse->containers[i]->name) : ++ util_strdup_s("-"); ++ summary_info[i]->runtime = cresponse->containers[i]->runtime ? ++ util_strdup_s(cresponse->containers[i]->runtime) : ++ util_strdup_s("-"); + summary_info[i]->has_pid = cresponse->containers[i]->pid != 0; + summary_info[i]->pid = cresponse->containers[i]->pid; + summary_info[i]->status = cresponse->containers[i]->status; +- summary_info[i]->image = cresponse->containers[i]->image ? util_strdup_s(cresponse->containers[i]->image) +- : util_strdup_s("-"); +- summary_info[i]->command = cresponse->containers[i]->command ? util_strdup_s(cresponse->containers[i]->command) +- : util_strdup_s("-"); +- summary_info[i]->startat = cresponse->containers[i]->startat ? util_strdup_s(cresponse->containers[i]->startat) +- : util_strdup_s("-"); ++ summary_info[i]->image = cresponse->containers[i]->image ? util_strdup_s(cresponse->containers[i]->image) : ++ util_strdup_s("-"); ++ summary_info[i]->command = cresponse->containers[i]->command ? ++ util_strdup_s(cresponse->containers[i]->command) : ++ util_strdup_s("-"); ++ summary_info[i]->startat = cresponse->containers[i]->startat ? ++ util_strdup_s(cresponse->containers[i]->startat) : ++ util_strdup_s("-"); + summary_info[i]->finishat = cresponse->containers[i]->finishat ? +- util_strdup_s(cresponse->containers[i]->finishat) : util_strdup_s("-"); ++ util_strdup_s(cresponse->containers[i]->finishat) : ++ util_strdup_s("-"); + summary_info[i]->exit_code = cresponse->containers[i]->exit_code; + summary_info[i]->restart_count = (unsigned int)cresponse->containers[i]->restartcount; + summary_info[i]->created = cresponse->containers[i]->created; +@@ -675,8 +672,8 @@ out: + } + + /* rest container list */ +-static int rest_container_list(const struct isula_list_request *ll_request, +- struct isula_list_response *ll_response, void *arg) ++static int rest_container_list(const struct isula_list_request *ll_request, struct isula_list_response *ll_response, ++ void *arg) + { + char *body = NULL; + int ret = 0; +@@ -741,8 +738,8 @@ out: + } + + /* rest container wait */ +-static int rest_container_wait(const struct isula_wait_request *lw_request, +- struct isula_wait_response *lw_response, void *arg) ++static int rest_container_wait(const struct isula_wait_request *lw_request, struct isula_wait_response *lw_response, ++ void *arg) + { + char *body = NULL; + int ret = 0; +@@ -842,8 +839,8 @@ out: + } + + /* rest container stop */ +-static int rest_container_stop(const struct isula_stop_request *ls_request, +- struct isula_stop_response *ls_response, void *arg) ++static int rest_container_stop(const struct isula_stop_request *ls_request, struct isula_stop_response *ls_response, ++ void *arg) + { + char *body = NULL; + int ret = 0; +@@ -976,14 +973,10 @@ out: + static int update_request_to_rest(const struct isula_update_request *lu_request, char **body, size_t *body_len) + { + container_update_request *crequest = NULL; +- isula_host_config_t srcconfig; + struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 }; + parser_error err = NULL; +- char *srcconfigjson = NULL; + int ret = 0; + +- (void)memset(&srcconfig, 0, sizeof(srcconfig)); +- + crequest = util_common_calloc_s(sizeof(container_update_request)); + if (crequest == NULL) { + ERROR("Out of memory"); +@@ -991,22 +984,14 @@ static int update_request_to_rest(const struct isula_update_request *lu_request, + goto out; + } + +- if (lu_request->updateconfig != NULL) { +- srcconfig.restart_policy = lu_request->updateconfig->restart_policy; +- srcconfig.cr = lu_request->updateconfig->cr; +- } +- ret = generate_hostconfig(&srcconfig, &srcconfigjson); +- if (ret != 0) { +- ERROR("Failed to generate hostconfig json"); +- ret = -1; +- goto out; +- } +- crequest->host_config = srcconfigjson; +- + if (lu_request->name != NULL) { + crequest->name = util_strdup_s(lu_request->name); + } + ++ if (lu_request->host_spec_json != NULL) { ++ crequest->host_config = util_strdup_s(lu_request->host_spec_json); ++ } ++ + *body = container_update_request_generate_json(crequest, &ctx, &err); + if (*body == NULL) { + ERROR("Failed to generate update request json:%s", err); +@@ -1261,8 +1246,8 @@ out: + } + + /* rest container pause */ +-static int rest_container_pause(const struct isula_pause_request *lp_request, +- struct isula_pause_response *lp_response, void *arg) ++static int rest_container_pause(const struct isula_pause_request *lp_request, struct isula_pause_response *lp_response, ++ void *arg) + { + char *body = NULL; + int ret = 0; +@@ -1361,8 +1346,8 @@ out: + } + + /* rest container kill */ +-static int rest_container_kill(const struct isula_kill_request *lk_request, +- struct isula_kill_response *lk_response, void *arg) ++static int rest_container_kill(const struct isula_kill_request *lk_request, struct isula_kill_response *lk_response, ++ void *arg) + { + char *body = NULL; + int ret = 0; +@@ -1716,8 +1701,8 @@ out: + } + + /* rest container exec */ +-static int rest_container_exec(const struct isula_exec_request *le_request, +- struct isula_exec_response *le_response, void *arg) ++static int rest_container_exec(const struct isula_exec_request *le_request, struct isula_exec_response *le_response, ++ void *arg) + { + char *body = NULL; + int ret = 0; +@@ -1773,4 +1758,3 @@ int rest_containers_client_ops_init(isula_connect_ops *ops) + + return 0; + } +- +diff --git a/src/client/connect/rest/rest_images_client.c b/src/client/connect/rest/rest_images_client.c +index e3ac0ac..3ad6c5b 100644 +--- a/src/client/connect/rest/rest_images_client.c ++++ b/src/client/connect/rest/rest_images_client.c +@@ -12,6 +12,7 @@ + * Create: 2018-11-08 + * Description: provide image restful client functions + ******************************************************************************/ ++#include "rest_images_client.h" + #include + #include "error.h" + #include +@@ -20,7 +21,6 @@ + #include "isula_connect.h" + #include "image.rest.h" + #include "rest_common.h" +-#include "rest_images_client.h" + + /* image load request to rest */ + static int image_load_request_to_rest(const struct isula_load_request *request, char **body, size_t *body_len) +diff --git a/src/cmd/CMakeLists.txt b/src/cmd/CMakeLists.txt +index 845cb0f..3d3e881 100644 +--- a/src/cmd/CMakeLists.txt ++++ b/src/cmd/CMakeLists.txt +@@ -1,13 +1,15 @@ + # get current directory sources files + aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} comm_srcs) + ++add_subdirectory(options) ++ + add_subdirectory(isula) +-set(ISULA_SRCS ${comm_srcs} ${CMD_ISULA_SRCS} PARENT_SCOPE) +-set(ISULA_INCS ${CMAKE_CURRENT_SOURCE_DIR} ${CMD_ISULA_INCS} PARENT_SCOPE) ++set(ISULA_SRCS ${comm_srcs} ${OPT_SRCS} ${CMD_ISULA_SRCS} PARENT_SCOPE) ++set(ISULA_INCS ${CMAKE_CURRENT_SOURCE_DIR} ${OPT_INCS} ${CMD_ISULA_INCS} PARENT_SCOPE) + + add_subdirectory(isulad) +-set(ISULAD_SRCS ${comm_srcs} ${CMD_ISULAD_SRCS} PARENT_SCOPE) +-set(ISULAD_INCS ${CMAKE_CURRENT_SOURCE_DIR} ${CMD_ISULAD_INCS} PARENT_SCOPE) ++set(ISULAD_SRCS ${comm_srcs} ${OPT_SRCS} ${CMD_ISULAD_SRCS} PARENT_SCOPE) ++set(ISULAD_INCS ${CMAKE_CURRENT_SOURCE_DIR} ${OPT_INCS} ${CMD_ISULAD_INCS} PARENT_SCOPE) + + add_subdirectory(isulad-shim) + set(ISULAD_SHIM_SRCS ${CMD_ISULAD_SHIM_SRCS} PARENT_SCOPE) +diff --git a/src/cmd/command_parser.c b/src/cmd/command_parser.c +index 33a1f37..f900cea 100644 +--- a/src/cmd/command_parser.c ++++ b/src/cmd/command_parser.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + + #include "constants.h" + #include "utils.h" +@@ -29,6 +30,7 @@ + #include "utils_convert.h" + #include "utils_string.h" + #include "utils_verify.h" ++#include "utils_timestamp.h" + + void command_help_isulad_head() + { +@@ -128,6 +130,19 @@ void command_init(command_t *self, command_option_t *opts, int opts_len, int arg + self->option_count = opts_len; + } + ++void subcommand_init(command_t *self, command_option_t *opts, int opts_len, int argc, const char **argv, ++ const char *description, const char *usage) ++{ ++ (void)memset(self, 0, sizeof(command_t)); ++ self->name = util_string_join(" ", argv, 2); ++ self->argc = argc - 3; ++ self->argv = argv + 3; ++ self->usage = usage; ++ self->description = description; ++ self->options = opts; ++ self->option_count = opts_len; ++} ++ + void command_option(command_t *self, command_option_type_t type, void *data, int small, const char *large, + const char *desc, command_callback_t cb) + { +@@ -242,7 +257,7 @@ static int command_get_option_data(command_t *self, command_option_t *option, co + case CMD_OPT_TYPE_CALLBACK: + return command_get_callback_option_data(self, option, opt_arg); + default: +- COMMAND_ERROR("Unkown command option type:%d", (int)(option->type)); ++ COMMAND_ERROR("Unknown command option type:%d", (int)(option->type)); + return -1; + } + } +@@ -304,7 +319,7 @@ static int command_parse_short_arg(command_t *self, const char *arg) + } while (found && opt_arg != NULL); + + if (opt_arg != NULL) { +- COMMAND_ERROR("Unkown flag found:'%c'", opt_arg[0]); ++ COMMAND_ERROR("Unknown flag found:'%c'", opt_arg[0]); + exit(EINVALIDARGS); + } + return 0; +@@ -328,7 +343,7 @@ static int command_parse_long_arg(command_t *self, const char *arg) + continue; + } + +- opt_arg = str_skip_str(arg, opt->large); ++ opt_arg = util_str_skip_str(arg, opt->large); + if (opt_arg == NULL) { + continue; + } +@@ -347,7 +362,7 @@ static int command_parse_long_arg(command_t *self, const char *arg) + } + return 0; + } +- COMMAND_ERROR("Unkown flag found:'--%s'\n", arg); ++ COMMAND_ERROR("Unknown flag found:'--%s'\n", arg); + exit(EINVALIDARGS); + } + +@@ -501,7 +516,7 @@ int command_convert_nanoseconds(command_option_t *option, const char *arg) + if (option == NULL) { + return -1; + } +- if (util_parse_time_str_to_nanoseconds(arg, option->data)) { ++ if (util_time_str_to_nanoseconds(arg, option->data)) { + COMMAND_ERROR("Invalid value \"%s\" for flag --%s", arg, option->large); + return EINVALIDARGS; + } +@@ -551,3 +566,48 @@ int command_convert_swappiness(command_option_t *option, const char *arg) + } + return 0; + } ++ ++int command_convert_nanocpus(command_option_t *option, const char *arg) ++{ ++ int ret = 0; ++ char *dup = NULL; ++ ++ if (option == NULL) { ++ return -1; ++ } ++ ++ if (!isdigit(arg[0])) { ++ COMMAND_ERROR("Invalid value \"%s\" for flag --%s", arg, option->large); ++ return EINVALIDARGS; ++ } ++ ++ dup = util_strdup_s(arg); ++ if (dup == NULL) { ++ COMMAND_ERROR("Invalid value \"%s\" for flag --%s", arg, option->large); ++ return EINVALIDARGS; ++ } ++ ++ if (util_parse_size_int_and_float(arg, 1e9, option->data)) { ++ COMMAND_ERROR("Invalid value \"%s\" for flag --%s", arg, option->large); ++ ret = EINVALIDARGS; ++ goto out; ++ } ++ ++out: ++ free(dup); ++ return ret; ++} ++ ++int command_convert_device_cgroup_rules(command_option_t *option, const char *arg) ++{ ++ if (option == NULL) { ++ return -1; ++ } ++ ++ if (!util_valid_device_cgroup_rule(arg)) { ++ COMMAND_ERROR("Invalid value \"%s\" for flag --%s", arg, option->large); ++ return EINVALIDARGS; ++ } ++ ++ return command_append_array(option, arg); ++} +diff --git a/src/cmd/command_parser.h b/src/cmd/command_parser.h +index cdf3e1e..f38bec6 100644 +--- a/src/cmd/command_parser.h ++++ b/src/cmd/command_parser.h +@@ -69,6 +69,10 @@ int command_valid_socket(command_option_t *option, const char *arg); + void command_init(command_t *self, command_option_t *opts, int opts_len, int argc, const char **argv, + const char *description, const char *usage); + ++void subcommand_init(command_t *self, command_option_t *opts, int opts_len, int argc, const char **argv, ++ const char *description, const char *usage); ++ ++ + int compare_options(const void *s1, const void *s2); + + void print_options(int options_len, const command_option_t *options); +@@ -100,10 +104,12 @@ int command_convert_membytes(command_option_t *option, const char *arg); + + int command_convert_memswapbytes(command_option_t *option, const char *arg); + +-int check_default_ulimit_type(const char *type); +- + int command_convert_swappiness(command_option_t *option, const char *arg); + ++int command_convert_nanocpus(command_option_t *option, const char *arg); ++ ++int command_convert_device_cgroup_rules(command_option_t *option, const char *arg); ++ + #ifdef __cplusplus + } + #endif +diff --git a/src/cmd/isula/CMakeLists.txt b/src/cmd/isula/CMakeLists.txt +index c1d1a47..c7bf2f8 100644 +--- a/src/cmd/isula/CMakeLists.txt ++++ b/src/cmd/isula/CMakeLists.txt +@@ -4,6 +4,7 @@ add_subdirectory(information) + add_subdirectory(extend) + add_subdirectory(stream) + add_subdirectory(images) ++add_subdirectory(volume) + aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} isula_srcs) + + set(CMD_ISULA_SRCS +@@ -11,6 +12,7 @@ set(CMD_ISULA_SRCS + ${ISULA_BASE_SRCS} + ${ISULA_EXTEND_SRCS} + ${ISULA_IMAGES_SRCS} ++ ${ISULA_VOLUME_SRCS} + ${ISULA_INFORMATION_SRCS} + ${ISULA_STREAM_SRCS} + PARENT_SCOPE +@@ -21,6 +23,7 @@ set(CMD_ISULA_INCS + ${CMAKE_CURRENT_SOURCE_DIR}/base + ${CMAKE_CURRENT_SOURCE_DIR}/extend + ${CMAKE_CURRENT_SOURCE_DIR}/images ++ ${CMAKE_CURRENT_SOURCE_DIR}/volume + ${CMAKE_CURRENT_SOURCE_DIR}/information + ${CMAKE_CURRENT_SOURCE_DIR}/stream + PARENT_SCOPE +diff --git a/src/cmd/isula/base/create.c b/src/cmd/isula/base/create.c +index 583664a..a79b18b 100644 +--- a/src/cmd/isula/base/create.c ++++ b/src/cmd/isula/base/create.c +@@ -12,6 +12,7 @@ + * Create: 2017-11-22 + * Description: provide container create functions + ******************************************************************************/ ++#include "create.h" + #include + #include + #include +@@ -32,17 +33,21 @@ + #include "isula_libutils/log.h" + #include "utils.h" + #include "utils_string.h" +-#include "create.h" + #include "isula_connect.h" + #include "path.h" + #include "pull.h" + #include "constants.h" + #include "connect.h" +-#include "libisula.h" ++ + #include "utils_array.h" + #include "utils_convert.h" + #include "utils_file.h" + #include "utils_verify.h" ++#include "isula_container_spec.h" ++#include "isula_host_spec.h" ++#include "utils_mount_spec.h" ++ ++#define DEFAULT_MOUNT_TYPE "volume" + + const char g_cmd_create_desc[] = "Create a new container"; + const char g_cmd_create_usage[] = "create [OPTIONS] --external-rootfs=PATH|IMAGE [COMMAND] [ARG...]"; +@@ -142,9 +147,18 @@ static int request_pack_host_config_cgroup(const struct client_arguments *args, + return -1; + } + ++ hostconfig->cr = util_common_calloc_s(sizeof(container_cgroup_resources_t)); ++ if (hostconfig->cr == NULL) { ++ COMMAND_ERROR("Memory out"); ++ return -1; ++ } ++ + /* blkio weight */ + hostconfig->cr->blkio_weight = args->cr.blkio_weight; + ++ /* nano cpus */ ++ hostconfig->cr->nano_cpus = args->cr.nano_cpus; ++ + /* cpu shares */ + hostconfig->cr->cpu_shares = args->cr.cpu_shares; + +@@ -161,10 +175,10 @@ static int request_pack_host_config_cgroup(const struct client_arguments *args, + hostconfig->cr->cpu_realtime_runtime = args->cr.cpu_rt_runtime; + + /* cpuset-cpus */ +- hostconfig->cr->cpuset_cpus = args->cr.cpuset_cpus; ++ hostconfig->cr->cpuset_cpus = util_strdup_s(args->cr.cpuset_cpus); + + /* cpuset memory */ +- hostconfig->cr->cpuset_mems = args->cr.cpuset_mems; ++ hostconfig->cr->cpuset_mems = util_strdup_s(args->cr.cpuset_mems); + + /* oom_score_adj */ + hostconfig->cr->oom_score_adj = args->cr.oom_score_adj; +@@ -188,54 +202,7 @@ static int request_pack_host_config_cgroup(const struct client_arguments *args, + return 0; + } + +-static int util_env_set_isulad_enable_plugins(char ***penv, const size_t *penv_len, const char *names) +-{ +- size_t env_len; +- size_t len = 0; +- char *val = NULL; +- char *kv = NULL; +- char **env = NULL; +- const char *arr[10] = { NULL }; +- +- if (penv == NULL || penv_len == NULL || names == NULL) { +- return -1; +- } +- +- env = *penv; +- env_len = *penv_len; +- +- arr[0] = ISULAD_ENABLE_PLUGINS; +- arr[1] = "="; +- arr[2] = names; +- len = 3; +- +- val = util_env_get_val(env, env_len, ISULAD_ENABLE_PLUGINS, strlen(ISULAD_ENABLE_PLUGINS)); +- if (val != NULL && strlen(val) != 0) { +- arr[3] = ISULAD_ENABLE_PLUGINS_SEPERATOR; +- arr[4] = val; +- len = 5; +- } +- +- kv = util_string_join("", arr, len); +- if (kv == NULL) { +- goto failed; +- } +- +- if (util_env_set_val(penv, penv_len, ISULAD_ENABLE_PLUGINS, strlen(ISULAD_ENABLE_PLUGINS), kv)) { +- goto failed; +- } +- +- free(val); +- free(kv); +- return 0; +- +-failed: +- free(val); +- free(kv); +- return -1; +-} +- +-static int request_pack_custom_env(struct client_arguments *args, isula_container_config_t *conf) ++static int request_pack_custom_env(const struct client_arguments *args, isula_container_config_t *conf) + { + int ret = 0; + char *pe = NULL; +@@ -244,7 +211,7 @@ static int request_pack_custom_env(struct client_arguments *args, isula_containe + if (args->custom_conf.env != NULL) { + size_t i; + for (i = 0; i < util_array_len((const char **)(args->custom_conf.env)); i++) { +- if (util_validate_env(args->custom_conf.env[i], &new_env) != 0) { ++ if (util_valid_env(args->custom_conf.env[i], &new_env) != 0) { + COMMAND_ERROR("Invalid environment %s", args->custom_conf.env[i]); + ret = -1; + goto out; +@@ -263,25 +230,6 @@ static int request_pack_custom_env(struct client_arguments *args, isula_containe + conf->env_len = util_array_len((const char **)(conf->env)); + } + +- if (args->custom_conf.accel != NULL) { +- pe = util_env_get_val(conf->env, conf->env_len, ISULAD_ENABLE_PLUGINS, strlen(ISULAD_ENABLE_PLUGINS)); +- if (pe == NULL) { +- if (util_array_append(&conf->env, ISULAD_ENABLE_PLUGINS "=")) { +- COMMAND_ERROR("init env ISULAD_ENABLE_PLUGINS failed"); +- ret = -1; +- goto out; +- } +- } +- conf->env_len = util_array_len((const char **)(conf->env)); +- conf->accel = args->custom_conf.accel; +- conf->accel_len = util_array_len((const char **)(args->custom_conf.accel)); +- if (util_env_set_isulad_enable_plugins(&conf->env, &conf->env_len, ISULAD_ISULA_ADAPTER)) { +- COMMAND_ERROR("init accel env failed"); +- ret = -1; +- goto out; +- } +- } +- + out: + free(pe); + free(new_env); +@@ -315,7 +263,7 @@ static int read_env_from_file(const char *path, size_t file_size, isula_containe + continue; + } + buf[len - 1] = '\0'; +- if (util_validate_env(buf, &new_env) != 0) { ++ if (util_valid_env(buf, &new_env) != 0) { + ret = -1; + goto out; + } +@@ -408,7 +356,7 @@ out: + return ret; + } + +-static int request_pack_custom_label(struct client_arguments *args, isula_container_config_t *conf) ++static int request_pack_custom_label(const struct client_arguments *args, isula_container_config_t *conf) + { + int ret = 0; + size_t i; +@@ -429,8 +377,6 @@ static int request_pack_custom_label(struct client_arguments *args, isula_contai + goto out; + } + } +- util_free_array(args->custom_conf.label); +- args->custom_conf.label = conf->label; /* make sure args->custom_conf.label point to valid memory. */ + conf->label_len = util_array_len((const char **)(conf->label)); + + out: +@@ -527,7 +473,7 @@ out: + static void request_pack_custom_user(const struct client_arguments *args, isula_container_config_t *conf) + { + if (args->custom_conf.user != NULL) { +- conf->user = args->custom_conf.user; ++ conf->user = util_strdup_s(args->custom_conf.user); + } + + return; +@@ -536,7 +482,7 @@ static void request_pack_custom_user(const struct client_arguments *args, isula_ + static void request_pack_custom_hostname(const struct client_arguments *args, isula_container_config_t *conf) + { + if (args->custom_conf.hostname != NULL) { +- conf->hostname = args->custom_conf.hostname; ++ conf->hostname = util_strdup_s(args->custom_conf.hostname); + } + + return; +@@ -560,39 +506,34 @@ static void request_pack_custom_system_container(const struct client_arguments * + /* ns change opt */ + if (!args->custom_conf.privileged) { + if (args->custom_conf.ns_change_opt != NULL) { +- conf->ns_change_opt = args->custom_conf.ns_change_opt; ++ conf->ns_change_opt = util_strdup_s(args->custom_conf.ns_change_opt); + } + } + + return; + } + +-static void request_pack_custom_mounts(const struct client_arguments *args, isula_container_config_t *conf) +-{ +- if (args->custom_conf.mounts != NULL) { +- conf->mounts_len = util_array_len((const char **)(args->custom_conf.mounts)); +- conf->mounts = args->custom_conf.mounts; +- } +- return; +-} +- + static void request_pack_custom_entrypoint(const struct client_arguments *args, isula_container_config_t *conf) + { + if (args->custom_conf.entrypoint != NULL) { +- conf->entrypoint = args->custom_conf.entrypoint; ++ conf->entrypoint = util_strdup_s(args->custom_conf.entrypoint); + } + + return; + } + +-static void request_pack_custom_args(const struct client_arguments *args, isula_container_config_t *conf) ++static int request_pack_custom_args(const struct client_arguments *args, isula_container_config_t *conf) + { +- if (args->argc != 0 && args->argv != NULL) { +- conf->cmd_len = (size_t)(args->argc); +- conf->cmd = (char **)args->argv; ++ if (args->argc == 0) { ++ return 0; + } + +- return; ++ if (util_dup_array_of_strings((const char **)args->argv, args->argc, &conf->cmd, &conf->cmd_len) != 0) { ++ COMMAND_ERROR("Failed to dup command"); ++ return -1; ++ } ++ ++ return 0; + } + + static void request_pack_custom_log_options(const struct client_arguments *args, isula_container_config_t *conf) +@@ -600,42 +541,11 @@ static void request_pack_custom_log_options(const struct client_arguments *args, + conf->log_driver = util_strdup_s(args->log_driver); + } + +-static int request_pack_custom_log_accel(struct client_arguments *args, isula_container_config_t *conf) +-{ +- int ret = 0; +- char *accargs = NULL; +- +- if (conf->accel != NULL) { +- accargs = util_string_join(ISULAD_ISULA_ACCEL_ARGS_SEPERATOR, (const char **)conf->accel, conf->accel_len); +- +- if (conf->annotations == NULL) { +- conf->annotations = util_common_calloc_s(sizeof(json_map_string_string)); +- if (conf->annotations == NULL) { +- COMMAND_ERROR("alloc annotations failed for accel"); +- ret = -1; +- goto out; +- } +- } +- +- ret = append_json_map_string_string(conf->annotations, ISULAD_ISULA_ACCEL_ARGS, accargs); +- if (ret != 0) { +- COMMAND_ERROR("init accel annotations failed accel=%s", accargs); +- ret = -1; +- goto out; +- } +- UTIL_FREE_AND_SET_NULL(accargs); +- } +- +-out: +- free(accargs); +- return ret; +-} +- + static void request_pack_custom_work_dir(const struct client_arguments *args, isula_container_config_t *conf) + { + /* work dir in container */ + if (args->custom_conf.workdir != NULL) { +- conf->workdir = args->custom_conf.workdir; ++ conf->workdir = util_strdup_s(args->custom_conf.workdir); + } + + return; +@@ -655,7 +565,7 @@ static void request_pack_custom_tty(const struct client_arguments *args, isula_c + static void request_pack_custom_health_check(const struct client_arguments *args, isula_container_config_t *conf) + { + if (args->custom_conf.health_cmd != NULL) { +- conf->health_cmd = args->custom_conf.health_cmd; ++ conf->health_cmd = util_strdup_s(args->custom_conf.health_cmd); + } + /* health check */ + conf->health_interval = args->custom_conf.health_interval; +@@ -668,30 +578,57 @@ static void request_pack_custom_health_check(const struct client_arguments *args + return; + } + +-static int request_pack_custom_conf(struct client_arguments *args, isula_container_config_t *conf) ++static int request_pack_custom_annotations(const struct client_arguments *args, isula_container_config_t *conf) + { +- if (args == NULL) { ++ if (args->annotations == NULL) { ++ return 0; ++ } ++ ++ conf->annotations = util_common_calloc_s(sizeof(json_map_string_string)); ++ if (conf->annotations == NULL) { ++ COMMAND_ERROR("Out of memory"); ++ return -1; ++ } ++ ++ if (dup_json_map_string_string(args->annotations, conf->annotations) != 0) { ++ COMMAND_ERROR("Failed to dup map"); + return -1; + } + ++ return 0; ++} ++ ++static isula_container_config_t *request_pack_custom_conf(const struct client_arguments *args) ++{ ++ isula_container_config_t *conf = NULL; ++ ++ if (args == NULL) { ++ return NULL; ++ } ++ ++ conf = util_common_calloc_s(sizeof(isula_container_config_t)); ++ if (conf == NULL) { ++ return NULL; ++ } ++ + /* append environment variables from env file */ + if (request_pack_custom_env_file(args, conf) != 0) { +- return -1; ++ goto error_out; + } + + /* make sure --env has higher priority than --env-file */ + if (request_pack_custom_env(args, conf) != 0) { +- return -1; ++ goto error_out; + } + + /* append labels from label file */ + if (request_pack_custom_label_file(args, conf) != 0) { +- return -1; ++ goto error_out; + } + + /* make sure --label has higher priority than --label-file */ + if (request_pack_custom_label(args, conf) != 0) { +- return -1; ++ goto error_out; + } + + /* user and group */ +@@ -705,23 +642,19 @@ static int request_pack_custom_conf(struct client_arguments *args, isula_contain + /* system container */ + request_pack_custom_system_container(args, conf); + +- /* mounts to mount filesystem */ +- request_pack_custom_mounts(args, conf); +- + /* entrypoint */ + request_pack_custom_entrypoint(args, conf); + + /* command args */ +- request_pack_custom_args(args, conf); ++ if (request_pack_custom_args(args, conf) != 0) { ++ goto error_out; ++ } + + /* console log options */ + request_pack_custom_log_options(args, conf); + +- conf->annotations = args->annotations; +- args->annotations = NULL; +- +- if (request_pack_custom_log_accel(args, conf) != 0) { +- return -1; ++ if (request_pack_custom_annotations(args, conf) != 0) { ++ goto error_out; + } + + /* work dir in container */ +@@ -731,7 +664,11 @@ static int request_pack_custom_conf(struct client_arguments *args, isula_contain + + request_pack_custom_health_check(args, conf); + +- return 0; ++ return conf; ++ ++error_out: ++ isula_container_config_free(conf); ++ return NULL; + } + + static int request_pack_host_ns_change_files(const struct client_arguments *args, isula_host_config_t *hostconfig) +@@ -786,182 +723,355 @@ static int request_pack_host_ns_change_files(const struct client_arguments *args + return ret; + } + +-static void request_pack_host_caps(const struct client_arguments *args, isula_host_config_t *hostconfig) ++static int request_pack_host_caps(const struct client_arguments *args, isula_host_config_t *hostconfig) + { + /* cap add */ + if (args->custom_conf.cap_adds != NULL) { +- hostconfig->cap_add_len = util_array_len((const char **)(args->custom_conf.cap_adds)); +- hostconfig->cap_add = args->custom_conf.cap_adds; ++ if (util_dup_array_of_strings((const char **)(args->custom_conf.cap_adds), ++ util_array_len((const char **)(args->custom_conf.cap_adds)), &hostconfig->cap_add, ++ &hostconfig->cap_add_len) != 0) { ++ COMMAND_ERROR("Failed to dup cap adds"); ++ return -1; ++ } + } + /* cap drop */ + if (args->custom_conf.cap_drops != NULL) { +- hostconfig->cap_drop_len = util_array_len((const char **)(args->custom_conf.cap_drops)); +- hostconfig->cap_drop = args->custom_conf.cap_drops; ++ if (util_dup_array_of_strings((const char **)(args->custom_conf.cap_drops), ++ util_array_len((const char **)(args->custom_conf.cap_drops)), ++ &hostconfig->cap_drop, &hostconfig->cap_drop_len) != 0) { ++ COMMAND_ERROR("Failed to dup cap drops"); ++ return -1; ++ } + } ++ ++ return 0; + } + +-static void request_pack_host_group_add(const struct client_arguments *args, isula_host_config_t *hostconfig) ++static int request_pack_host_group_add(const struct client_arguments *args, isula_host_config_t *hostconfig) + { + /* group add */ + if (args->custom_conf.group_add != NULL) { +- hostconfig->group_add_len = util_array_len((const char **)(args->custom_conf.group_add)); +- hostconfig->group_add = args->custom_conf.group_add; ++ if (util_dup_array_of_strings((const char **)(args->custom_conf.group_add), ++ util_array_len((const char **)(args->custom_conf.group_add)), ++ &hostconfig->group_add, &hostconfig->group_add_len) != 0) { ++ COMMAND_ERROR("Failed to dup group adds"); ++ return -1; ++ } + } ++ ++ return 0; + } + +-static void request_pack_host_extra_hosts(const struct client_arguments *args, isula_host_config_t *hostconfig) ++static int request_pack_host_extra_hosts(const struct client_arguments *args, isula_host_config_t *hostconfig) + { + /* extra hosts */ + if (args->custom_conf.extra_hosts != NULL) { +- hostconfig->extra_hosts_len = util_array_len((const char **)(args->custom_conf.extra_hosts)); +- hostconfig->extra_hosts = args->custom_conf.extra_hosts; ++ if (util_dup_array_of_strings((const char **)(args->custom_conf.extra_hosts), ++ util_array_len((const char **)(args->custom_conf.extra_hosts)), ++ &hostconfig->extra_hosts, &hostconfig->extra_hosts_len) != 0) { ++ COMMAND_ERROR("Failed to dup extra hosts"); ++ return -1; ++ } + } ++ ++ return 0; + } + +-static void request_pack_host_dns(const struct client_arguments *args, isula_host_config_t *hostconfig) ++static int request_pack_host_dns(const struct client_arguments *args, isula_host_config_t *hostconfig) + { + /* dns */ + if (args->custom_conf.dns != NULL) { +- hostconfig->dns_len = util_array_len((const char **)(args->custom_conf.dns)); +- hostconfig->dns = args->custom_conf.dns; ++ if (util_dup_array_of_strings((const char **)(args->custom_conf.dns), ++ util_array_len((const char **)(args->custom_conf.dns)), &hostconfig->dns, ++ &hostconfig->dns_len) != 0) { ++ COMMAND_ERROR("Failed to dup dns"); ++ return -1; ++ } + } + + /* dns options */ + if (args->custom_conf.dns_options != NULL) { +- hostconfig->dns_options_len = util_array_len((const char **)(args->custom_conf.dns_options)); +- hostconfig->dns_options = args->custom_conf.dns_options; ++ if (util_dup_array_of_strings((const char **)(args->custom_conf.dns_options), ++ util_array_len((const char **)(args->custom_conf.dns_options)), ++ &hostconfig->dns_options, &hostconfig->dns_options_len) != 0) { ++ COMMAND_ERROR("Failed to dup dns options"); ++ return -1; ++ } + } + + /* dns search */ + if (args->custom_conf.dns_search != NULL) { +- hostconfig->dns_search_len = util_array_len((const char **)(args->custom_conf.dns_search)); +- hostconfig->dns_search = args->custom_conf.dns_search; ++ if (util_dup_array_of_strings((const char **)(args->custom_conf.dns_search), ++ util_array_len((const char **)(args->custom_conf.dns_search)), ++ &hostconfig->dns_search, &hostconfig->dns_search_len) != 0) { ++ COMMAND_ERROR("Failed to dup dns search"); ++ return -1; ++ } + } ++ ++ return 0; + } + +-static void request_pack_host_ulimit(const struct client_arguments *args, isula_host_config_t *hostconfig) ++inline static int request_pack_host_ulimit(const struct client_arguments *args, isula_host_config_t *hostconfig) + { + /* ulimit options */ + if (args->custom_conf.ulimits != NULL) { +- hostconfig->ulimits_len = util_array_len((const char **)(args->custom_conf.ulimits)); +- hostconfig->ulimits = args->custom_conf.ulimits; ++ if (util_dup_array_of_strings((const char **)(args->custom_conf.ulimits), ++ util_array_len((const char **)(args->custom_conf.ulimits)), &hostconfig->ulimits, ++ &hostconfig->ulimits_len) != 0) { ++ COMMAND_ERROR("Failed to dup ulimits"); ++ return -1; ++ } + } ++ ++ return 0; + } + +-static void request_pack_host_weight_devices(const struct client_arguments *args, isula_host_config_t *hostconfig) ++inline static int request_pack_host_weight_devices(const struct client_arguments *args, isula_host_config_t *hostconfig) + { + /* blkio weight devices */ + if (args->custom_conf.weight_devices != NULL) { +- hostconfig->blkio_weight_device_len = util_array_len((const char **)(args->custom_conf.weight_devices)); +- hostconfig->blkio_weight_device = args->custom_conf.weight_devices; ++ if (util_dup_array_of_strings((const char **)(args->custom_conf.weight_devices), ++ util_array_len((const char **)(args->custom_conf.weight_devices)), ++ &hostconfig->blkio_weight_device, &hostconfig->blkio_weight_device_len) != 0) { ++ COMMAND_ERROR("Failed to dup weight devices"); ++ return -1; ++ } + } ++ ++ return 0; + } + +-static void request_pack_host_device_read_bps(const struct client_arguments *args, isula_host_config_t *hostconfig) ++inline static int request_pack_host_device_read_bps(const struct client_arguments *args, ++ isula_host_config_t *hostconfig) + { + if (args->custom_conf.blkio_throttle_read_bps_device != NULL) { +- hostconfig->blkio_throttle_read_bps_device_len = +- util_array_len((const char **)(args->custom_conf.blkio_throttle_read_bps_device)); +- hostconfig->blkio_throttle_read_bps_device = args->custom_conf.blkio_throttle_read_bps_device; ++ if (util_dup_array_of_strings((const char **)(args->custom_conf.blkio_throttle_read_bps_device), ++ util_array_len((const char **)(args->custom_conf.blkio_throttle_read_bps_device)), ++ &hostconfig->blkio_throttle_read_bps_device, ++ &hostconfig->blkio_throttle_read_bps_device_len) != 0) { ++ COMMAND_ERROR("Failed to dup blkio_throttle_read_bps_device"); ++ return -1; ++ } + } ++ ++ return 0; + } + +-static void request_pack_host_device_write_bps(const struct client_arguments *args, isula_host_config_t *hostconfig) ++inline static int request_pack_host_device_write_bps(const struct client_arguments *args, ++ isula_host_config_t *hostconfig) + { + if (args->custom_conf.blkio_throttle_write_bps_device != NULL) { +- hostconfig->blkio_throttle_write_bps_device_len = +- util_array_len((const char **)(args->custom_conf.blkio_throttle_write_bps_device)); +- hostconfig->blkio_throttle_write_bps_device = args->custom_conf.blkio_throttle_write_bps_device; ++ if (util_dup_array_of_strings((const char **)(args->custom_conf.blkio_throttle_write_bps_device), ++ util_array_len((const char **)(args->custom_conf.blkio_throttle_write_bps_device)), ++ &hostconfig->blkio_throttle_write_bps_device, ++ &hostconfig->blkio_throttle_write_bps_device_len) != 0) { ++ COMMAND_ERROR("Failed to dup blkio_throttle_write_bps_device"); ++ return -1; ++ } + } ++ ++ return 0; + } + +-static void request_pack_host_blockio(const struct client_arguments *args, isula_host_config_t *hostconfig) ++inline static int request_pack_host_device_read_iops(const struct client_arguments *args, ++ isula_host_config_t *hostconfig) + { +- request_pack_host_weight_devices(args, hostconfig); +- request_pack_host_device_read_bps(args, hostconfig); +- request_pack_host_device_write_bps(args, hostconfig); ++ if (args->custom_conf.blkio_throttle_read_iops_device != NULL) { ++ if (util_dup_array_of_strings((const char **)(args->custom_conf.blkio_throttle_read_iops_device), ++ util_array_len((const char **)(args->custom_conf.blkio_throttle_read_iops_device)), ++ &hostconfig->blkio_throttle_read_iops_device, ++ &hostconfig->blkio_throttle_read_iops_device_len) != 0) { ++ COMMAND_ERROR("Failed to dup blkio_throttle_read_iops_device"); ++ return -1; ++ } ++ } ++ ++ return 0; + } + +-static void request_pack_host_devices(const struct client_arguments *args, isula_host_config_t *hostconfig) ++inline static int request_pack_host_device_write_iops(const struct client_arguments *args, ++ isula_host_config_t *hostconfig) ++{ ++ if (args->custom_conf.blkio_throttle_write_iops_device != NULL) { ++ if (util_dup_array_of_strings( ++ (const char **)(args->custom_conf.blkio_throttle_write_iops_device), ++ util_array_len((const char **)(args->custom_conf.blkio_throttle_write_iops_device)), ++ &hostconfig->blkio_throttle_write_iops_device, ++ &hostconfig->blkio_throttle_write_iops_device_len) != 0) { ++ COMMAND_ERROR("Failed to dup blkio_throttle_write_iops_device"); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++inline static int request_pack_host_device_cgroup_rules(const struct client_arguments *args, ++ isula_host_config_t *hostconfig) ++{ ++ if (args->custom_conf.device_cgroup_rules != NULL) { ++ if (util_dup_array_of_strings((const char **)(args->custom_conf.device_cgroup_rules), ++ util_array_len((const char **)(args->custom_conf.device_cgroup_rules)), ++ &hostconfig->device_cgroup_rules, &hostconfig->device_cgroup_rules_len) != 0) { ++ COMMAND_ERROR("Failed to dup device_cgroup_rules"); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++inline static int request_pack_host_blockio(const struct client_arguments *args, isula_host_config_t *hostconfig) ++{ ++ return (request_pack_host_weight_devices(args, hostconfig) || request_pack_host_device_read_bps(args, hostconfig) || ++ request_pack_host_device_write_bps(args, hostconfig) || ++ request_pack_host_device_read_iops(args, hostconfig) || ++ request_pack_host_device_write_iops(args, hostconfig)); ++} ++ ++inline static int request_pack_host_devices(const struct client_arguments *args, isula_host_config_t *hostconfig) + { + /* devices */ + if (args->custom_conf.devices != NULL) { +- hostconfig->devices_len = util_array_len((const char **)(args->custom_conf.devices)); +- hostconfig->devices = args->custom_conf.devices; ++ if (util_dup_array_of_strings((const char **)(args->custom_conf.devices), ++ util_array_len((const char **)(args->custom_conf.devices)), &hostconfig->devices, ++ &hostconfig->devices_len) != 0) { ++ COMMAND_ERROR("Failed to dup devices"); ++ return -1; ++ } + } ++ ++ return 0; + } + +-static void request_pack_host_hugepage_limits(const struct client_arguments *args, isula_host_config_t *hostconfig) ++inline static int request_pack_host_hugepage_limits(const struct client_arguments *args, ++ isula_host_config_t *hostconfig) + { + /* hugepage limits */ + if (args->custom_conf.hugepage_limits != NULL) { +- hostconfig->hugetlbs_len = util_array_len((const char **)(args->custom_conf.hugepage_limits)); +- hostconfig->hugetlbs = args->custom_conf.hugepage_limits; ++ if (util_dup_array_of_strings((const char **)(args->custom_conf.hugepage_limits), ++ util_array_len((const char **)(args->custom_conf.hugepage_limits)), ++ &hostconfig->hugetlbs, &hostconfig->hugetlbs_len) != 0) { ++ COMMAND_ERROR("Failed to dup hugepage_limits"); ++ return -1; ++ } + } ++ ++ return 0; + } + +-static void request_pack_host_binds(const struct client_arguments *args, isula_host_config_t *hostconfig) ++inline static int request_pack_host_binds(const struct client_arguments *args, isula_host_config_t *hostconfig) + { + /* volumes to binds */ + if (args->custom_conf.volumes != NULL) { +- hostconfig->binds_len = (size_t)util_array_len((const char **)(args->custom_conf.volumes)); +- hostconfig->binds = args->custom_conf.volumes; ++ if (util_dup_array_of_strings((const char **)(args->custom_conf.volumes), ++ util_array_len((const char **)(args->custom_conf.volumes)), &hostconfig->binds, ++ &hostconfig->binds_len) != 0) { ++ COMMAND_ERROR("Failed to dup volumes"); ++ return -1; ++ } + } ++ ++ return 0; + } + +-static void request_pack_host_hook_spec(const struct client_arguments *args, isula_host_config_t *hostconfig) ++inline static int request_pack_host_volumes_from(const struct client_arguments *args, isula_host_config_t *hostconfig) + { +- /* hook-spec file */ +- if (args->custom_conf.hook_spec != NULL) { +- hostconfig->hook_spec = args->custom_conf.hook_spec; ++ /* volumes-from */ ++ if (args->custom_conf.volumes_from != NULL) { ++ if (util_dup_array_of_strings((const char **)(args->custom_conf.volumes_from), ++ util_array_len((const char **)(args->custom_conf.volumes_from)), ++ &hostconfig->volumes_from, &hostconfig->volumes_from_len) != 0) { ++ COMMAND_ERROR("Failed to dup volumes-from"); ++ return -1; ++ } + } ++ ++ return 0; + } + +-static void request_pack_host_restart_policy(const struct client_arguments *args, isula_host_config_t *hostconfig) ++static int request_pack_host_mounts(const struct client_arguments *args, isula_host_config_t *hostconfig) + { +- if (args->restart != NULL) { +- hostconfig->restart_policy = args->restart; ++ size_t size = 0; ++ size_t i = 0; ++ mount_spec *mount = NULL; ++ char *errmsg = NULL; ++ ++ if (args->custom_conf.mounts == NULL) { ++ return 0; ++ } ++ ++ size = (size_t)util_array_len((const char **)(args->custom_conf.mounts)); ++ hostconfig->mounts = util_common_calloc_s(sizeof(mount_spec *) * size); ++ if (hostconfig->mounts == NULL) { ++ COMMAND_ERROR("out of memory"); ++ return -1; + } ++ ++ for (i = 0; i < size; i++) { ++ if (util_parse_mount_spec(args->custom_conf.mounts[i], &mount, &errmsg) != 0) { ++ COMMAND_ERROR("%s", errmsg); ++ free(errmsg); ++ return -1; ++ } ++ hostconfig->mounts[hostconfig->mounts_len++] = mount; ++ } ++ ++ return 0; ++} ++ ++inline static void request_pack_host_hook_spec(const struct client_arguments *args, isula_host_config_t *hostconfig) ++{ ++ /* hook-spec file */ ++ hostconfig->hook_spec = util_strdup_s(args->custom_conf.hook_spec); ++} ++ ++inline static void request_pack_host_restart_policy(const struct client_arguments *args, ++ isula_host_config_t *hostconfig) ++{ ++ hostconfig->restart_policy = util_strdup_s(args->restart); + } + + static void request_pack_host_namespaces(const struct client_arguments *args, isula_host_config_t *hostconfig) + { +- if (args->host_channel != NULL) { +- hostconfig->host_channel = args->host_channel; +- } ++ hostconfig->network_mode = util_strdup_s(args->custom_conf.share_ns[NAMESPACE_NET]); + +- if (args->custom_conf.share_ns[NAMESPACE_NET] != NULL) { +- hostconfig->network_mode = args->custom_conf.share_ns[NAMESPACE_NET]; +- } +- if (args->custom_conf.share_ns[NAMESPACE_IPC] != NULL) { +- hostconfig->ipc_mode = args->custom_conf.share_ns[NAMESPACE_IPC]; +- } +- if (args->custom_conf.share_ns[NAMESPACE_USER] != NULL) { +- hostconfig->userns_mode = args->custom_conf.share_ns[NAMESPACE_USER]; +- } +- if (args->custom_conf.share_ns[NAMESPACE_UTS] != NULL) { +- hostconfig->uts_mode = args->custom_conf.share_ns[NAMESPACE_UTS]; +- } +- if (args->custom_conf.share_ns[NAMESPACE_PID] != NULL) { +- hostconfig->pid_mode = args->custom_conf.share_ns[NAMESPACE_PID]; +- } ++ hostconfig->ipc_mode = util_strdup_s(args->custom_conf.share_ns[NAMESPACE_IPC]); ++ ++ hostconfig->userns_mode = util_strdup_s(args->custom_conf.share_ns[NAMESPACE_USER]); ++ ++ hostconfig->uts_mode = util_strdup_s(args->custom_conf.share_ns[NAMESPACE_UTS]); ++ ++ hostconfig->pid_mode = util_strdup_s(args->custom_conf.share_ns[NAMESPACE_PID]); + } + +-static void request_pack_host_security(const struct client_arguments *args, isula_host_config_t *hostconfig) ++inline static int request_pack_host_security(const struct client_arguments *args, isula_host_config_t *hostconfig) + { + /* security opt */ + if (args->custom_conf.security != NULL) { +- hostconfig->security_len = util_array_len((const char **)(args->custom_conf.security)); +- hostconfig->security = args->custom_conf.security; ++ if (util_dup_array_of_strings((const char **)(args->custom_conf.security), ++ util_array_len((const char **)(args->custom_conf.security)), ++ &hostconfig->security, &hostconfig->security_len) != 0) { ++ COMMAND_ERROR("Failed to dup security"); ++ return -1; ++ } + } ++ ++ return 0; + } + +-static int request_pack_host_config(const struct client_arguments *args, isula_host_config_t *hostconfig) ++static isula_host_config_t *request_pack_host_config(const struct client_arguments *args) + { +- int ret = 0; ++ isula_host_config_t *hostconfig = NULL; + + if (args == NULL) { +- return -1; ++ return NULL; ++ } ++ ++ hostconfig = util_common_calloc_s(sizeof(isula_host_config_t)); ++ if (hostconfig == NULL) { ++ return NULL; + } + + /* privileged */ +@@ -977,7 +1087,7 @@ static int request_pack_host_config(const struct client_arguments *args, isula_h + hostconfig->shm_size = args->custom_conf.shm_size; + + /* user remap */ +- hostconfig->user_remap = args->custom_conf.user_remap; ++ hostconfig->user_remap = util_strdup_s(args->custom_conf.user_remap); + + /* auto remove */ + hostconfig->auto_remove = args->custom_conf.auto_remove; +@@ -986,50 +1096,72 @@ static int request_pack_host_config(const struct client_arguments *args, isula_h + hostconfig->readonly_rootfs = args->custom_conf.readonly; + + /* env target file */ +- hostconfig->env_target_file = args->custom_conf.env_target_file; ++ hostconfig->env_target_file = util_strdup_s(args->custom_conf.env_target_file); + + /* cgroup parent */ +- hostconfig->cgroup_parent = args->custom_conf.cgroup_parent; ++ hostconfig->cgroup_parent = util_strdup_s(args->custom_conf.cgroup_parent); + +- ret = request_pack_host_config_cgroup(args, hostconfig); +- if (ret != 0) { +- return ret; ++ if (request_pack_host_config_cgroup(args, hostconfig) != 0) { ++ goto error_out; + } + + /* storage options */ +- ret = request_pack_host_config_storage_opts(args, hostconfig); +- if (ret != 0) { +- return ret; ++ if (request_pack_host_config_storage_opts(args, hostconfig) != 0) { ++ goto error_out; + } + + /* sysctls */ +- ret = request_pack_host_config_sysctls(args, hostconfig); +- if (ret != 0) { +- return ret; ++ if (request_pack_host_config_sysctls(args, hostconfig) != 0) { ++ goto error_out; + } + +- ret = request_pack_host_ns_change_files(args, hostconfig); +- if (ret != 0) { +- return ret; ++ if (request_pack_host_ns_change_files(args, hostconfig) != 0) { ++ goto error_out; + } + +- request_pack_host_caps(args, hostconfig); ++ if (request_pack_host_mounts(args, hostconfig) != 0) { ++ goto error_out; ++ } + +- request_pack_host_group_add(args, hostconfig); ++ if (request_pack_host_caps(args, hostconfig) != 0) { ++ goto error_out; ++ } + +- request_pack_host_extra_hosts(args, hostconfig); ++ if (request_pack_host_group_add(args, hostconfig) != 0) { ++ goto error_out; ++ } + +- request_pack_host_dns(args, hostconfig); ++ if (request_pack_host_extra_hosts(args, hostconfig) != 0) { ++ goto error_out; ++ } + +- request_pack_host_ulimit(args, hostconfig); ++ if (request_pack_host_dns(args, hostconfig) != 0) { ++ goto error_out; ++ } + +- request_pack_host_blockio(args, hostconfig); ++ if (request_pack_host_ulimit(args, hostconfig) != 0) { ++ goto error_out; ++ } ++ ++ if (request_pack_host_blockio(args, hostconfig) != 0) { ++ goto error_out; ++ } + +- request_pack_host_devices(args, hostconfig); ++ if (request_pack_host_devices(args, hostconfig) != 0) { ++ goto error_out; ++ } + +- request_pack_host_hugepage_limits(args, hostconfig); ++ if (request_pack_host_hugepage_limits(args, hostconfig) != 0) { ++ goto error_out; ++ } + +- request_pack_host_binds(args, hostconfig); ++ if (request_pack_host_binds(args, hostconfig) != 0) { ++ goto error_out; ++ } ++ ++ if (request_pack_host_volumes_from(args, hostconfig) != 0) { ++ goto error_out; ++ } + + request_pack_host_hook_spec(args, hostconfig); + +@@ -1037,9 +1169,21 @@ static int request_pack_host_config(const struct client_arguments *args, isula_h + + request_pack_host_namespaces(args, hostconfig); + +- request_pack_host_security(args, hostconfig); ++ hostconfig->host_channel = util_strdup_s(args->host_channel); + +- return ret; ++ if (request_pack_host_security(args, hostconfig) != 0) { ++ goto error_out; ++ } ++ ++ if (request_pack_host_device_cgroup_rules(args, hostconfig) != 0) { ++ goto error_out; ++ } ++ ++ return hostconfig; ++ ++error_out: ++ isula_host_config_free(hostconfig); ++ return NULL; + } + + #define IMAGE_NOT_FOUND_ERROR "No such image" +@@ -1116,57 +1260,52 @@ out: + return ret; + } + +-static void free_alloced_memory_in_host_config(isula_host_config_t *hostconfig) +-{ +- isula_ns_change_files_free(hostconfig); +- isula_host_config_storage_opts_free(hostconfig); +- isula_host_config_sysctl_free(hostconfig); +-} +- +-static void free_alloced_memory_in_config(isula_container_config_t *custom_conf) +-{ +- if (custom_conf == NULL) { +- return; +- } +- +- free_json_map_string_string(custom_conf->annotations); +- custom_conf->annotations = NULL; +- +- free(custom_conf->log_driver); +- custom_conf->log_driver = NULL; +-} +- + /* + * Create a create request message and call RPC + */ + int client_create(struct client_arguments *args) + { + int ret = 0; +- struct isula_create_request request = { 0 }; ++ struct isula_create_request *request = NULL; + struct isula_create_response *response = NULL; +- isula_container_config_t custom_conf = { 0 }; +- isula_host_config_t host_config = { 0 }; +- container_cgroup_resources_t cr = { 0 }; +- +- request.name = args->name; +- request.rootfs = args->create_rootfs; +- request.runtime = args->runtime; +- request.image = args->image_name; +- request.hostconfig = &host_config; +- request.config = &custom_conf; +- host_config.cr = &cr; +- +- ret = request_pack_custom_conf(args, request.config); +- if (ret != 0) { ++ isula_container_config_t *container_spec = NULL; ++ isula_host_config_t *host_spec = NULL; ++ ++ request = util_common_calloc_s(sizeof(struct isula_create_request)); ++ if (request == NULL) { ++ COMMAND_ERROR("Memery out"); ++ ret = -1; + goto out; + } + +- ret = request_pack_host_config(args, request.hostconfig); +- if (ret != 0) { ++ request->name = util_strdup_s(args->name); ++ request->rootfs = util_strdup_s(args->create_rootfs); ++ request->runtime = util_strdup_s(args->runtime); ++ request->image = util_strdup_s(args->image_name); ++ ++ container_spec = request_pack_custom_conf(args); ++ if (container_spec == NULL) { ++ ret = EINVALIDARGS; ++ goto out; ++ } ++ ++ if (generate_container_config(container_spec, &request->container_spec_json) != 0) { ++ ret = EINVALIDARGS; + goto out; + } + +- ret = client_try_to_create(args, &request, &response); ++ host_spec = request_pack_host_config(args); ++ if (host_spec == NULL) { ++ ret = EINVALIDARGS; ++ goto out; ++ } ++ ++ if (generate_hostconfig(host_spec, &request->host_spec_json) != 0) { ++ ret = EINVALIDARGS; ++ goto out; ++ } ++ ++ ret = client_try_to_create(args, request, &response); + if (ret != 0) { + goto out; + } +@@ -1180,9 +1319,10 @@ int client_create(struct client_arguments *args) + goto out; + } + out: +- free_alloced_memory_in_host_config(request.hostconfig); +- free_alloced_memory_in_config(request.config); ++ isula_host_config_free(host_spec); ++ isula_container_config_free(container_spec); + isula_create_response_free(response); ++ isula_create_request_free(request); + return ret; + } + +@@ -1596,10 +1736,13 @@ static bool check_volumes_valid(const char *volume) + // volume format: src:dst:mode + switch (alen) { + case 1: ++#ifdef ENABLE_OCI_IMAGE ++ // anonymous volume, do nothing ++#else + COMMAND_ERROR("Not supported volume format '%s'", volume); + ret = false; ++#endif + goto free_out; +- /* fall-through */ + case 2: + if (util_valid_mount_mode(array[1])) { + // Destination + Mode is not a valid volume - volumes +@@ -1628,7 +1771,11 @@ static bool check_volumes_valid(const char *volume) + goto free_out; + } + ++#ifdef ENABLE_OCI_IMAGE ++ if (array[1][0] != '/' || strcmp(array[1], "/") == 0) { ++#else + if (array[0][0] != '/' || array[1][0] != '/' || strcmp(array[1], "/") == 0) { ++#endif + COMMAND_ERROR("Invalid volume: path must be absolute, and destination can't be '/'"); + ret = false; + goto free_out; +@@ -1655,276 +1802,6 @@ static bool check_volumes_conf_valid(const char *volume) + return check_volumes_valid(volume); + } + +-struct valid_mounts_state { +- char *mount; +- bool has_type; +- bool has_src; +- bool has_dst; +- bool type_squashfs; +- char *source; +-}; +- +-#define MOUNT_STATE_CHECK_SUCCESS 0 +-#define MOUNT_STATE_CHECK_IGNORE 1 +-#define MOUNT_STATE_CHECK_INVALID_ARG 2 +- +-static int parse_mount_item_type(const char *value, struct valid_mounts_state *state) +-{ +- /* If value of type is NULL, ignore it */ +- if (value == NULL) { +- return MOUNT_STATE_CHECK_IGNORE; +- } +- +- if (state->has_type) { +- COMMAND_ERROR("Invalid mount specification '%s'.More than one type found", state->mount); +- return MOUNT_STATE_CHECK_INVALID_ARG; +- } +- +- if (strcmp(value, "squashfs") && strcmp(value, "bind")) { +- COMMAND_ERROR("Invalid mount specification '%s'.Type must be squashfs or bind", state->mount); +- return MOUNT_STATE_CHECK_INVALID_ARG; +- } +- +- if (strcmp(value, "squashfs") == 0) { +- state->type_squashfs = true; +- } +- +- state->has_type = true; +- return MOUNT_STATE_CHECK_SUCCESS; +-} +- +-static int parse_mount_item_src(const char *value, struct valid_mounts_state *state) +-{ +- /* If value of source is NULL, ignore it */ +- if (value == NULL) { +- return MOUNT_STATE_CHECK_IGNORE; +- } +- +- if (state->has_src) { +- COMMAND_ERROR("Invalid mount specification '%s'.More than one source found", state->mount); +- return MOUNT_STATE_CHECK_INVALID_ARG; +- } +- +- if (value[0] != '/') { +- COMMAND_ERROR("Invalid mount specification '%s'.Source must be absolute path", state->mount); +- return MOUNT_STATE_CHECK_INVALID_ARG; +- } +- +- free(state->source); +- state->source = util_strdup_s(value); +- +- state->has_src = true; +- return MOUNT_STATE_CHECK_SUCCESS; +-} +- +-static int parse_mount_item_dst(const char *value, struct valid_mounts_state *state) +-{ +- char dstpath[PATH_MAX] = { 0 }; +- +- /* If value of destination is NULL, ignore it */ +- if (value == NULL) { +- return MOUNT_STATE_CHECK_IGNORE; +- } +- +- if (state->has_dst) { +- COMMAND_ERROR("Invalid mount specification '%s'.More than one destination found", state->mount); +- return MOUNT_STATE_CHECK_INVALID_ARG; +- } +- +- if (value[0] != '/') { +- COMMAND_ERROR("Invalid mount specification '%s'.Destination must be absolute path", state->mount); +- return MOUNT_STATE_CHECK_INVALID_ARG; +- } +- +- if (strcmp(value, "/") == 0) { +- COMMAND_ERROR("Invalid mount specification '%s'.Destination can't be '/'", state->mount); +- return MOUNT_STATE_CHECK_INVALID_ARG; +- } +- +- if (!cleanpath(value, dstpath, sizeof(dstpath))) { +- COMMAND_ERROR("Invalid mount specification '%s'.Can't translate destination path to clean path", state->mount); +- return MOUNT_STATE_CHECK_INVALID_ARG; +- } +- +- state->has_dst = true; +- return MOUNT_STATE_CHECK_SUCCESS; +-} +- +-static int parse_mount_item_ro(const char *value, const struct valid_mounts_state *state) +-{ +- if (value != NULL) { +- if (strcmp(value, "1") && strcmp(value, "true") && strcmp(value, "0") && strcmp(value, "false")) { +- COMMAND_ERROR("Invalid mount specification '%s'.Invalid readonly mode:%s", state->mount, value); +- return MOUNT_STATE_CHECK_INVALID_ARG; +- } +- } +- return MOUNT_STATE_CHECK_SUCCESS; +-} +- +-static int parse_mount_item_propagation(const char *value, const struct valid_mounts_state *state) +-{ +- if (value == NULL) { +- return MOUNT_STATE_CHECK_IGNORE; +- } +- +- if (!util_valid_propagation_mode(value)) { +- COMMAND_ERROR("Invalid mount specification '%s'.Invalid propagation mode:%s", state->mount, value); +- return MOUNT_STATE_CHECK_INVALID_ARG; +- } +- return MOUNT_STATE_CHECK_SUCCESS; +-} +- +-static int parse_mount_item_selinux(const char *value, const struct valid_mounts_state *state) +-{ +- if (value == NULL) { +- return MOUNT_STATE_CHECK_IGNORE; +- } +- +- if (!util_valid_label_mode(value)) { +- COMMAND_ERROR("Invalid mount specification '%s'.Invalid bind selinux opts:%s", state->mount, value); +- return MOUNT_STATE_CHECK_INVALID_ARG; +- } +- return MOUNT_STATE_CHECK_SUCCESS; +-} +- +-/* +- * 0: success +- * 1: ignore this item, continue +- * 2: failed +- */ +-static int valid_mounts_item(const char *mntkey, const char *value, struct valid_mounts_state *state) +-{ +- if (strcmp(mntkey, "type") == 0) { +- return parse_mount_item_type(value, state); +- } else if (strcmp(mntkey, "src") == 0 || strcmp(mntkey, "source") == 0) { +- return parse_mount_item_src(value, state); +- } else if (strcmp(mntkey, "dst") == 0 || strcmp(mntkey, "destination") == 0) { +- return parse_mount_item_dst(value, state); +- } else if (strcmp(mntkey, "ro") == 0 || strcmp(mntkey, "readonly") == 0) { +- return parse_mount_item_ro(value, state); +- } else if (strcmp(mntkey, "bind-propagation") == 0) { +- return parse_mount_item_propagation(value, state); +- } else if (strcmp(mntkey, "bind-selinux-opts") == 0) { +- return parse_mount_item_selinux(value, state); +- } else { +- COMMAND_ERROR("Invalid mount specification '%s'.Unsupported item:%s", state->mount, mntkey); +- return MOUNT_STATE_CHECK_INVALID_ARG; +- } +-} +- +-static int parse_mounts_conf(const char *mount, struct valid_mounts_state *state) +-{ +- int ret = 0; +- size_t i = 0; +- size_t items_len = 0; +- char **items = NULL; +- char **key_val = NULL; +- +- items = util_string_split(mount, ','); +- if (items == NULL) { +- ret = EINVALIDARGS; +- COMMAND_ERROR("Invalid mount specification '%s'. unsupported format", mount); +- goto out; +- } +- +- items_len = util_array_len((const char **)items); +- +- for (i = 0; i < items_len; i++) { +- key_val = util_string_split(items[i], '='); +- if (key_val == NULL) { +- continue; +- } +- +- ret = valid_mounts_item(key_val[0], key_val[1], state); +- if (ret == MOUNT_STATE_CHECK_IGNORE) { /* ignore this item */ +- ret = 0; +- util_free_array(key_val); +- key_val = NULL; +- continue; +- } else if (ret == MOUNT_STATE_CHECK_INVALID_ARG) { /* invalid args */ +- ret = EINVALIDARGS; +- goto out; +- } +- util_free_array(key_val); +- key_val = NULL; +- } +- +-out: +- util_free_array(key_val); +- util_free_array(items); +- return ret; +-} +- +-static int check_parsed_mounts_conf(const char *mount, const struct valid_mounts_state *state) +-{ +- int ret = 0; +- char real_path[PATH_MAX] = { 0 }; /* Init to zero every time loop enter here. */ +- +- if (!state->has_type) { +- ret = EINVALIDARGS; +- COMMAND_ERROR("Invalid mount specification '%s'.Missing type", mount); +- goto out; +- } +- +- if (!state->has_src) { +- ret = EINVALIDARGS; +- COMMAND_ERROR("Invalid mount specification '%s'.Missing source", mount); +- goto out; +- } +- +- if (!state->has_dst) { +- ret = EINVALIDARGS; +- COMMAND_ERROR("Invalid mount specification '%s'.Missing destination", mount); +- goto out; +- } +- +- if (state->type_squashfs) { +- if (strlen(state->source) > PATH_MAX || realpath(state->source, real_path) == NULL) { +- ret = EINVALIDARGS; +- COMMAND_ERROR("Invalid mount specification '%s'.Source %s not exist", mount, state->source); +- goto out; +- } +- +- /* Make sure it's a regular file */ +- if (!util_valid_file(real_path, S_IFREG)) { +- ret = EINVALIDARGS; +- COMMAND_ERROR("Invalid mount specification '%s'.Source %s is not a squashfs file", mount, state->source); +- goto out; +- } +- } +-out: +- return ret; +-} +- +-static bool check_mounts_conf_valid(const char *mount) +-{ +- int ret = 0; +- struct valid_mounts_state state = { (char *)mount, false, false, false, NULL }; +- +- if (mount == NULL) { +- COMMAND_ERROR("Invalid mount specification: can't be empty"); +- return false; +- } +- if (!mount[0]) { +- COMMAND_ERROR("Invalid mount specification: can't be empty"); +- return false; +- } +- +- ret = parse_mounts_conf(mount, &state); +- if (ret != 0) { +- goto out; +- } +- +- ret = check_parsed_mounts_conf(mount, &state); +- if (ret != 0) { +- goto out; +- } +- +-out: +- free(state.source); +- return ret ? false : true; +-} +- + static int check_hook_spec_file(const char *hook_spec) + { + struct stat hookstat = { 0 }; +@@ -2101,6 +1978,18 @@ out: + return ret; + } + ++static bool check_mounts_conf_valid(const char *mount_str) ++{ ++ char *errmsg = NULL; ++ ++ if (!util_valid_mount_spec(mount_str, &errmsg)) { ++ COMMAND_ERROR("%s", errmsg); ++ free(errmsg); ++ return false; ++ } ++ return true; ++} ++ + static int create_devices_volumes_checker(const struct client_arguments *args) + { + int ret = 0; +@@ -2139,7 +2028,7 @@ static int create_namespaces_checker(const struct client_arguments *args) + const char *net_mode = args->custom_conf.share_ns[NAMESPACE_NET]; + + if (args->custom_conf.share_ns[NAMESPACE_NET]) { +- if (!is_host(net_mode) && !is_container(net_mode) && !is_none(net_mode)) { ++ if (!namespace_is_host(net_mode) && !namespace_is_container(net_mode) && !namespace_is_none(net_mode)) { + COMMAND_ERROR("Unsupported network mode %s", net_mode); + ret = -1; + goto out; +@@ -2228,7 +2117,7 @@ static bool do_create_check_sysctl(const char *sysctl) + if (p != NULL) { + *p = '\0'; + if (strcmp("kernel.pid_max", sysctl) == 0) { +- if (!pid_max_kernel_namespaced()) { ++ if (!util_check_pid_max_kernel_namespaced()) { + COMMAND_ERROR("Sysctl '%s' is not kernel namespaced, it cannot be changed", sysctl); + restore_to_equate(p); + return false; +@@ -2237,7 +2126,7 @@ static bool do_create_check_sysctl(const char *sysctl) + return true; + } + } +- if (!check_sysctl_valid(sysctl)) { ++ if (!util_valid_sysctl(sysctl)) { + restore_to_equate(p); + COMMAND_ERROR("Sysctl '%s' is not whitelist", sysctl); + return false; +@@ -2286,7 +2175,7 @@ static int create_check_env_target_file(const struct client_arguments *args) + COMMAND_ERROR("external rootfs not specified"); + return 0; + } +- if (realpath_in_scope(args->external_rootfs, env_target_file, &env_path) < 0) { ++ if (util_realpath_in_scope(args->external_rootfs, env_target_file, &env_path) < 0) { + COMMAND_ERROR("env target file '%s' real path must be under '%s'", env_target_file, args->external_rootfs); + ret = -1; + goto out; +diff --git a/src/cmd/isula/base/create.h b/src/cmd/isula/base/create.h +index d8733e0..97047f7 100644 +--- a/src/cmd/isula/base/create.h ++++ b/src/cmd/isula/base/create.h +@@ -26,396 +26,445 @@ + extern "C" { + #endif + +-#define CREATE_OPTIONS(cmdargs) \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "accel", \ +- 0, \ +- &(cmdargs).custom_conf.accel, \ +- "Accelerator bindings (format: [=][@[,]])", \ +- command_append_array }, \ +- { CMD_OPT_TYPE_BOOL, \ +- false, \ +- "read-only", \ +- 0, \ +- &(cmdargs).custom_conf.readonly, \ +- "Make container rootfs readonly", \ +- NULL }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "cap-add", \ +- 0, \ +- &(cmdargs).custom_conf.cap_adds, \ +- "Add Linux capabilities ('ALL' to add all capabilities)", \ +- command_append_array }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "cap-drop", \ +- 0, \ +- &(cmdargs).custom_conf.cap_drops, \ +- "Drop Linux capabilities ('ALL' to drop all capabilities)", \ +- command_append_array }, \ +- { CMD_OPT_TYPE_CALLBACK, false, "cpu-shares", 0, &(cmdargs).cr.cpu_shares, "CPU shares (relative weight)", \ +- command_convert_llong }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "cpu-period", \ +- 0, \ +- &(cmdargs).cr.cpu_period, \ +- "Limit CPU CFS (Completely Fair Scheduler) period", \ +- command_convert_llong }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "cpu-quota", \ +- 0, \ +- &(cmdargs).cr.cpu_quota, \ +- "Limit CPU CFS (Completely Fair Scheduler) quota", \ +- command_convert_llong }, \ +- { CMD_OPT_TYPE_STRING, \ +- false, \ +- "cpuset-cpus", \ +- 0, \ +- &(cmdargs).cr.cpuset_cpus, \ +- "CPUs in which to allow execution (e.g. 0-3, 0,1)", \ +- NULL }, \ +- { CMD_OPT_TYPE_STRING, \ +- false, \ +- "cpuset-mems", \ +- 0, \ +- &(cmdargs).cr.cpuset_mems, \ +- "MEMs in which to allow execution (0-3, 0,1)", \ +- NULL }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "device-read-bps", \ +- 0, \ +- &(cmdargs).custom_conf.blkio_throttle_read_bps_device, \ +- "Limit read rate (bytes per second) from a device (default [])", \ +- command_append_array }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "device-write-bps", \ +- 0, \ +- &(cmdargs).custom_conf.blkio_throttle_write_bps_device, \ +- "Limit write rate (bytes per second) to a device (default [])", \ +- command_append_array }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "oom-score-adj", \ +- 0, \ +- &(cmdargs).cr.oom_score_adj, \ +- "Tune host's OOM preferences (-1000 to 1000)", \ +- command_convert_llong }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "device", \ +- 0, \ +- &(cmdargs).custom_conf.devices, \ +- "Add a host device to the container", \ +- command_append_array }, \ +- { CMD_OPT_TYPE_CALLBACK, false, "env", 'e', &(cmdargs).custom_conf.env, "Set environment variables", \ +- command_append_array }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "env-file", \ +- 0, \ +- &(cmdargs).custom_conf.env_file, \ +- "Read in a file of environment variables", \ +- command_append_array }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "label", \ +- 'l', \ +- &(cmdargs).custom_conf.label, \ +- "Set metadata on container (default [])", \ +- command_append_array }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "label-file", \ +- 0, \ +- &(cmdargs).custom_conf.label_file, \ +- "Read in a line delimited file of labels (default [])", \ +- command_append_array }, \ +- { CMD_OPT_TYPE_STRING_DUP, \ +- false, \ +- "entrypoint", \ +- 0, \ +- &(cmdargs).custom_conf.entrypoint, \ +- "Entrypoint to run when starting the container", \ +- NULL }, \ +- { CMD_OPT_TYPE_STRING, \ +- false, \ +- "external-rootfs", \ +- 0, \ +- &(cmdargs).external_rootfs, \ +- "Specify the custom rootfs that is not managed by isulad for the container, directory or block device", \ +- NULL }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "files-limit", \ +- 0, \ +- &(cmdargs).custom_conf.files_limit, \ +- "Tune container files limit (set -1 for unlimited)", \ +- command_convert_llong }, \ +- { CMD_OPT_TYPE_STRING_DUP, \ +- false, \ +- "hook-spec", \ +- 0, \ +- &(cmdargs).custom_conf.hook_spec, \ +- "File containing hook definition(prestart, poststart, poststop)", \ +- NULL }, \ +- { CMD_OPT_TYPE_STRING_DUP, false, "hostname", 'h', &(cmdargs).custom_conf.hostname, \ +- "Container host name", NULL }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "add-host", \ +- 0, \ +- &(cmdargs).custom_conf.extra_hosts, \ +- "Add a custom host-to-IP mapping (host:ip)", \ +- command_append_array }, \ +- { CMD_OPT_TYPE_CALLBACK, false, "dns", 0, &(cmdargs).custom_conf.dns, "Set custom DNS servers", \ +- command_append_array }, \ +- { CMD_OPT_TYPE_CALLBACK, false, "dns-opt", 0, &(cmdargs).custom_conf.dns_options, "Set DNS options", \ +- command_append_array }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "dns-search", \ +- 0, \ +- &(cmdargs).custom_conf.dns_search, \ +- "Set custom DNS search domains", \ +- command_append_array }, \ +- { CMD_OPT_TYPE_STRING, \ +- false, \ +- "user-remap", \ +- 0, \ +- &(cmdargs).custom_conf.user_remap, \ +- "Set user remap for container", \ +- NULL }, \ +- { CMD_OPT_TYPE_STRING_DUP, false, "ipc", 0, &(cmdargs).custom_conf.share_ns[NAMESPACE_IPC], \ +- "IPC namespace to use", NULL }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "shm-size", \ +- 0, \ +- &(cmdargs).custom_conf.shm_size, \ +- "Size of /dev/shm, default value is 64MB", \ +- command_convert_membytes }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "kernel-memory", \ +- 0, \ +- &(cmdargs).cr.kernel_memory_limit, \ +- "Kernel memory limit", \ +- command_convert_membytes }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "hugetlb-limit", \ +- 0, \ +- &(cmdargs).custom_conf.hugepage_limits, \ +- "Huge page limit (format: [size:], e.g. --hugetlb-limit 2MB:32MB)", \ +- command_append_array }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "log-driver", \ +- 0, \ +- &(cmdargs), \ +- "Container log driver, support syslog and json-file", \ +- callback_log_driver }, \ +- { CMD_OPT_TYPE_CALLBACK, false, "log-opt", 0, &(cmdargs), "Container log options, value formate: key=value", \ +- callback_log_opt }, \ +- { CMD_OPT_TYPE_CALLBACK, false, "memory", 'm', &(cmdargs).cr.memory_limit, "Memory limit", \ +- command_convert_membytes }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "memory-reservation", \ +- 0, \ +- &(cmdargs).cr.memory_reservation, \ +- "Memory soft limit", \ +- command_convert_membytes }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "memory-swap", \ +- 0, \ +- &(cmdargs).cr.memory_swap, \ +- "Swap limit equal to memory plus swap: '-1' to enable unlimited swap", \ +- command_convert_memswapbytes }, \ +- { CMD_OPT_TYPE_CALLBACK, false, \ +- "memory-swappiness", 0, \ +- &(cmdargs).cr.swappiness, "Tune container memory swappiness (0 to 100) (default -1)", \ +- command_convert_swappiness }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "mount", \ +- 0, \ +- &(cmdargs).custom_conf.mounts, \ +- "Attach a filesystem mount to the service", \ +- command_append_array }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "group-add", \ +- 0, \ +- &(cmdargs).custom_conf.group_add, \ +- "Add additional groups to join", \ +- command_append_array }, \ +- { CMD_OPT_TYPE_STRING_DUP, false, "name", 'n', &(cmdargs).name, "Name of the container", NULL }, \ +- { CMD_OPT_TYPE_STRING_DUP, \ +- false, \ +- "net", \ +- 0, \ +- &(cmdargs).custom_conf.share_ns[NAMESPACE_NET], \ +- "Connect a container to a network", \ +- NULL }, \ +- { CMD_OPT_TYPE_STRING_DUP, false, "pid", 0, &(cmdargs).custom_conf.share_ns[NAMESPACE_PID], \ +- "PID namespace to use", NULL }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "pids-limit", \ +- 0, \ +- &(cmdargs).custom_conf.pids_limit, \ +- "Tune container pids limit (set -1 for unlimited)", \ +- command_convert_llong }, \ +- { CMD_OPT_TYPE_BOOL, \ +- false, \ +- "privileged", \ +- 0, \ +- &(cmdargs).custom_conf.privileged, \ +- "Give extended privileges to this container", \ +- NULL }, \ +- { CMD_OPT_TYPE_BOOL, false, "tty", 't', &(cmdargs).custom_conf.tty, "Allocate a pseudo-TTY", NULL }, \ +- { CMD_OPT_TYPE_STRING, \ +- false, \ +- "restart", \ +- 0, \ +- &(cmdargs).restart, \ +- "Restart policy to apply when a container exits(no, always, on-reboot, on-failure[:max-retries])", \ +- NULL }, \ +- { CMD_OPT_TYPE_STRING, \ +- false, \ +- "host-channel", \ +- 0, \ +- &(cmdargs).host_channel, \ +- "Create share memory between host and container", \ +- NULL }, \ +- { CMD_OPT_TYPE_STRING, \ +- false, \ +- "runtime", \ +- 'R', \ +- &(cmdargs).runtime, \ +- "Runtime to use for containers(default: lcr)", \ +- NULL }, \ +- { CMD_OPT_TYPE_STRING_DUP, \ +- false, \ +- "user", \ +- 'u', \ +- &(cmdargs).custom_conf.user, \ +- "Username or UID (format: [:])", \ +- NULL }, \ +- { CMD_OPT_TYPE_STRING_DUP, false, "uts", 0, &(cmdargs).custom_conf.share_ns[NAMESPACE_UTS], \ +- "UTS namespace to use", NULL }, \ +- { CMD_OPT_TYPE_CALLBACK, false, "volume", 'v', &(cmdargs).custom_conf.volumes, "Bind mount a volume", \ +- command_append_array }, \ +- { CMD_OPT_TYPE_CALLBACK, false, "annotation", 0, &(cmdargs), "Set annotations on a container", \ +- callback_annotation }, \ +- { CMD_OPT_TYPE_STRING_DUP, \ +- false, \ +- "workdir", \ +- 0, \ +- &(cmdargs).custom_conf.workdir, \ +- "Working directory inside the container", \ +- NULL }, \ +- { CMD_OPT_TYPE_BOOL, \ +- false, \ +- "system-container", \ +- 0, \ +- &(cmdargs).custom_conf.system_container, \ +- "Extend some features only needed by running system container", \ +- NULL }, \ +- { CMD_OPT_TYPE_BOOL, false, "oom-kill-disable", 0, &(cmdargs).custom_conf.oom_kill_disable, \ +- "Disable OOM Killer", NULL }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "security-opt", \ +- 0, \ +- &(cmdargs).custom_conf.security, \ +- "Security Options (default [])", \ +- command_append_array }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "storage-opt", \ +- 0, \ +- &(cmdargs).custom_conf.storage_opts, \ +- "Storage driver options for the container", \ +- command_append_array }, \ +- { CMD_OPT_TYPE_STRING_DUP, false, "health-cmd", 0, &(cmdargs).custom_conf.health_cmd, \ +- "Command to run to check health", NULL }, \ +- { CMD_OPT_TYPE_CALLBACK, false, "sysctl", 0, &(cmdargs).custom_conf.sysctls, "Sysctl options", \ +- command_append_array }, \ +- { CMD_OPT_TYPE_STRING_DUP, \ +- false, \ +- "env-target-file", \ +- 0, \ +- &(cmdargs).custom_conf.env_target_file, \ +- "Export env to target file path in rootfs", \ +- NULL }, \ +- { CMD_OPT_TYPE_STRING_DUP, \ +- false, \ +- "cgroup-parent", \ +- 0, \ +- &(cmdargs).custom_conf.cgroup_parent, \ +- "Optional parent cgroup for the container", \ +- NULL }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "health-interval", \ +- 0, \ +- &(cmdargs).custom_conf.health_interval, \ +- "Time between running the check (ms|s|m|h) (default 30s)", \ +- command_convert_nanoseconds }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "health-retries", \ +- 0, \ +- &(cmdargs).custom_conf.health_retries, \ +- "Consecutive failures needed to report unhealthy (default 3)", \ +- command_convert_int }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "health-timeout", \ +- 0, \ +- &(cmdargs).custom_conf.health_timeout, \ +- "Maximum time to allow one check to run (ms|s|m|h) (default 30s)", \ +- command_convert_nanoseconds }, \ +- { CMD_OPT_TYPE_CALLBACK, \ +- false, \ +- "health-start-period", \ +- 0, \ +- &(cmdargs).custom_conf.health_start_period, \ +- "Start period for the container to initialize before starting health-retries countdown (ms|s|m|h) " \ +- "(default 0s)", \ +- command_convert_nanoseconds }, \ +- { CMD_OPT_TYPE_BOOL, \ +- false, \ +- "no-healthcheck", \ +- 0, \ +- &(cmdargs).custom_conf.no_healthcheck, \ +- "Disable any container-specified HEALTHCHECK", \ +- NULL }, \ +- { CMD_OPT_TYPE_BOOL, \ +- false, \ +- "health-exit-on-unhealthy", \ +- 0, \ +- &(cmdargs).custom_conf.exit_on_unhealthy, \ +- "Kill the container when it is detected to be unhealthy", \ +- NULL }, \ +- { CMD_OPT_TYPE_STRING, \ +- false, \ +- "ns-change-opt", \ +- 0, \ +- &(cmdargs).custom_conf.ns_change_opt, \ +- "Namespaced kernel param options for system container (default [])", \ +- NULL }, \ +- { CMD_OPT_TYPE_CALLBACK, false, "ulimit", 0, &(cmdargs).custom_conf.ulimits, "Ulimit options (default [])", \ +- command_append_array }, ++#define CREATE_OPTIONS(cmdargs) \ ++ { \ ++ CMD_OPT_TYPE_BOOL, \ ++ false, \ ++ "read-only", \ ++ 0, \ ++ &(cmdargs).custom_conf.readonly, \ ++ "Make container rootfs readonly", \ ++ NULL \ ++ }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "cap-add", \ ++ 0, \ ++ &(cmdargs).custom_conf.cap_adds, \ ++ "Add Linux capabilities ('ALL' to add all capabilities)", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "cap-drop", \ ++ 0, \ ++ &(cmdargs).custom_conf.cap_drops, \ ++ "Drop Linux capabilities ('ALL' to drop all capabilities)", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_CALLBACK, false, "cpu-shares", 0, &(cmdargs).cr.cpu_shares, "CPU shares (relative weight)", \ ++ command_convert_llong }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "cpu-period", \ ++ 0, \ ++ &(cmdargs).cr.cpu_period, \ ++ "Limit CPU CFS (Completely Fair Scheduler) period", \ ++ command_convert_llong }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "cpu-quota", \ ++ 0, \ ++ &(cmdargs).cr.cpu_quota, \ ++ "Limit CPU CFS (Completely Fair Scheduler) quota", \ ++ command_convert_llong }, \ ++ { CMD_OPT_TYPE_STRING, \ ++ false, \ ++ "cpuset-cpus", \ ++ 0, \ ++ &(cmdargs).cr.cpuset_cpus, \ ++ "CPUs in which to allow execution (e.g. 0-3, 0,1)", \ ++ NULL }, \ ++ { CMD_OPT_TYPE_STRING, \ ++ false, \ ++ "cpuset-mems", \ ++ 0, \ ++ &(cmdargs).cr.cpuset_mems, \ ++ "MEMs in which to allow execution (0-3, 0,1)", \ ++ NULL }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "device-read-bps", \ ++ 0, \ ++ &(cmdargs).custom_conf.blkio_throttle_read_bps_device, \ ++ "Limit read rate (bytes per second) from a device (default []),format: :[], Number is a positive integer", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "device-write-bps", \ ++ 0, \ ++ &(cmdargs).custom_conf.blkio_throttle_write_bps_device, \ ++ "Limit write rate (bytes per second) to a device (default []),format: :[], Number is a positive integer", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "oom-score-adj", \ ++ 0, \ ++ &(cmdargs).cr.oom_score_adj, \ ++ "Tune host's OOM preferences (-1000 to 1000)", \ ++ command_convert_llong }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "device", \ ++ 0, \ ++ &(cmdargs).custom_conf.devices, \ ++ "Add a host device to the container", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_CALLBACK, false, "env", 'e', &(cmdargs).custom_conf.env, "Set environment variables", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "env-file", \ ++ 0, \ ++ &(cmdargs).custom_conf.env_file, \ ++ "Read in a file of environment variables", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "label", \ ++ 'l', \ ++ &(cmdargs).custom_conf.label, \ ++ "Set metadata on container (default [])", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "label-file", \ ++ 0, \ ++ &(cmdargs).custom_conf.label_file, \ ++ "Read in a line delimited file of labels (default [])", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_STRING_DUP, \ ++ false, \ ++ "entrypoint", \ ++ 0, \ ++ &(cmdargs).custom_conf.entrypoint, \ ++ "Entrypoint to run when starting the container", \ ++ NULL }, \ ++ { CMD_OPT_TYPE_STRING, \ ++ false, \ ++ "external-rootfs", \ ++ 0, \ ++ &(cmdargs).external_rootfs, \ ++ "Specify the custom rootfs that is not managed by isulad for the container, directory or block device", \ ++ NULL }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "files-limit", \ ++ 0, \ ++ &(cmdargs).custom_conf.files_limit, \ ++ "Tune container files limit (set -1 for unlimited)", \ ++ command_convert_llong }, \ ++ { CMD_OPT_TYPE_STRING_DUP, \ ++ false, \ ++ "hook-spec", \ ++ 0, \ ++ &(cmdargs).custom_conf.hook_spec, \ ++ "File containing hook definition(prestart, poststart, poststop)", \ ++ NULL }, \ ++ { CMD_OPT_TYPE_STRING_DUP, false, "hostname", 'h', &(cmdargs).custom_conf.hostname, \ ++ "Container host name", NULL }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "add-host", \ ++ 0, \ ++ &(cmdargs).custom_conf.extra_hosts, \ ++ "Add a custom host-to-IP mapping (host:ip)", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_CALLBACK, false, "dns", 0, &(cmdargs).custom_conf.dns, "Set custom DNS servers", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_CALLBACK, false, "dns-opt", 0, &(cmdargs).custom_conf.dns_options, "Set DNS options", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "dns-search", \ ++ 0, \ ++ &(cmdargs).custom_conf.dns_search, \ ++ "Set custom DNS search domains", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_STRING, \ ++ false, \ ++ "user-remap", \ ++ 0, \ ++ &(cmdargs).custom_conf.user_remap, \ ++ "Set user remap for container", \ ++ NULL }, \ ++ { CMD_OPT_TYPE_STRING_DUP, false, "ipc", 0, &(cmdargs).custom_conf.share_ns[NAMESPACE_IPC], \ ++ "IPC namespace to use", NULL }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "shm-size", \ ++ 0, \ ++ &(cmdargs).custom_conf.shm_size, \ ++ "Size of /dev/shm, default value is 64MB", \ ++ command_convert_membytes }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "kernel-memory", \ ++ 0, \ ++ &(cmdargs).cr.kernel_memory_limit, \ ++ "Kernel memory limit", \ ++ command_convert_membytes }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "hugetlb-limit", \ ++ 0, \ ++ &(cmdargs).custom_conf.hugepage_limits, \ ++ "Huge page limit (format: [size:], e.g. --hugetlb-limit 2MB:32MB)", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "log-driver", \ ++ 0, \ ++ &(cmdargs), \ ++ "Container log driver, support syslog and json-file", \ ++ callback_log_driver }, \ ++ { CMD_OPT_TYPE_CALLBACK, false, "log-opt", 0, &(cmdargs), "Container log options, value formate: key=value", \ ++ callback_log_opt }, \ ++ { CMD_OPT_TYPE_CALLBACK, false, "memory", 'm', &(cmdargs).cr.memory_limit, "Memory limit", \ ++ command_convert_membytes }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "memory-reservation", \ ++ 0, \ ++ &(cmdargs).cr.memory_reservation, \ ++ "Memory soft limit", \ ++ command_convert_membytes }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "memory-swap", \ ++ 0, \ ++ &(cmdargs).cr.memory_swap, \ ++ "Swap limit equal to memory plus swap: '-1' to enable unlimited swap", \ ++ command_convert_memswapbytes }, \ ++ { CMD_OPT_TYPE_CALLBACK, false, \ ++ "memory-swappiness", 0, \ ++ &(cmdargs).cr.swappiness, "Tune container memory swappiness (0 to 100) (default -1)", \ ++ command_convert_swappiness }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "mount", \ ++ 0, \ ++ &(cmdargs).custom_conf.mounts, \ ++ "Attach a filesystem mount to the service", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "group-add", \ ++ 0, \ ++ &(cmdargs).custom_conf.group_add, \ ++ "Add additional groups to join", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_STRING_DUP, false, "name", 'n', &(cmdargs).name, "Name of the container", NULL }, \ ++ { CMD_OPT_TYPE_STRING_DUP, \ ++ false, \ ++ "net", \ ++ 0, \ ++ &(cmdargs).custom_conf.share_ns[NAMESPACE_NET], \ ++ "Connect a container to a network", \ ++ NULL }, \ ++ { CMD_OPT_TYPE_STRING_DUP, false, "pid", 0, &(cmdargs).custom_conf.share_ns[NAMESPACE_PID], \ ++ "PID namespace to use", NULL }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "pids-limit", \ ++ 0, \ ++ &(cmdargs).custom_conf.pids_limit, \ ++ "Tune container pids limit (set -1 for unlimited)", \ ++ command_convert_llong }, \ ++ { CMD_OPT_TYPE_BOOL, \ ++ false, \ ++ "privileged", \ ++ 0, \ ++ &(cmdargs).custom_conf.privileged, \ ++ "Give extended privileges to this container", \ ++ NULL }, \ ++ { CMD_OPT_TYPE_BOOL, false, "tty", 't', &(cmdargs).custom_conf.tty, "Allocate a pseudo-TTY", NULL }, \ ++ { CMD_OPT_TYPE_STRING, \ ++ false, \ ++ "restart", \ ++ 0, \ ++ &(cmdargs).restart, \ ++ "Restart policy to apply when a container exits(no, always, on-reboot, on-failure[:max-retries])", \ ++ NULL }, \ ++ { CMD_OPT_TYPE_STRING, \ ++ false, \ ++ "host-channel", \ ++ 0, \ ++ &(cmdargs).host_channel, \ ++ "Create share memory between host and container", \ ++ NULL }, \ ++ { CMD_OPT_TYPE_STRING, \ ++ false, \ ++ "runtime", \ ++ 'R', \ ++ &(cmdargs).runtime, \ ++ "Runtime to use for containers(default: lcr)", \ ++ NULL }, \ ++ { CMD_OPT_TYPE_STRING_DUP, \ ++ false, \ ++ "user", \ ++ 'u', \ ++ &(cmdargs).custom_conf.user, \ ++ "Username or UID (format: [:])", \ ++ NULL }, \ ++ { CMD_OPT_TYPE_STRING_DUP, false, "uts", 0, &(cmdargs).custom_conf.share_ns[NAMESPACE_UTS], \ ++ "UTS namespace to use", NULL }, \ ++ { CMD_OPT_TYPE_CALLBACK, false, "volume", 'v', &(cmdargs).custom_conf.volumes, "Bind mount a volume", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_CALLBACK, false, "volumes-from", 0, &(cmdargs).custom_conf.volumes_from, \ ++ "Mount volumes from the specified container(s)", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_CALLBACK, false, "annotation", 0, &(cmdargs), "Set annotations on a container", \ ++ callback_annotation }, \ ++ { CMD_OPT_TYPE_STRING_DUP, \ ++ false, \ ++ "workdir", \ ++ 0, \ ++ &(cmdargs).custom_conf.workdir, \ ++ "Working directory inside the container", \ ++ NULL }, \ ++ { CMD_OPT_TYPE_BOOL, \ ++ false, \ ++ "system-container", \ ++ 0, \ ++ &(cmdargs).custom_conf.system_container, \ ++ "Extend some features only needed by running system container", \ ++ NULL }, \ ++ { CMD_OPT_TYPE_BOOL, false, "oom-kill-disable", 0, &(cmdargs).custom_conf.oom_kill_disable, \ ++ "Disable OOM Killer", NULL }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "security-opt", \ ++ 0, \ ++ &(cmdargs).custom_conf.security, \ ++ "Security Options (default [])", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "storage-opt", \ ++ 0, \ ++ &(cmdargs).custom_conf.storage_opts, \ ++ "Storage driver options for the container", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_STRING_DUP, false, "health-cmd", 0, &(cmdargs).custom_conf.health_cmd, \ ++ "Command to run to check health", NULL }, \ ++ { CMD_OPT_TYPE_CALLBACK, false, "sysctl", 0, &(cmdargs).custom_conf.sysctls, "Sysctl options", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_STRING_DUP, \ ++ false, \ ++ "env-target-file", \ ++ 0, \ ++ &(cmdargs).custom_conf.env_target_file, \ ++ "Export env to target file path in rootfs", \ ++ NULL }, \ ++ { CMD_OPT_TYPE_STRING_DUP, \ ++ false, \ ++ "cgroup-parent", \ ++ 0, \ ++ &(cmdargs).custom_conf.cgroup_parent, \ ++ "Optional parent cgroup for the container", \ ++ NULL }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "health-interval", \ ++ 0, \ ++ &(cmdargs).custom_conf.health_interval, \ ++ "Time between running the check (ms|s|m|h) (default 30s)", \ ++ command_convert_nanoseconds }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "health-retries", \ ++ 0, \ ++ &(cmdargs).custom_conf.health_retries, \ ++ "Consecutive failures needed to report unhealthy (default 3)", \ ++ command_convert_int }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "health-timeout", \ ++ 0, \ ++ &(cmdargs).custom_conf.health_timeout, \ ++ "Maximum time to allow one check to run (ms|s|m|h) (default 30s)", \ ++ command_convert_nanoseconds }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "health-start-period", \ ++ 0, \ ++ &(cmdargs).custom_conf.health_start_period, \ ++ "Start period for the container to initialize before starting health-retries countdown (ms|s|m|h) " \ ++ "(default 0s)", \ ++ command_convert_nanoseconds }, \ ++ { CMD_OPT_TYPE_BOOL, \ ++ false, \ ++ "no-healthcheck", \ ++ 0, \ ++ &(cmdargs).custom_conf.no_healthcheck, \ ++ "Disable any container-specified HEALTHCHECK", \ ++ NULL }, \ ++ { CMD_OPT_TYPE_BOOL, \ ++ false, \ ++ "health-exit-on-unhealthy", \ ++ 0, \ ++ &(cmdargs).custom_conf.exit_on_unhealthy, \ ++ "Kill the container when it is detected to be unhealthy", \ ++ NULL }, \ ++ { CMD_OPT_TYPE_STRING, \ ++ false, \ ++ "ns-change-opt", \ ++ 0, \ ++ &(cmdargs).custom_conf.ns_change_opt, \ ++ "Namespaced kernel param options for system container (default [])", \ ++ NULL }, \ ++ { CMD_OPT_TYPE_CALLBACK, false, "ulimit", 0, &(cmdargs).custom_conf.ulimits, "Ulimit options (default [])", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "blkio-weight", \ ++ 0, \ ++ &(cmdargs).cr.blkio_weight, \ ++ "Block IO (relative weight), between 10 and 1000, or 0 to disable (default 0)", \ ++ command_convert_u16 }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "blkio-weight-device", \ ++ 0, \ ++ &(cmdargs).custom_conf.weight_devices, \ ++ "Block IO weight (relative device weight) (default []), format: DEVICE_NAME:WEIGHT, weight value between 10 and 1000, or 0 to disable (default 0)", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "device-read-iops", \ ++ 0, \ ++ &(cmdargs).custom_conf.blkio_throttle_read_iops_device, \ ++ "Limit read rate (IO per second) from a device (format: :),number is unsigned 64 bytes integer", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "device-write-iops", \ ++ 0, \ ++ &(cmdargs).custom_conf.blkio_throttle_write_iops_device, \ ++ "Limit write rate (IO per second) to a device (format: :),number is unsigned 64 bytes integer.", \ ++ command_append_array }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "cpu-rt-period", \ ++ 0, \ ++ &((cmdargs).cr).cpu_rt_period, \ ++ "Limit CPU real-time period in microseconds.", \ ++ command_convert_llong }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "cpu-rt-runtime", \ ++ 0, \ ++ &((cmdargs).cr).cpu_rt_runtime, \ ++ "Limit CPU real-time runtime in microseconds.", \ ++ command_convert_llong }, \ ++ { CMD_OPT_TYPE_CALLBACK, false, "cpus", 0, &((cmdargs).cr).nano_cpus, "Number of CPUs.", \ ++ command_convert_nanocpus }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "device-cgroup-rule", \ ++ 0, \ ++ &(cmdargs).custom_conf.device_cgroup_rules, \ ++ "Add a rule to the cgroup allowed devices list.", \ ++ command_convert_device_cgroup_rules }, + + #define CREATE_EXTEND_OPTIONS(cmdargs) \ + { CMD_OPT_TYPE_BOOL, \ +diff --git a/src/cmd/isula/base/kill.c b/src/cmd/isula/base/kill.c +index da1e3ce..b8e8545 100644 +--- a/src/cmd/isula/base/kill.c ++++ b/src/cmd/isula/base/kill.c +@@ -12,16 +12,16 @@ + * Create: 2018-11-08 + * Description: provide container kill functions + ******************************************************************************/ ++#include "kill.h" + #include + #include + #include + + #include "client_arguments.h" +-#include "kill.h" + #include "isula_libutils/log.h" + #include "isula_connect.h" + #include "connect.h" +-#include "libisula.h" ++ + #include "utils.h" + #include "utils_verify.h" + +diff --git a/src/cmd/isula/base/rename.c b/src/cmd/isula/base/rename.c +index 652e091..aafc9bd 100644 +--- a/src/cmd/isula/base/rename.c ++++ b/src/cmd/isula/base/rename.c +@@ -22,7 +22,6 @@ + #include "isula_connect.h" + #include "command_parser.h" + #include "connect.h" +-#include "libisula.h" + + const char g_cmd_rename_desc[] = "Rename a container"; + const char g_cmd_rename_usage[] = "rename [OPTIONS] OLD_NAME NEW_NAME"; +diff --git a/src/cmd/isula/base/restart.c b/src/cmd/isula/base/restart.c +index 2d58d33..cedfaec 100644 +--- a/src/cmd/isula/base/restart.c ++++ b/src/cmd/isula/base/restart.c +@@ -12,16 +12,15 @@ + * Create: 2018-11-08 + * Description: provide container restart functions + ******************************************************************************/ ++#include "restart.h" + #include + #include + +-#include "restart.h" + #include "client_arguments.h" + #include "isula_libutils/log.h" + #include "utils.h" + #include "isula_connect.h" + #include "connect.h" +-#include "libisula.h" + + const char g_cmd_restart_desc[] = "Restart one or more containers"; + const char g_cmd_restart_usage[] = "restart [OPTIONS] CONTAINER [CONTAINER...]"; +diff --git a/src/cmd/isula/base/rm.c b/src/cmd/isula/base/rm.c +index eeff9aa..52a715f 100644 +--- a/src/cmd/isula/base/rm.c ++++ b/src/cmd/isula/base/rm.c +@@ -12,19 +12,18 @@ + * Create: 2018-11-08 + * Description: provide container remove functions + ******************************************************************************/ ++#include "rm.h" + #include + #include + #include + +-#include "rm.h" + #include "client_arguments.h" + #include "isula_libutils/log.h" + #include "isula_connect.h" +-#include "isula_commands.h" + #include "console.h" + #include "utils.h" + #include "connect.h" +-#include "libisula.h" ++ + #include "utils_file.h" + + const char g_cmd_delete_desc[] = "Remove one or more containers"; +diff --git a/src/cmd/isula/base/run.c b/src/cmd/isula/base/run.c +index fa71abb..68058f6 100644 +--- a/src/cmd/isula/base/run.c ++++ b/src/cmd/isula/base/run.c +@@ -12,16 +12,15 @@ + * Create: 2018-11-08 + * Description: provide container run functions + ******************************************************************************/ ++#include "run.h" + #include + #include + #include +-#include // IWYU pragma: keep + #include + #include + #include + #include + +-#include "run.h" + #include "client_arguments.h" + #include "isula_libutils/log.h" + #include "utils.h" +@@ -30,7 +29,7 @@ + #include "error.h" + #include "connect.h" + #include "create.h" +-#include "libisula.h" ++ + #include "start.h" + #include "wait.h" + +@@ -175,59 +174,6 @@ out: + return ret; + } + +-static void *run_console_resize_thread(void *arg) +-{ +- int ret = 0; +- const struct client_arguments *args = arg; +- static struct winsize s_pre_wsz; +- struct winsize wsz; +- +- if (!isatty(STDIN_FILENO)) { +- goto out; +- } +- +- ret = pthread_detach(pthread_self()); +- if (ret != 0) { +- CRIT("Start: set thread detach fail"); +- goto out; +- } +- +- while (true) { +- sleep(1); // check the windows size per 1s +- ret = ioctl(STDIN_FILENO, TIOCGWINSZ, &wsz); +- if (ret < 0) { +- WARN("Failed to get window size"); +- continue; +- } +- if (wsz.ws_row == s_pre_wsz.ws_row && wsz.ws_col == s_pre_wsz.ws_col) { +- continue; +- } +- ret = do_resize_run_console(args, wsz.ws_row, wsz.ws_col); +- if (ret != 0) { +- continue; +- } +- s_pre_wsz.ws_row = wsz.ws_row; +- s_pre_wsz.ws_col = wsz.ws_col; +- } +- +-out: +- return NULL; +-} +- +-int run_client_console_resize_thread(struct client_arguments *args) +-{ +- int res = 0; +- pthread_t a_thread; +- +- res = pthread_create(&a_thread, NULL, run_console_resize_thread, (void *)(args)); +- if (res != 0) { +- CRIT("Thread creation failed"); +- return -1; +- } +- +- return 0; +-} +- + int cmd_run_main(int argc, const char **argv) + { + int ret = 0; +@@ -241,6 +187,7 @@ int cmd_run_main(int argc, const char **argv) + } + g_cmd_run_args.custom_conf.attach_stdout = true; + g_cmd_run_args.custom_conf.attach_stderr = true; ++ g_cmd_run_args.resize_cb = do_resize_run_console; + + g_cmd_run_args.progname = argv[0]; + g_cmd_run_args.subcommand = argv[1]; +@@ -270,7 +217,7 @@ int cmd_run_main(int argc, const char **argv) + } + + if (g_cmd_run_args.custom_conf.tty && isatty(STDIN_FILENO)) { +- (void)run_client_console_resize_thread(&g_cmd_run_args); ++ (void)start_client_console_resize_thread(&g_cmd_run_args); + } + + if (strncmp(g_cmd_run_args.socket, "tcp://", strlen("tcp://")) == 0) { +diff --git a/src/cmd/isula/base/start.c b/src/cmd/isula/base/start.c +index 8ed491e..023d9c9 100644 +--- a/src/cmd/isula/base/start.c ++++ b/src/cmd/isula/base/start.c +@@ -12,6 +12,7 @@ + * Create: 2018-11-08 + * Description: provide container start functions + ******************************************************************************/ ++#include "start.h" + #include + #include // IWYU pragma: keep + #include +@@ -22,7 +23,6 @@ + + #include "error.h" + #include "client_arguments.h" +-#include "start.h" + #include "isula_libutils/log.h" + #include "isula_connect.h" + #include "console.h" +@@ -30,7 +30,6 @@ + #include "isula_commands.h" + #include "command_parser.h" + #include "connect.h" +-#include "libisula.h" + + const char g_cmd_start_desc[] = "Start one or more stopped containers"; + const char g_cmd_start_usage[] = "start [OPTIONS] CONTAINER [CONTAINER...]"; +diff --git a/src/cmd/isula/base/start.h b/src/cmd/isula/base/start.h +index 112f14a..8633c9c 100644 +--- a/src/cmd/isula/base/start.h ++++ b/src/cmd/isula/base/start.h +@@ -19,7 +19,7 @@ + #include + + #include "client_arguments.h" +-#include "isula_commands.h" ++#include "client_console.h" + + #ifdef __cplusplus + extern "C" { +diff --git a/src/cmd/isula/base/stop.c b/src/cmd/isula/base/stop.c +index c4fa666..e52db79 100644 +--- a/src/cmd/isula/base/stop.c ++++ b/src/cmd/isula/base/stop.c +@@ -22,7 +22,6 @@ + #include "utils.h" + #include "isula_connect.h" + #include "connect.h" +-#include "libisula.h" + + const char g_cmd_stop_desc[] = "Stop one or more containers"; + const char g_cmd_stop_usage[] = "stop [OPTIONS] CONTAINER [CONTAINER...]"; +diff --git a/src/cmd/isula/client_arguments.c b/src/cmd/isula/client_arguments.c +index 7160ea7..ad6ba40 100644 +--- a/src/cmd/isula/client_arguments.c ++++ b/src/cmd/isula/client_arguments.c +@@ -148,6 +148,9 @@ void client_arguments_free(struct client_arguments *args) + return; + } + ++ util_free_sensitive_string(args->username); ++ util_free_sensitive_string(args->password); ++ + free(args->name); + args->name = NULL; + +@@ -238,6 +241,21 @@ void client_arguments_free(struct client_arguments *args) + + free(args->key_file); + args->key_file = NULL; ++ ++ util_free_array(custom_conf->blkio_throttle_read_bps_device); ++ custom_conf->blkio_throttle_read_bps_device = NULL; ++ ++ util_free_array(custom_conf->blkio_throttle_write_bps_device); ++ custom_conf->blkio_throttle_write_bps_device = NULL; ++ ++ util_free_array(custom_conf->blkio_throttle_read_iops_device); ++ custom_conf->blkio_throttle_read_iops_device = NULL; ++ ++ util_free_array(custom_conf->blkio_throttle_write_iops_device); ++ custom_conf->blkio_throttle_write_iops_device = NULL; ++ ++ util_free_array(custom_conf->device_cgroup_rules); ++ custom_conf->device_cgroup_rules = NULL; + } + + /* print common help */ +diff --git a/src/cmd/isula/client_arguments.h b/src/cmd/isula/client_arguments.h +index ccd7b03..58c5af2 100644 +--- a/src/cmd/isula/client_arguments.h ++++ b/src/cmd/isula/client_arguments.h +@@ -20,6 +20,8 @@ + #include + #include + #include ++#include // IWYU pragma: keep ++#include + + #include "command_parser.h" + #include "isula_libutils/json_common.h" +@@ -34,6 +36,8 @@ extern "C" { + /* max arguments can be specify in client */ + #define MAX_CLIENT_ARGS 1000 + ++#define CLIENT_RUNDIR "/var/run/isula" ++ + struct client_arguments; + struct custom_configs; + +@@ -59,6 +63,9 @@ struct custom_configs { + /* hook-spec file */ + char *hook_spec; + ++ /* volumes-from container(s) */ ++ char **volumes_from; ++ + /* volumes to mount */ + char **volumes; + +@@ -183,9 +190,6 @@ struct custom_configs { + /* oom kill disable */ + bool oom_kill_disable; + +- /* create/run accel options */ +- char **accel; +- + /* env target file */ + char *env_target_file; + +@@ -197,6 +201,15 @@ struct custom_configs { + + /* device write bps */ + char **blkio_throttle_write_bps_device; ++ ++ /* device read iops */ ++ char **blkio_throttle_read_iops_device; ++ ++ /* device write iops */ ++ char **blkio_throttle_write_iops_device; ++ ++ /* device cgroup rules */ ++ char **device_cgroup_rules; + }; + + struct args_cgroup_resources { +@@ -214,8 +227,13 @@ struct args_cgroup_resources { + int64_t memory_reservation; + int64_t kernel_memory_limit; + int64_t swappiness; ++ int64_t nano_cpus; + }; + ++struct client_arguments; ++ ++typedef int (*do_resize_call_back_t)(const struct client_arguments *args, unsigned int height, unsigned int width); ++ + struct client_arguments { + const char *progname; /* main progname name */ + const char *subcommand; /* sub command name */ +@@ -283,6 +301,7 @@ struct client_arguments { + + // logs + bool follow; ++ bool timestamps; + /* + * tail < 0: show all logs + * tail = 0: do not show log +@@ -325,6 +344,9 @@ struct client_arguments { + char *ca_file; + char *cert_file; + char *key_file; ++ ++ do_resize_call_back_t resize_cb; ++ struct winsize s_pre_wsz; + }; + + #define LOG_OPTIONS(log) { CMD_OPT_TYPE_BOOL_FALSE, false, "debug", 'D', &(log).quiet, "Enable debug mode", NULL }, +diff --git a/src/cmd/isula/client_console.c b/src/cmd/isula/client_console.c +new file mode 100644 +index 0000000..d6d82f7 +--- /dev/null ++++ b/src/cmd/isula/client_console.c +@@ -0,0 +1,319 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2017-2019. 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: lifeng ++ * Create: 2020-10-20 ++ * Description: provide container command functions ++ ******************************************************************************/ ++#include "client_console.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "client_arguments.h" ++#include "isula_libutils/log.h" ++#include "utils.h" ++#include "console.h" ++#include "utils_file.h" ++ ++/* free command fifo names */ ++void free_command_fifo_config(struct command_fifo_config *fifos) ++{ ++ if (fifos != NULL) { ++ if (fifos->stdin_path != NULL) { ++ free(fifos->stdin_path); ++ fifos->stdin_path = NULL; ++ } ++ if (fifos->stdout_path != NULL) { ++ free(fifos->stdout_path); ++ fifos->stdout_path = NULL; ++ } ++ if (fifos->stderr_path != NULL) { ++ free(fifos->stderr_path); ++ fifos->stderr_path = NULL; ++ } ++ if (fifos->stdin_name != NULL) { ++ free(fifos->stdin_name); ++ fifos->stdin_name = NULL; ++ } ++ if (fifos->stdout_name != NULL) { ++ free(fifos->stdout_name); ++ fifos->stdout_name = NULL; ++ } ++ if (fifos->stderr_name != NULL) { ++ free(fifos->stderr_name); ++ fifos->stderr_name = NULL; ++ } ++ free(fifos); ++ } ++} ++ ++/* delete command fifo */ ++void delete_command_fifo(struct command_fifo_config *fifos) ++{ ++ int ret; ++ ++ if (fifos == NULL) { ++ return; ++ } ++ ++ ret = console_fifo_delete(fifos->stdin_name); ++ if (ret) { ++ WARN("Delete fifo failed: %s", fifos->stdin_name); ++ } ++ ret = console_fifo_delete(fifos->stdout_name); ++ if (ret) { ++ WARN("Delete fifo failed: %s", fifos->stdout_name); ++ } ++ ret = console_fifo_delete(fifos->stderr_name); ++ if (ret) { ++ WARN("Delete fifo failed: %s", fifos->stderr_name); ++ } ++ ret = util_recursive_rmdir(fifos->stdin_path, 0); ++ if (ret) { ++ WARN("Remove directory failed: %s", fifos->stdin_path); ++ } ++ ret = util_recursive_rmdir(fifos->stdout_path, 0); ++ if (ret) { ++ WARN("Remove directory failed: %s", fifos->stdout_path); ++ } ++ ret = util_recursive_rmdir(fifos->stderr_path, 0); ++ if (ret) { ++ WARN("Remove directory failed: %s", fifos->stderr_path); ++ } ++ ++ free_command_fifo_config(fifos); ++} ++ ++static int do_create_console_fifo(const char *subpath, const char *stdflag, char **out_fifo_dir, char **out_fifo_name) ++{ ++ int ret = 0; ++ char fifo_dir[PATH_MAX] = { 0 }; ++ char fifo_name[PATH_MAX] = { 0 }; ++ ++ ret = console_fifo_name(CLIENT_RUNDIR, subpath, stdflag, fifo_name, sizeof(fifo_name), fifo_dir, sizeof(fifo_dir), ++ true); ++ if (ret != 0) { ++ ERROR("Failed to get console fifo name."); ++ ret = -1; ++ goto out; ++ } ++ ++ if (console_fifo_create(fifo_name)) { ++ ERROR("Failed to create console fifo."); ++ ret = -1; ++ goto out; ++ } ++ ++ *out_fifo_dir = util_strdup_s(fifo_dir); ++ *out_fifo_name = util_strdup_s(fifo_name); ++ ++out: ++ return ret; ++} ++ ++int create_console_fifos(bool attach_stdin, bool attach_stdout, bool attach_stderr, const char *name, const char *type, ++ struct command_fifo_config **pconsole_fifos) ++{ ++ int ret = 0; ++ char subpath[PATH_MAX] = { 0 }; ++ struct command_fifo_config *fifos = NULL; ++ ++ fifos = util_common_calloc_s(sizeof(struct command_fifo_config)); ++ if (fifos == NULL) { ++ ERROR("Failed to malloc memory for FIFO names."); ++ return -1; ++ } ++ ++ ret = snprintf(subpath, sizeof(subpath), "%s/%s-%u-%u", name, type, (unsigned int)getpid(), ++ (unsigned int)pthread_self()); ++ if (ret < 0 || (size_t)ret >= sizeof(subpath)) { ++ ERROR("Path is too long"); ++ goto cleanup; ++ } ++ ++ if (attach_stdin) { ++ ret = do_create_console_fifo(subpath, "in", &fifos->stdin_path, &fifos->stdin_name); ++ if (ret != 0) { ++ goto cleanup; ++ } ++ INFO("FIFO:%s create for start success.", fifos->stdin_name); ++ } ++ ++ if (attach_stdout) { ++ ret = do_create_console_fifo(subpath, "out", &fifos->stdout_path, &fifos->stdout_name); ++ if (ret != 0) { ++ goto cleanup; ++ } ++ INFO("FIFO:%s create for start success.", fifos->stdout_name); ++ } ++ ++ if (attach_stderr) { ++ ret = do_create_console_fifo(subpath, "err", &fifos->stderr_path, &fifos->stderr_name); ++ if (ret != 0) { ++ goto cleanup; ++ } ++ INFO("FIFO:%s create for start success.", fifos->stderr_name); ++ } ++ ++ *pconsole_fifos = fifos; ++ return 0; ++ ++cleanup: ++ console_fifo_delete(fifos->stdin_name); ++ console_fifo_delete(fifos->stdout_name); ++ console_fifo_delete(fifos->stderr_name); ++ free_command_fifo_config(fifos); ++ return -1; ++} ++ ++struct console_loop_thread_args { ++ struct command_fifo_config *fifo_config; ++ bool tty; ++}; ++ ++static void *client_console_loop_thread(void *arg) ++{ ++ int ret = 0; ++ int fifoinfd = -1; ++ int fifooutfd = -1; ++ int fifoerrfd = -1; ++ const struct console_loop_thread_args *args = arg; ++ bool tty = args->tty; ++ struct command_fifo_config *fifo_config = args->fifo_config; ++ sem_t *wait_open = fifo_config->wait_open; ++ sem_t *wait_exit = fifo_config->wait_exit; ++ ++ ret = pthread_detach(pthread_self()); ++ if (ret != 0) { ++ CRIT("Start: set thread detach fail"); ++ goto err1; ++ } ++ ++ if (fifo_config->stdin_name) { ++ if (console_fifo_open_withlock(fifo_config->stdin_name, &fifoinfd, O_RDWR | O_NONBLOCK)) { ++ ERROR("Start: failed to open console fifo."); ++ goto err2; ++ } ++ INFO("FIFO:%s open success for start.", fifo_config->stdin_name); ++ } ++ ++ if (fifo_config->stdout_name) { ++ if (console_fifo_open(fifo_config->stdout_name, &fifooutfd, O_RDONLY | O_NONBLOCK)) { ++ ERROR("Failed to open console fifo."); ++ goto err2; ++ } ++ INFO("FIFO:%s open success for start.", fifo_config->stdout_name); ++ } ++ ++ if (fifo_config->stderr_name) { ++ if (console_fifo_open(fifo_config->stderr_name, &fifoerrfd, O_RDONLY | O_NONBLOCK)) { ++ ERROR("Start: failed to open console fifo."); ++ goto err2; ++ } ++ INFO("FIFO:%s open success for start.", fifo_config->stderr_name); ++ } ++ ++ sem_post(wait_open); ++ console_loop_with_std_fd(0, 1, 2, fifoinfd, fifooutfd, fifoerrfd, 1, tty); ++ ++err2: ++ if (fifoinfd >= 0) { ++ console_fifo_close(fifoinfd); ++ } ++ if (fifooutfd >= 0) { ++ console_fifo_close(fifooutfd); ++ } ++ if (fifoerrfd >= 0) { ++ console_fifo_close(fifoerrfd); ++ } ++err1: ++ sem_post(wait_open); ++ sem_post(wait_exit); ++ return NULL; ++} ++ ++int start_client_console_thread(struct command_fifo_config *console_fifos, bool tty) ++{ ++ int res = 0; ++ pthread_t a_thread; ++ struct console_loop_thread_args args; ++ ++ args.fifo_config = console_fifos; ++ args.tty = tty; ++ res = pthread_create(&a_thread, NULL, client_console_loop_thread, (void *)(&args)); ++ if (res != 0) { ++ CRIT("Thread creation failed"); ++ return -1; ++ } ++ ++ sem_wait(console_fifos->wait_open); ++ ++ return 0; ++} ++ ++static void *client_console_resize_thread(void *arg) ++{ ++ int ret = 0; ++ struct client_arguments *args = arg; ++ struct winsize wsz = { 0 }; ++ ++ if (!isatty(STDIN_FILENO)) { ++ goto out; ++ } ++ ++ ret = pthread_detach(pthread_self()); ++ if (ret != 0) { ++ CRIT("Start: set thread detach fail"); ++ goto out; ++ } ++ ++ while (true) { ++ sleep(1); // check the windows size per 1s ++ ret = ioctl(STDIN_FILENO, TIOCGWINSZ, &wsz); ++ if (ret < 0) { ++ WARN("Failed to get window size"); ++ continue; ++ } ++ if (wsz.ws_row == args->s_pre_wsz.ws_row && wsz.ws_col == args->s_pre_wsz.ws_col) { ++ continue; ++ } ++ if (args->resize_cb != NULL) { ++ ret = args->resize_cb(args, wsz.ws_row, wsz.ws_col); ++ if (ret != 0) { ++ continue; ++ } ++ args->s_pre_wsz.ws_row = wsz.ws_row; ++ args->s_pre_wsz.ws_col = wsz.ws_col; ++ } ++ } ++ ++out: ++ return NULL; ++} ++ ++int start_client_console_resize_thread(struct client_arguments *args) ++{ ++ int res = 0; ++ pthread_t a_thread; ++ ++ res = pthread_create(&a_thread, NULL, client_console_resize_thread, (void *)(args)); ++ if (res != 0) { ++ CRIT("Thread creation failed"); ++ return -1; ++ } ++ ++ return 0; ++} +\ No newline at end of file +diff --git a/src/cmd/isula/client_console.h b/src/cmd/isula/client_console.h +new file mode 100644 +index 0000000..c264820 +--- /dev/null ++++ b/src/cmd/isula/client_console.h +@@ -0,0 +1,52 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2017-2019. 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: lifeng ++ * Create: 2020-10-20 ++ * Description: provide client console functions ++ ******************************************************************************/ ++#ifndef CMD_ISULA_CLIENT_CONSOLE_H ++#define CMD_ISULA_CLIENT_CONSOLE_H ++ ++#include ++#include ++#include "client_arguments.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++struct command_fifo_config { ++ char *stdin_path; ++ char *stdout_path; ++ char *stderr_path; ++ char *stdin_name; ++ char *stdout_name; ++ char *stderr_name; ++ sem_t *wait_open; ++ sem_t *wait_exit; ++}; ++ ++int create_console_fifos(bool attach_stdin, bool attach_stdout, bool attach_stderr, const char *name, const char *type, ++ struct command_fifo_config **pconsole_fifos); ++ ++int start_client_console_thread(struct command_fifo_config *console_fifos, bool tty); ++ ++void free_command_fifo_config(struct command_fifo_config *fifos); ++ ++void delete_command_fifo(struct command_fifo_config *fifos); ++ ++int start_client_console_resize_thread(struct client_arguments *args); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif // CMD_ISULA_ISULA_COMMANDS_H +diff --git a/src/cmd/isula/extend/events.c b/src/cmd/isula/extend/events.c +index 3040e28..9dbd777 100644 +--- a/src/cmd/isula/extend/events.c ++++ b/src/cmd/isula/extend/events.c +@@ -12,17 +12,17 @@ + * Create: 2018-11-08 + * Description: provide container events functions + ******************************************************************************/ ++#include "events.h" + #include + #include + #include + + #include "error.h" +-#include "events.h" + #include "client_arguments.h" + #include "isula_libutils/log.h" + #include "isula_connect.h" + #include "connect.h" +-#include "libisula.h" ++ + #include "utils.h" + #include "utils_timestamp.h" + +@@ -124,7 +124,7 @@ err_out: + + static void print_events_callback(const container_events_format_t *event) + { +- char timebuffer[512] = { 0 }; ++ char timebuffer[TIME_STR_SIZE] = { 0 }; + char *msg = NULL; + size_t msg_len = 0; + +@@ -132,7 +132,7 @@ static void print_events_callback(const container_events_format_t *event) + return; + } + +- if (!get_time_buffer(&(event->timestamp), timebuffer, sizeof(timebuffer))) { ++ if (!util_get_time_buffer(&(event->timestamp), timebuffer, sizeof(timebuffer))) { + (void)strcpy(timebuffer, "-"); + } + +@@ -176,13 +176,13 @@ static int client_event(struct client_arguments *args) + goto out; + } + +- if (args->since && !get_timestamp(args->since, &request.since)) { ++ if (args->since && !util_get_timestamp(args->since, &request.since)) { + COMMAND_ERROR("Failed to get since timestamp"); + ret = -1; + goto out; + } + +- if (args->until && !get_timestamp(args->until, &request.until)) { ++ if (args->until && !util_get_timestamp(args->until, &request.until)) { + COMMAND_ERROR("Failed to get until timestamp"); + ret = -1; + goto out; +diff --git a/src/cmd/isula/extend/export.c b/src/cmd/isula/extend/export.c +index fd3bb4d..476cf77 100644 +--- a/src/cmd/isula/extend/export.c ++++ b/src/cmd/isula/extend/export.c +@@ -26,7 +26,6 @@ + #include "isula_libutils/log.h" + #include "isula_connect.h" + #include "connect.h" +-#include "libisula.h" + + const char g_cmd_export_desc[] = "export container"; + const char g_cmd_export_usage[] = "export [command options] [ID|NAME]"; +diff --git a/src/cmd/isula/extend/pause.c b/src/cmd/isula/extend/pause.c +index f4db507..4d508e7 100644 +--- a/src/cmd/isula/extend/pause.c ++++ b/src/cmd/isula/extend/pause.c +@@ -24,7 +24,6 @@ + #include "isula_connect.h" + #include "command_parser.h" + #include "connect.h" +-#include "libisula.h" + + const char g_cmd_pause_desc[] = "Pause all processes within one or more containers"; + const char g_cmd_pause_usage[] = "pause [OPTIONS] CONTAINER [CONTAINER...]"; +diff --git a/src/cmd/isula/extend/resume.c b/src/cmd/isula/extend/resume.c +index 0a020b6..c3c4376 100644 +--- a/src/cmd/isula/extend/resume.c ++++ b/src/cmd/isula/extend/resume.c +@@ -24,7 +24,6 @@ + #include "isula_connect.h" + #include "command_parser.h" + #include "connect.h" +-#include "libisula.h" + + const char g_cmd_resume_desc[] = "Unpause all processes within one or more containers"; + const char g_cmd_resume_usage[] = "unpause [OPTIONS] CONTAINER [CONTAINER...]"; +diff --git a/src/cmd/isula/extend/stats.c b/src/cmd/isula/extend/stats.c +index da0ce03..655332b 100644 +--- a/src/cmd/isula/extend/stats.c ++++ b/src/cmd/isula/extend/stats.c +@@ -13,6 +13,7 @@ + * Description: provide container stats functions + ******************************************************************************/ + #define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */ ++#include "stats.h" + #include + #include + #include +@@ -21,12 +22,10 @@ + #include + + #include "client_arguments.h" +-#include "stats.h" + #include "utils.h" + #include "isula_libutils/log.h" + #include "isula_connect.h" + #include "connect.h" +-#include "libisula.h" + + #define ESC "\033" + #define TERMCLEAR ESC "[H" ESC "[J" +@@ -140,8 +139,8 @@ static void stats_print(const struct isula_container_info *stats) + static void stats_print_original_data_header(void) + { + printf("%-16s %-10s %-10s %-20s %-20s %-15s %-15s %-15s %-15s %-15s %-15s %-15s %-40s", "ID", "PIDS", "Status", +- "CpuUseNanos", "CpuSystemUse", "OnlineCpus", "BlkioRead", "BlkioWrite", "MemUsed", "MemLimit", +- "KmemUsed", "CacheUsage", "NAME"); ++ "CpuUseNanos", "CpuSystemUse", "OnlineCpus", "BlkioRead", "BlkioWrite", "MemUsed", "MemLimit", "KmemUsed", ++ "CacheUsage", "NAME"); + printf("\n"); + } + +@@ -157,8 +156,8 @@ static void stats_print_original_data(const struct isula_container_info *stats) + + printf("%-16s %-10llu %-10s %-20lu %-20lu %-15u %-15lu %-15lu %-15lu %-15lu %-15lu %-15lu %-40s", short_id, + (unsigned long long)stats->pids_current, stats->status, stats->cpu_use_nanos, stats->cpu_system_use, +- stats->online_cpus, stats->blkio_read, stats->blkio_write, stats->mem_used, stats->mem_limit, stats->kmem_used, +- stats->cache, stats->name); ++ stats->online_cpus, stats->blkio_read, stats->blkio_write, stats->mem_used, stats->mem_limit, ++ stats->kmem_used, stats->cache, stats->name); + + free(short_id); + } +diff --git a/src/cmd/isula/extend/update.c b/src/cmd/isula/extend/update.c +index 84240a1..da472b0 100644 +--- a/src/cmd/isula/extend/update.c ++++ b/src/cmd/isula/extend/update.c +@@ -12,17 +12,18 @@ + * Create: 2018-11-08 + * Description: provide container update functions + ******************************************************************************/ +-#include ++#include "update.h" ++ + #include + #include + + #include "client_arguments.h" +-#include "update.h" + #include "utils.h" + #include "isula_libutils/log.h" + #include "isula_connect.h" + #include "connect.h" +-#include "libisula.h" ++ ++#include "isula_host_spec.h" + + const char g_cmd_update_desc[] = "Update configuration of one or more containers"; + const char g_cmd_update_usage[] = "update [OPTIONS] CONTAINER [CONTAINER...]"; +@@ -31,57 +32,88 @@ struct client_arguments g_cmd_update_args = { + .restart = NULL, + }; + +-static int pack_update_request(const struct client_arguments *args, struct isula_update_request *request) ++static isula_host_config_t *pack_update_request(const struct client_arguments *args) + { +- int ret = 0; ++ isula_host_config_t *host_config = NULL; + +- request->updateconfig->restart_policy = args->restart; ++ host_config = util_common_calloc_s(sizeof(isula_host_config_t)); ++ if (host_config == NULL) { ++ COMMAND_ERROR("Memeory out"); ++ goto error_out; ++ } ++ host_config->restart_policy = util_strdup_s(args->restart); + +- request->updateconfig->cr->blkio_weight = args->cr.blkio_weight; ++ host_config->cr = util_common_calloc_s(sizeof(container_cgroup_resources_t)); ++ if (host_config->cr == NULL) { ++ COMMAND_ERROR("Memeory out"); ++ goto error_out; ++ } + +- request->updateconfig->cr->cpu_shares = args->cr.cpu_shares; ++ host_config->cr->blkio_weight = args->cr.blkio_weight; + +- request->updateconfig->cr->cpu_period = args->cr.cpu_period; ++ host_config->cr->nano_cpus = args->cr.nano_cpus; + +- request->updateconfig->cr->cpu_quota = args->cr.cpu_quota; ++ host_config->cr->cpu_shares = args->cr.cpu_shares; + +- request->updateconfig->cr->cpuset_cpus = args->cr.cpuset_cpus; ++ host_config->cr->cpu_period = args->cr.cpu_period; + +- request->updateconfig->cr->cpuset_mems = args->cr.cpuset_mems; ++ host_config->cr->cpu_quota = args->cr.cpu_quota; + +- request->updateconfig->cr->memory = args->cr.memory_limit; ++ host_config->cr->cpu_realtime_period = args->cr.cpu_rt_period; + +- request->updateconfig->cr->memory_swap = args->cr.memory_swap; ++ host_config->cr->cpu_realtime_runtime = args->cr.cpu_rt_runtime; + +- request->updateconfig->cr->memory_reservation = args->cr.memory_reservation; ++ host_config->cr->cpuset_cpus = util_strdup_s(args->cr.cpuset_cpus); + +- request->updateconfig->cr->kernel_memory = args->cr.kernel_memory_limit; ++ host_config->cr->cpuset_mems = util_strdup_s(args->cr.cpuset_mems); + +- return ret; ++ host_config->cr->memory = args->cr.memory_limit; ++ ++ host_config->cr->memory_swap = args->cr.memory_swap; ++ ++ host_config->cr->memory_reservation = args->cr.memory_reservation; ++ ++ host_config->cr->kernel_memory = args->cr.kernel_memory_limit; ++ ++ return host_config; ++ ++error_out: ++ isula_host_config_free(host_config); ++ return NULL; + } + + static int client_update(const struct client_arguments *args) + { + int ret = 0; + isula_connect_ops *ops = NULL; +- container_cgroup_resources_t cr = { 0 }; +- isula_update_config_t updateconfig = { 0 }; +- struct isula_update_request request = { 0 }; ++ isula_host_config_t *host_spec = NULL; ++ struct isula_update_request *request = NULL; + struct isula_update_response *response = NULL; + client_connect_config_t config = { 0 }; + ++ request = util_common_calloc_s(sizeof(struct isula_update_request)); ++ if (request == NULL) { ++ ERROR("Out of memory"); ++ ret = -1; ++ goto out; ++ } ++ + response = util_common_calloc_s(sizeof(struct isula_update_response)); + if (response == NULL) { + ERROR("Out of memory"); +- return -1; ++ ret = -1; ++ goto out; + } + +- updateconfig.cr = &cr; +- request.updateconfig = &updateconfig; +- request.name = args->name; ++ request->name = util_strdup_s(args->name); + +- ret = pack_update_request(args, &request); +- if (ret) { ++ host_spec = pack_update_request(args); ++ if (host_spec == NULL) { ++ ret = -1; ++ goto out; ++ } ++ ++ if (generate_hostconfig(host_spec, &request->host_spec_json) != 0) { + ret = -1; + goto out; + } +@@ -94,13 +126,15 @@ static int client_update(const struct client_arguments *args) + } + + config = get_connect_config(args); +- ret = ops->container.update(&request, response, &config); ++ ret = ops->container.update(request, response, &config); + if (ret) { + client_print_error(response->cc, response->server_errono, response->errmsg); + goto out; + } + + out: ++ isula_host_config_free(host_spec); ++ isula_update_request_free(request); + isula_update_response_free(response); + return ret; + } +@@ -111,8 +145,8 @@ int cmd_update_main(int argc, const char **argv) + int i = 0; + struct isula_libutils_log_config lconf = { 0 }; + command_t cmd; +- struct command_option options[] = { LOG_OPTIONS(lconf) UPDATE_OPTIONS(g_cmd_update_args), +- COMMON_OPTIONS(g_cmd_update_args) ++ struct command_option options[] = { LOG_OPTIONS(lconf) UPDATE_OPTIONS(g_cmd_update_args) ++ COMMON_OPTIONS(g_cmd_update_args) + }; + + isula_libutils_default_log_config(argv[0], &lconf); +diff --git a/src/cmd/isula/extend/update.h b/src/cmd/isula/extend/update.h +index 361f10b..a527b46 100644 +--- a/src/cmd/isula/extend/update.h ++++ b/src/cmd/isula/extend/update.h +@@ -79,10 +79,36 @@ extern "C" { + &(cmdargs).cr.memory_swap, \ + "Swap limit equal to memory plus swap: '-1' to enable unlimited swap", \ + command_convert_memswapbytes }, \ +- { \ +- CMD_OPT_TYPE_STRING, false, "restart", 0, &(cmdargs).restart, \ +- "Restart policy to apply when a container exits", NULL \ +- } ++ { CMD_OPT_TYPE_STRING, \ ++ false, \ ++ "restart", \ ++ 0, \ ++ &(cmdargs).restart, \ ++ "Restart policy to apply when a container exits", \ ++ NULL }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "blkio-weight", \ ++ 0, \ ++ &(cmdargs).cr.blkio_weight, \ ++ "Block IO (relative weight), between 10 and 1000, or 0 to disable (default 0)", \ ++ command_convert_u16 }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "cpu-rt-period", \ ++ 0, \ ++ &((cmdargs).cr).cpu_rt_period, \ ++ "Limit CPU real-time period in microseconds.", \ ++ command_convert_llong }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "cpu-rt-runtime", \ ++ 0, \ ++ &((cmdargs).cr).cpu_rt_runtime, \ ++ "Limit CPU real-time runtime in microseconds.", \ ++ command_convert_llong }, \ ++ { CMD_OPT_TYPE_CALLBACK, false, "cpus", 0, &((cmdargs).cr).nano_cpus, "Number of CPUs.", \ ++ command_convert_nanocpus }, + + extern const char g_cmd_update_desc[]; + extern const char g_cmd_update_usage[]; +diff --git a/src/cmd/isula/images/images.c b/src/cmd/isula/images/images.c +index c028bc7..f60e750 100644 +--- a/src/cmd/isula/images/images.c ++++ b/src/cmd/isula/images/images.c +@@ -28,7 +28,7 @@ + #include "isula_libutils/log.h" + #include "command_parser.h" + #include "connect.h" +-#include "libisula.h" ++ + #include "utils_array.h" + #include "utils_file.h" + #include "utils_verify.h" +diff --git a/src/cmd/isula/images/import.c b/src/cmd/isula/images/import.c +index 5d84274..2dcc648 100644 +--- a/src/cmd/isula/images/import.c ++++ b/src/cmd/isula/images/import.c +@@ -27,7 +27,7 @@ + #include "isula_libutils/log.h" + #include "command_parser.h" + #include "connect.h" +-#include "libisula.h" ++ + #include "utils_verify.h" + + const char g_cmd_import_desc[] = "Import the contents from a tarball to create a filesystem image"; +diff --git a/src/cmd/isula/images/load.c b/src/cmd/isula/images/load.c +index c804ebf..343d8d6 100644 +--- a/src/cmd/isula/images/load.c ++++ b/src/cmd/isula/images/load.c +@@ -26,7 +26,6 @@ + #include "isula_connect.h" + #include "isula_libutils/log.h" + #include "connect.h" +-#include "libisula.h" + + #ifdef ENABLE_EMBEDDED_IMAGE + const char g_cmd_load_desc[] = "load an image from a manifest or a tar archive"; +diff --git a/src/cmd/isula/images/login.c b/src/cmd/isula/images/login.c +index 32d6ea9..9255035 100644 +--- a/src/cmd/isula/images/login.c ++++ b/src/cmd/isula/images/login.c +@@ -24,7 +24,6 @@ + #include "isula_connect.h" + #include "isula_libutils/log.h" + #include "connect.h" +-#include "libisula.h" + + const char g_cmd_login_desc[] = "Log in to a Docker registry"; + const char g_cmd_login_usage[] = "login [OPTIONS] SERVER"; +@@ -216,6 +215,8 @@ int cmd_login_main(int argc, const char **argv) + } + + ret = client_login(&g_cmd_login_args); ++ util_free_sensitive_string(g_cmd_login_args.username); ++ util_free_sensitive_string(g_cmd_login_args.password); + if (ret != 0) { + exit(exit_code); + } +diff --git a/src/cmd/isula/images/login.h b/src/cmd/isula/images/login.h +index dad619a..5f9a676 100644 +--- a/src/cmd/isula/images/login.h ++++ b/src/cmd/isula/images/login.h +@@ -25,8 +25,8 @@ extern "C" { + #endif + + #define LOGIN_OPTIONS(cmdargs) \ +- { CMD_OPT_TYPE_STRING, false, "username", 'u', &(cmdargs).username, "Username", NULL }, \ +- { CMD_OPT_TYPE_STRING, false, "password", 'p', &(cmdargs).password, "Password", NULL }, \ ++ { CMD_OPT_TYPE_STRING_DUP, false, "username", 'u', &(cmdargs).username, "Username", NULL }, \ ++ { CMD_OPT_TYPE_STRING_DUP, false, "password", 'p', &(cmdargs).password, "Password", NULL }, \ + { CMD_OPT_TYPE_BOOL, \ + false, \ + "password-stdin", \ +diff --git a/src/cmd/isula/images/logout.c b/src/cmd/isula/images/logout.c +index 12645d4..8efec1e 100644 +--- a/src/cmd/isula/images/logout.c ++++ b/src/cmd/isula/images/logout.c +@@ -23,7 +23,6 @@ + #include "isula_libutils/log.h" + #include "command_parser.h" + #include "connect.h" +-#include "libisula.h" + + const char g_cmd_logout_desc[] = "Log out from a Docker registry"; + const char g_cmd_logout_usage[] = "logout SERVER"; +diff --git a/src/cmd/isula/images/pull.c b/src/cmd/isula/images/pull.c +index fff8898..b72b030 100644 +--- a/src/cmd/isula/images/pull.c ++++ b/src/cmd/isula/images/pull.c +@@ -23,7 +23,6 @@ + #include "isula_libutils/log.h" + #include "command_parser.h" + #include "connect.h" +-#include "libisula.h" + + const char g_cmd_pull_desc[] = "Pull an image or a repository from a registry"; + const char g_cmd_pull_usage[] = "pull [OPTIONS] NAME[:TAG|@DIGEST]"; +diff --git a/src/cmd/isula/images/rmi.c b/src/cmd/isula/images/rmi.c +index 70ff660..53ea734 100644 +--- a/src/cmd/isula/images/rmi.c ++++ b/src/cmd/isula/images/rmi.c +@@ -23,7 +23,6 @@ + #include "isula_connect.h" + #include "isula_libutils/log.h" + #include "connect.h" +-#include "libisula.h" + + const char g_cmd_rmi_desc[] = "Remove one or more images"; + const char g_cmd_rmi_usage[] = "rmi [OPTIONS] IMAGE [IMAGE...]"; +diff --git a/src/cmd/isula/images/tag.c b/src/cmd/isula/images/tag.c +index 822030c..e5a8670 100644 +--- a/src/cmd/isula/images/tag.c ++++ b/src/cmd/isula/images/tag.c +@@ -23,7 +23,7 @@ + #include "isula_libutils/log.h" + #include "command_parser.h" + #include "connect.h" +-#include "libisula.h" ++ + #include "utils_verify.h" + + const char g_cmd_tag_desc[] = "Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE"; +diff --git a/src/cmd/isula/information/health.c b/src/cmd/isula/information/health.c +deleted file mode 100644 +index 417c543..0000000 +--- a/src/cmd/isula/information/health.c ++++ /dev/null +@@ -1,108 +0,0 @@ +-/****************************************************************************** +- * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. 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: lifeng +- * Create: 2018-11-08 +- * Description: provide container health functions +- ******************************************************************************/ +-#include "health.h" +- +-#include +-#include +- +-#include "utils.h" +-#include "client_arguments.h" +-#include "isula_libutils/log.h" +-#include "isula_connect.h" +-#include "connect.h" +-#include "constants.h" +-#include "libisula.h" +- +-const char g_cmd_health_check_desc[] = "iSulad health check"; +-const char g_cmd_health_check_usage[] = "health [command options]"; +- +-struct client_arguments g_cmd_health_check_args = { +- .service = NULL, +-}; +- +-/* +- * Create a health check request message and call RPC +- */ +-static int client_health_check(const struct client_arguments *args) +-{ +- isula_connect_ops *ops = NULL; +- struct isula_health_check_request request = { 0 }; +- struct isula_health_check_response *response = NULL; +- client_connect_config_t config = { 0 }; +- int ret = 0; +- +- response = util_common_calloc_s(sizeof(struct isula_health_check_response)); +- if (response == NULL) { +- ERROR("Health: Out of memory"); +- return -1; +- } +- +- request.service = args->service; +- +- ops = get_connect_client_ops(); +- if (ops == NULL || !ops->health.check) { +- ERROR("Unimplemented health op"); +- ret = -1; +- goto out; +- } +- +- config = get_connect_config(args); +- ret = ops->health.check(&request, response, &config); +- if (ret || response->health_status != HEALTH_SERVING_STATUS_SERVING) { +- ret = -1; +- } +-out: +- isula_health_check_response_free(response); +- return ret; +-} +- +-int cmd_health_check_main(int argc, const char **argv) +-{ +- struct isula_libutils_log_config lconf = { 0 }; +- +- lconf.name = argv[0]; +- lconf.priority = "ERROR"; +- lconf.file = NULL; +- lconf.quiet = true; +- lconf.driver = "stdout"; +- if (isula_libutils_log_enable(&lconf)) { +- COMMAND_ERROR("Health: log init failed"); +- exit(ECOMMON); +- } +- +- command_t cmd; +- if (client_arguments_init(&g_cmd_health_check_args)) { +- COMMAND_ERROR("client arguments init failed"); +- exit(ECOMMON); +- } +- g_cmd_health_check_args.progname = argv[0]; +- struct command_option options[] = { HEALTH_OPTIONS(g_cmd_health_check_args), +- COMMON_OPTIONS(g_cmd_health_check_args) +- }; +- +- command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, +- g_cmd_health_check_desc, g_cmd_health_check_usage); +- if (command_parse_args(&cmd, &g_cmd_health_check_args.argc, &g_cmd_health_check_args.argv)) { +- exit(EINVALIDARGS); +- } +- +- if (client_health_check(&g_cmd_health_check_args)) { +- printf("iSulad with socket name '%s' is NOT SERVING\n", g_cmd_health_check_args.socket); +- exit(ECOMMON); +- } +- +- printf("iSulad with socket name '%s' is SERVING\n", g_cmd_health_check_args.socket); +- exit(EXIT_SUCCESS); +-} +diff --git a/src/cmd/isula/information/info.c b/src/cmd/isula/information/info.c +index 955d58d..d6f6f7b 100644 +--- a/src/cmd/isula/information/info.c ++++ b/src/cmd/isula/information/info.c +@@ -25,7 +25,6 @@ + #include "isula_connect.h" + #include "command_parser.h" + #include "connect.h" +-#include "libisula.h" + + const char g_cmd_info_desc[] = "Display system-wide information"; + const char g_cmd_info_usage[] = "info"; +@@ -77,7 +76,7 @@ static void client_info_server(const struct isula_info_response *response) + printf("Logging Driver: %s\n", response->logging_driver); + } + if (response->cgroup_driver != NULL) { +- printf("Cgroup Driverr: %s\n", response->cgroup_driver); ++ printf("Cgroup Driver: %s\n", response->cgroup_driver); + } + if (response->huge_page_size != NULL) { + printf("Hugetlb Pagesize: %s\n", response->huge_page_size); +diff --git a/src/cmd/isula/information/inspect.c b/src/cmd/isula/information/inspect.c +index 8341640..76caaba 100644 +--- a/src/cmd/isula/information/inspect.c ++++ b/src/cmd/isula/information/inspect.c +@@ -25,7 +25,6 @@ + #include "isula_connect.h" + #include "utils.h" + #include "connect.h" +-#include "libisula.h" + + const char g_cmd_inspect_desc[] = "Return low-level information on a container or image"; + const char g_cmd_inspect_usage[] = "inspect [options] CONTAINER|IMAGE [CONTAINER|IMAGE...]"; +diff --git a/src/cmd/isula/information/logs.c b/src/cmd/isula/information/logs.c +index 0f603c2..2ddd16e 100644 +--- a/src/cmd/isula/information/logs.c ++++ b/src/cmd/isula/information/logs.c +@@ -23,7 +23,7 @@ + #include "isula_libutils/log.h" + #include "isula_connect.h" + #include "connect.h" +-#include "libisula.h" ++ + #include "utils.h" + #include "utils_convert.h" + +@@ -67,7 +67,7 @@ static int do_logs(const struct client_arguments *args) + request->runtime = util_strdup_s(args->runtime); + request->follow = args->follow; + request->tail = (int64_t)args->tail; +- ++ request->timestamps = args->timestamps; + config = get_connect_config(args); + ret = ops->container.logs(request, response, &config); + if (ret != 0) { +@@ -105,8 +105,8 @@ static int cmd_logs_init(int argc, const char **argv) + return ECOMMON; + } + g_cmd_logs_args.progname = argv[0]; +- struct command_option options[] = { LOG_OPTIONS(lconf) LOGS_OPTIONS(g_cmd_logs_args), +- COMMON_OPTIONS(g_cmd_logs_args) ++ struct command_option options[] = { LOG_OPTIONS(lconf) LOGS_OPTIONS(g_cmd_logs_args) ++ COMMON_OPTIONS(g_cmd_logs_args) + }; + + command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_logs_desc, +diff --git a/src/cmd/isula/information/logs.h b/src/cmd/isula/information/logs.h +index 477d3aa..05717a6 100644 +--- a/src/cmd/isula/information/logs.h ++++ b/src/cmd/isula/information/logs.h +@@ -25,12 +25,16 @@ + extern "C" { + #endif + +-#define LOGS_OPTIONS(cmdargs) \ +- { CMD_OPT_TYPE_BOOL, false, "follow", 'f', &(cmdargs).follow, "Follow log output", NULL }, \ +- { \ +- CMD_OPT_TYPE_CALLBACK, false, "tail", 0, &(cmdargs).tail, "Number of lines to show from the end of the logs", \ +- callback_tail \ +- } ++#define LOGS_OPTIONS(cmdargs) \ ++ { CMD_OPT_TYPE_BOOL, false, "follow", 'f', &(cmdargs).follow, "Follow log output", NULL }, \ ++ { CMD_OPT_TYPE_CALLBACK, \ ++ false, \ ++ "tail", \ ++ 0, \ ++ &(cmdargs).tail, \ ++ "Number of lines to show from the end of the logs", \ ++ callback_tail }, \ ++ { CMD_OPT_TYPE_BOOL, false, "timestamps", 't', &(cmdargs).timestamps, "Show timestamps", NULL }, + + extern const char g_cmd_logs_desc[]; + extern const char g_cmd_logs_usage[]; +diff --git a/src/cmd/isula/information/ps.c b/src/cmd/isula/information/ps.c +index 860ae01..125353a 100644 +--- a/src/cmd/isula/information/ps.c ++++ b/src/cmd/isula/information/ps.c +@@ -26,7 +26,7 @@ + #include "isula_connect.h" + #include "connect.h" + #include "constants.h" +-#include "libisula.h" ++ + #include "utils_array.h" + #include "utils_string.h" + #include "utils_timestamp.h" +@@ -36,7 +36,6 @@ const char g_cmd_list_usage[] = "ps [command options]"; + + #define COMMAND_LENGTH_MAX 22 + #define TIME_DURATION_MAX_LEN 32 +-#define MAX_TIMESTAMP_LEN 128 + + struct client_arguments g_cmd_list_args = { + .dispname = false, +@@ -121,7 +120,7 @@ static int append_field(struct filters *ff, struct filter_field *field) + old_size = ff->field_len * sizeof(struct filters); + new_size = old_size + sizeof(struct filters); + +- if (mem_realloc((void **)(&tmp_fields), new_size, ff->fields, old_size) != 0) { ++ if (util_mem_realloc((void **)(&tmp_fields), new_size, ff->fields, old_size) != 0) { + ERROR("Out of memory"); + return -1; + } +@@ -209,8 +208,8 @@ static int mix_container_status(const struct isula_container_summary_info *in, c + char finishat_duration[TIME_DURATION_MAX_LEN] = { 0 }; + char *start_at = NULL; + char *finish_at = NULL; +- time_format_duration(in->startat, startat_duration, sizeof(startat_duration)); +- time_format_duration_ago(in->finishat, finishat_duration, sizeof(finishat_duration)); ++ util_time_format_duration(in->startat, startat_duration, sizeof(startat_duration)); ++ util_time_format_duration_ago(in->finishat, finishat_duration, sizeof(finishat_duration)); + start_at = in->startat ? startat_duration : "-"; + finish_at = in->finishat ? finishat_duration : "-"; + +@@ -344,7 +343,7 @@ static int get_created_time_buffer(int64_t created, char *timebuffer, size_t len + ERROR("Failed to get timestamp"); + return -1; + } +- if (!get_time_buffer(×tamp, timebuffer, len)) { ++ if (!util_get_time_buffer(×tamp, timebuffer, len)) { + ERROR("Failed to get timebuffer from timestamp"); + return -1; + } +@@ -353,13 +352,13 @@ static int get_created_time_buffer(int64_t created, char *timebuffer, size_t len + } + static void print_created_field(int64_t created, unsigned int length) + { +- char timebuffer[MAX_TIMESTAMP_LEN] = { 0 }; ++ char timebuffer[TIME_STR_SIZE] = { 0 }; + char created_duration[TIME_DURATION_MAX_LEN] = { 0 }; + +- if (get_created_time_buffer(created, timebuffer, MAX_TIMESTAMP_LEN) != 0) { ++ if (get_created_time_buffer(created, timebuffer, TIME_STR_SIZE) != 0) { + return; + } +- if (time_format_duration_ago(timebuffer, created_duration, sizeof(created_duration)) != 0) { ++ if (util_time_format_duration_ago(timebuffer, created_duration, sizeof(created_duration)) != 0) { + return; + } + printf("%-*s", (int)length, created_duration); +@@ -405,11 +404,11 @@ static void print_extern_container_info_item(const struct isula_container_summar + printf("%-*u", (int)length->rscont_length, in->restart_count); + } else if (strcmp(name, "StartAt") == 0) { + char startat_duration[TIME_DURATION_MAX_LEN] = { 0 }; +- time_format_duration(in->startat, startat_duration, sizeof(startat_duration)); ++ util_time_format_duration(in->startat, startat_duration, sizeof(startat_duration)); + printf("%-*s", (int)length->startat_length, in->startat ? startat_duration : "-"); + } else if (strcmp(name, "FinishAt") == 0) { + char finishat_duration[TIME_DURATION_MAX_LEN] = { 0 }; +- time_format_duration(in->finishat, finishat_duration, sizeof(finishat_duration)); ++ util_time_format_duration(in->finishat, finishat_duration, sizeof(finishat_duration)); + printf("%-*s", (int)length->finishat_length, in->finishat ? finishat_duration : "-"); + } else if (strcmp(name, "Runtime") == 0) { + printf("%-*s", (int)length->runtime_length, in->runtime ? in->runtime : "lcr"); +@@ -531,7 +530,7 @@ static void calculate_time_str_length(const char *str, unsigned int *length) + size_t len = 0; + char time_duration[TIME_DURATION_MAX_LEN]; + +- if (time_format_duration_ago(str, time_duration, sizeof(time_duration)) < 0) { ++ if (util_time_format_duration_ago(str, time_duration, sizeof(time_duration)) < 0) { + ERROR("Format time duration failed"); + } + +@@ -543,9 +542,9 @@ static void calculate_time_str_length(const char *str, unsigned int *length) + + static void calculate_created_str_length(int64_t created, unsigned int *length) + { +- char timebuffer[MAX_TIMESTAMP_LEN] = { 0 }; ++ char timebuffer[TIME_STR_SIZE] = { 0 }; + +- if (get_created_time_buffer(created, timebuffer, MAX_TIMESTAMP_LEN) != 0) { ++ if (get_created_time_buffer(created, timebuffer, TIME_STR_SIZE) != 0) { + return; + } + +diff --git a/src/cmd/isula/information/top.c b/src/cmd/isula/information/top.c +index bb0fa45..5d0e3f0 100644 +--- a/src/cmd/isula/information/top.c ++++ b/src/cmd/isula/information/top.c +@@ -25,7 +25,6 @@ + #include "attach.h" + #include "command_parser.h" + #include "connect.h" +-#include "libisula.h" + + const char g_cmd_top_desc[] = "Display the running processes of a container"; + const char g_cmd_top_usage[] = "top [OPTIONS] CONTAINER [ps OPTIONS]"; +diff --git a/src/cmd/isula/information/version.c b/src/cmd/isula/information/version.c +index 36e985b..62ee564 100644 +--- a/src/cmd/isula/information/version.c ++++ b/src/cmd/isula/information/version.c +@@ -25,7 +25,6 @@ + #include "command_parser.h" + #include "connect.h" + #include "constants.h" +-#include "libisula.h" + + const char g_cmd_version_desc[] = "Display information about isula"; + const char g_cmd_version_usage[] = "version"; +diff --git a/src/cmd/isula/information/wait.c b/src/cmd/isula/information/wait.c +index 5926536..b39c495 100644 +--- a/src/cmd/isula/information/wait.c ++++ b/src/cmd/isula/information/wait.c +@@ -12,18 +12,18 @@ + * Create: 2018-11-08 + * Description: provide container wait functions + ******************************************************************************/ ++#include "wait.h" + #include + #include + #include + +-#include "wait.h" + #include "client_arguments.h" + #include "isula_libutils/log.h" + #include "isula_connect.h" + #include "command_parser.h" + #include "connect.h" + #include "constants.h" +-#include "libisula.h" ++ + #include "utils.h" + + const char g_cmd_wait_desc[] = "Block until one or more containers stop, then print their exit codes"; +diff --git a/src/cmd/isula/isula_commands.c b/src/cmd/isula/isula_commands.c +index 8208aa3..db37f70 100644 +--- a/src/cmd/isula/isula_commands.c ++++ b/src/cmd/isula/isula_commands.c +@@ -17,17 +17,16 @@ + #include + #include + #include +-#include + #include + #include + #include + #include ++#include + + #include "client_arguments.h" + #include "config.h" + #include "isula_libutils/log.h" + #include "utils.h" +-#include "console.h" + #include "constants.h" + #include "utils_file.h" + #include "utils_string.h" +@@ -122,11 +121,11 @@ const struct command *command_by_name(const struct command *cmds, const char * c + } + + // Default help command if implementation doesn't provide one +-int command_default_help(const char * const program_name, struct command *commands, int argc, const char **argv) ++int command_default_help(const char * const program_name, struct command *all_commands, int argc, const char **argv) + { +- const struct command *command = NULL; ++ const struct command *current_command = NULL; + +- if (commands == NULL) { ++ if (all_commands == NULL) { + return 1; + } + +@@ -136,16 +135,30 @@ int command_default_help(const char * const program_name, struct command *comman + printf("USAGE:\n"); + printf("\t%s [args...]\n", program_name); + printf("\n"); +- printf("COMMANDS:\n"); +- for (i = 0; commands[i].name != NULL; i++) { +- size_t cmd_size = strlen(commands[i].name); ++ ++ for (i = 0; all_commands[i].name != NULL; i++) { ++ size_t cmd_size = strlen(all_commands[i].name); + if (cmd_size > max_size) { + max_size = cmd_size; + } + } +- qsort(commands, i, sizeof(commands[0]), compare_commands); +- for (i = 0; commands[i].name != NULL; i++) { +- printf("\t%*s\t%s\n", -(int)max_size, commands[i].name, commands[i].description); ++ qsort(all_commands, i, sizeof(all_commands[0]), compare_commands); ++ ++ printf("MANAGEMENT COMMANDS:\n"); ++ for (i = 0; all_commands[i].name != NULL; i++) { ++ if (!all_commands[i].have_subcmd) { ++ continue; ++ } ++ printf("\t%*s\t%s\n", -(int)max_size, all_commands[i].name, all_commands[i].description); ++ } ++ printf("\n"); ++ ++ printf("COMMANDS:\n"); ++ for (i = 0; all_commands[i].name != NULL; i++) { ++ if (all_commands[i].have_subcmd) { ++ continue; ++ } ++ printf("\t%*s\t%s\n", -(int)max_size, all_commands[i].name, all_commands[i].description); + } + + printf("\n"); +@@ -156,282 +169,93 @@ int command_default_help(const char * const program_name, struct command *comman + return 1; + } + +- command = command_by_name(commands, argv[0]); +- +- if (command == NULL) { ++ current_command = command_by_name(all_commands, argv[0]); ++ if (current_command == NULL) { + printf("%s: sub-command \"%s\" not found\n", program_name, argv[0]); + printf("run `isula --help` for a list of sub-commands\n"); + return 1; + } + +- if (command->longdesc != NULL) { +- printf("%s\n", command->longdesc); ++ if (current_command->longdesc != NULL) { ++ printf("%s\n", current_command->longdesc); + } + return 0; + } + +-/* run command */ +-int run_command(struct command *commands, int argc, const char **argv) ++int command_subcmd_help(const char * const program_name, struct command *all_commands, int argc, const char **argv) + { +- const struct command *command = NULL; +- +- if (argc == 1) { +- return command_default_help(argv[0], commands, argc - 1, (const char **)(argv + 1)); +- } ++ const struct command *current_command = NULL; + +- if (strcmp(argv[1], "--help") == 0) { +- // isula help command format: isula --help args +- return command_default_help(argv[0], commands, argc - 2, (const char **)(argv + 2)); +- } +- +- if (strcmp(argv[1], "--version") == 0) { +- print_version(); +- return 0; +- } +- +- command = command_by_name(commands, argv[1]); +- if (command != NULL) { +- send_msg_to_syslog(argc, argv); +- return command->executor(argc, (const char **)argv); ++ if (all_commands == NULL) { ++ return 1; + } + +- printf("%s: command \"%s\" not found\n", argv[0], argv[1]); +- printf("run `%s --help` for a list of sub-commands\n", argv[0]); +- return 1; +-} +- +-/* free command fifo names */ +-void free_command_fifo_config(struct command_fifo_config *fifos) +-{ +- if (fifos != NULL) { +- if (fifos->stdin_path != NULL) { +- free(fifos->stdin_path); +- fifos->stdin_path = NULL; +- } +- if (fifos->stdout_path != NULL) { +- free(fifos->stdout_path); +- fifos->stdout_path = NULL; +- } +- if (fifos->stderr_path != NULL) { +- free(fifos->stderr_path); +- fifos->stderr_path = NULL; +- } +- if (fifos->stdin_name != NULL) { +- free(fifos->stdin_name); +- fifos->stdin_name = NULL; +- } +- if (fifos->stdout_name != NULL) { +- free(fifos->stdout_name); +- fifos->stdout_name = NULL; ++ if (argc == 0) { ++ size_t i = 0; ++ size_t max_size = 0; ++ printf("USAGE:\n"); ++ printf("\t%s [args...]\n", program_name); ++ printf("\n"); ++ printf("COMMANDS:\n"); ++ for (i = 0; all_commands[i].name != NULL; i++) { ++ size_t cmd_size = strlen(all_commands[i].name); ++ if (cmd_size > max_size) { ++ max_size = cmd_size; ++ } + } +- if (fifos->stderr_name != NULL) { +- free(fifos->stderr_name); +- fifos->stderr_name = NULL; ++ qsort(all_commands, i, sizeof(all_commands[0]), compare_commands); ++ for (i = 0; all_commands[i].name != NULL; i++) { ++ printf("\t%*s\t%s\n", -(int)max_size, all_commands[i].name, all_commands[i].description); + } +- free(fifos); +- } +-} +- +-/* delete command fifo */ +-void delete_command_fifo(struct command_fifo_config *fifos) +-{ +- int ret; + +- if (fifos == NULL) { +- return; +- } +- +- ret = console_fifo_delete(fifos->stdin_name); +- if (ret) { +- WARN("Delete fifo failed: %s", fifos->stdin_name); +- } +- ret = console_fifo_delete(fifos->stdout_name); +- if (ret) { +- WARN("Delete fifo failed: %s", fifos->stdout_name); +- } +- ret = console_fifo_delete(fifos->stderr_name); +- if (ret) { +- WARN("Delete fifo failed: %s", fifos->stderr_name); +- } +- ret = util_recursive_rmdir(fifos->stdin_path, 0); +- if (ret) { +- WARN("Remove directory failed: %s", fifos->stdin_path); +- } +- ret = util_recursive_rmdir(fifos->stdout_path, 0); +- if (ret) { +- WARN("Remove directory failed: %s", fifos->stdout_path); +- } +- ret = util_recursive_rmdir(fifos->stderr_path, 0); +- if (ret) { +- WARN("Remove directory failed: %s", fifos->stderr_path); +- } +- +- free_command_fifo_config(fifos); +-} +- +-static int do_create_console_fifo(const char *subpath, const char *stdflag, char **out_fifo_dir, char **out_fifo_name) +-{ +- int ret = 0; +- char fifo_dir[PATH_MAX] = { 0 }; +- char fifo_name[PATH_MAX] = { 0 }; +- +- ret = console_fifo_name(CLIENT_RUNDIR, subpath, stdflag, fifo_name, sizeof(fifo_name), fifo_dir, sizeof(fifo_dir), +- true); +- if (ret != 0) { +- ERROR("Failed to get console fifo name."); +- ret = -1; +- goto out; +- } +- +- if (console_fifo_create(fifo_name)) { +- ERROR("Failed to create console fifo."); +- ret = -1; +- goto out; +- } +- +- *out_fifo_dir = util_strdup_s(fifo_dir); +- *out_fifo_name = util_strdup_s(fifo_name); +- +-out: +- return ret; +-} +- +-int create_console_fifos(bool attach_stdin, bool attach_stdout, bool attach_stderr, const char *name, const char *type, +- struct command_fifo_config **pconsole_fifos) +-{ +- int ret = 0; +- char subpath[PATH_MAX] = { 0 }; +- struct command_fifo_config *fifos = NULL; +- +- fifos = util_common_calloc_s(sizeof(struct command_fifo_config)); +- if (fifos == NULL) { +- ERROR("Failed to malloc memory for FIFO names."); +- return -1; +- } +- +- ret = snprintf(subpath, sizeof(subpath), "%s/%s-%u-%u", name, type, (unsigned int)getpid(), +- (unsigned int)pthread_self()); +- if (ret < 0 || (size_t)ret >= sizeof(subpath)) { +- ERROR("Path is too long"); +- goto cleanup; +- } +- +- if (attach_stdin) { +- ret = do_create_console_fifo(subpath, "in", &fifos->stdin_path, &fifos->stdin_name); +- if (ret != 0) { +- goto cleanup; +- } +- INFO("FIFO:%s create for start success.", fifos->stdin_name); ++ printf("\n"); ++ printf("Run %s COMMAND --help for more information on the COMMAND", program_name); ++ printf("\n"); ++ return 0; ++ } else if (argc > 1) { ++ printf("%s: unrecognized command: \"%s\"\n", program_name, argv[1]); ++ return 1; + } + +- if (attach_stdout) { +- ret = do_create_console_fifo(subpath, "out", &fifos->stdout_path, &fifos->stdout_name); +- if (ret != 0) { +- goto cleanup; +- } +- INFO("FIFO:%s create for start success.", fifos->stdout_name); ++ current_command = command_by_name(all_commands, argv[0]); ++ if (current_command == NULL) { ++ printf("%s: sub-command \"%s\" not found\n", program_name, argv[0]); ++ printf("Run `%s --help` for a list of sub-commands\n", program_name); ++ return 1; + } + +- if (attach_stderr) { +- ret = do_create_console_fifo(subpath, "err", &fifos->stderr_path, &fifos->stderr_name); +- if (ret != 0) { +- goto cleanup; +- } +- INFO("FIFO:%s create for start success.", fifos->stderr_name); ++ if (current_command->longdesc != NULL) { ++ printf("%s\n", current_command->longdesc); + } +- +- *pconsole_fifos = fifos; + return 0; +- +-cleanup: +- console_fifo_delete(fifos->stdin_name); +- console_fifo_delete(fifos->stdout_name); +- console_fifo_delete(fifos->stderr_name); +- free_command_fifo_config(fifos); +- return -1; + } + +-struct console_loop_thread_args { +- struct command_fifo_config *fifo_config; +- bool tty; +-}; +- +-static void *client_console_loop_thread(void *arg) ++/* run command */ ++int run_command(struct command *all_commands, int argc, const char **argv) + { +- int ret = 0; +- int fifoinfd = -1; +- int fifooutfd = -1; +- int fifoerrfd = -1; +- const struct console_loop_thread_args *args = arg; +- bool tty = args->tty; +- struct command_fifo_config *fifo_config = args->fifo_config; +- sem_t *wait_open = fifo_config->wait_open; +- sem_t *wait_exit = fifo_config->wait_exit; +- +- ret = pthread_detach(pthread_self()); +- if (ret != 0) { +- CRIT("Start: set thread detach fail"); +- goto err1; +- } +- +- if (fifo_config->stdin_name) { +- if (console_fifo_open_withlock(fifo_config->stdin_name, &fifoinfd, O_RDWR | O_NONBLOCK)) { +- ERROR("Start: failed to open console fifo."); +- goto err2; +- } +- INFO("FIFO:%s open success for start.", fifo_config->stdin_name); +- } ++ const struct command *current_command = NULL; + +- if (fifo_config->stdout_name) { +- if (console_fifo_open(fifo_config->stdout_name, &fifooutfd, O_RDONLY | O_NONBLOCK)) { +- ERROR("Failed to open console fifo."); +- goto err2; +- } +- INFO("FIFO:%s open success for start.", fifo_config->stdout_name); ++ if (argc == 1) { ++ return command_default_help(argv[0], all_commands, argc - 1, (const char **)(argv + 1)); + } + +- if (fifo_config->stderr_name) { +- if (console_fifo_open(fifo_config->stderr_name, &fifoerrfd, O_RDONLY | O_NONBLOCK)) { +- ERROR("Start: failed to open console fifo."); +- goto err2; +- } +- INFO("FIFO:%s open success for start.", fifo_config->stderr_name); ++ if (strcmp(argv[1], "--help") == 0) { ++ // isula help command format: isula --help args ++ return command_default_help(argv[0], all_commands, argc - 2, (const char **)(argv + 2)); + } + +- sem_post(wait_open); +- console_loop_with_std_fd(0, 1, 2, fifoinfd, fifooutfd, fifoerrfd, 1, tty); +- +-err2: +- if (fifoinfd >= 0) { +- console_fifo_close(fifoinfd); +- } +- if (fifooutfd >= 0) { +- console_fifo_close(fifooutfd); +- } +- if (fifoerrfd >= 0) { +- console_fifo_close(fifoerrfd); ++ if (strcmp(argv[1], "--version") == 0) { ++ print_version(); ++ return 0; + } +-err1: +- sem_post(wait_open); +- sem_post(wait_exit); +- return NULL; +-} + +-int start_client_console_thread(struct command_fifo_config *console_fifos, bool tty) +-{ +- int res = 0; +- pthread_t a_thread; +- struct console_loop_thread_args args; +- +- args.fifo_config = console_fifos; +- args.tty = tty; +- res = pthread_create(&a_thread, NULL, client_console_loop_thread, (void *)(&args)); +- if (res != 0) { +- CRIT("Thread creation failed"); +- return -1; ++ current_command = command_by_name(all_commands, argv[1]); ++ if (current_command != NULL) { ++ send_msg_to_syslog(argc, argv); ++ return current_command->executor(argc, (const char **)argv); + } + +- sem_wait(console_fifos->wait_open); +- +- return 0; ++ printf("%s: command \"%s\" not found\n", argv[0], argv[1]); ++ printf("run `%s --help` for a list of sub-commands\n", argv[0]); ++ return 1; + } +diff --git a/src/cmd/isula/isula_commands.h b/src/cmd/isula/isula_commands.h +index 7ac2501..1bbb7b3 100644 +--- a/src/cmd/isula/isula_commands.h ++++ b/src/cmd/isula/isula_commands.h +@@ -15,7 +15,6 @@ + #ifndef CMD_ISULA_ISULA_COMMANDS_H + #define CMD_ISULA_ISULA_COMMANDS_H + +-#include + #include + + #include "client_arguments.h" +@@ -24,51 +23,34 @@ + extern "C" { + #endif + +-#define CLIENT_RUNDIR "/var/run/isula" +- + // A command is described by: + // @name: The name which should be passed as a second parameter + // @executor: The function that will be executed if the command + // matches. Receives the argc of the program minus two, and + // the rest os argv + // @description: Brief description, will show in help messages +-// @longdesc: Long descripton to show when you run `help ` ++// @longdesc: Long description to show when you run `help ` + struct command { + const char * const name; ++ const bool have_subcmd; + int (*executor)(int, const char **); + const char * const description; + const char * const longdesc; + struct client_arguments *args; + }; + +-struct command_fifo_config { +- char *stdin_path; +- char *stdout_path; +- char *stderr_path; +- char *stdin_name; +- char *stdout_name; +- char *stderr_name; +- sem_t *wait_open; +- sem_t *wait_exit; +-}; +- +-int create_console_fifos(bool attach_stdin, bool attach_stdout, bool attach_stderr, const char *name, const char *type, +- struct command_fifo_config **pconsole_fifos); +- +-int start_client_console_thread(struct command_fifo_config *console_fifos, bool tty); +- +-void free_command_fifo_config(struct command_fifo_config *fifos); +- +-void delete_command_fifo(struct command_fifo_config *fifos); +- + // Gets a pointer to a command, to allow implementing custom behavior + // returns null if not found. + // + // NOTE: Command arrays must end in a command with all member is NULL + const struct command *command_by_name(const struct command *cmds, const char * const name); + ++int compare_commands(const void *s1, const void *s2); ++ + // Default help command if implementation doesn't prvide one +-int commmand_default_help(const char * const program_name, struct command *commands, int argc, const char **argv); ++int command_default_help(const char * const program_name, struct command *commands, int argc, const char **argv); ++ ++int command_subcmd_help(const char * const program_name, struct command *commands, int argc, const char **argv); + + int run_command(struct command *commands, int argc, const char **argv); + +diff --git a/src/cmd/isula/isula_container_spec.c b/src/cmd/isula/isula_container_spec.c +new file mode 100644 +index 0000000..d9b3f8c +--- /dev/null ++++ b/src/cmd/isula/isula_container_spec.c +@@ -0,0 +1,450 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. 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: lifeng ++ * Create: 2020-09-28 ++ * Description: provide generate container spec in client ++ ******************************************************************************/ ++#include "isula_container_spec.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "isula_libutils/log.h" ++#include "utils.h" ++#include "isula_libutils/container_config.h" ++#include "utils_array.h" ++#include "utils_string.h" ++#include "utils_verify.h" ++ ++static int pack_container_custom_config_args(container_config *container_spec, ++ const isula_container_config_t *custom_conf) ++{ ++ int ret = 0; ++ int i; ++ ++ /* entrypoint */ ++ if (util_valid_str(custom_conf->entrypoint)) { ++ container_spec->entrypoint = util_common_calloc_s(sizeof(char *)); ++ if (container_spec->entrypoint == NULL) { ++ ret = -1; ++ goto out; ++ } ++ container_spec->entrypoint[0] = util_strdup_s(custom_conf->entrypoint); ++ container_spec->entrypoint_len++; ++ } ++ ++ /* commands */ ++ if ((custom_conf->cmd_len != 0 && custom_conf->cmd)) { ++ if (custom_conf->cmd_len > SIZE_MAX / sizeof(char *)) { ++ COMMAND_ERROR("The length of cmd is too long!"); ++ ret = -1; ++ goto out; ++ } ++ container_spec->cmd = util_common_calloc_s(custom_conf->cmd_len * sizeof(char *)); ++ if (container_spec->cmd == NULL) { ++ ret = -1; ++ goto out; ++ } ++ for (i = 0; i < (int)custom_conf->cmd_len; i++) { ++ container_spec->cmd[container_spec->cmd_len] = util_strdup_s(custom_conf->cmd[i]); ++ container_spec->cmd_len++; ++ } ++ } ++ ++out: ++ return ret; ++} ++ ++static int pack_container_custom_config_array(container_config *container_spec, ++ const isula_container_config_t *custom_conf) ++{ ++ int ret = 0; ++ int i = 0; ++ ++ /* environment variables */ ++ if (custom_conf->env_len != 0 && custom_conf->env) { ++ if (custom_conf->env_len > SIZE_MAX / sizeof(char *)) { ++ COMMAND_ERROR("Too many environment variables"); ++ return -1; ++ } ++ container_spec->env = util_common_calloc_s(custom_conf->env_len * sizeof(char *)); ++ if (container_spec->env == NULL) { ++ ret = -1; ++ goto out; ++ } ++ for (i = 0; i < (int)custom_conf->env_len; i++) { ++ container_spec->env[container_spec->env_len] = util_strdup_s(custom_conf->env[i]); ++ container_spec->env_len++; ++ } ++ } ++ ++out: ++ return ret; ++} ++ ++static int get_label_key_value(const char *label, char **key, char **value) ++{ ++ int ret = 0; ++ char **arr = util_string_split_n(label, '=', 2); ++ if (arr == NULL) { ++ ERROR("Failed to split input label"); ++ ret = -1; ++ goto out; ++ } ++ ++ *key = util_strdup_s(arr[0]); ++ if (util_array_len((const char **)arr) == 1) { ++ *value = util_strdup_s(""); ++ } else { ++ *value = util_strdup_s(arr[1]); ++ } ++ ++out: ++ util_free_array(arr); ++ return ret; ++} ++ ++static int pack_container_custom_config_labels(container_config *container_spec, ++ const isula_container_config_t *custom_conf) ++{ ++ int ret = 0; ++ int i; ++ char *key = NULL; ++ char *value = NULL; ++ ++ if (custom_conf->label_len == 0 || custom_conf->label == NULL) { ++ return 0; ++ } ++ ++ /* labels */ ++ container_spec->labels = util_common_calloc_s(sizeof(json_map_string_string)); ++ if (container_spec->labels == NULL) { ++ ERROR("Out of memory"); ++ ret = -1; ++ goto out; ++ } ++ ++ for (i = 0; i < custom_conf->label_len; i++) { ++ if (get_label_key_value(custom_conf->label[i], &key, &value) != 0) { ++ ERROR("Failed to get key and value of label"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (append_json_map_string_string(container_spec->labels, key, value)) { ++ ERROR("Append map failed"); ++ ret = -1; ++ goto out; ++ } ++ free(key); ++ key = NULL; ++ free(value); ++ value = NULL; ++ } ++ ++out: ++ free(key); ++ free(value); ++ return ret; ++} ++ ++static bool have_health_check(const isula_container_config_t *custom_conf) ++{ ++ bool have_health_settings = false; ++ ++ if ((custom_conf->health_cmd != NULL && strlen(custom_conf->health_cmd) != 0) || ++ custom_conf->health_interval != 0 || custom_conf->health_timeout != 0 || ++ custom_conf->health_start_period != 0 || custom_conf->health_retries != 0) { ++ have_health_settings = true; ++ } ++ ++ return have_health_settings; ++} ++ ++static int pack_custom_no_health_check(container_config *container_spec, bool have_health_settings, ++ defs_health_check *health_config) ++{ ++ int ret = 0; ++ ++ if (have_health_settings) { ++ COMMAND_ERROR("--no-healthcheck conflicts with --health-* options"); ++ ret = -1; ++ goto out; ++ } ++ health_config->test = util_common_calloc_s(sizeof(char *)); ++ if (health_config->test == NULL) { ++ ret = -1; ++ goto out; ++ } ++ health_config->test[health_config->test_len++] = util_strdup_s("NONE"); ++ container_spec->healthcheck = health_config; ++ ++out: ++ return ret; ++} ++ ++static int pack_custom_with_health_check(container_config *container_spec, const isula_container_config_t *custom_conf, ++ bool have_health_settings, defs_health_check *health_config) ++{ ++ int ret = 0; ++ ++ if (custom_conf->health_cmd != NULL && strlen(custom_conf->health_cmd) != 0) { ++ health_config->test = util_common_calloc_s(2 * sizeof(char *)); ++ if (health_config->test == NULL) { ++ ret = -1; ++ goto out; ++ } ++ health_config->test[health_config->test_len++] = util_strdup_s("CMD-SHELL"); ++ health_config->test[health_config->test_len++] = util_strdup_s(custom_conf->health_cmd); ++ } else { ++ COMMAND_ERROR("--health-cmd required!"); ++ ret = -1; ++ goto out; ++ } ++ health_config->interval = custom_conf->health_interval; ++ health_config->timeout = custom_conf->health_timeout; ++ health_config->start_period = custom_conf->health_start_period; ++ health_config->retries = custom_conf->health_retries; ++ health_config->exit_on_unhealthy = custom_conf->exit_on_unhealthy; ++ if (container_spec->healthcheck != NULL) { ++ free_defs_health_check(container_spec->healthcheck); ++ } ++ container_spec->healthcheck = health_config; ++ ++out: ++ return ret; ++} ++ ++static int pack_container_custom_config_health(container_config *container_spec, ++ const isula_container_config_t *custom_conf) ++{ ++ int ret = 0; ++ bool have_health_settings = false; ++ defs_health_check *health_config = NULL; ++ ++ if (container_spec == NULL || custom_conf == NULL) { ++ return 0; ++ } ++ ++ have_health_settings = have_health_check(custom_conf); ++ ++ health_config = util_common_calloc_s(sizeof(defs_health_check)); ++ if (health_config == NULL) { ++ ret = -1; ++ goto out; ++ } ++ ++ if (custom_conf->no_healthcheck) { ++ ret = pack_custom_no_health_check(container_spec, have_health_settings, health_config); ++ if (ret != 0) { ++ goto out; ++ } ++ } else if (have_health_settings) { ++ ret = pack_custom_with_health_check(container_spec, custom_conf, have_health_settings, health_config); ++ if (ret != 0) { ++ goto out; ++ } ++ } else { ++ goto out; ++ } ++ ++ return ret; ++ ++out: ++ free_defs_health_check(health_config); ++ return ret; ++} ++ ++static int pack_container_custom_config_annotation(container_config *container_spec, ++ const isula_container_config_t *custom_conf) ++{ ++ int ret = 0; ++ size_t j; ++ ++ container_spec->annotations = util_common_calloc_s(sizeof(json_map_string_string)); ++ if (container_spec->annotations == NULL) { ++ ERROR("Out of memory"); ++ ret = -1; ++ goto out; ++ } ++ if (custom_conf->annotations != NULL) { ++ for (j = 0; j < custom_conf->annotations->len; j++) { ++ if (append_json_map_string_string(container_spec->annotations, custom_conf->annotations->keys[j], ++ custom_conf->annotations->values[j])) { ++ ERROR("Append map failed"); ++ ret = -1; ++ goto out; ++ } ++ } ++ } ++out: ++ return ret; ++} ++ ++static int pack_container_custom_config_pre(container_config *container_spec, ++ const isula_container_config_t *custom_conf) ++{ ++ int ret = 0; ++ ++ ret = pack_container_custom_config_args(container_spec, custom_conf); ++ if (ret != 0) { ++ goto out; ++ } ++ ++ ret = pack_container_custom_config_array(container_spec, custom_conf); ++ if (ret != 0) { ++ goto out; ++ } ++ ++ ret = pack_container_custom_config_labels(container_spec, custom_conf); ++ if (ret != 0) { ++ goto out; ++ } ++ ++ ret = pack_container_custom_config_health(container_spec, custom_conf); ++ if (ret != 0) { ++ goto out; ++ } ++out: ++ return ret; ++} ++ ++/* translate create_custom_config to container_config */ ++static int pack_container_custom_config(container_config *container_spec, const isula_container_config_t *custom_conf) ++{ ++ int ret = -1; ++ ++ if (container_spec == NULL || custom_conf == NULL) { ++ return ret; ++ } ++ ++ ret = pack_container_custom_config_pre(container_spec, custom_conf); ++ if (ret != 0) { ++ goto out; ++ } ++ ++ if (custom_conf->hostname != NULL) { ++ container_spec->hostname = util_strdup_s(custom_conf->hostname); ++ } ++ container_spec->log_driver = util_strdup_s(custom_conf->log_driver); ++ ++ /* console config */ ++ container_spec->tty = custom_conf->tty; ++ container_spec->open_stdin = custom_conf->open_stdin; ++ container_spec->attach_stdin = custom_conf->attach_stdin; ++ container_spec->attach_stdout = custom_conf->attach_stdout; ++ container_spec->attach_stderr = custom_conf->attach_stderr; ++ ++ /* user and group */ ++ if (custom_conf->user != NULL) { ++ container_spec->user = util_strdup_s(custom_conf->user); ++ } ++ ++ /* settings for system container */ ++ if (custom_conf->system_container) { ++ container_spec->system_container = custom_conf->system_container; ++ } ++ ++ if (custom_conf->ns_change_opt != NULL) { ++ container_spec->ns_change_opt = util_strdup_s(custom_conf->ns_change_opt); ++ } ++ ++ ret = pack_container_custom_config_annotation(container_spec, custom_conf); ++ if (ret != 0) { ++ goto out; ++ } ++ ++ if (custom_conf->workdir != NULL) { ++ container_spec->working_dir = util_strdup_s(custom_conf->workdir); ++ } ++ ++out: ++ return ret; ++} ++ ++int generate_container_config(const isula_container_config_t *custom_conf, char **container_config_str) ++{ ++ int ret = 0; ++ container_config *container_spec = NULL; ++ struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 }; ++ parser_error err = NULL; ++ ++ /* step 1: malloc the container config */ ++ container_spec = util_common_calloc_s(sizeof(container_config)); ++ if (container_spec == NULL) { ++ ERROR("Memory out"); ++ ret = -1; ++ goto out; ++ } ++ ++ /* step 2: pack the container custom config */ ++ ret = pack_container_custom_config(container_spec, custom_conf); ++ if (ret != 0) { ++ ERROR("Failed to pack the container custom config"); ++ ret = -1; ++ goto out; ++ } ++ ++ /* step 3: generate the config string */ ++ *container_config_str = container_config_generate_json(container_spec, &ctx, &err); ++ if (*container_config_str == NULL) { ++ ERROR("Failed to generate OCI specification json string"); ++ ret = -1; ++ goto out; ++ } ++ ++out: ++ free_container_config(container_spec); ++ free(err); ++ ++ return ret; ++} ++ ++/* isula container config free */ ++void isula_container_config_free(isula_container_config_t *config) ++{ ++ if (config == NULL) { ++ return; ++ } ++ ++ util_free_array_by_len(config->env, config->env_len); ++ config->env = NULL; ++ config->env_len = 0; ++ ++ free(config->hostname); ++ config->hostname = NULL; ++ ++ free(config->user); ++ config->user = NULL; ++ ++ util_free_array_by_len(config->cmd, config->cmd_len); ++ config->cmd = NULL; ++ config->cmd_len = 0; ++ ++ free(config->entrypoint); ++ config->entrypoint = NULL; ++ ++ free(config->log_driver); ++ config->log_driver = NULL; ++ ++ free_json_map_string_string(config->annotations); ++ config->annotations = NULL; ++ ++ free(config->workdir); ++ config->workdir = NULL; ++ ++ free(config); ++} +diff --git a/src/cmd/isula/isula_container_spec.h b/src/cmd/isula/isula_container_spec.h +new file mode 100644 +index 0000000..898c5d8 +--- /dev/null ++++ b/src/cmd/isula/isula_container_spec.h +@@ -0,0 +1,89 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. 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: lifeng ++ * Create: 2020-09-28 ++ * Description: provide generate container spec in client ++ ******************************************************************************/ ++#ifndef CMD_ISULA_GENERATE_CONTAINER_SPEC_H ++#define CMD_ISULA_GENERATE_CONTAINER_SPEC_H ++ ++#include ++#include ++#include ++#include "isula_libutils/json_common.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++typedef struct isula_container_config { ++ char **env; ++ size_t env_len; ++ ++ char **label; ++ size_t label_len; ++ ++ char *hostname; ++ ++ char *user; ++ ++ bool attach_stdin; ++ ++ bool attach_stdout; ++ ++ bool attach_stderr; ++ ++ bool open_stdin; ++ ++ bool tty; ++ ++ bool readonly; ++ ++ bool all_devices; ++ ++ bool system_container; ++ char *ns_change_opt; ++ ++ char *entrypoint; ++ ++ char **cmd; ++ size_t cmd_len; ++ ++ char *log_driver; ++ ++ json_map_string_string *annotations; ++ ++ char *workdir; ++ ++ char *health_cmd; ++ ++ int64_t health_interval; ++ ++ int health_retries; ++ ++ int64_t health_timeout; ++ ++ int64_t health_start_period; ++ ++ bool no_healthcheck; ++ ++ bool exit_on_unhealthy; ++ ++} isula_container_config_t; ++ ++int generate_container_config(const isula_container_config_t *custom_conf, char **container_config_str); ++ ++void isula_container_config_free(isula_container_config_t *config); ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +diff --git a/src/client/connect/pack_config.c b/src/cmd/isula/isula_host_spec.c +similarity index 52% +rename from src/client/connect/pack_config.c +rename to src/cmd/isula/isula_host_spec.c +index fbcd7b4..1b5fc25 100644 +--- a/src/client/connect/pack_config.c ++++ b/src/cmd/isula/isula_host_spec.c +@@ -8,10 +8,12 @@ + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. +- * Author: tanyifeng +- * Create: 2018-11-08 +- * Description: provide container package configure functions ++ * Author: lifeng ++ * Create: 2020-09-28 ++ * Description: provide generate host spec in client + ******************************************************************************/ ++#include "isula_host_spec.h" ++ + #include + #include + #include +@@ -25,17 +27,16 @@ + #include + + #include "isula_libutils/log.h" +-#include "pack_config.h" + #include "isula_libutils/host_config.h" + #include "utils.h" + #include "isula_libutils/parse_common.h" + #include "path.h" +-#include "isula_libutils/container_config.h" + #include "utils_array.h" + #include "utils_convert.h" + #include "utils_file.h" + #include "utils_string.h" + #include "utils_verify.h" ++#include "opt_ulimit.h" + + static bool parse_restart_policy(const char *policy, host_config_restart_policy **rp) + { +@@ -79,32 +80,13 @@ cleanup: + + static int pack_host_config_ns_change_files(host_config *dstconfig, const isula_host_config_t *srcconfig) + { +- int ret = 0; +- size_t i = 0; +- +- if (dstconfig == NULL || srcconfig == NULL) { ++ if (util_dup_array_of_strings((const char **)srcconfig->ns_change_files, srcconfig->ns_change_files_len, ++ &dstconfig->ns_change_files, &dstconfig->ns_change_files_len) != 0) { ++ COMMAND_ERROR("Failed to dup ns change files"); + return -1; + } + +- if (srcconfig->ns_change_files_len != 0 && srcconfig->ns_change_files != NULL) { +- if (srcconfig->ns_change_files_len > SIZE_MAX / sizeof(char *)) { +- COMMAND_ERROR("Too many capabilities to add!"); +- ret = -1; +- goto out; +- } +- dstconfig->ns_change_files = util_common_calloc_s(srcconfig->ns_change_files_len * sizeof(char *)); +- if (dstconfig->ns_change_files == NULL) { +- ret = -1; +- goto out; +- } +- for (i = 0; i < srcconfig->ns_change_files_len; i++) { +- dstconfig->ns_change_files[dstconfig->ns_change_files_len] = util_strdup_s(srcconfig->ns_change_files[i]); +- dstconfig->ns_change_files_len++; +- } +- } +- +-out: +- return ret; ++ return 0; + } + + static int pack_host_config_cap_add(host_config *dstconfig, const isula_host_config_t *srcconfig) +@@ -113,21 +95,10 @@ static int pack_host_config_cap_add(host_config *dstconfig, const isula_host_con + size_t i = 0; + + /* cap-add */ +- if (srcconfig->cap_add_len != 0 && srcconfig->cap_add != NULL) { +- if (srcconfig->cap_add_len > SIZE_MAX / sizeof(char *)) { +- COMMAND_ERROR("Too many capabilities to add!"); +- ret = -1; +- goto out; +- } +- dstconfig->cap_add = util_common_calloc_s(srcconfig->cap_add_len * sizeof(char *)); +- if (dstconfig->cap_add == NULL) { +- ret = -1; +- goto out; +- } +- for (i = 0; i < srcconfig->cap_add_len; i++) { +- dstconfig->cap_add[dstconfig->cap_add_len] = util_strdup_s(srcconfig->cap_add[i]); +- dstconfig->cap_add_len++; +- } ++ if (util_dup_array_of_strings((const char **)srcconfig->cap_add, srcconfig->cap_add_len, &dstconfig->cap_add, ++ &dstconfig->cap_add_len) != 0) { ++ COMMAND_ERROR("Failed to dup cap add"); ++ return -1; + } + + for (i = 0; i < dstconfig->cap_add_len; i++) { +@@ -152,21 +123,10 @@ static int pack_host_config_cap_drop(host_config *dstconfig, const isula_host_co + size_t i = 0; + + /* cap-drops */ +- if (srcconfig->cap_drop_len != 0 && srcconfig->cap_drop != NULL) { +- if (srcconfig->cap_drop_len > SIZE_MAX / sizeof(char *)) { +- COMMAND_ERROR("Too many capabilities to drop!"); +- ret = -1; +- goto out; +- } +- dstconfig->cap_drop = util_common_calloc_s(srcconfig->cap_drop_len * sizeof(char *)); +- if (dstconfig->cap_drop == NULL) { +- ret = -1; +- goto out; +- } +- for (i = 0; i < srcconfig->cap_drop_len; i++) { +- dstconfig->cap_drop[dstconfig->cap_drop_len] = util_strdup_s(srcconfig->cap_drop[i]); +- dstconfig->cap_drop_len++; +- } ++ if (util_dup_array_of_strings((const char **)srcconfig->cap_drop, srcconfig->cap_drop_len, &dstconfig->cap_drop, ++ &dstconfig->cap_drop_len) != 0) { ++ COMMAND_ERROR("Failed to dup cap drop"); ++ return -1; + } + + for (i = 0; i < dstconfig->cap_drop_len; i++) { +@@ -208,119 +168,43 @@ out: + + static int pack_host_network_extra_hosts(host_config *dstconfig, const isula_host_config_t *srcconfig) + { +- int ret = 0; +- size_t i = 0; +- + /* extra hosts */ +- if (srcconfig->extra_hosts_len != 0 && srcconfig->extra_hosts != NULL) { +- if (srcconfig->extra_hosts_len > SIZE_MAX / sizeof(char *)) { +- COMMAND_ERROR("Too many extra hosts to add!"); +- ret = -1; +- goto out; +- } +- dstconfig->extra_hosts = util_common_calloc_s(srcconfig->extra_hosts_len * sizeof(char *)); +- if (dstconfig->extra_hosts == NULL) { +- ret = -1; +- goto out; +- } +- for (i = 0; i < srcconfig->extra_hosts_len; i++) { +- dstconfig->extra_hosts[dstconfig->extra_hosts_len] = util_strdup_s(srcconfig->extra_hosts[i]); +- dstconfig->extra_hosts_len++; +- } ++ if (util_dup_array_of_strings((const char **)srcconfig->extra_hosts, srcconfig->extra_hosts_len, ++ &dstconfig->extra_hosts, &dstconfig->extra_hosts_len) != 0) { ++ COMMAND_ERROR("Failed to dup extra hosts"); ++ return -1; + } +-out: +- return ret; ++ ++ return 0; + } + + static int pack_host_network_dns(host_config *dstconfig, const isula_host_config_t *srcconfig) + { +- int ret = 0; +- size_t i = 0; +- +- /* dns */ +- if (srcconfig->dns_len != 0 && srcconfig->dns != NULL) { +- if (srcconfig->dns_len > SIZE_MAX / sizeof(char *)) { +- COMMAND_ERROR("Too many dns to add!"); +- ret = -1; +- goto out; +- } +- dstconfig->dns = util_common_calloc_s(srcconfig->dns_len * sizeof(char *)); +- if (dstconfig->dns == NULL) { +- ret = -1; +- goto out; +- } +- for (i = 0; i < srcconfig->dns_len; i++) { +- dstconfig->dns[dstconfig->dns_len] = util_strdup_s(srcconfig->dns[i]); +- dstconfig->dns_len++; +- } ++ if (util_dup_array_of_strings((const char **)srcconfig->dns, srcconfig->dns_len, &dstconfig->dns, ++ &dstconfig->dns_len) != 0) { ++ COMMAND_ERROR("Failed to dup dns"); ++ return -1; + } + +-out: +- return ret; +-} +- +-static int pack_host_network_dns_options(host_config *dstconfig, const isula_host_config_t *srcconfig) +-{ +- int ret = 0; +- size_t i = 0; +- +- /* dns options */ +- if (srcconfig->dns_options_len != 0 && srcconfig->dns_options != NULL) { +- if (srcconfig->dns_options_len > SIZE_MAX / sizeof(char *)) { +- COMMAND_ERROR("Too many dns options to add!"); +- ret = -1; +- goto out; +- } +- dstconfig->dns_options = util_common_calloc_s(srcconfig->dns_options_len * sizeof(char *)); +- if (dstconfig->dns_options == NULL) { +- ret = -1; +- goto out; +- } +- for (i = 0; i < srcconfig->dns_options_len; i++) { +- dstconfig->dns_options[dstconfig->dns_options_len] = util_strdup_s(srcconfig->dns_options[i]); +- dstconfig->dns_options_len++; +- } ++ if (util_dup_array_of_strings((const char **)srcconfig->dns_options, srcconfig->dns_options_len, ++ &dstconfig->dns_options, &dstconfig->dns_options_len) != 0) { ++ COMMAND_ERROR("Failed to dup dns options"); ++ return -1; + } + +-out: +- return ret; +-} +- +-static int pack_host_network_dns_search(host_config *dstconfig, const isula_host_config_t *srcconfig) +-{ +- int ret = 0; +- size_t i = 0; +- +- /* dns search */ +- if (srcconfig->dns_search_len != 0 && srcconfig->dns_search != NULL) { +- if (srcconfig->dns_search_len > SIZE_MAX / sizeof(char *)) { +- COMMAND_ERROR("Too many dns search to add!"); +- ret = -1; +- goto out; +- } +- dstconfig->dns_search = util_common_calloc_s(srcconfig->dns_search_len * sizeof(char *)); +- if (dstconfig->dns_search == NULL) { +- ret = -1; +- goto out; +- } +- for (i = 0; i < srcconfig->dns_search_len; i++) { +- dstconfig->dns_search[dstconfig->dns_search_len] = util_strdup_s(srcconfig->dns_search[i]); +- dstconfig->dns_search_len++; +- } ++ if (util_dup_array_of_strings((const char **)srcconfig->dns_search, srcconfig->dns_search_len, ++ &dstconfig->dns_search, &dstconfig->dns_search_len) != 0) { ++ COMMAND_ERROR("Failed to dup dns search"); ++ return -1; + } + +-out: +- return ret; ++ return 0; + } + + static int pack_host_config_network(host_config *dstconfig, const isula_host_config_t *srcconfig) + { + int ret = 0; + +- if (dstconfig == NULL) { +- return -1; +- } +- + ret = pack_host_network_extra_hosts(dstconfig, srcconfig); + if (ret != 0) { + goto out; +@@ -331,16 +215,6 @@ static int pack_host_config_network(host_config *dstconfig, const isula_host_con + goto out; + } + +- ret = pack_host_network_dns_options(dstconfig, srcconfig); +- if (ret != 0) { +- goto out; +- } +- +- ret = pack_host_network_dns_search(dstconfig, srcconfig); +- if (ret != 0) { +- goto out; +- } +- + out: + return ret; + } +@@ -356,9 +230,8 @@ static int check_parsed_device(const host_config_devices_element *device_map) + } + + if (!util_file_exists(device_map->path_on_host)) { +- COMMAND_ERROR( +- "Error gathering device information while adding device \"%s\",stat %s:no such file or directory", +- device_map->path_on_host, device_map->path_on_host); ++ COMMAND_ERROR("Error gathering device information while adding device \"%s\",stat %s:no such file or directory", ++ device_map->path_on_host, device_map->path_on_host); + ret = -1; + goto out; + } +@@ -428,169 +301,6 @@ erro_out: + return NULL; + } + +-static int check_ulimit_input(const char *val) +-{ +- int ret = 0; +- if (val == NULL || strcmp(val, "") == 0) { +- COMMAND_ERROR("ulimit argument can't be empty"); +- ret = -1; +- goto out; +- } +- +- if (val[0] == '=' || val[strlen(val) - 1] == '=') { +- COMMAND_ERROR("Invalid ulimit argument: \"%s\", delimiter '=' can't" +- " be the first or the last character", val); +- ret = -1; +- } +- +-out: +- return ret; +-} +- +-static void get_ulimit_split_parts(const char *val, char ***parts, size_t *parts_len, char deli) +-{ +- *parts = util_string_split_multi(val, deli); +- if (*parts == NULL) { +- COMMAND_ERROR("Out of memory"); +- return; +- } +- *parts_len = util_array_len((const char **)(*parts)); +-} +- +-static int parse_soft_hard_ulimit(const char *val, char **limitvals, size_t limitvals_len, int64_t *soft, int64_t *hard) +-{ +- int ret = 0; +- // parse soft +- ret = util_safe_llong(limitvals[0], (long long *)soft); +- if (ret < 0) { +- COMMAND_ERROR("Invalid ulimit soft value: \"%s\", parse int64 failed: %s", val, strerror(-ret)); +- ret = -1; +- goto out; +- } +- +- // parse hard if exists +- if (limitvals_len > 1) { +- ret = util_safe_llong(limitvals[1], (long long *)hard); +- if (ret < 0) { +- COMMAND_ERROR("Invalid ulimit hard value: \"%s\", parse int64 failed: %s", val, strerror(-ret)); +- ret = -1; +- goto out; +- } +- +- if (*soft > *hard) { +- COMMAND_ERROR("Ulimit soft limit must be less than or equal to hard limit: %lld > %lld", +- (long long int)(*soft), (long long int)(*hard)); +- ret = -1; +- goto out; +- } +- } else { +- *hard = *soft; // default to soft in case no hard was set +- } +-out: +- return ret; +-} +- +-static int check_ulimit_type(const char *type) +-{ +- int ret = 0; +- char **tmptype = NULL; +- char *ulimit_valid_type[] = { +- // "as", // Disabled since this doesn't seem usable with the way Docker inits a container. +- "core", "cpu", "data", "fsize", "locks", "memlock", "msgqueue", "nice", +- "nofile", "nproc", "rss", "rtprio", "rttime", "sigpending", "stack", NULL +- }; +- +- for (tmptype = ulimit_valid_type; *tmptype != NULL; tmptype++) { +- if (strcmp(type, *tmptype) == 0) { +- break; +- } +- } +- +- if (*tmptype == NULL) { +- COMMAND_ERROR("Invalid ulimit type: %s", type); +- ret = -1; +- } +- return ret; +-} +- +-static host_config_ulimits_element *parse_ulimit(const char *val) +-{ +- int ret = 0; +- int64_t soft = 0; +- int64_t hard = 0; +- size_t parts_len = 0; +- size_t limitvals_len = 0; +- char **parts = NULL; +- char **limitvals = NULL; +- host_config_ulimits_element *ulimit = NULL; +- +- ret = check_ulimit_input(val); +- if (ret != 0) { +- return NULL; +- } +- +- get_ulimit_split_parts(val, &parts, &parts_len, '='); +- if (parts == NULL) { +- ERROR("Out of memory"); +- return NULL; +- } else if (parts_len != 2) { +- COMMAND_ERROR("Invalid ulimit argument: %s", val); +- ret = -1; +- goto out; +- } +- +- ret = check_ulimit_type(parts[0]); +- if (ret != 0) { +- ret = -1; +- goto out; +- } +- +- if (parts[1][0] == ':' || parts[1][strlen(parts[1]) - 1] == ':') { +- COMMAND_ERROR("Invalid ulimit value: \"%s\", delimiter ':' can't be the first" +- " or the last character", val); +- ret = -1; +- goto out; +- } +- +- // parse value +- get_ulimit_split_parts(parts[1], &limitvals, &limitvals_len, ':'); +- if (limitvals == NULL) { +- ret = -1; +- goto out; +- } +- +- if (limitvals_len > 2) { +- COMMAND_ERROR("Too many limit value arguments - %s, can only have up to two, `soft[:hard]`", +- parts[1]); +- ret = -1; +- goto out; +- } +- +- ret = parse_soft_hard_ulimit(val, limitvals, limitvals_len, &soft, &hard); +- if (ret < 0) { +- goto out; +- } +- +- ulimit = util_common_calloc_s(sizeof(host_config_ulimits_element)); +- if (ulimit == NULL) { +- ret = -1; +- goto out; +- } +- ulimit->name = util_strdup_s(parts[0]); +- ulimit->hard = hard; +- ulimit->soft = soft; +- +-out: +- util_free_array(parts); +- util_free_array(limitvals); +- if (ret != 0) { +- free_host_config_ulimits_element(ulimit); +- ulimit = NULL; +- } +- +- return ulimit; +-} +- + static void pack_cgroup_resources_cpu(host_config *dstconfig, const isula_host_config_t *srcconfig) + { + /* cgroup blkio weight */ +@@ -598,6 +308,11 @@ static void pack_cgroup_resources_cpu(host_config *dstconfig, const isula_host_c + dstconfig->blkio_weight = srcconfig->cr->blkio_weight; + } + ++ /* cpus */ ++ if (srcconfig->cr->nano_cpus != 0) { ++ dstconfig->nano_cpus = srcconfig->cr->nano_cpus; ++ } ++ + /* cpu shares */ + if (srcconfig->cr->cpu_shares) { + dstconfig->cpu_shares = srcconfig->cr->cpu_shares; +@@ -703,7 +418,7 @@ static int pack_hostconfig_ulimits(host_config *dstconfig, const isula_host_conf + bool exists = false; + host_config_ulimits_element *tmp = NULL; + +- tmp = parse_ulimit(srcconfig->ulimits[i]); ++ tmp = parse_opt_ulimit(srcconfig->ulimits[i]); + if (tmp == NULL) { + ret = -1; + goto out; +@@ -739,19 +454,19 @@ static int pack_hostconfig_cgroup(host_config *dstconfig, const isula_host_confi + return ret; + } + +-static host_config_blkio_weight_device_element *pack_blkio_weight_devices(const char *devices) ++static defs_blkio_weight_device *pack_blkio_weight_devices(const char *devices) + { + char **tmp_str = NULL; + unsigned int weight = 0; + size_t tmp_str_len = 0; +- host_config_blkio_weight_device_element *weight_dev = NULL; ++ defs_blkio_weight_device *weight_dev = NULL; + + if (devices == NULL || !strcmp(devices, "")) { + COMMAND_ERROR("Weight devices can't be empty"); + return NULL; + } + +- weight_dev = util_common_calloc_s(sizeof(host_config_blkio_weight_device_element)); ++ weight_dev = util_common_calloc_s(sizeof(defs_blkio_weight_device)); + if (weight_dev == NULL) { + ERROR("Out of memory"); + return NULL; +@@ -793,11 +508,11 @@ static host_config_blkio_weight_device_element *pack_blkio_weight_devices(const + + erro_out: + util_free_array(tmp_str); +- free_host_config_blkio_weight_device_element(weight_dev); ++ free_defs_blkio_weight_device(weight_dev); + return NULL; + } + +-static int parse_blkio_throttle_bps_device(const char *device, char **path, const uint64_t *rate) ++static int parse_blkio_throttle_bps_device(const char *device, char **path, uint64_t *rate) + { + int ret = 0; + char **split = NULL; +@@ -817,7 +532,8 @@ static int parse_blkio_throttle_bps_device(const char *device, char **path, cons + + if (util_parse_byte_size_string(split[1], (int64_t *)rate) != 0) { + COMMAND_ERROR("invalid rate for device: %s. The correct format is :[]." +- " Number must be a positive integer. Unit is optional and can be kb, mb, or gb", device); ++ " Number must be a positive integer. Unit is optional and can be kb, mb, or gb", ++ device); + ret = -1; + goto out; + } +@@ -829,19 +545,19 @@ out: + } + + // validate that the specified string has a valid device-rate format. +-static host_config_blkio_device_read_bps_element *pack_throttle_read_bps_device(const char *device) ++static defs_blkio_device *pack_throttle_bps_device(const char *device) + { + char *path = NULL; + uint64_t rate = 0; +- host_config_blkio_device_read_bps_element *read_bps_dev = NULL; ++ defs_blkio_device *bps_dev = NULL; + + if (device == NULL || !strcmp(device, "")) { + COMMAND_ERROR("blkio throttle read bps device can't be empty"); + return NULL; + } + +- read_bps_dev = util_common_calloc_s(sizeof(host_config_blkio_device_read_bps_element)); +- if (read_bps_dev == NULL) { ++ bps_dev = util_common_calloc_s(sizeof(defs_blkio_device)); ++ if (bps_dev == NULL) { + ERROR("Out of memory"); + return NULL; + } +@@ -850,47 +566,88 @@ static host_config_blkio_device_read_bps_element *pack_throttle_read_bps_device( + goto error_out; + } + +- read_bps_dev->path = path; +- read_bps_dev->rate = rate; ++ bps_dev->path = path; ++ bps_dev->rate = rate; + +- return read_bps_dev; ++ return bps_dev; + + error_out: + free(path); +- free_host_config_blkio_device_read_bps_element(read_bps_dev); ++ free_defs_blkio_device(bps_dev); + return NULL; + } + ++static int parse_blkio_throttle_iops_device(const char *device, char **path, uint64_t *rate) ++{ ++ int ret = 0; ++ char **split = NULL; ++ ++ split = util_string_split_multi(device, ':'); ++ if (split == NULL || util_array_len((const char **)split) != 2) { ++ COMMAND_ERROR("bad format: %s", device); ++ ret = -1; ++ goto out; ++ } ++ ++ if (strncmp(split[0], "/dev/", strlen("/dev/")) != 0) { ++ COMMAND_ERROR("bad format for device path: %s", device); ++ ret = -1; ++ goto out; ++ } ++ ++ if (!util_valid_positive_interger(split[1])) { ++ COMMAND_ERROR("invalid rate for device: %s. The correct format is :." ++ " Number must be unsigned 64 bytes integer.", ++ device); ++ ret = -1; ++ goto out; ++ } ++ ++ if (util_safe_uint64(split[1], rate) != 0) { ++ COMMAND_ERROR("invalid rate for device: %s. The correct format is :." ++ " Number must be unsigned 64 bytes integer.", ++ device); ++ ret = -1; ++ goto out; ++ } ++ ++ *path = util_strdup_s(split[0]); ++ ++out: ++ util_free_array(split); ++ return ret; ++} ++ + // validate that the specified string has a valid device-rate format. +-static host_config_blkio_device_write_bps_element *pack_throttle_write_bps_device(const char *device) ++static defs_blkio_device *pack_throttle_iops_device(const char *device) + { + char *path = NULL; + uint64_t rate = 0; +- host_config_blkio_device_write_bps_element *write_bps_dev = NULL; ++ defs_blkio_device *iops_dev = NULL; + + if (device == NULL || !strcmp(device, "")) { +- COMMAND_ERROR("blkio throttle write bps device can't be empty"); ++ COMMAND_ERROR("blkio throttle read bps device can't be empty"); + return NULL; + } + +- write_bps_dev = util_common_calloc_s(sizeof(host_config_blkio_device_write_bps_element)); +- if (write_bps_dev == NULL) { ++ iops_dev = util_common_calloc_s(sizeof(defs_blkio_device)); ++ if (iops_dev == NULL) { + ERROR("Out of memory"); + return NULL; + } + +- if (parse_blkio_throttle_bps_device(device, &path, &rate) != 0) { ++ if (parse_blkio_throttle_iops_device(device, &path, &rate) != 0) { + goto error_out; + } + +- write_bps_dev->path = path; +- write_bps_dev->rate = rate; ++ iops_dev->path = path; ++ iops_dev->rate = rate; + +- return write_bps_dev; ++ return iops_dev; + + error_out: + free(path); +- free_host_config_blkio_device_write_bps_element(write_bps_dev); ++ free_defs_blkio_device(iops_dev); + return NULL; + } + +@@ -1034,7 +791,7 @@ static bool parse_host_path(const char *input, const char *token, host_config_ho + COMMAND_ERROR("Host channel host path should be absolute: %s", token); + return false; + } +- if (cleanpath(token, real_path, sizeof(real_path)) == NULL) { ++ if (util_clean_path(token, real_path, sizeof(real_path)) == NULL) { + ERROR("Failed to clean path: '%s'", token); + return false; + } +@@ -1058,7 +815,7 @@ static bool parse_container_path(const char *input, const char *token, host_conf + COMMAND_ERROR("Host channel container path should be absolute: %s", token); + return false; + } +- if (cleanpath(token, real_path, sizeof(real_path)) == NULL) { ++ if (util_clean_path(token, real_path, sizeof(real_path)) == NULL) { + ERROR("Failed to clean path: '%s'", token); + return false; + } +@@ -1178,25 +935,10 @@ erro_out: + } + static int append_no_new_privileges_to_security_opts(host_config *dstconfig) + { +- int ret = 0; +- size_t new_size, old_size; +- char **tmp_security_opt = NULL; +- +- if (dstconfig->security_opt_len > (SIZE_MAX / sizeof(char *)) - 1) { +- COMMAND_ERROR("Out of memory"); +- return -1; +- } +- new_size = (dstconfig->security_opt_len + 1) * sizeof(char *); +- old_size = dstconfig->security_opt_len * sizeof(char *); +- ret = mem_realloc((void **)(&tmp_security_opt), new_size, (void *)dstconfig->security_opt, old_size); +- if (ret != 0) { +- COMMAND_ERROR("Out of memory"); +- return ret; +- } +- dstconfig->security_opt = tmp_security_opt; +- dstconfig->security_opt[dstconfig->security_opt_len++] = util_strdup_s("no-new-privileges"); ++ dstconfig->security_opt[dstconfig->security_opt_len] = util_strdup_s("no-new-privileges"); ++ dstconfig->security_opt_len++; + +- return ret; ++ return 0; + } + + static int append_seccomp_to_security_opts(const char *full_opt, const char *seccomp_file, host_config *dstconfig) +@@ -1218,8 +960,7 @@ static int append_seccomp_to_security_opts(const char *full_opt, const char *sec + + seccomp_spec = get_seccomp_security_opt_spec(seccomp_file); + if (seccomp_spec == NULL) { +- ERROR("Failed to parse docker format seccomp specification file \"%s\", error message: %s", +- seccomp_file, err); ++ ERROR("Failed to parse docker format seccomp specification file \"%s\", error message: %s", seccomp_file, err); + COMMAND_ERROR("failed to parse seccomp file: %s", seccomp_file); + ret = -1; + goto out; +@@ -1262,29 +1003,15 @@ out: + return ret; + } + ++#ifdef ENABLE_SELINUX + static int append_selinux_label_to_security_opts(const char *selinux_label, host_config *dstconfig) + { +- int ret = 0; +- size_t new_size; +- size_t old_size; +- char **tmp_security_opt = NULL; +- +- if (dstconfig->security_opt_len > (SIZE_MAX / sizeof(char *)) - 1) { +- COMMAND_ERROR("Too large security options"); +- return -1; +- } +- new_size = (dstconfig->security_opt_len + 1) * sizeof(char *); +- old_size = dstconfig->security_opt_len * sizeof(char *); +- ret = mem_realloc((void **)(&tmp_security_opt), new_size, (void *)dstconfig->security_opt, old_size); +- if (ret != 0) { +- COMMAND_ERROR("Out of memory"); +- return ret; +- } +- dstconfig->security_opt = tmp_security_opt; +- dstconfig->security_opt[dstconfig->security_opt_len++] = util_strdup_s(selinux_label); ++ dstconfig->security_opt[dstconfig->security_opt_len] = util_strdup_s(selinux_label); ++ dstconfig->security_opt_len++; + +- return ret; ++ return 0; + } ++#endif + + static int parse_security_opts(const isula_host_config_t *srcconfig, host_config *dstconfig) + { +@@ -1303,8 +1030,10 @@ static int parse_security_opts(const isula_host_config_t *srcconfig, host_config + } else { + if (strcmp(items[0], "seccomp") == 0) { + ret = append_seccomp_to_security_opts(srcconfig->security[i], items[1], dstconfig); ++#ifdef ENABLE_SELINUX + } else if (strcmp(items[0], "label") == 0) { + ret = append_selinux_label_to_security_opts(srcconfig->security[i], dstconfig); ++#endif + } else { + ret = -1; + } +@@ -1325,61 +1054,55 @@ out: + return ret; + } + +-int generate_storage_opts(host_config **dstconfig, const isula_host_config_t *srcconfig) ++int generate_storage_opts(host_config *dstconfig, const isula_host_config_t *srcconfig) + { + int ret = 0; +- size_t j; + +- if (srcconfig->storage_opts == NULL || dstconfig == NULL) { ++ if (srcconfig->storage_opts == NULL) { + goto out; + } + +- (*dstconfig)->storage_opt = util_common_calloc_s(sizeof(json_map_string_string)); +- if ((*dstconfig)->storage_opt == NULL) { ++ dstconfig->storage_opt = util_common_calloc_s(sizeof(json_map_string_string)); ++ if (dstconfig->storage_opt == NULL) { + ret = -1; + goto out; + } +- for (j = 0; j < srcconfig->storage_opts->len; j++) { +- ret = append_json_map_string_string((*dstconfig)->storage_opt, +- srcconfig->storage_opts->keys[j], +- srcconfig->storage_opts->values[j]); +- if (ret != 0) { +- ERROR("Append map failed"); +- ret = -1; +- goto out; +- } +- } + +-out: ++ if (dup_json_map_string_string(srcconfig->storage_opts, dstconfig->storage_opt) != 0) { ++ COMMAND_ERROR("Failed to dup storage opts"); ++ ret = -1; ++ goto out; ++ } ++ ++out: + return ret; + } + +-static int generate_sysctls(host_config **dstconfig, const isula_host_config_t *srcconfig) ++static int generate_sysctls(host_config *dstconfig, const isula_host_config_t *srcconfig) + { + int ret = 0; +- size_t j; + +- if (srcconfig->sysctls == NULL || dstconfig == NULL) { ++ if (srcconfig->sysctls == NULL) { + goto out; + } + +- (*dstconfig)->sysctls = util_common_calloc_s(sizeof(json_map_string_string)); +- if ((*dstconfig)->sysctls == NULL) { ++ dstconfig->sysctls = util_common_calloc_s(sizeof(json_map_string_string)); ++ if (dstconfig->sysctls == NULL) { + ret = -1; + goto out; + } +- for (j = 0; j < srcconfig->sysctls->len; j++) { +- ret = append_json_map_string_string((*dstconfig)->sysctls, srcconfig->sysctls->keys[j], +- srcconfig->sysctls->values[j]); +- if (ret < 0) { +- goto out; +- } ++ ++ if (dup_json_map_string_string(srcconfig->sysctls, dstconfig->sysctls) != 0) { ++ COMMAND_ERROR("Failed to dup sysctls"); ++ ret = -1; ++ goto out; + } ++ + out: + return ret; + } + +-int generate_devices(host_config **dstconfig, const isula_host_config_t *srcconfig) ++int generate_devices(host_config *dstconfig, const isula_host_config_t *srcconfig) + { + int ret = 0; + size_t i = 0; +@@ -1393,26 +1116,26 @@ int generate_devices(host_config **dstconfig, const isula_host_config_t *srcconf + ret = -1; + goto out; + } +- (*dstconfig)->devices = util_common_calloc_s(sizeof(host_config_devices_element *) * srcconfig->devices_len); +- if ((*dstconfig)->devices == NULL) { ++ dstconfig->devices = util_common_calloc_s(sizeof(host_config_devices_element *) * srcconfig->devices_len); ++ if (dstconfig->devices == NULL) { + ret = -1; + goto out; + } + for (i = 0; i < srcconfig->devices_len; i++) { +- (*dstconfig)->devices[i] = parse_device(srcconfig->devices[i]); +- if ((*dstconfig)->devices[i] == NULL) { ++ dstconfig->devices[i] = parse_device(srcconfig->devices[i]); ++ if (dstconfig->devices[i] == NULL) { + ERROR("Failed to parse devices:%s", srcconfig->devices[i]); + ret = -1; + goto out; + } + +- (*dstconfig)->devices_len++; ++ dstconfig->devices_len++; + } + out: + return ret; + } + +-static int generate_blkio_weight_device(host_config **dstconfig, const isula_host_config_t *srcconfig) ++static int generate_blkio_weight_device(host_config *dstconfig, const isula_host_config_t *srcconfig) + { + int ret = 0; + size_t i = 0; +@@ -1421,118 +1144,153 @@ static int generate_blkio_weight_device(host_config **dstconfig, const isula_hos + goto out; + } + +- if (srcconfig->blkio_weight_device_len > SIZE_MAX / sizeof(host_config_blkio_weight_device_element *)) { +- ERROR("Too many blkio weight devies to get!"); ++ dstconfig->blkio_weight_device = ++ util_smart_calloc_s(sizeof(defs_blkio_weight_device *), srcconfig->blkio_weight_device_len); ++ if (dstconfig->blkio_weight_device == NULL) { + ret = -1; + goto out; + } + +- (*dstconfig)->blkio_weight_device = +- util_common_calloc_s(srcconfig->blkio_weight_device_len * sizeof(host_config_blkio_weight_device_element *)); +- if ((*dstconfig)->blkio_weight_device == NULL) { +- ret = -1; +- goto out; +- } + for (i = 0; i < srcconfig->blkio_weight_device_len; i++) { +- (*dstconfig)->blkio_weight_device[(*dstconfig)->blkio_weight_device_len] = ++ dstconfig->blkio_weight_device[dstconfig->blkio_weight_device_len] = + pack_blkio_weight_devices(srcconfig->blkio_weight_device[i]); +- if ((*dstconfig)->blkio_weight_device[(*dstconfig)->blkio_weight_device_len] == NULL) { ++ if (dstconfig->blkio_weight_device[dstconfig->blkio_weight_device_len] == NULL) { + ERROR("Failed to get blkio weight devies"); + ret = -1; + goto out; + } + +- (*dstconfig)->blkio_weight_device_len++; ++ dstconfig->blkio_weight_device_len++; + } + out: + return ret; + } + +-static int generate_blkio_throttle_read_bps_device(host_config **dstconfig, const isula_host_config_t *srcconfig) ++static int generate_blkio_throttle_read_bps_device(host_config *dstconfig, const isula_host_config_t *srcconfig) + { + int ret = 0; + size_t i = 0; + +- if (dstconfig == NULL || *dstconfig == NULL) { ++ if (srcconfig->blkio_throttle_read_bps_device == NULL || srcconfig->blkio_throttle_read_bps_device_len == 0) { + goto out; + } + +- if (srcconfig->blkio_throttle_read_bps_device == NULL || srcconfig->blkio_throttle_read_bps_device_len == 0) { ++ dstconfig->blkio_device_read_bps = ++ util_smart_calloc_s(sizeof(defs_blkio_device *), srcconfig->blkio_throttle_read_bps_device_len); ++ if (dstconfig->blkio_device_read_bps == NULL) { ++ ret = -1; + goto out; + } + +- if (srcconfig->blkio_throttle_read_bps_device_len > +- SIZE_MAX / sizeof(host_config_blkio_device_read_bps_element *)) { +- ERROR("Too many blkio throttle read bps devies to get!"); +- ret = -1; ++ for (i = 0; i < srcconfig->blkio_throttle_read_bps_device_len; i++) { ++ dstconfig->blkio_device_read_bps[dstconfig->blkio_device_read_bps_len] = ++ pack_throttle_bps_device(srcconfig->blkio_throttle_read_bps_device[i]); ++ if (dstconfig->blkio_device_read_bps[dstconfig->blkio_device_read_bps_len] == NULL) { ++ ERROR("Failed to get blkio throttle read bps devices"); ++ ret = -1; ++ goto out; ++ } ++ ++ dstconfig->blkio_device_read_bps_len++; ++ } ++out: ++ return ret; ++} ++ ++static int generate_blkio_throttle_write_bps_device(host_config *dstconfig, const isula_host_config_t *srcconfig) ++{ ++ int ret = 0; ++ size_t i = 0; ++ ++ if (srcconfig->blkio_throttle_write_bps_device == NULL || srcconfig->blkio_throttle_write_bps_device_len == 0) { + goto out; + } + +- (*dstconfig)->blkio_device_read_bps = +- util_common_calloc_s(srcconfig->blkio_throttle_read_bps_device_len * +- sizeof(host_config_blkio_device_read_bps_element *)); +- if ((*dstconfig)->blkio_device_read_bps == NULL) { ++ dstconfig->blkio_device_write_bps = ++ util_smart_calloc_s(sizeof(defs_blkio_device *), srcconfig->blkio_throttle_write_bps_device_len); ++ if (dstconfig->blkio_device_write_bps == NULL) { + ret = -1; + goto out; + } +- for (i = 0; i < srcconfig->blkio_throttle_read_bps_device_len; i++) { +- (*dstconfig)->blkio_device_read_bps[(*dstconfig)->blkio_device_read_bps_len] = +- pack_throttle_read_bps_device(srcconfig->blkio_throttle_read_bps_device[i]); +- if ((*dstconfig)->blkio_device_read_bps[(*dstconfig)->blkio_device_read_bps_len] == NULL) { +- ERROR("Failed to get blkio throttle read bps devices"); ++ ++ for (i = 0; i < srcconfig->blkio_throttle_write_bps_device_len; i++) { ++ dstconfig->blkio_device_write_bps[dstconfig->blkio_device_write_bps_len] = ++ pack_throttle_bps_device(srcconfig->blkio_throttle_write_bps_device[i]); ++ if (dstconfig->blkio_device_write_bps[dstconfig->blkio_device_write_bps_len] == NULL) { ++ ERROR("Failed to get blkio throttle write bps devices"); + ret = -1; + goto out; + } + +- (*dstconfig)->blkio_device_read_bps_len++; ++ dstconfig->blkio_device_write_bps_len++; + } + out: + return ret; + } + +-static int generate_blkio_throttle_write_bps_device(host_config **dstconfig, const isula_host_config_t *srcconfig) ++static int generate_blkio_throttle_read_iops_device(host_config *dstconfig, const isula_host_config_t *srcconfig) + { + int ret = 0; + size_t i = 0; + +- if (dstconfig == NULL || *dstconfig == NULL) { ++ if (srcconfig->blkio_throttle_read_iops_device == NULL || srcconfig->blkio_throttle_read_iops_device_len == 0) { + goto out; + } + +- if (srcconfig->blkio_throttle_write_bps_device == NULL || srcconfig->blkio_throttle_write_bps_device_len == 0) { ++ dstconfig->blkio_device_read_iops = ++ util_smart_calloc_s(sizeof(defs_blkio_device *), srcconfig->blkio_throttle_read_iops_device_len); ++ if (dstconfig->blkio_device_read_iops == NULL) { ++ ret = -1; + goto out; + } + ++ for (i = 0; i < srcconfig->blkio_throttle_read_iops_device_len; i++) { ++ dstconfig->blkio_device_read_iops[dstconfig->blkio_device_read_iops_len] = ++ pack_throttle_iops_device(srcconfig->blkio_throttle_read_iops_device[i]); ++ if (dstconfig->blkio_device_read_iops[dstconfig->blkio_device_read_iops_len] == NULL) { ++ ERROR("Failed to get blkio throttle read iops devices"); ++ ret = -1; ++ goto out; ++ } + +- if (srcconfig->blkio_throttle_write_bps_device_len > +- SIZE_MAX / sizeof(host_config_blkio_device_write_bps_element *)) { +- ERROR("Too many blkio throttle write bps devies to get!"); +- ret = -1; ++ dstconfig->blkio_device_read_iops_len++; ++ } ++out: ++ return ret; ++} ++ ++static int generate_blkio_throttle_write_iops_device(host_config *dstconfig, const isula_host_config_t *srcconfig) ++{ ++ int ret = 0; ++ size_t i = 0; ++ ++ if (srcconfig->blkio_throttle_write_iops_device == NULL || srcconfig->blkio_throttle_write_iops_device_len == 0) { + goto out; + } + +- (*dstconfig)->blkio_device_write_bps = util_common_calloc_s(srcconfig->blkio_throttle_write_bps_device_len * +- sizeof(host_config_blkio_device_write_bps_element *)); +- if ((*dstconfig)->blkio_device_write_bps == NULL) { ++ dstconfig->blkio_device_write_iops = ++ util_smart_calloc_s(sizeof(defs_blkio_device *), srcconfig->blkio_throttle_write_iops_device_len); ++ if (dstconfig->blkio_device_write_iops == NULL) { + ret = -1; + goto out; + } +- for (i = 0; i < srcconfig->blkio_throttle_write_bps_device_len; i++) { +- (*dstconfig)->blkio_device_write_bps[(*dstconfig)->blkio_device_write_bps_len] = +- pack_throttle_write_bps_device(srcconfig->blkio_throttle_write_bps_device[i]); +- if ((*dstconfig)->blkio_device_write_bps[(*dstconfig)->blkio_device_write_bps_len] == NULL) { +- ERROR("Failed to get blkio throttle write bps devices"); ++ ++ for (i = 0; i < srcconfig->blkio_throttle_write_iops_device_len; i++) { ++ dstconfig->blkio_device_write_iops[dstconfig->blkio_device_write_iops_len] = ++ pack_throttle_iops_device(srcconfig->blkio_throttle_write_iops_device[i]); ++ if (dstconfig->blkio_device_write_iops[dstconfig->blkio_device_write_iops_len] == NULL) { ++ ERROR("Failed to get blkio throttle write iops devices"); + ret = -1; + goto out; + } + +- (*dstconfig)->blkio_device_write_bps_len++; ++ dstconfig->blkio_device_write_iops_len++; + } + out: + return ret; + } + +-static int generate_blkio(host_config **dstconfig, const isula_host_config_t *srcconfig) ++static int generate_blkio(host_config *dstconfig, const isula_host_config_t *srcconfig) + { + int ret; + +@@ -1541,6 +1299,7 @@ static int generate_blkio(host_config **dstconfig, const isula_host_config_t *sr + if (ret < 0) { + goto out; + } ++ + /* blkio throttle read bps devies */ + ret = generate_blkio_throttle_read_bps_device(dstconfig, srcconfig); + if (ret < 0) { +@@ -1553,11 +1312,23 @@ static int generate_blkio(host_config **dstconfig, const isula_host_config_t *sr + goto out; + } + ++ /* blkio throttle read iops devies */ ++ ret = generate_blkio_throttle_read_iops_device(dstconfig, srcconfig); ++ if (ret < 0) { ++ goto out; ++ } ++ ++ /* blkio throttle write iops devies */ ++ ret = generate_blkio_throttle_write_iops_device(dstconfig, srcconfig); ++ if (ret < 0) { ++ goto out; ++ } ++ + out: + return ret; + } + +-int generate_hugetlb_limits(host_config **dstconfig, const isula_host_config_t *srcconfig) ++int generate_hugetlb_limits(host_config *dstconfig, const isula_host_config_t *srcconfig) + { + int ret = 0; + size_t i = 0; +@@ -1572,83 +1343,147 @@ int generate_hugetlb_limits(host_config **dstconfig, const isula_host_config_t * + goto out; + } + +- (*dstconfig)->hugetlbs = util_common_calloc_s(srcconfig->hugetlbs_len * sizeof(host_config_hugetlbs_element *)); +- if ((*dstconfig)->hugetlbs == NULL) { ++ dstconfig->hugetlbs = util_common_calloc_s(srcconfig->hugetlbs_len * sizeof(host_config_hugetlbs_element *)); ++ if (dstconfig->hugetlbs == NULL) { + ret = -1; + goto out; + } + for (i = 0; i < srcconfig->hugetlbs_len; i++) { +- (*dstconfig)->hugetlbs[(*dstconfig)->hugetlbs_len] = pase_hugetlb_limit(srcconfig->hugetlbs[i]); +- if ((*dstconfig)->hugetlbs[(*dstconfig)->hugetlbs_len] == NULL) { ++ dstconfig->hugetlbs[dstconfig->hugetlbs_len] = pase_hugetlb_limit(srcconfig->hugetlbs[i]); ++ if (dstconfig->hugetlbs[dstconfig->hugetlbs_len] == NULL) { + ERROR("Failed to get hugepage limits"); + ret = -1; + goto out; + } + +- (*dstconfig)->hugetlbs_len++; ++ dstconfig->hugetlbs_len++; + } + out: + return ret; + } + +-int generate_binds(host_config **dstconfig, const isula_host_config_t *srcconfig) ++int generate_volumes_from(host_config *dstconfig, const isula_host_config_t *srcconfig) + { +- int ret = 0; +- size_t i = 0; ++ if (util_dup_array_of_strings((const char **)srcconfig->volumes_from, srcconfig->volumes_from_len, ++ &dstconfig->volumes_from, &dstconfig->volumes_from_len) != 0) { ++ COMMAND_ERROR("Failed to dup volumes-from"); ++ return -1; ++ } + +- if (srcconfig->binds == NULL || srcconfig->binds_len == 0) { +- goto out; ++ return 0; ++} ++ ++int generate_binds(host_config *dstconfig, const isula_host_config_t *srcconfig) ++{ ++ if (util_dup_array_of_strings((const char **)srcconfig->binds, srcconfig->binds_len, &dstconfig->binds, ++ &dstconfig->binds_len) != 0) { ++ COMMAND_ERROR("Failed to dup binds"); ++ return -1; + } + +- if (srcconfig->binds_len > SIZE_MAX / sizeof(char *)) { +- COMMAND_ERROR("Too many binds to mount!"); +- ret = -1; +- goto out; ++ return 0; ++} ++ ++int generate_device_cgroup_rules(host_config *dstconfig, const isula_host_config_t *srcconfig) ++{ ++ if (util_dup_array_of_strings((const char **)srcconfig->device_cgroup_rules, srcconfig->device_cgroup_rules_len, ++ &dstconfig->device_cgroup_rules, &dstconfig->device_cgroup_rules_len) != 0) { ++ COMMAND_ERROR("Failed to dup device cgroup rules"); ++ return -1; + } + +- (*dstconfig)->binds = util_common_calloc_s(srcconfig->binds_len * sizeof(char *)); +- if ((*dstconfig)->binds == NULL) { +- ret = -1; +- goto out; ++ return 0; ++} ++ ++static mount_spec *dup_mount_spec(mount_spec *spec) ++{ ++ int ret = 0; ++ mount_spec *m = NULL; ++ ++ m = util_common_calloc_s(sizeof(mount_spec)); ++ if (m == NULL) { ++ ERROR("out of memory"); ++ return NULL; + } +- for (i = 0; i < srcconfig->binds_len; i++) { +- (*dstconfig)->binds[(*dstconfig)->binds_len] = util_strdup_s(srcconfig->binds[i]); +- (*dstconfig)->binds_len++; ++ ++ m->type = util_strdup_s(spec->type); ++ m->source = util_strdup_s(spec->source); ++ m->target = util_strdup_s(spec->target); ++ m->readonly = spec->readonly; ++ m->consistency = util_strdup_s(spec->consistency); ++ if (spec->bind_options != NULL) { ++ m->bind_options = util_common_calloc_s(sizeof(bind_options)); ++ if (m->bind_options == NULL) { ++ ret = -1; ++ goto out; ++ } ++ m->bind_options->propagation = util_strdup_s(spec->bind_options->propagation); ++ m->bind_options->selinux_opts = util_strdup_s(spec->bind_options->selinux_opts); ++ } ++ if (spec->volume_options != NULL) { ++ m->volume_options = util_common_calloc_s(sizeof(volume_options)); ++ if (m->volume_options == NULL) { ++ ret = -1; ++ goto out; ++ } ++ m->volume_options->no_copy = spec->volume_options->no_copy; + } + + out: +- return ret; ++ if (ret != 0) { ++ free_mount_spec(m); ++ m = NULL; ++ } ++ ++ return m; + } + +-int generate_groups(host_config **dstconfig, const isula_host_config_t *srcconfig) ++static int generate_mounts(host_config *dstconfig, const isula_host_config_t *srcconfig) + { + int ret = 0; +- size_t i = 0; ++ int i = 0; + +- if (srcconfig->group_add == NULL || srcconfig->group_add_len == 0 || dstconfig == NULL) { ++ if (srcconfig->mounts == NULL || srcconfig->mounts_len == 0) { + goto out; + } + +- if (srcconfig->group_add_len > SIZE_MAX / sizeof(char *)) { +- COMMAND_ERROR("Too many groups to add!"); ++ if (srcconfig->mounts_len > SIZE_MAX / sizeof(char *)) { ++ COMMAND_ERROR("Too many mounts to mount!"); + ret = -1; + goto out; + } + +- (*dstconfig)->group_add = util_common_calloc_s(srcconfig->group_add_len * sizeof(char *)); +- if ((*dstconfig)->group_add == NULL) { ++ dstconfig->mounts = util_common_calloc_s(srcconfig->mounts_len * sizeof(mount_spec*)); ++ if (dstconfig->mounts == NULL) { + ret = -1; + goto out; + } +- for (i = 0; i < srcconfig->group_add_len; i++) { +- (*dstconfig)->group_add[(*dstconfig)->group_add_len] = util_strdup_s(srcconfig->group_add[i]); +- (*dstconfig)->group_add_len++; ++ for (i = 0; i < srcconfig->mounts_len; i++) { ++ dstconfig->mounts[dstconfig->mounts_len] = dup_mount_spec(srcconfig->mounts[i]); ++ if (dstconfig->mounts[dstconfig->mounts_len] == NULL) { ++ ret = -1; ++ goto out; ++ } ++ dstconfig->mounts_len++; + } ++ + out: ++ + return ret; + } + +-int generate_security(host_config **dstconfig, const isula_host_config_t *srcconfig) ++int generate_groups(host_config *dstconfig, const isula_host_config_t *srcconfig) ++{ ++ if (util_dup_array_of_strings((const char **)srcconfig->group_add, srcconfig->group_add_len, &dstconfig->group_add, ++ &dstconfig->group_add_len) != 0) { ++ COMMAND_ERROR("Failed to dup device group add"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int generate_security(host_config *dstconfig, const isula_host_config_t *srcconfig) + { + int ret = 0; + +@@ -1662,13 +1497,13 @@ int generate_security(host_config **dstconfig, const isula_host_config_t *srccon + goto out; + } + +- (*dstconfig)->security_opt = util_common_calloc_s(srcconfig->security_len * sizeof(char *)); +- if ((*dstconfig)->security_opt == NULL) { ++ dstconfig->security_opt = util_common_calloc_s(srcconfig->security_len * sizeof(char *)); ++ if (dstconfig->security_opt == NULL) { + ret = -1; + goto out; + } + +- if (parse_security_opts(srcconfig, (*dstconfig)) != 0) { ++ if (parse_security_opts(srcconfig, dstconfig) != 0) { + ret = -1; + goto out; + } +@@ -1703,12 +1538,12 @@ static int pack_host_config_common(host_config *dstconfig, const isula_host_conf + goto out; + } + +- ret = generate_storage_opts(&dstconfig, srcconfig); ++ ret = generate_storage_opts(dstconfig, srcconfig); + if (ret < 0) { + goto out; + } + +- ret = generate_sysctls(&dstconfig, srcconfig); ++ ret = generate_sysctls(dstconfig, srcconfig); + if (ret < 0) { + goto out; + } +@@ -1719,40 +1554,59 @@ static int pack_host_config_common(host_config *dstconfig, const isula_host_conf + } + + /* devices which will be populated into container */ +- ret = generate_devices(&dstconfig, srcconfig); ++ ret = generate_devices(dstconfig, srcconfig); + if (ret < 0) { + goto out; + } + + /* blkio device */ +- ret = generate_blkio(&dstconfig, srcconfig); ++ ret = generate_blkio(dstconfig, srcconfig); + if (ret < 0) { + goto out; + } + + /* hugepage limits */ +- ret = generate_hugetlb_limits(&dstconfig, srcconfig); ++ ret = generate_hugetlb_limits(dstconfig, srcconfig); + if (ret < 0) { + goto out; + } + +- /* binds to mount */ +- ret = generate_binds(&dstconfig, srcconfig); ++ /* --volumes-from parameters */ ++ ret = generate_volumes_from(dstconfig, srcconfig); ++ if (ret != 0) { ++ goto out; ++ } ++ ++ /* -v parameters */ ++ ret = generate_binds(dstconfig, srcconfig); + if (ret < 0) { + goto out; + } + ++ /* --mount parameters */ ++ ret = generate_mounts(dstconfig, srcconfig); ++ if (ret != 0) { ++ goto out; ++ } ++ + /* groups to add */ +- ret = generate_groups(&dstconfig, srcconfig); ++ ret = generate_groups(dstconfig, srcconfig); + if (ret < 0) { + goto out; + } + + /* security opt */ +- ret = generate_security(&dstconfig, srcconfig); ++ ret = generate_security(dstconfig, srcconfig); + if (ret < 0) { + goto out; + } ++ ++ /* device cgroup rules*/ ++ ret = generate_device_cgroup_rules(dstconfig, srcconfig); ++ if (ret < 0) { ++ goto out; ++ } ++ + out: + return ret; + } +@@ -1764,7 +1618,7 @@ int generate_hostconfig(const isula_host_config_t *srcconfig, char **hostconfigs + host_config *dstconfig = NULL; + struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 }; + +- dstconfig = util_common_calloc_s(sizeof(*dstconfig)); ++ dstconfig = util_common_calloc_s(sizeof(host_config)); + if (dstconfig == NULL) { + ret = -1; + goto out; +@@ -1823,421 +1677,165 @@ out: + return ret; + } + +-static int pack_container_custom_config_args(container_config *container_spec, +- const isula_container_config_t *custom_conf) +-{ +- int ret = 0; +- int i; +- +- /* entrypoint */ +- if (util_valid_str(custom_conf->entrypoint)) { +- container_spec->entrypoint = util_common_calloc_s(sizeof(char *)); +- if (container_spec->entrypoint == NULL) { +- ret = -1; +- goto out; +- } +- container_spec->entrypoint[0] = util_strdup_s(custom_conf->entrypoint); +- container_spec->entrypoint_len++; +- } +- +- /* commands */ +- if ((custom_conf->cmd_len != 0 && custom_conf->cmd)) { +- if (custom_conf->cmd_len > SIZE_MAX / sizeof(char *)) { +- COMMAND_ERROR("The length of cmd is too long!"); +- ret = -1; +- goto out; +- } +- container_spec->cmd = util_common_calloc_s(custom_conf->cmd_len * sizeof(char *)); +- if (container_spec->cmd == NULL) { +- ret = -1; +- goto out; +- } +- for (i = 0; i < (int)custom_conf->cmd_len; i++) { +- container_spec->cmd[container_spec->cmd_len] = util_strdup_s(custom_conf->cmd[i]); +- container_spec->cmd_len++; +- } +- } +- +-out: +- return ret; +-} +- +-static int pack_container_custom_config_mounts(container_config *container_spec, +- const isula_container_config_t *custom_conf) ++void isula_ns_change_files_free(isula_host_config_t *hostconfig) + { +- int ret = 0; +- int i = 0; +- +- /* mounts to mount filesystem */ +- if (custom_conf->mounts != NULL && custom_conf->mounts_len > 0) { +- if (custom_conf->mounts_len > SIZE_MAX / sizeof(char *)) { +- COMMAND_ERROR("Too many mounts to mount filesystem!"); +- ret = -1; +- goto out; +- } +- container_spec->mounts = util_common_calloc_s(custom_conf->mounts_len * sizeof(char *)); +- if (container_spec->mounts == NULL) { +- ret = -1; +- goto out; +- } +- for (i = 0; i < (int)custom_conf->mounts_len; i++) { +- container_spec->mounts[container_spec->mounts_len] = util_strdup_s(custom_conf->mounts[i]); +- container_spec->mounts_len++; +- } +- } +-out: +- return ret; +-} +- +-static int pack_container_custom_config_array(container_config *container_spec, +- const isula_container_config_t *custom_conf) +-{ +- int ret = 0; +- int i = 0; +- +- /* environment variables */ +- if (custom_conf->env_len != 0 && custom_conf->env) { +- if (custom_conf->env_len > SIZE_MAX / sizeof(char *)) { +- COMMAND_ERROR("Too many environment variables"); +- return -1; +- } +- container_spec->env = util_common_calloc_s(custom_conf->env_len * sizeof(char *)); +- if (container_spec->env == NULL) { +- ret = -1; +- goto out; +- } +- for (i = 0; i < (int)custom_conf->env_len; i++) { +- container_spec->env[container_spec->env_len] = util_strdup_s(custom_conf->env[i]); +- container_spec->env_len++; +- } ++ if (hostconfig == NULL) { ++ return; + } + +-out: +- return ret; ++ util_free_array_by_len(hostconfig->ns_change_files, hostconfig->ns_change_files_len); ++ hostconfig->ns_change_files = NULL; ++ hostconfig->ns_change_files_len = 0; + } + +-static int get_label_key_value(const char *label, char **key, char **value) ++void isula_host_config_storage_opts_free(isula_host_config_t *hostconfig) + { +- int ret = 0; +- char **arr = util_string_split_n(label, '=', 2); +- if (arr == NULL) { +- ERROR("Failed to split input label"); +- ret = -1; +- goto out; +- } +- +- *key = util_strdup_s(arr[0]); +- if (util_array_len((const char **)arr) == 1) { +- *value = util_strdup_s(""); +- } else { +- *value = util_strdup_s(arr[1]); ++ if (hostconfig == NULL) { ++ return; + } + +-out: +- util_free_array(arr); +- return ret; ++ free_json_map_string_string(hostconfig->storage_opts); ++ hostconfig->storage_opts = NULL; + } + +-static int pack_container_custom_config_labels(container_config *container_spec, +- const isula_container_config_t *custom_conf) ++void isula_host_config_sysctl_free(isula_host_config_t *hostconfig) + { +- int ret = 0; +- int i; +- char *key = NULL; +- char *value = NULL; +- +- if (custom_conf->label_len == 0 || custom_conf->label == NULL) { +- return 0; +- } +- +- /* labels */ +- container_spec->labels = util_common_calloc_s(sizeof(json_map_string_string)); +- if (container_spec->labels == NULL) { +- ERROR("Out of memory"); +- ret = -1; +- goto out; +- } +- +- for (i = 0; i < custom_conf->label_len; i++) { +- if (get_label_key_value(custom_conf->label[i], &key, &value) != 0) { +- ERROR("Failed to get key and value of label"); +- ret = -1; +- goto out; +- } +- +- if (append_json_map_string_string(container_spec->labels, key, value)) { +- ERROR("Append map failed"); +- ret = -1; +- goto out; +- } +- free(key); +- key = NULL; +- free(value); +- value = NULL; ++ if (hostconfig == NULL) { ++ return; + } + +-out: +- free(key); +- free(value); +- return ret; ++ free_json_map_string_string(hostconfig->sysctls); ++ hostconfig->sysctls = NULL; + } + +-static bool have_health_check(const isula_container_config_t *custom_conf) ++/* container cgroup resources free */ ++static void container_cgroup_resources_free(container_cgroup_resources_t *cr) + { +- bool have_health_settings = false; +- +- if ((custom_conf->health_cmd != NULL && strlen(custom_conf->health_cmd) != 0) || +- custom_conf->health_interval != 0 || custom_conf->health_timeout != 0 || +- custom_conf->health_start_period != 0 || custom_conf->health_retries != 0) { +- have_health_settings = true; ++ if (cr == NULL) { ++ return; + } ++ free(cr->cpuset_cpus); ++ cr->cpuset_cpus = NULL; + +- return have_health_settings; +-} +- +-static int pack_custom_no_health_check(container_config *container_spec, bool have_health_settings, +- defs_health_check *health_config) +-{ +- int ret = 0; +- +- if (have_health_settings) { +- COMMAND_ERROR("--no-healthcheck conflicts with --health-* options"); +- ret = -1; +- goto out; +- } +- health_config->test = util_common_calloc_s(sizeof(char *)); +- if (health_config->test == NULL) { +- ret = -1; +- goto out; +- } +- health_config->test[health_config->test_len++] = util_strdup_s("NONE"); +- container_spec->healthcheck = health_config; ++ free(cr->cpuset_mems); ++ cr->cpuset_mems = NULL; + +-out: +- return ret; ++ free(cr); + } + +-static int pack_custom_with_health_check(container_config *container_spec, +- const isula_container_config_t *custom_conf, bool have_health_settings, +- defs_health_check *health_config) ++/* isula host config free */ ++void isula_host_config_free(isula_host_config_t *hostconfig) + { +- int ret = 0; ++ size_t i = 0; + +- if (custom_conf->health_cmd != NULL && strlen(custom_conf->health_cmd) != 0) { +- health_config->test = util_common_calloc_s(2 * sizeof(char *)); +- if (health_config->test == NULL) { +- ret = -1; +- goto out; +- } +- health_config->test[health_config->test_len++] = util_strdup_s("CMD-SHELL"); +- health_config->test[health_config->test_len++] = util_strdup_s(custom_conf->health_cmd); +- } else { +- COMMAND_ERROR("--health-cmd required!"); +- ret = -1; +- goto out; +- } +- health_config->interval = custom_conf->health_interval; +- health_config->timeout = custom_conf->health_timeout; +- health_config->start_period = custom_conf->health_start_period; +- health_config->retries = custom_conf->health_retries; +- health_config->exit_on_unhealthy = custom_conf->exit_on_unhealthy; +- if (container_spec->healthcheck != NULL) { +- free_defs_health_check(container_spec->healthcheck); ++ if (hostconfig == NULL) { ++ return; + } +- container_spec->healthcheck = health_config; + +-out: +- return ret; +-} ++ util_free_array_by_len(hostconfig->cap_add, hostconfig->cap_add_len); ++ hostconfig->cap_add = NULL; ++ hostconfig->cap_add_len = 0; + +-static int pack_container_custom_config_health(container_config *container_spec, +- const isula_container_config_t *custom_conf) +-{ +- int ret = 0; +- bool have_health_settings = false; +- defs_health_check *health_config = NULL; ++ util_free_array_by_len(hostconfig->cap_drop, hostconfig->cap_drop_len); ++ hostconfig->cap_drop = NULL; ++ hostconfig->cap_drop_len = 0; + +- if (container_spec == NULL || custom_conf == NULL) { +- return 0; +- } ++ free_json_map_string_string(hostconfig->storage_opts); ++ hostconfig->storage_opts = NULL; + +- have_health_settings = have_health_check(custom_conf); ++ free_json_map_string_string(hostconfig->sysctls); ++ hostconfig->sysctls = NULL; + +- health_config = util_common_calloc_s(sizeof(defs_health_check)); +- if (health_config == NULL) { +- ret = -1; +- goto out; +- } ++ util_free_array_by_len(hostconfig->devices, hostconfig->devices_len); ++ hostconfig->devices = NULL; ++ hostconfig->devices_len = 0; + +- if (custom_conf->no_healthcheck) { +- ret = pack_custom_no_health_check(container_spec, have_health_settings, health_config); +- if (ret != 0) { +- goto out; +- } +- } else if (have_health_settings) { +- ret = pack_custom_with_health_check(container_spec, custom_conf, have_health_settings, health_config); +- if (ret != 0) { +- goto out; +- } +- } else { +- goto out; +- } +- +- return ret; +- +-out: +- free_defs_health_check(health_config); +- return ret; +-} +- +-static int pack_container_custom_config_annotation(container_config *container_spec, +- const isula_container_config_t *custom_conf) +-{ +- int ret = 0; +- size_t j; +- +- container_spec->annotations = util_common_calloc_s(sizeof(json_map_string_string)); +- if (container_spec->annotations == NULL) { +- ERROR("Out of memory"); +- ret = -1; +- goto out; +- } +- if (custom_conf->annotations != NULL) { +- for (j = 0; j < custom_conf->annotations->len; j++) { +- if (append_json_map_string_string(container_spec->annotations, custom_conf->annotations->keys[j], +- custom_conf->annotations->values[j])) { +- ERROR("Append map failed"); +- ret = -1; +- goto out; +- } +- } +- } +-out: +- return ret; +-} ++ util_free_array_by_len(hostconfig->ns_change_files, hostconfig->ns_change_files_len); ++ hostconfig->ns_change_files = NULL; ++ hostconfig->ns_change_files_len = 0; + +-static int pack_container_custom_config_pre(container_config *container_spec, +- const isula_container_config_t *custom_conf) +-{ +- int ret = 0; ++ util_free_array_by_len(hostconfig->hugetlbs, hostconfig->hugetlbs_len); ++ hostconfig->hugetlbs = NULL; ++ hostconfig->hugetlbs_len = 0; + +- ret = pack_container_custom_config_args(container_spec, custom_conf); +- if (ret != 0) { +- goto out; +- } ++ free(hostconfig->network_mode); ++ hostconfig->network_mode = NULL; + +- ret = pack_container_custom_config_mounts(container_spec, custom_conf); +- if (ret != 0) { +- goto out; +- } ++ free(hostconfig->ipc_mode); ++ hostconfig->ipc_mode = NULL; + +- ret = pack_container_custom_config_array(container_spec, custom_conf); +- if (ret != 0) { +- goto out; +- } ++ free(hostconfig->pid_mode); ++ hostconfig->pid_mode = NULL; + +- ret = pack_container_custom_config_labels(container_spec, custom_conf); +- if (ret != 0) { +- goto out; +- } ++ free(hostconfig->uts_mode); ++ hostconfig->uts_mode = NULL; + +- ret = pack_container_custom_config_health(container_spec, custom_conf); +- if (ret != 0) { +- goto out; +- } +-out: +- return ret; +-} ++ free(hostconfig->userns_mode); ++ hostconfig->userns_mode = NULL; + +-/* translate create_custom_config to container_config */ +-static int pack_container_custom_config(container_config *container_spec, +- const isula_container_config_t *custom_conf) +-{ +- int ret = -1; ++ free(hostconfig->user_remap); ++ hostconfig->user_remap = NULL; + +- if (container_spec == NULL || custom_conf == NULL) { +- return ret; +- } ++ util_free_array_by_len(hostconfig->ulimits, hostconfig->ulimits_len); ++ hostconfig->ulimits = NULL; ++ hostconfig->ulimits_len = 0; + +- ret = pack_container_custom_config_pre(container_spec, custom_conf); +- if (ret != 0) { +- goto out; +- } ++ free(hostconfig->restart_policy); ++ hostconfig->restart_policy = NULL; + +- if (custom_conf->hostname != NULL) { +- container_spec->hostname = util_strdup_s(custom_conf->hostname); +- } +- container_spec->log_driver = util_strdup_s(custom_conf->log_driver); ++ free(hostconfig->host_channel); ++ hostconfig->host_channel = NULL; + +- /* console config */ +- container_spec->tty = custom_conf->tty; +- container_spec->open_stdin = custom_conf->open_stdin; +- container_spec->attach_stdin = custom_conf->attach_stdin; +- container_spec->attach_stdout = custom_conf->attach_stdout; +- container_spec->attach_stderr = custom_conf->attach_stderr; ++ free(hostconfig->hook_spec); ++ hostconfig->hook_spec = NULL; + +- /* user and group */ +- if (custom_conf->user != NULL) { +- container_spec->user = util_strdup_s(custom_conf->user); +- } ++ free(hostconfig->env_target_file); ++ hostconfig->env_target_file = NULL; + +- /* settings for system container */ +- if (custom_conf->system_container) { +- container_spec->system_container = custom_conf->system_container; +- } ++ free(hostconfig->cgroup_parent); ++ hostconfig->cgroup_parent = NULL; + +- if (custom_conf->ns_change_opt != NULL) { +- container_spec->ns_change_opt = util_strdup_s(custom_conf->ns_change_opt); +- } ++ util_free_array_by_len(hostconfig->binds, hostconfig->binds_len); ++ hostconfig->binds = NULL; ++ hostconfig->binds_len = 0; + +- ret = pack_container_custom_config_annotation(container_spec, custom_conf); +- if (ret != 0) { +- goto out; ++ for (i = 0; i < hostconfig->mounts_len; i++) { ++ free_mount_spec(hostconfig->mounts[i]); ++ hostconfig->mounts[i] = NULL; + } ++ free(hostconfig->mounts); ++ hostconfig->mounts = NULL; ++ hostconfig->mounts_len = 0; + +- if (custom_conf->workdir != NULL) { +- container_spec->working_dir = util_strdup_s(custom_conf->workdir); +- } ++ util_free_array_by_len(hostconfig->blkio_weight_device, hostconfig->blkio_weight_device_len); ++ hostconfig->blkio_weight_device = NULL; ++ hostconfig->blkio_weight_device_len = 0; + +-out: +- return ret; +-} ++ util_free_array_by_len(hostconfig->blkio_throttle_read_bps_device, hostconfig->blkio_throttle_read_bps_device_len); ++ hostconfig->blkio_throttle_read_bps_device = NULL; ++ hostconfig->blkio_throttle_read_bps_device_len = 0; + +-int generate_container_config(const isula_container_config_t *custom_conf, char **container_config_str) +-{ +- int ret = 0; +- container_config *container_spec = NULL; +- struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 }; +- parser_error err = NULL; ++ util_free_array_by_len(hostconfig->blkio_throttle_write_bps_device, ++ hostconfig->blkio_throttle_write_bps_device_len); ++ hostconfig->blkio_throttle_write_bps_device = NULL; ++ hostconfig->blkio_throttle_write_bps_device_len = 0; + +- /* step 1: malloc the container config */ +- container_spec = util_common_calloc_s(sizeof(container_config)); +- if (container_spec == NULL) { +- ERROR("Memory out"); +- ret = -1; +- goto out; +- } ++ util_free_array_by_len(hostconfig->blkio_throttle_read_iops_device, ++ hostconfig->blkio_throttle_read_iops_device_len); ++ hostconfig->blkio_throttle_read_iops_device = NULL; ++ hostconfig->blkio_throttle_read_iops_device_len = 0; + +- /* step 2: pack the container custom config */ +- ret = pack_container_custom_config(container_spec, custom_conf); +- if (ret != 0) { +- ERROR("Failed to pack the container custom config"); +- ret = -1; +- goto out; +- } ++ util_free_array_by_len(hostconfig->blkio_throttle_write_iops_device, ++ hostconfig->blkio_throttle_write_iops_device_len); ++ hostconfig->blkio_throttle_write_iops_device = NULL; ++ hostconfig->blkio_throttle_write_iops_device_len = 0; + +- /* step 3: generate the config string */ +- *container_config_str = container_config_generate_json(container_spec, &ctx, &err); +- if (*container_config_str == NULL) { +- ERROR("Failed to generate OCI specification json string"); +- ret = -1; +- goto out; +- } ++ util_free_array_by_len(hostconfig->device_cgroup_rules, hostconfig->device_cgroup_rules_len); ++ hostconfig->device_cgroup_rules = NULL; ++ hostconfig->device_cgroup_rules_len = 0; + +-out: +- free_container_config(container_spec); +- free(err); ++ container_cgroup_resources_free(hostconfig->cr); ++ hostconfig->cr = NULL; + +- return ret; ++ free(hostconfig); + } +- +diff --git a/src/cmd/isula/isula_host_spec.h b/src/cmd/isula/isula_host_spec.h +new file mode 100644 +index 0000000..0041752 +--- /dev/null ++++ b/src/cmd/isula/isula_host_spec.h +@@ -0,0 +1,163 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. 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: lifeng ++ * Create: 2020-09-28 ++ * Description: provide generate host spec in client ++ ******************************************************************************/ ++#ifndef CMD_ISULA_GENERATE_HOST_SPEC_H ++#define CMD_ISULA_GENERATE_HOST_SPEC_H ++ ++#include ++#include ++#include ++#include "isula_libutils/json_common.h" ++#include "isula_libutils/mount_spec.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++typedef struct container_cgroup_resources { ++ uint16_t blkio_weight; ++ int64_t cpu_shares; ++ int64_t cpu_period; ++ int64_t cpu_quota; ++ int64_t cpu_realtime_period; ++ int64_t cpu_realtime_runtime; ++ char *cpuset_cpus; ++ char *cpuset_mems; ++ int64_t memory; ++ int64_t memory_swap; ++ int64_t memory_reservation; ++ int64_t kernel_memory; ++ int64_t pids_limit; ++ int64_t files_limit; ++ int64_t oom_score_adj; ++ int64_t swappiness; ++ int64_t nano_cpus; ++} container_cgroup_resources_t; ++ ++typedef struct isula_host_config { ++ char **devices; ++ size_t devices_len; ++ ++ char **hugetlbs; ++ size_t hugetlbs_len; ++ ++ char **group_add; ++ size_t group_add_len; ++ ++ char *network_mode; ++ ++ char *ipc_mode; ++ ++ char *pid_mode; ++ ++ char *uts_mode; ++ ++ char *userns_mode; ++ ++ char *user_remap; ++ ++ char **ulimits; ++ size_t ulimits_len; ++ ++ char *restart_policy; ++ ++ char *host_channel; ++ ++ char **cap_add; ++ size_t cap_add_len; ++ ++ char **cap_drop; ++ size_t cap_drop_len; ++ ++ json_map_string_string *storage_opts; ++ ++ json_map_string_string *sysctls; ++ ++ char **dns; ++ size_t dns_len; ++ ++ char **dns_options; ++ size_t dns_options_len; ++ ++ char **dns_search; ++ size_t dns_search_len; ++ ++ char **extra_hosts; ++ size_t extra_hosts_len; ++ ++ char *hook_spec; ++ ++ char **volumes_from; ++ size_t volumes_from_len; ++ ++ char **binds; ++ size_t binds_len; ++ ++ mount_spec **mounts; ++ size_t mounts_len; ++ ++ char **blkio_weight_device; ++ size_t blkio_weight_device_len; ++ ++ char **blkio_throttle_read_bps_device; ++ size_t blkio_throttle_read_bps_device_len; ++ ++ char **blkio_throttle_write_bps_device; ++ size_t blkio_throttle_write_bps_device_len; ++ ++ char **blkio_throttle_read_iops_device; ++ size_t blkio_throttle_read_iops_device_len; ++ ++ char **blkio_throttle_write_iops_device; ++ size_t blkio_throttle_write_iops_device_len; ++ ++ char **device_cgroup_rules; ++ size_t device_cgroup_rules_len; ++ ++ bool privileged; ++ bool system_container; ++ char **ns_change_files; ++ size_t ns_change_files_len; ++ bool auto_remove; ++ ++ bool oom_kill_disable; ++ ++ int64_t shm_size; ++ ++ bool readonly_rootfs; ++ ++ char *env_target_file; ++ ++ char *cgroup_parent; ++ ++ container_cgroup_resources_t *cr; ++ ++ char **security; ++ size_t security_len; ++} isula_host_config_t; ++ ++int generate_hostconfig(const isula_host_config_t *srcconfig, char **hostconfigstr); ++void isula_host_config_free(isula_host_config_t *hostconfig); ++ ++void isula_ns_change_files_free(isula_host_config_t *hostconfig); ++ ++void isula_host_config_storage_opts_free(isula_host_config_t *hostconfig); ++ ++void isula_host_config_sysctl_free(isula_host_config_t *hostconfig); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +diff --git a/src/cmd/isula/main.c b/src/cmd/isula/main.c +index ac4a72c..d4a6669 100644 +--- a/src/cmd/isula/main.c ++++ b/src/cmd/isula/main.c +@@ -50,148 +50,156 @@ + #include "version.h" + #include "rename.h" + #include "utils.h" ++#include "volume.h" ++#include "remove.h" ++#include "prune.h" ++#include "list.h" + + // The list of our supported commands + struct command g_commands[] = { + { + // `create` sub-command +- "create", cmd_create_main, g_cmd_create_desc, NULL, &g_cmd_create_args ++ "create", false, cmd_create_main, g_cmd_create_desc, NULL, &g_cmd_create_args + }, + { + // `rm` sub-command +- "rm", cmd_delete_main, g_cmd_delete_desc, NULL, &g_cmd_delete_args ++ "rm", false, cmd_delete_main, g_cmd_delete_desc, NULL, &g_cmd_delete_args + }, + { + // `ps` sub-command +- "ps", cmd_list_main, g_cmd_list_desc, NULL, &g_cmd_list_args ++ "ps", false, cmd_list_main, g_cmd_list_desc, NULL, &g_cmd_list_args + }, + { + // `start` sub-command +- "start", cmd_start_main, g_cmd_start_desc, NULL, &g_cmd_start_args ++ "start", false, cmd_start_main, g_cmd_start_desc, NULL, &g_cmd_start_args + }, + { + // `run` sub-command +- "run", cmd_run_main, g_cmd_run_desc, NULL, &g_cmd_run_args ++ "run", false, cmd_run_main, g_cmd_run_desc, NULL, &g_cmd_run_args + }, + { + // `restart` sub-command +- "restart", cmd_restart_main, g_cmd_restart_desc, NULL, &g_cmd_restart_args ++ "restart", false, cmd_restart_main, g_cmd_restart_desc, NULL, &g_cmd_restart_args + }, + { + // `inspect` sub-command +- "inspect", cmd_inspect_main, g_cmd_inspect_desc, NULL, &g_cmd_inspect_args ++ "inspect", false, cmd_inspect_main, g_cmd_inspect_desc, NULL, &g_cmd_inspect_args + }, + { + // `pause` sub-command +- "pause", cmd_pause_main, g_cmd_pause_desc, NULL, &g_cmd_pause_args ++ "pause", false, cmd_pause_main, g_cmd_pause_desc, NULL, &g_cmd_pause_args + }, + { + // `unpause` sub-command +- "unpause", cmd_resume_main, g_cmd_resume_desc, NULL, &g_cmd_resume_args ++ "unpause", false, cmd_resume_main, g_cmd_resume_desc, NULL, &g_cmd_resume_args + }, + #ifdef ENABLE_OCI_IMAGE + { + // `stats` sub-command +- "stats", cmd_stats_main, g_cmd_stats_desc, NULL, &g_cmd_stats_args ++ "stats", false, cmd_stats_main, g_cmd_stats_desc, NULL, &g_cmd_stats_args + }, + { + // `cp` sub-command +- "cp", cmd_cp_main, g_cmd_cp_desc, NULL, &g_cmd_cp_args ++ "cp", false, cmd_cp_main, g_cmd_cp_desc, NULL, &g_cmd_cp_args + }, + #endif + { + // `stop` sub-command +- "stop", cmd_stop_main, g_cmd_stop_desc, NULL, &g_cmd_stop_args ++ "stop", false, cmd_stop_main, g_cmd_stop_desc, NULL, &g_cmd_stop_args + }, + { + // `version` sub-command +- "version", cmd_version_main, g_cmd_version_desc, NULL, &g_cmd_version_args ++ "version", false, cmd_version_main, g_cmd_version_desc, NULL, &g_cmd_version_args + }, + { + // `exec` sub-command +- "exec", cmd_exec_main, g_cmd_exec_desc, NULL, &g_cmd_exec_args ++ "exec", false, cmd_exec_main, g_cmd_exec_desc, NULL, &g_cmd_exec_args + }, + { + // `images` sub-command +- "images", cmd_images_main, g_cmd_images_desc, NULL, &g_cmd_images_args ++ "images", false, cmd_images_main, g_cmd_images_desc, NULL, &g_cmd_images_args + }, + #ifdef ENABLE_OCI_IMAGE + { + // `info` sub-command +- "info", cmd_info_main, g_cmd_info_desc, NULL, &g_cmd_info_args ++ "info", false, cmd_info_main, g_cmd_info_desc, NULL, &g_cmd_info_args + }, + #endif + { + // `remove images` sub-command +- "rmi", cmd_rmi_main, g_cmd_rmi_desc, NULL, &g_cmd_rmi_args ++ "rmi", false, cmd_rmi_main, g_cmd_rmi_desc, NULL, &g_cmd_rmi_args + }, + #ifdef ENABLE_OCI_IMAGE + { + // `wait` sub-command +- "wait", cmd_wait_main, g_cmd_wait_desc, NULL, &g_cmd_wait_args ++ "wait", false, cmd_wait_main, g_cmd_wait_desc, NULL, &g_cmd_wait_args + }, + { + // `logs` sub-command +- "logs", cmd_logs_main, g_cmd_logs_desc, NULL, &g_cmd_logs_args ++ "logs", false, cmd_logs_main, g_cmd_logs_desc, NULL, &g_cmd_logs_args + }, + { + // `events` sub-command +- "events", cmd_events_main, g_cmd_events_desc, NULL, &g_cmd_events_args ++ "events", false, cmd_events_main, g_cmd_events_desc, NULL, &g_cmd_events_args + }, + #endif + { + // `kill` sub-command +- "kill", cmd_kill_main, g_cmd_kill_desc, NULL, &g_cmd_kill_args ++ "kill", false, cmd_kill_main, g_cmd_kill_desc, NULL, &g_cmd_kill_args + }, + { + // `load` sub-command +- "load", cmd_load_main, g_cmd_load_desc, NULL, &g_cmd_load_args ++ "load", false, cmd_load_main, g_cmd_load_desc, NULL, &g_cmd_load_args + }, + #ifdef ENABLE_OCI_IMAGE + { + // `update` sub-command +- "update", cmd_update_main, g_cmd_update_desc, NULL, &g_cmd_update_args ++ "update", false, cmd_update_main, g_cmd_update_desc, NULL, &g_cmd_update_args + }, + #endif + { + // `attach` sub-command +- "attach", cmd_attach_main, g_cmd_attach_desc, NULL, &g_cmd_attach_args ++ "attach", false, cmd_attach_main, g_cmd_attach_desc, NULL, &g_cmd_attach_args + }, + #ifdef ENABLE_OCI_IMAGE + { + // `export` sub-command +- "export", cmd_export_main, g_cmd_export_desc, NULL, &g_cmd_export_args ++ "export", false, cmd_export_main, g_cmd_export_desc, NULL, &g_cmd_export_args + }, + { + // `top` sub-command +- "top", cmd_top_main, g_cmd_top_desc, NULL, &g_cmd_top_args ++ "top", false, cmd_top_main, g_cmd_top_desc, NULL, &g_cmd_top_args + }, + { + // `rename` sub-command +- "rename", cmd_rename_main, g_cmd_rename_desc, NULL, &g_cmd_rename_args ++ "rename", false, cmd_rename_main, g_cmd_rename_desc, NULL, &g_cmd_rename_args + }, + { + // `pull` sub-command +- "pull", cmd_pull_main, g_cmd_pull_desc, NULL, &g_cmd_pull_args ++ "pull", false, cmd_pull_main, g_cmd_pull_desc, NULL, &g_cmd_pull_args + }, + { + // `login` sub-command +- "login", cmd_login_main, g_cmd_login_desc, NULL, &g_cmd_login_args ++ "login", false, cmd_login_main, g_cmd_login_desc, NULL, &g_cmd_login_args + }, + { + // `logout` sub-command +- "logout", cmd_logout_main, g_cmd_logout_desc, NULL, &g_cmd_logout_args ++ "logout", false, cmd_logout_main, g_cmd_logout_desc, NULL, &g_cmd_logout_args + }, + { + // `tag` sub-command +- "tag", cmd_tag_main, g_cmd_tag_desc, NULL, &g_cmd_tag_args ++ "tag", false, cmd_tag_main, g_cmd_tag_desc, NULL, &g_cmd_tag_args + }, + { + // `import` sub-command +- "import", cmd_import_main, g_cmd_import_desc, NULL, &g_cmd_import_args ++ "import", false, cmd_import_main, g_cmd_import_desc, NULL, &g_cmd_import_args ++ }, ++ { ++ // `volume` sub-command ++ "volume", true, cmd_volume_main, g_cmd_volume_desc, NULL, NULL + }, + #endif +- { NULL, NULL, NULL, NULL, NULL } // End of the list ++ { NULL, false, NULL, NULL, NULL, NULL } // End of the list + }; + + int main(int argc, char **argv) +diff --git a/src/cmd/isula/stream/attach.c b/src/cmd/isula/stream/attach.c +index 669bb70..f0a77a1 100644 +--- a/src/cmd/isula/stream/attach.c ++++ b/src/cmd/isula/stream/attach.c +@@ -12,6 +12,7 @@ + * Create: 2017-11-22 + * Description: provide container attach functions + ******************************************************************************/ ++#include "attach.h" + #include + #include + #include +@@ -32,11 +33,9 @@ + #include "isula_connect.h" + #include "console.h" + #include "utils.h" +-#include "attach.h" + #include "command_parser.h" + #include "connect.h" + #include "constants.h" +-#include "libisula.h" + + const char g_cmd_attach_desc[] = "Attach to a running container"; + const char g_cmd_attach_usage[] = "attach [OPTIONS] CONTAINER"; +diff --git a/src/cmd/isula/stream/cp.c b/src/cmd/isula/stream/cp.c +index b894b37..4ebca2b 100644 +--- a/src/cmd/isula/stream/cp.c ++++ b/src/cmd/isula/stream/cp.c +@@ -12,6 +12,7 @@ + * Create: 2019-04-17 + * Description: provide container cp functions + ******************************************************************************/ ++#include "cp.h" + #include + #include + #include +@@ -21,7 +22,6 @@ + #include + + #include "error.h" +-#include "cp.h" + #include "client_arguments.h" + #include "isula_libutils/log.h" + #include "path.h" +@@ -30,7 +30,7 @@ + #include "command_parser.h" + #include "connect.h" + #include "io_wrapper.h" +-#include "libisula.h" ++ + #include "utils.h" + + #define FromContainer 0x01u +@@ -48,12 +48,12 @@ static char *resolve_local_path(const char *path) + { + char abs_path[PATH_MAX] = { 0 }; + +- if (cleanpath(path, abs_path, sizeof(abs_path)) == NULL) { ++ if (util_clean_path(path, abs_path, sizeof(abs_path)) == NULL) { + ERROR("Failed to clean path"); + return NULL; + } + +- return preserve_trailing_dot_or_separator(abs_path, path); ++ return util_preserve_trailing_dot_or_separator(abs_path, path); + } + + static void print_copy_from_container_error(const char *ops_err, const char *archive_err, int ret, +diff --git a/src/cmd/isula/stream/exec.c b/src/cmd/isula/stream/exec.c +index 6ac1a7a..761c4c0 100644 +--- a/src/cmd/isula/stream/exec.c ++++ b/src/cmd/isula/stream/exec.c +@@ -12,11 +12,10 @@ + * Create: 2018-11-08 + * Description: provide container exec functions + ******************************************************************************/ ++#include "exec.h" + #include + #include + #include +-#include +-#include + #include + #include + #include +@@ -24,7 +23,7 @@ + #include + + #include "client_arguments.h" +-#include "exec.h" ++#include "client_console.h" + #include "isula_libutils/log.h" + #include "isula_connect.h" + #include "console.h" +@@ -33,7 +32,7 @@ + #include "isula_libutils/container_inspect.h" + #include "connect.h" + #include "constants.h" +-#include "libisula.h" ++ + #include "utils_array.h" + #include "utils_string.h" + +@@ -67,8 +66,8 @@ static int fill_exec_request(const struct client_arguments *args, const struct c + + request->user = util_strdup_s(args->custom_conf.user); + +- if (dup_array_of_strings((const char **)args->argv, args->argc, &(request->argv), (size_t *) & (request->argc)) != +- 0) { ++ if (util_dup_array_of_strings((const char **)args->argv, args->argc, &(request->argv), ++ (size_t *) & (request->argc)) != 0) { + ERROR("Failed to dup args"); + ret = -1; + goto out; +@@ -76,7 +75,7 @@ static int fill_exec_request(const struct client_arguments *args, const struct c + + /* environment variables */ + for (i = 0; i < util_array_len((const char **)(args->extra_env)); i++) { +- if (util_validate_env(args->extra_env[i], &new_env) != 0) { ++ if (util_valid_env(args->extra_env[i], &new_env) != 0) { + ERROR("Invalid environment %s", args->extra_env[i]); + ret = -1; + goto out; +@@ -151,6 +150,45 @@ out: + return ret; + } + ++static int do_resize_exec_console(const struct client_arguments *args, unsigned int height, unsigned int width) ++{ ++ int ret = 0; ++ isula_connect_ops *ops = NULL; ++ struct isula_resize_request request = { 0 }; ++ struct isula_resize_response *response = NULL; ++ client_connect_config_t config = { 0 }; ++ ++ ops = get_connect_client_ops(); ++ if (ops == NULL || ops->container.resize == NULL) { ++ ERROR("Unimplemented ops"); ++ ret = -1; ++ goto out; ++ } ++ ++ request.id = args->name; ++ request.suffix = args->exec_suffix; ++ request.height = height; ++ request.width = width; ++ ++ response = util_common_calloc_s(sizeof(struct isula_resize_response)); ++ if (response == NULL) { ++ ERROR("Out of memory"); ++ ret = -1; ++ goto out; ++ } ++ ++ config = get_connect_config(args); ++ ret = ops->container.resize(&request, response, &config); ++ if (ret != 0) { ++ ERROR("Failed to call resize"); ++ goto out; ++ } ++ ++out: ++ isula_resize_response_free(response); ++ return ret; ++} ++ + static int exec_cmd_init(int argc, const char **argv) + { + command_t cmd; +@@ -197,6 +235,8 @@ static int exec_cmd_init(int argc, const char **argv) + return ECOMMON; + } + ++ g_cmd_exec_args.resize_cb = do_resize_exec_console; ++ + return 0; + } + +@@ -367,98 +407,6 @@ out: + return exec_suffix; + } + +-static int do_resize_exec_console(const struct client_arguments *args, unsigned int height, unsigned int width) +-{ +- int ret = 0; +- isula_connect_ops *ops = NULL; +- struct isula_resize_request request = { 0 }; +- struct isula_resize_response *response = NULL; +- client_connect_config_t config = { 0 }; +- +- ops = get_connect_client_ops(); +- if (ops == NULL || ops->container.resize == NULL) { +- ERROR("Unimplemented ops"); +- ret = -1; +- goto out; +- } +- +- request.id = args->name; +- request.suffix = args->exec_suffix; +- request.height = height; +- request.width = width; +- +- response = util_common_calloc_s(sizeof(struct isula_resize_response)); +- if (response == NULL) { +- ERROR("Out of memory"); +- ret = -1; +- goto out; +- } +- +- config = get_connect_config(args); +- ret = ops->container.resize(&request, response, &config); +- if (ret != 0) { +- ERROR("Failed to call resize"); +- goto out; +- } +- +-out: +- isula_resize_response_free(response); +- return ret; +-} +- +-static void *exec_console_resize_thread(void *arg) +-{ +- int ret = 0; +- const struct client_arguments *args = arg; +- static struct winsize s_pre_wsz; +- struct winsize wsz; +- +- if (!isatty(STDIN_FILENO)) { +- goto out; +- } +- +- ret = pthread_detach(pthread_self()); +- if (ret != 0) { +- CRIT("Start: set thread detach fail"); +- goto out; +- } +- +- while (true) { +- sleep(1); // check the windows size per 1s +- ret = ioctl(STDIN_FILENO, TIOCGWINSZ, &wsz); +- if (ret < 0) { +- WARN("Failed to get window size"); +- continue; +- } +- if (wsz.ws_row == s_pre_wsz.ws_row && wsz.ws_col == s_pre_wsz.ws_col) { +- continue; +- } +- ret = do_resize_exec_console(args, wsz.ws_row, wsz.ws_col); +- if (ret != 0) { +- continue; +- } +- s_pre_wsz.ws_row = wsz.ws_row; +- s_pre_wsz.ws_col = wsz.ws_col; +- } +- +-out: +- return NULL; +-} +- +-int exec_client_console_resize_thread(struct client_arguments *args) +-{ +- int res = 0; +- pthread_t a_thread; +- +- res = pthread_create(&a_thread, NULL, exec_console_resize_thread, (void *)(args)); +- if (res != 0) { +- CRIT("Thread creation failed"); +- return -1; +- } +- +- return 0; +-} +- + int cmd_exec_main(int argc, const char **argv) + { + int ret = 0; +@@ -503,7 +451,7 @@ int cmd_exec_main(int argc, const char **argv) + + if (custom_cfg->tty && isatty(STDIN_FILENO) && + (custom_cfg->attach_stdin || custom_cfg->attach_stdout || custom_cfg->attach_stderr)) { +- (void)exec_client_console_resize_thread(&g_cmd_exec_args); ++ (void)start_client_console_resize_thread(&g_cmd_exec_args); + } + + if (strncmp(g_cmd_exec_args.socket, "tcp://", strlen("tcp://")) == 0) { +diff --git a/src/cmd/isula/volume/CMakeLists.txt b/src/cmd/isula/volume/CMakeLists.txt +new file mode 100644 +index 0000000..0b618ed +--- /dev/null ++++ b/src/cmd/isula/volume/CMakeLists.txt +@@ -0,0 +1,7 @@ ++# get current directory sources files ++aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} isula_volume_srcs) ++ ++set(ISULA_VOLUME_SRCS ++ ${isula_volume_srcs} ++ PARENT_SCOPE ++ ) +diff --git a/src/cmd/isula/volume/list.c b/src/cmd/isula/volume/list.c +new file mode 100644 +index 0000000..f58abc0 +--- /dev/null ++++ b/src/cmd/isula/volume/list.c +@@ -0,0 +1,170 @@ ++/****************************************************************************** ++ * 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-09-05 ++ * Description: provide list volume functions ++ ******************************************************************************/ ++#include "list.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "utils.h" ++#include "client_arguments.h" ++#include "isula_connect.h" ++#include "isula_libutils/log.h" ++#include "command_parser.h" ++#include "connect.h" ++#include "protocol_type.h" ++#include "utils_array.h" ++#include "utils_file.h" ++#include "utils_verify.h" ++ ++#define VOLUME_OPTIONS(cmdargs) \ ++ { CMD_OPT_TYPE_BOOL, false, "quiet", 'q', &((cmdargs).dispname), "Only display volume names", NULL }, ++ ++const char g_cmd_volume_ls_desc[] = "List volumes"; ++const char g_cmd_volume_ls_usage[] = "ls [OPTIONS]"; ++ ++struct client_arguments g_cmd_volume_ls_args; ++ ++/* keep track of field widths for printing. */ ++struct lengths { ++ unsigned int driver_length; ++ unsigned int name_length; ++}; ++ ++/* list print table */ ++static void list_print_table(const struct isula_list_volume_response *resp, const struct lengths *length) ++{ ++ size_t i = 0; ++ ++ /* print header */ ++ printf("%-*s ", (int)length->driver_length, "DRIVER"); ++ printf("%-*s ", (int)length->name_length, "VOLUME NAME"); ++ printf("\n"); ++ ++ for (i = 0; i < resp->volumes_len; i++) { ++ printf("%-*s ", (int)length->driver_length, resp->volumes[i].driver); ++ printf("%-*s ", (int)length->name_length, resp->volumes[i].name); ++ printf("\n"); ++ } ++} ++ ++/* ++ * list all volume from isulad ++ */ ++static void volume_info_print(const struct isula_list_volume_response *response) ++{ ++ struct lengths max_len = { ++ .driver_length = 20, ++ .name_length = 10, ++ }; ++ ++ list_print_table(response, &max_len); ++} ++ ++/* volume info print quiet */ ++static void volume_info_print_quiet(const struct isula_list_volume_response *response) ++{ ++ size_t i = 0; ++ ++ for (i = 0; i < response->volumes_len; i++) { ++ printf("%s\n", response->volumes[i].name); ++ } ++} ++ ++/* ++ * list volume ++ */ ++static int list_volume(const struct client_arguments *args) ++{ ++ isula_connect_ops *ops = NULL; ++ struct isula_list_volume_request request = { 0 }; ++ struct isula_list_volume_response *response = NULL; ++ client_connect_config_t config = { 0 }; ++ int ret = 0; ++ ++ response = util_common_calloc_s(sizeof(struct isula_list_volume_response)); ++ if (response == NULL) { ++ ERROR("volume ls: Out of memory"); ++ return -1; ++ } ++ ++ ops = get_connect_client_ops(); ++ if (ops == NULL || ops->volume.list == NULL) { ++ ERROR("Unimplemented volume list op"); ++ ret = -1; ++ goto out; ++ } ++ ++ config = get_connect_config(args); ++ ret = ops->volume.list(&request, response, &config); ++ if (ret != 0) { ++ client_print_error(response->cc, response->server_errono, response->errmsg); ++ goto out; ++ } ++ ++ if (args->dispname) { ++ volume_info_print_quiet(response); ++ } else { ++ volume_info_print(response); ++ } ++ ++out: ++ isula_list_volume_response_free(response); ++ return ret; ++} ++ ++/* cmd volume main */ ++int cmd_volume_ls_main(int argc, const char **argv) ++{ ++ struct isula_libutils_log_config lconf = { 0 }; ++ int exit_code = ECOMMON; ++ command_t cmd; ++ ++ if (client_arguments_init(&g_cmd_volume_ls_args)) { ++ COMMAND_ERROR("client arguments init failed"); ++ exit(ECOMMON); ++ } ++ g_cmd_volume_ls_args.progname = util_string_join(" ", argv, 2); ++ struct command_option options[] = { LOG_OPTIONS(lconf) VOLUME_OPTIONS(g_cmd_volume_ls_args) ++ COMMON_OPTIONS(g_cmd_volume_ls_args) ++ }; ++ ++ subcommand_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_volume_ls_desc, ++ g_cmd_volume_ls_usage); ++ if (command_parse_args(&cmd, &g_cmd_volume_ls_args.argc, &g_cmd_volume_ls_args.argv)) { ++ exit(exit_code); ++ } ++ isula_libutils_default_log_config(argv[0], &lconf); ++ if (isula_libutils_log_enable(&lconf)) { ++ COMMAND_ERROR("volume ls: log init failed"); ++ exit(exit_code); ++ } ++ ++ if (g_cmd_volume_ls_args.argc != 0) { ++ COMMAND_ERROR("%s: \"volume ls\" requires exactly 0 arguments.", g_cmd_volume_ls_args.progname); ++ exit(exit_code); ++ } ++ ++ if (list_volume(&g_cmd_volume_ls_args) != 0) { ++ ERROR("Can not list any volume"); ++ exit(exit_code); ++ } ++ ++ exit(EXIT_SUCCESS); ++} +diff --git a/src/cmd/isula/volume/list.h b/src/cmd/isula/volume/list.h +new file mode 100644 +index 0000000..c748eb5 +--- /dev/null ++++ b/src/cmd/isula/volume/list.h +@@ -0,0 +1,33 @@ ++/****************************************************************************** ++ * 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-09-05 ++ * Description: provide list volume definition ++ ******************************************************************************/ ++#ifndef CMD_ISULA_VOLUME_LIST_H ++#define CMD_ISULA_VOLUME_LIST_H ++ ++#include "client_arguments.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++extern const char g_cmd_volume_ls_desc[]; ++extern const char g_cmd_volume_ls_usage[]; ++extern struct client_arguments g_cmd_volume_ls_args; ++int cmd_volume_ls_main(int argc, const char **argv); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif // CMD_ISULA_VOLUME_LIST_H +diff --git a/src/cmd/isula/volume/prune.c b/src/cmd/isula/volume/prune.c +new file mode 100644 +index 0000000..e9d628d +--- /dev/null ++++ b/src/cmd/isula/volume/prune.c +@@ -0,0 +1,134 @@ ++/****************************************************************************** ++ * 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-09-05 ++ * Description: provide volume prune functions ++ ******************************************************************************/ ++#include "prune.h" ++ ++#include ++#include ++#include ++ ++#include "utils.h" ++#include "client_arguments.h" ++#include "isula_connect.h" ++#include "isula_libutils/log.h" ++#include "connect.h" ++#include "protocol_type.h" ++ ++#define PRUNE_OPTIONS(cmdargs) \ ++ { CMD_OPT_TYPE_BOOL, false, "force", 'f', &(cmdargs).force, "Do not prompt for confirmation", NULL }, ++ ++const char g_cmd_volume_prune_desc[] = "Remove all unused local volumes"; ++const char g_cmd_volume_prune_usage[] = "prune [OPTIONS]"; ++ ++struct client_arguments g_cmd_volume_prune_args; ++ ++/* ++ * Remove all unused local volumes ++ */ ++static int client_volume_prune(const struct client_arguments *args, char ***volumes, size_t *volumes_len) ++{ ++ isula_connect_ops *ops = NULL; ++ struct isula_prune_volume_request request = { 0 }; ++ struct isula_prune_volume_response *response = NULL; ++ client_connect_config_t config = { 0 }; ++ int ret = 0; ++ ++ response = util_common_calloc_s(sizeof(struct isula_prune_volume_response)); ++ if (response == NULL) { ++ ERROR("Out of memory"); ++ return -1; ++ } ++ ++ ops = get_connect_client_ops(); ++ if (ops == NULL || ops->volume.prune == NULL) { ++ ERROR("Unimplemented ops"); ++ ret = -1; ++ goto out; ++ } ++ config = get_connect_config(args); ++ ret = ops->volume.prune(&request, response, &config); ++ if (ret != 0) { ++ client_print_error(response->cc, response->server_errono, response->errmsg); ++ if (response->server_errono) { ++ ret = ESERVERERROR; ++ } ++ goto out; ++ } ++ ++ ret = util_dup_array_of_strings((const char **)response->volumes, response->volumes_len, volumes, volumes_len); ++ if (ret != 0) { ++ COMMAND_ERROR("dup volumes failed"); ++ goto out; ++ } ++ ++out: ++ isula_prune_volume_response_free(response); ++ return ret; ++} ++ ++int cmd_volume_prune_main(int argc, const char **argv) ++{ ++ int i = 0; ++ struct isula_libutils_log_config lconf = { 0 }; ++ int exit_code = 1; ++ command_t cmd; ++ char **volumes = NULL; ++ size_t volumes_len = 0; ++ char ch = 'n'; ++ struct command_option options[] = { LOG_OPTIONS(lconf) COMMON_OPTIONS(g_cmd_volume_prune_args) ++ PRUNE_OPTIONS(g_cmd_volume_prune_args) ++ }; ++ ++ isula_libutils_default_log_config(argv[0], &lconf); ++ if (client_arguments_init(&g_cmd_volume_prune_args)) { ++ COMMAND_ERROR("client arguments init failed"); ++ exit(ECOMMON); ++ } ++ g_cmd_volume_prune_args.progname = util_string_join(" ", argv, 2); ++ subcommand_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_volume_prune_desc, ++ g_cmd_volume_prune_usage); ++ ++ if (command_parse_args(&cmd, &g_cmd_volume_prune_args.argc, &g_cmd_volume_prune_args.argv)) { ++ exit(exit_code); ++ } ++ if (isula_libutils_log_enable(&lconf)) { ++ COMMAND_ERROR("volume prune: log init failed"); ++ exit(exit_code); ++ } ++ ++ if (g_cmd_volume_prune_args.argc != 0) { ++ COMMAND_ERROR("%s: \"volume prune\" requires exactly 0 arguments.", g_cmd_volume_prune_args.progname); ++ exit(exit_code); ++ } ++ ++ if (!g_cmd_volume_prune_args.force) { ++ printf("WARNING! This will remove all local volumes not used by at least one container.\n"); ++ printf("Are you sure you want to continue? [y/N]"); ++ ch = getchar(); ++ if (ch != 'y' && ch != 'Y') { ++ exit(EXIT_SUCCESS); ++ } ++ } ++ ++ if (client_volume_prune(&g_cmd_volume_prune_args, &volumes, &volumes_len) != 0) { ++ ERROR("Prune volumes failed"); ++ exit(exit_code); ++ } ++ ++ for (i = 0; i < volumes_len; i++) { ++ printf("%s\n", volumes[i]); ++ } ++ ++ exit(EXIT_SUCCESS); ++} +diff --git a/src/cmd/isula/volume/prune.h b/src/cmd/isula/volume/prune.h +new file mode 100644 +index 0000000..9629fc2 +--- /dev/null ++++ b/src/cmd/isula/volume/prune.h +@@ -0,0 +1,37 @@ ++/****************************************************************************** ++ * 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-09-05 ++ * Description: provide volume prune definition ++ ******************************************************************************/ ++#ifndef CMD_ISULA_VOLUME_PRUNE_H ++#define CMD_ISULA_VOLUME_PRUNE_H ++ ++#include ++#include ++ ++#include "client_arguments.h" ++#include "command_parser.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++extern const char g_cmd_volume_prune_desc[]; ++extern const char g_cmd_volume_prune_usage[]; ++extern struct client_arguments g_cmd_volume_prune_args; ++int cmd_volume_prune_main(int argc, const char **argv); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif // CMD_ISULA_VOLUME_PRUNE_H +diff --git a/src/cmd/isula/volume/remove.c b/src/cmd/isula/volume/remove.c +new file mode 100644 +index 0000000..2d10a00 +--- /dev/null ++++ b/src/cmd/isula/volume/remove.c +@@ -0,0 +1,124 @@ ++/****************************************************************************** ++ * 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-09-04 ++ * Description: provide volume remove functions ++ ******************************************************************************/ ++#include "remove.h" ++ ++#include ++#include ++#include ++ ++#include "utils.h" ++#include "client_arguments.h" ++#include "isula_connect.h" ++#include "isula_libutils/log.h" ++#include "connect.h" ++#include "protocol_type.h" ++ ++const char g_cmd_volume_rm_desc[] = ++ "Remove one or more volumes. You cannot remove a volume that is in use by a container."; ++const char g_cmd_volume_rm_usage[] = "rm [OPTIONS] VOLUME [VOLUME...]"; ++ ++struct client_arguments g_cmd_volume_rm_args; ++ ++/* ++ * remove a single volume ++ */ ++static int client_volume_rm(const struct client_arguments *args) ++{ ++ isula_connect_ops *ops = NULL; ++ struct isula_remove_volume_request request = { 0 }; ++ struct isula_remove_volume_response *response = NULL; ++ client_connect_config_t config = { 0 }; ++ int ret = 0; ++ ++ response = util_common_calloc_s(sizeof(struct isula_remove_volume_response)); ++ if (response == NULL) { ++ ERROR("Out of memory"); ++ return -1; ++ } ++ ++ request.name = args->name; ++ ++ ops = get_connect_client_ops(); ++ if (ops == NULL || ops->volume.remove == NULL) { ++ ERROR("Unimplemented ops"); ++ ret = -1; ++ goto out; ++ } ++ config = get_connect_config(args); ++ ret = ops->volume.remove(&request, response, &config); ++ if (ret != 0) { ++ client_print_error(response->cc, response->server_errono, response->errmsg); ++ if (response->server_errono) { ++ ret = ESERVERERROR; ++ } ++ goto out; ++ } ++ ++out: ++ isula_remove_volume_response_free(response); ++ return ret; ++} ++ ++int cmd_volume_rm_main(int argc, const char **argv) ++{ ++ int i = 0; ++ int err = 0; ++ struct isula_libutils_log_config lconf = { 0 }; ++ int exit_code = 1; ++ command_t cmd; ++ struct command_option options[] = { LOG_OPTIONS(lconf) COMMON_OPTIONS(g_cmd_volume_rm_args) }; ++ ++ isula_libutils_default_log_config(argv[0], &lconf); ++ if (client_arguments_init(&g_cmd_volume_rm_args)) { ++ COMMAND_ERROR("client arguments init failed"); ++ exit(ECOMMON); ++ } ++ g_cmd_volume_rm_args.progname = util_string_join(" ", argv, 2); ++ subcommand_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_volume_rm_desc, ++ g_cmd_volume_rm_usage); ++ if (command_parse_args(&cmd, &g_cmd_volume_rm_args.argc, &g_cmd_volume_rm_args.argv)) { ++ exit(exit_code); ++ } ++ if (isula_libutils_log_enable(&lconf)) { ++ COMMAND_ERROR("volume rm: log init failed"); ++ exit(exit_code); ++ } ++ ++ if (g_cmd_volume_rm_args.argc == 0) { ++ COMMAND_ERROR("\"volume rm\" requires at least 1 volume name"); ++ exit(exit_code); ++ } ++ ++ if (g_cmd_volume_rm_args.argc >= MAX_CLIENT_ARGS) { ++ COMMAND_ERROR("You specify too many volumes to remove."); ++ exit(exit_code); ++ } ++ ++ for (i = 0; i < g_cmd_volume_rm_args.argc; i++) { ++ g_cmd_volume_rm_args.name = g_cmd_volume_rm_args.argv[i]; ++ int ret = client_volume_rm(&g_cmd_volume_rm_args); ++ if (ret != 0) { ++ ERROR("Volume \"%s\" remove failed", g_cmd_volume_rm_args.name); ++ err = ret; ++ continue; ++ } ++ printf("%s\n", g_cmd_volume_rm_args.name); ++ } ++ ++ if (err) { ++ exit(exit_code); ++ } ++ exit(EXIT_SUCCESS); ++} +diff --git a/src/cmd/isula/volume/remove.h b/src/cmd/isula/volume/remove.h +new file mode 100644 +index 0000000..f62c8a6 +--- /dev/null ++++ b/src/cmd/isula/volume/remove.h +@@ -0,0 +1,37 @@ ++/****************************************************************************** ++ * 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-09-04 ++ * Description: provide volume remove definition ++ ******************************************************************************/ ++#ifndef CMD_ISULA_VOLUME_REMOVE_H ++#define CMD_ISULA_VOLUME_REMOVE_H ++ ++#include ++#include ++ ++#include "client_arguments.h" ++#include "command_parser.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++extern const char g_cmd_volume_rm_desc[]; ++extern const char g_cmd_volume_rm_usage[]; ++extern struct client_arguments g_cmd_volume_rm_args; ++int cmd_volume_rm_main(int argc, const char **argv); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif // CMD_ISULA_VOLUME_REMOVE_H +diff --git a/src/cmd/isula/volume/volume.c b/src/cmd/isula/volume/volume.c +new file mode 100644 +index 0000000..3c1a1e9 +--- /dev/null ++++ b/src/cmd/isula/volume/volume.c +@@ -0,0 +1,67 @@ ++/****************************************************************************** ++ * 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-10-14 ++ * Description: provide volume functions ++ ******************************************************************************/ ++#include "volume.h" ++ ++#include "isula_commands.h" ++#include "isula_libutils/log.h" ++#include "utils.h" ++#include "prune.h" ++#include "list.h" ++#include "remove.h" ++ ++const char g_cmd_volume_desc[] = "Manage volumes"; ++ ++struct command g_volume_commands[] = { ++ { ++ // `volume ls` sub-command ++ "ls", false, cmd_volume_ls_main, g_cmd_volume_ls_desc, NULL, &g_cmd_volume_ls_args ++ }, ++ { ++ // `volume prune` sub-command ++ "prune", false, cmd_volume_prune_main, g_cmd_volume_prune_desc, NULL, &g_cmd_volume_prune_args ++ }, ++ { ++ // `volume rm` sub-command ++ "rm", false, cmd_volume_rm_main, g_cmd_volume_rm_desc, NULL, &g_cmd_volume_rm_args ++ }, ++ { NULL, false, NULL, NULL, NULL, NULL } // End of the list ++}; ++ ++int cmd_volume_main(int argc, const char **argv) ++{ ++ const struct command *command = NULL; ++ char *program = NULL; ++ ++ program = util_string_join(" ", argv, 2); ++ ++ if (argc == 2) { ++ return command_subcmd_help(program, g_volume_commands, argc - 2, (const char **)(argv + 2)); ++ } ++ ++ if (strcmp(argv[2], "--help") == 0) { ++ // isula volume help command format: isula volume --help ++ return command_subcmd_help(program, g_volume_commands, argc - 3, (const char **)(argv + 3)); ++ } ++ ++ command = command_by_name(g_volume_commands, argv[2]); ++ if (command != NULL) { ++ return command->executor(argc, (const char **)argv); ++ } ++ ++ printf("%s: command \"%s\" not found\n", program, argv[2]); ++ printf("Run `%s --help` for a list of sub-commands\n", program); ++ return 1; ++} ++ +diff --git a/src/cmd/isula/volume/volume.h b/src/cmd/isula/volume/volume.h +new file mode 100644 +index 0000000..7439386 +--- /dev/null ++++ b/src/cmd/isula/volume/volume.h +@@ -0,0 +1,29 @@ ++/****************************************************************************** ++ * 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-10-14 ++ * Description: provide volume definition ++ ******************************************************************************/ ++#ifndef CMD_ISULA_VOLUME_H ++#define CMD_ISULA_VOLUME_H ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++extern const char g_cmd_volume_desc[]; ++int cmd_volume_main(int argc, const char **argv); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif // CMD_ISULA_VOLUME_H +diff --git a/src/cmd/isulad-shim/common.c b/src/cmd/isulad-shim/common.c +index e8d94d9..84124ea 100644 +--- a/src/cmd/isulad-shim/common.c ++++ b/src/cmd/isulad-shim/common.c +@@ -14,6 +14,7 @@ + ******************************************************************************/ + + #define _GNU_SOURCE ++#include "common.h" + #include + #include + #include +@@ -26,8 +27,6 @@ + #include + #include + +-#include "common.h" +- + extern int g_log_fd; + + int set_fd_no_inherited(int fd) +@@ -122,7 +121,7 @@ int cmd_combined_output(const char *binary, const char *params[], void *output, + } + + pid = fork(); +- if (pid == (pid_t) - 1) { ++ if (pid == (pid_t) -1) { + return SHIM_ERR; + } + +@@ -254,10 +253,8 @@ char *read_text_file(const char *path) + + readlen = fread(buf, 1, (size_t)len, filp); + if (((readlen < (size_t)len) && (!feof(filp))) || (readlen > (size_t)len)) { +- if (buf != NULL) { +- free(buf); +- buf = NULL; +- } ++ free(buf); ++ buf = NULL; + goto err_out; + } + +@@ -298,4 +295,3 @@ int open_no_inherit(const char *path, int flag, mode_t mode) + + return fd; + } +- +diff --git a/src/cmd/isulad-shim/main.c b/src/cmd/isulad-shim/main.c +index 50b864d..3ab22d8 100644 +--- a/src/cmd/isulad-shim/main.c ++++ b/src/cmd/isulad-shim/main.c +@@ -71,7 +71,7 @@ static int parse_args(int argc, char **argv, char **cid, char **bundle, char **r + *cid = strdup(argv[1]); + *bundle = strdup(argv[2]); + *rt_name = strdup(argv[3]); +- if (*cid == NULL || *bundle == NULL || rt_name == NULL) { ++ if (*cid == NULL || *bundle == NULL || *rt_name == NULL) { + return SHIM_ERR; + } + +@@ -85,7 +85,10 @@ static int parse_args(int argc, char **argv, char **cid, char **bundle, char **r + return SHIM_OK; + } + +- ++/* ++ * Note: ++ * All files created in the working directory are cleared by the parent process isulad ++ */ + int main(int argc, char **argv) + { + char *container_id = NULL; +@@ -101,6 +104,10 @@ int main(int argc, char **argv) + _exit(EXIT_FAILURE); + } + ++ /* ++ * The default value of DEFAULT_TIME is 120 seconds, ++ * which is the same as the default value of containerd ++ */ + set_timeout_exit(DEFAULT_TIMEOUT); + + ret = set_subreaper(); +@@ -121,7 +128,11 @@ int main(int argc, char **argv) + exit(EXIT_FAILURE); + } + +- // open exit pipe ++ /* ++ * Open exit pipe ++ * The exit pipe exists only when the container is started, ++ * and the exec operation does not contain the exit pipe. ++ */ + if (!p->state->exec) { + if (p->state->exit_fifo != NULL) { + efd = open_no_inherit("exit_fifo", O_WRONLY, -1); +@@ -133,7 +144,7 @@ int main(int argc, char **argv) + } + } + +- // create main loop and start epoll ++ /* create main loop and start epoll for io copy */ + ret = process_io_init(p); + if (ret != SHIM_OK) { + write_message(g_log_fd, ERR_MSG, "process io init failed:%d", ret); +@@ -147,6 +158,9 @@ int main(int argc, char **argv) + + ret = create_process(p); + if (ret != SHIM_OK) { ++ if (p->console_sock_path != NULL) { ++ (void)unlink(p->console_sock_path); ++ } + exit(EXIT_FAILURE); + } + +diff --git a/src/cmd/isulad-shim/process.c b/src/cmd/isulad-shim/process.c +index 0baa615..606a3df 100644 +--- a/src/cmd/isulad-shim/process.c ++++ b/src/cmd/isulad-shim/process.c +@@ -14,6 +14,7 @@ + ******************************************************************************/ + + #define _GNU_SOURCE ++#include "process.h" + #include + #include + #include +@@ -35,7 +36,6 @@ + #include + + #include "common.h" +-#include "process.h" + #include "terminal.h" + + #define MAX_EVENTS 100 +@@ -57,14 +57,13 @@ 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"); + } +- +- if (err != NULL) { +- free(err); +- } ++ /* "err" will definitely be allocated memory in the function above */ ++ free(err); + + return p_state; + } +@@ -73,7 +72,7 @@ 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 ++ /* 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)); +@@ -99,6 +98,7 @@ static int receive_fd(int sock) + iov[0].iov_len = sizeof(buf); + + struct msghdr msg; ++ (void)memset(&msg, 0, sizeof(struct msghdr)); + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_name = NULL; +@@ -106,10 +106,16 @@ static int receive_fd(int sock) + msg.msg_control = cmptr; + msg.msg_controllen = cmsgsize; + ++ /* ++ * return value: ++ * 0: the peer has performed an orderly shutdown ++ * -1: an error occurred ++ * >0: the number of bytes received ++ */ + int ret = recvmsg(sock, &msg, 0); +- if (ret == -1) { +- free(cmptr); ++ if (ret <= 0) { + write_message(g_log_fd, ERR_MSG, "get console fd failed:%d", SHIM_SYS_ERR(errno)); ++ free(cmptr); + return -1; + } + +@@ -140,19 +146,11 @@ static int add_io_dispatch(int epfd, io_thread_t *io_thd, int from, int to) + } + + io_copy_t *ioc = io_thd->ioc; +- fd_node_t *fn = (fd_node_t *)calloc(1, sizeof(fd_node_t)); +- if (fn == NULL) { ++ ++ if (pthread_mutex_lock(&(ioc->mutex)) != 0) { + return SHIM_ERR; + } +- fn->fd = to; +- fn->is_log = false; +- if (io_thd->terminal != NULL && to == io_thd->terminal->fd) { +- fn->is_log = true; +- } +- fn->next = NULL; +- +- pthread_mutex_lock(&(ioc->mutex)); +- // add src fd ++ /* add src fd */ + if (from != -1 && ioc->fd_from == -1) { + ioc->fd_from = from; + struct epoll_event ev; +@@ -161,15 +159,27 @@ static int add_io_dispatch(int epfd, io_thread_t *io_thd, int from, int to) + + ret = epoll_ctl(epfd, EPOLL_CTL_ADD, from, &ev); + if (ret != SHIM_OK) { +- free(fn); + 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 ++ /* add dest fd */ + if (to != -1) { ++ /* new fd_node_t for dest fd */ ++ fd_node_t *fn = (fd_node_t *)calloc(1, sizeof(fd_node_t)); ++ if (fn == NULL) { ++ pthread_mutex_unlock(&(ioc->mutex)); ++ return SHIM_ERR; ++ } ++ fn->fd = to; ++ fn->is_log = false; ++ if (io_thd->terminal != NULL && to == io_thd->terminal->fd) { ++ fn->is_log = true; ++ } ++ fn->next = NULL; ++ + if (ioc->fd_to == NULL) { + ioc->fd_to = fn; + } else { +@@ -192,10 +202,13 @@ static void remove_io_dispatch(io_thread_t *io_thd, int from, int to) + } + io_copy_t *ioc = io_thd->ioc; + +- pthread_mutex_lock(&(ioc->mutex)); ++ if (pthread_mutex_lock(&(ioc->mutex))) { ++ return; ++ } ++ + fd_node_t *tmp = NULL; + do { +- // remove src fd ++ /* remove src fd */ + if (from != -1 && from == ioc->fd_from) { + struct epoll_event ev; + ev.events = EPOLLIN; +@@ -203,12 +216,12 @@ static void remove_io_dispatch(io_thread_t *io_thd, int from, int to) + (void)epoll_ctl(io_thd->epfd, EPOLL_CTL_DEL, ioc->fd_from, &ev); + } + +- // remove dest fd ++ /* remove dest fd */ + if (ioc->fd_to == NULL) { + break; + } + if (ioc->fd_to->fd == to) { +- // remove the first fd node ++ /* remove the first fd node */ + tmp = ioc->fd_to; + ioc->fd_to = ioc->fd_to->next; + break; +@@ -225,6 +238,7 @@ static void remove_io_dispatch(io_thread_t *io_thd, int from, int to) + } while (0); + if (tmp != NULL) { + free(tmp); ++ tmp = NULL; + } + pthread_mutex_unlock(&(ioc->mutex)); + } +@@ -238,7 +252,7 @@ static void *task_io_copy(void *data) + io_copy_t *ioc = io_thd->ioc; + char *buf = calloc(1, DEFAULT_IO_COPY_BUF + 1); + if (buf == NULL) { +- _exit(EXIT_FAILURE); ++ return NULL; + } + + for (;;) { +@@ -250,13 +264,12 @@ static void *task_io_copy(void *data) + + 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. ++ /* End of file. The remote has closed the connection */ + break; + } else { + fd_node_t *fn = ioc->fd_to; +@@ -265,10 +278,9 @@ static void *task_io_copy(void *data) + shim_write_container_log_file(io_thd->terminal, ioc->id == stdid_out ? "stdout" : "stderr", buf, + r_count); + } else { +- int w_count = 0; +- w_count = write_nointr(fn->fd, buf, r_count); ++ int w_count = write_nointr(fn->fd, buf, r_count); + if (w_count < 0) { +- // remove the write fd ++ /* When any error occurs, remove the write fd */ + remove_io_dispatch(io_thd, -1, fn->fd); + } + } +@@ -366,6 +378,7 @@ static int start_io_copy_threads(process_t *p) + int ret = SHIM_ERR; + int i; + ++ /* 3 threads for stdin, stdout and stderr */ + for (i = 0; i < 3; i++) { + ret = process_io_start(p, i); + if (ret != SHIM_OK) { +@@ -423,7 +436,7 @@ static int connect_to_isulad(process_t *p, int std_id, const char *isulad_stdio, + 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 ++ /* if no I/O source is available, the I/O thread nead to be destroyed */ + destroy_io_thread(p, std_id); + + return SHIM_OK; +@@ -448,36 +461,43 @@ static void *task_console_accept(void *data) + goto out; + } + +- // do console io copy +- // +- // p.state.stdin---->runtime.console ++ /* 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) { + goto out; + } + +- // p.state.stdout<------runtime.console ++ /* p.state.stdout<------runtime.console */ + ret = connect_to_isulad(ac->p, stdid_out, ac->p->state->isulad_stdout, recv_fd); + if (ret != SHIM_OK) { + goto out; + } + +- // if the terminal is used, we do not need to active the io copy of stderr pipe ++ /* ++ * if the terminal is used, we do not need to active the io copy of stderr pipe, ++ * for stderr and stdout are mixed together ++ */ + destroy_io_thread(ac->p, stdid_err); + + out: +- // release listen socket ++ /* release listen socket at the first time */ + close_fd(&ac->listen_fd); + if (ac->p->console_sock_path != NULL) { +- unlink(ac->p->console_sock_path); ++ (void)unlink(ac->p->console_sock_path); + free(ac->p->console_sock_path); + ac->p->console_sock_path = NULL; + } + free(ac); + if (ret != SHIM_OK) { ++ /* ++ * When an error occurs during the receiving of the fd , the process ++ * exits directly. The files created in the working directory will be ++ * deleted by its parent process isulad ++ */ + exit(EXIT_FAILURE); + } +- + return NULL; + } + +@@ -495,8 +515,7 @@ static void *task_io_loop(void *data) + } + (void)sem_post(&p->sem_mainloop); + +- // begin wait +- while (1) { ++ for (;;) { + wait_fds = epoll_wait(p->io_loop_fd, evs, MAX_EVENTS, -1); + if (wait_fds < 0) { + if (errno == EINTR) { +@@ -526,7 +545,12 @@ static int new_temp_console_path(process_t *p) + if (p->console_sock_path == NULL) { + return SHIM_ERR; + } +- snprintf(p->console_sock_path, MAX_CONSOLE_SOCK_LEN, "/run/isulad%s-pty.sock", str_rand); ++ int nret = snprintf(p->console_sock_path, MAX_CONSOLE_SOCK_LEN, "/run/isulad%s-pty.sock", str_rand); ++ if (nret < 0 || nret >= MAX_CONSOLE_SOCK_LEN) { ++ free(p->console_sock_path); ++ p->console_sock_path = NULL; ++ return SHIM_ERR; ++ } + + return SHIM_OK; + } +@@ -548,14 +572,12 @@ static int console_init(process_t *p) + 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)); +@@ -584,17 +606,44 @@ failure: + close_fd(&fd); + if (ac != NULL) { + free(ac); ++ ac = NULL; + } +- unlink(p->console_sock_path); ++ (void)unlink(p->console_sock_path); + + return SHIM_ERR; + } + ++static int stdio_chown(int (*stdio_fd)[2], int uid, int gid) ++{ ++ int i, j; ++ ++ for (i = 0; i < 3; i++) { ++ for (j = 0; j < 2; j++) { ++ int ret = fchown(stdio_fd[i][j], uid, gid); ++ if (ret != SHIM_OK) { ++ return SHIM_ERR; ++ } ++ } ++ } ++ return SHIM_OK; ++} ++ ++static void stdio_release(int (*stdio_fd)[2]) ++{ ++ int i, j; ++ ++ for (i = 0; i < 3; i++) { ++ for (j = 0; j < 2; j++) { ++ if (stdio_fd[i][j] > 0) { ++ close(stdio_fd[i][j]); ++ } ++ } ++ } ++} ++ + 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)); +@@ -615,13 +664,8 @@ static stdio_t *initialize_io(process_t *p) + 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; +- } +- } ++ if (stdio_chown(stdio_fd, p->state->root_uid, p->state->root_gid) != SHIM_OK) { ++ goto failure; + } + + return stdio; +@@ -635,13 +679,7 @@ failure: + 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]); +- } +- } +- } ++ stdio_release(stdio_fd); + + return NULL; + } +@@ -656,7 +694,7 @@ static int open_terminal_io(process_t *p) + return SHIM_ERR; + } + +- // begin listen and accept fd from p->console_sock_path ++ /* begin listen and accept fd from p->console_sock_path */ + return console_init(p); + } + +@@ -669,17 +707,17 @@ static int open_generic_io(process_t *p) + return SHIM_ERR; + } + p->shim_io = io; +- // stdin ++ /* stdin */ + ret = connect_to_isulad(p, stdid_in, p->state->isulad_stdin, io->in); + if (ret != SHIM_OK) { + return SHIM_ERR; + } +- // stdout ++ /* stdout */ + ret = connect_to_isulad(p, stdid_out, p->state->isulad_stdout, io->out); + if (ret != SHIM_OK) { + return SHIM_ERR; + } +- // stderr ++ /* stderr */ + ret = connect_to_isulad(p, stdid_err, p->state->isulad_stderr, io->err); + if (ret != SHIM_OK) { + return SHIM_ERR; +@@ -690,7 +728,7 @@ static int open_generic_io(process_t *p) + + 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 ++ /* 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); +@@ -931,7 +969,11 @@ static void process_delete(process_t *p) + write_message(g_log_fd, ERR_MSG, "get cwd failed when do process delete"); + return; + } +- snprintf(log_path, PATH_MAX, "%s/log.json", cwd); ++ int nret = snprintf(log_path, PATH_MAX, "%s/log.json", cwd); ++ if (nret < 0 || nret >= PATH_MAX) { ++ free(cwd); ++ return; ++ } + + params[i++] = p->runtime; + for (j = 0; j < p->state->runtime_args_len; j++) { +@@ -952,9 +994,66 @@ static void process_delete(process_t *p) + return; + } + ++static void exec_runtime_process(process_t *p, int exec_fd) ++{ ++ 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, "memory error: %s", strerror(errno)); ++ _exit(EXIT_FAILURE); ++ } ++ ++ int nret = snprintf(log_path, PATH_MAX, "%s/log.json", cwd); ++ if (nret < 0 || nret >= PATH_MAX) { ++ _exit(EXIT_FAILURE); ++ } ++ nret = snprintf(pid_path, PATH_MAX, "%s/pid", cwd); ++ if (nret < 0 || nret >= PATH_MAX) { ++ _exit(EXIT_FAILURE); ++ } ++ ++ char *process_desc = NULL; ++ if (p->state->exec) { ++ process_desc = (char *)calloc(1, PATH_MAX); ++ if (process_desc == NULL) { ++ (void)dprintf(exec_fd, "memory error: %s", strerror(errno)); ++ _exit(EXIT_FAILURE); ++ } ++ nret = snprintf(process_desc, PATH_MAX, "%s/process.json", cwd); ++ if (nret < 0 || nret >= PATH_MAX) { ++ _exit(EXIT_FAILURE); ++ } ++ } ++ ++ 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, "fork/exec error: %s", strerror(errno)); ++ _exit(EXIT_FAILURE); ++} ++ + int create_process(process_t *p) + { +- int ret = -1; ++ int ret = SHIM_ERR; + char *data = NULL; + int exec_fd[2] = { -1, -1 }; + char exec_buff[BUFSIZ + 1] = { 0 }; +@@ -971,56 +1070,13 @@ int create_process(process_t *p) + return SHIM_ERR; + } + +- // child:runtime ++ /* child:runtime process */ + 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); ++ exec_runtime_process(p, exec_fd[1]); + } + +- // parent ++ /* parent:isulad-shim process */ + close_fd(&exec_fd[1]); + if (p->stdio != NULL) { + close_fd(&p->stdio->in); +@@ -1034,7 +1090,7 @@ int create_process(process_t *p) + goto out; + } + +- // block to wait pid exit ++ /* block to wait runtime 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)); +@@ -1042,7 +1098,7 @@ int create_process(process_t *p) + goto out; + } + +- // save pid ++ /* save runtime pid */ + data = read_text_file("pid"); + if (data == NULL) { + write_message(g_log_fd, ERR_MSG, "read pid of runtime failed"); +@@ -1061,6 +1117,7 @@ out: + close_fd(&exec_fd[0]); + if (data != NULL) { + free(data); ++ data = NULL; + } + + return ret; +@@ -1089,7 +1146,7 @@ int process_signal_handle_routine(process_t *p) + } + } + } else if (ret == SHIM_ERR_WAIT) { +- // avoid thread entering the infinite loop ++ /* avoid thread entering the infinite loop */ + usleep(1000); + continue; + } +diff --git a/src/cmd/isulad-shim/terminal.c b/src/cmd/isulad-shim/terminal.c +index 0be4b4d..9b7d55e 100644 +--- a/src/cmd/isulad-shim/terminal.c ++++ b/src/cmd/isulad-shim/terminal.c +@@ -13,6 +13,7 @@ + * Description: container logs ops + ******************************************************************************/ + #define _GNU_SOURCE ++#include "terminal.h" + #include + #include + #include +@@ -28,7 +29,6 @@ + #include + #include + +-#include "terminal.h" + #include "common.h" + + #define BUF_CACHE_SIZE (16 * 1024) +@@ -170,7 +170,7 @@ static int shim_json_data_write(log_terminal *terminal, const char *buf, int rea + return (read_count - ret); + } + +-static bool get_time_buffer(struct timespec *timestamp, char *timebuffer, size_t maxsize) ++static bool util_get_time_buffer(struct timespec *timestamp, char *timebuffer, size_t maxsize) + { + struct tm tm_utc = { 0 }; + int32_t nanos = 0; +@@ -196,7 +196,7 @@ static bool get_time_buffer(struct timespec *timestamp, char *timebuffer, size_t + return true; + } + +-static bool get_now_time_buffer(char *timebuffer, size_t maxsize) ++static bool util_get_now_time_buffer(char *timebuffer, size_t maxsize) + { + int err = 0; + struct timespec ts; +@@ -206,7 +206,7 @@ static bool get_now_time_buffer(char *timebuffer, size_t maxsize) + return false; + } + +- return get_time_buffer(&ts, timebuffer, maxsize); ++ return util_get_time_buffer(&ts, timebuffer, maxsize); + } + + static ssize_t shim_logger_write(log_terminal *terminal, const char *type, const char *buf, int read_count) +@@ -236,7 +236,7 @@ static ssize_t shim_logger_write(log_terminal *terminal, const char *type, const + msg->log_len = read_count; + msg->stream = type ? safe_strdup(type) : safe_strdup("stdout"); + +- get_now_time_buffer(timebuffer, sizeof(timebuffer)); ++ util_get_now_time_buffer(timebuffer, sizeof(timebuffer)); + msg->time = safe_strdup(timebuffer); + json = logger_json_file_generate_json(msg, &ctx, &err); + if (!json) { +diff --git a/src/cmd/isulad/isulad_commands.c b/src/cmd/isulad/isulad_commands.c +index 4b1ace0..11e166f 100644 +--- a/src/cmd/isulad/isulad_commands.c ++++ b/src/cmd/isulad/isulad_commands.c +@@ -12,15 +12,14 @@ + * Create: 2017-11-22 + * Description: provide container commands functions + ******************************************************************************/ ++#include "isulad_commands.h" + #include + #include + #include + #include + #include +-#include + #include + +-#include "isulad_commands.h" + #include "config.h" + #include "isula_libutils/log.h" + #include "path.h" +@@ -30,9 +29,9 @@ + #include "constants.h" + #include "isula_libutils/isulad_daemon_configs.h" + #include "utils_array.h" +-#include "utils_convert.h" + #include "utils_string.h" + #include "utils_verify.h" ++#include "opt_ulimit.h" + + const char isulad_desc[] = "GLOBAL OPTIONS:"; + const char isulad_usage[] = "[global options]"; +@@ -42,171 +41,6 @@ void print_version() + printf("Version %s, commit %s\n", VERSION, ISULAD_GIT_COMMIT); + } + +-static int check_default_ulimit_input(const char *val) +-{ +- int ret = 0; +- if (val == NULL || strcmp(val, "") == 0) { +- COMMAND_ERROR("ulimit argument can't be empty"); +- ret = -1; +- goto out; +- } +- +- if (val[0] == '=' || val[strlen(val) - 1] == '=') { +- COMMAND_ERROR("Invalid ulimit argument: \"%s\", delimiter '=' can't" +- " be the first or the last character", +- val); +- ret = -1; +- } +- +-out: +- return ret; +-} +- +-static void get_default_ulimit_split_parts(const char *val, char ***parts, size_t *parts_len, char deli) +-{ +- *parts = util_string_split_multi(val, deli); +- if (*parts == NULL) { +- ERROR("Out of memory"); +- return; +- } +- *parts_len = util_array_len((const char **)(*parts)); +-} +- +-static int parse_soft_hard_default_ulimit(const char *val, char **limitvals, size_t limitvals_len, int64_t *soft, +- int64_t *hard) +-{ +- int ret = 0; +- // parse soft +- ret = util_safe_llong(limitvals[0], (long long *)soft); +- if (ret < 0) { +- COMMAND_ERROR("Invalid ulimit soft value: \"%s\", parse int64 failed: %s", val, strerror(-ret)); +- ret = -1; +- goto out; +- } +- +- // parse hard if exists +- if (limitvals_len > 1) { +- ret = util_safe_llong(limitvals[1], (long long *)hard); +- if (ret < 0) { +- COMMAND_ERROR("Invalid ulimit hard value: \"%s\", parse int64 failed: %s", val, strerror(-ret)); +- ret = -1; +- goto out; +- } +- +- if (*soft > *hard) { +- COMMAND_ERROR("Ulimit soft limit must be less than or equal to hard limit: %lld > %lld", +- (long long int)(*soft), (long long int)(*hard)); +- ret = -1; +- goto out; +- } +- } else { +- *hard = *soft; // default to soft in case no hard was set +- } +-out: +- return ret; +-} +- +-int check_default_ulimit_type(const char *type) +-{ +- int ret = 0; +- char **tmptype = NULL; +- char *ulimit_valid_type[] = { +- // "as", // Disabled since this doesn't seem usable with the way Docker inits a container. +- "core", "cpu", "data", "fsize", "locks", "memlock", "msgqueue", "nice", +- "nofile", "nproc", "rss", "rtprio", "rttime", "sigpending", "stack", NULL +- }; +- +- for (tmptype = ulimit_valid_type; *tmptype != NULL; tmptype++) { +- if (strcmp(type, *tmptype) == 0) { +- break; +- } +- } +- +- if (*tmptype == NULL) { +- COMMAND_ERROR("Invalid ulimit type: %s", type); +- ret = -1; +- } +- return ret; +-} +- +-static host_config_ulimits_element *parse_default_ulimit(const char *val) +-{ +- int ret = 0; +- int64_t soft = 0; +- int64_t hard = 0; +- size_t parts_len = 0; +- size_t limitvals_len = 0; +- char **parts = NULL; +- char **limitvals = NULL; +- host_config_ulimits_element *ulimit = NULL; +- +- ret = check_default_ulimit_input(val); +- if (ret != 0) { +- return NULL; +- } +- +- get_default_ulimit_split_parts(val, &parts, &parts_len, '='); +- if (parts == NULL) { +- ERROR("Out of memory"); +- return NULL; +- } else if (parts_len != 2) { +- COMMAND_ERROR("Invalid ulimit argument: %s", val); +- ret = -1; +- goto out; +- } +- +- ret = check_default_ulimit_type(parts[0]); +- if (ret != 0) { +- ret = -1; +- goto out; +- } +- +- if (parts[1][0] == ':' || parts[1][strlen(parts[1]) - 1] == ':') { +- COMMAND_ERROR("Invalid ulimit value: \"%s\", delimiter ':' can't be the first" +- " or the last character", +- val); +- ret = -1; +- goto out; +- } +- +- // parse value +- get_default_ulimit_split_parts(parts[1], &limitvals, &limitvals_len, ':'); +- if (limitvals == NULL) { +- ret = -1; +- goto out; +- } +- +- if (limitvals_len > 2) { +- COMMAND_ERROR("Too many limit value arguments - %s, can only have up to two, `soft[:hard]`", parts[1]); +- ret = -1; +- goto out; +- } +- +- ret = parse_soft_hard_default_ulimit(val, limitvals, limitvals_len, &soft, &hard); +- if (ret < 0) { +- goto out; +- } +- +- ulimit = util_common_calloc_s(sizeof(host_config_ulimits_element)); +- if (ulimit == NULL) { +- ret = -1; +- goto out; +- } +- ulimit->name = util_strdup_s(parts[0]); +- ulimit->hard = hard; +- ulimit->soft = soft; +- +-out: +- util_free_array(parts); +- util_free_array(limitvals); +- if (ret != 0) { +- free_host_config_ulimits_element(ulimit); +- ulimit = NULL; +- } +- +- return ulimit; +-} +- + int command_default_ulimit_append(command_option_t *option, const char *arg) + { + int ret = 0; +@@ -219,7 +53,7 @@ int command_default_ulimit_append(command_option_t *option, const char *arg) + goto out; + } + +- tmp = parse_default_ulimit(arg); ++ tmp = parse_opt_ulimit(arg); + if (tmp == NULL) { + ERROR("parse default ulimit from arg failed"); + ret = -1; +@@ -361,6 +195,7 @@ static int check_args_graph_path(struct service_arguments *args) + { + int ret = 0; + char dstpath[PATH_MAX] = { 0 }; ++ char *real_path = NULL; + + ret = util_validate_absolute_path(args->json_confs->graph); + if (ret) { +@@ -368,13 +203,20 @@ static int check_args_graph_path(struct service_arguments *args) + ret = -1; + goto out; + } +- if (cleanpath(args->json_confs->graph, dstpath, sizeof(dstpath)) == NULL) { ++ if (util_clean_path(args->json_confs->graph, dstpath, sizeof(dstpath)) == NULL) { + ERROR("failed to get clean path"); + ret = -1; + goto out; + } ++ ++ if (util_realpath_in_scope("/", dstpath, &real_path) != 0) { ++ ERROR("failed to get real path"); ++ ret = -1; ++ goto out; ++ } ++ + free(args->json_confs->graph); +- args->json_confs->graph = util_strdup_s(dstpath); ++ args->json_confs->graph = real_path; + + out: + return ret; +@@ -384,6 +226,7 @@ static int check_args_state_path(struct service_arguments *args) + { + int ret = 0; + char dstpath[PATH_MAX] = { 0 }; ++ char *real_path = NULL; + + ret = util_validate_absolute_path(args->json_confs->state); + if (ret != 0) { +@@ -391,13 +234,20 @@ static int check_args_state_path(struct service_arguments *args) + ret = -1; + goto out; + } +- if (cleanpath(args->json_confs->state, dstpath, sizeof(dstpath)) == NULL) { ++ if (util_clean_path(args->json_confs->state, dstpath, sizeof(dstpath)) == NULL) { + ERROR("failed to get clean path"); + ret = -1; + goto out; + } ++ ++ if (util_realpath_in_scope("/", dstpath, &real_path) != 0) { ++ ERROR("failed to get real path"); ++ ret = -1; ++ goto out; ++ } ++ + free(args->json_confs->state); +- args->json_confs->state = util_strdup_s(dstpath); ++ args->json_confs->state = real_path; + + out: + return ret; +@@ -722,7 +572,7 @@ static int check_conf_default_ulimit(const struct service_arguments *args) + goto out; + } + +- ret = check_default_ulimit_type(type); ++ ret = check_opt_ulimit_type(type); + if (ret != 0) { + goto out; + } +diff --git a/src/cmd/isulad/isulad_commands.h b/src/cmd/isulad/isulad_commands.h +index 68dca4e..78ec584 100644 +--- a/src/cmd/isulad/isulad_commands.h ++++ b/src/cmd/isulad/isulad_commands.h +@@ -29,7 +29,7 @@ void print_common_help(); + void print_version(); + + // Default help command if implementation doesn't prvide one +-int commmand_default_help(const char * const program_name, int argc, char **argv); ++int command_default_help(const char * const program_name, int argc, char **argv); + int command_isulad_valid_socket(command_option_t *option, const char *arg); + int parse_args(struct service_arguments *args, int argc, const char **argv); + int check_args(struct service_arguments *args); +@@ -105,7 +105,7 @@ int command_default_ulimit_append(command_option_t *option, const char *arg); + "group", \ + 'G', \ + &(cmdargs)->json_confs->group, \ +- "Group for the unix socket(default is isulad)", \ ++ "Group for the unix socket(default is isula)", \ + NULL }, \ + { CMD_OPT_TYPE_STRING_DUP, \ + false, \ +diff --git a/src/cmd/isulad/main.c b/src/cmd/isulad/main.c +index b019ac0..bef78f8 100644 +--- a/src/cmd/isulad/main.c ++++ b/src/cmd/isulad/main.c +@@ -58,7 +58,9 @@ + #include "log_gather_api.h" + #include "container_api.h" + #include "plugin_api.h" ++#ifdef ENABLE_SELINUX + #include "selinux_label.h" ++#endif + #include "http.h" + #include "runtime_api.h" + #include "daemon_arguments.h" +@@ -67,6 +69,7 @@ + #include "utils_file.h" + #include "utils_string.h" + #include "utils_verify.h" ++#include "volume_api.h" + + #ifdef GRPC_CONNECTOR + #include "clibcni/api.h" +@@ -79,20 +82,30 @@ static int create_client_run_path(const char *group) + { + int ret = 0; + const char *rundir = "/var/run/isula"; ++ + if (group == NULL) { + return -1; + } +- ret = util_mkdir_p(rundir, DEFAULT_SECURE_DIRECTORY_MODE); +- if (ret < 0) { ++ ++ if (util_mkdir_p(rundir, ISULA_CLIENT_DIRECTORY_MODE) < 0) { + ERROR("Unable to create client run directory %s.", rundir); +- return ret; ++ ret = -1; ++ goto out; + } + +- ret = chmod(rundir, DEFAULT_SECURE_DIRECTORY_MODE); +- if (ret < 0) { ++ if (chmod(rundir, ISULA_CLIENT_DIRECTORY_MODE) < 0) { + ERROR("Failed to chmod for client run path: %s", rundir); ++ ret = -1; ++ goto out; ++ } ++ ++ if (util_set_file_group(rundir, group) != 0) { ++ ERROR("set group of the path: %s failed", rundir); ++ ret = -1; ++ goto out; + } + ++out: + return ret; + } + +@@ -747,6 +760,7 @@ out: + return ret; + } + ++#ifdef ENABLE_SELINUX + static int overlay_supports_selinux(bool *supported) + { + #define KALLSYMS_ITEM_MAX_LEN 100 +@@ -820,6 +834,7 @@ static int configure_kernel_security_support(const struct service_arguments *arg + } + return 0; + } ++#endif + + static int update_server_args(struct service_arguments *args) + { +@@ -868,12 +883,14 @@ static int update_server_args(struct service_arguments *args) + goto out; + } + ++#ifdef ENABLE_SELINUX + // Configure and validate the kernels security support. Note this is a Linux/FreeBSD + // operation only, so it is safe to pass *just* the runtime OS graphdriver. + if (configure_kernel_security_support(args)) { + ret = -1; + goto out; + } ++#endif + + out: + return ret; +@@ -949,7 +966,7 @@ static int init_log_gather_thread(const char *log_full_path, struct isula_libuti + return -1; + } + while (1) { +- usleep_nointerupt(1000); ++ util_usleep_nointerupt(1000); + if (log_gather_exitcode >= 0) { + break; + } +@@ -1076,6 +1093,11 @@ static int isulad_server_init_common() + goto out; + } + ++ if (volume_init(args->json_confs->graph) != 0) { ++ ERROR("Failed to init volume"); ++ goto out; ++ } ++ + if (image_module_init(args->json_confs) != 0) { + ERROR("Failed to init image manager"); + goto out; +@@ -1398,11 +1420,6 @@ int main(int argc, char **argv) + goto failure; + } + +- if (init_cgroups_path("/lxc", 0)) { +- msg = g_isulad_errmsg ? g_isulad_errmsg : "Failed to init cgroups path"; +- goto failure; +- } +- + if (add_sighandler()) { + msg = "Failed to add sig handlers"; + goto failure; +diff --git a/src/cmd/options/CMakeLists.txt b/src/cmd/options/CMakeLists.txt +new file mode 100644 +index 0000000..358634b +--- /dev/null ++++ b/src/cmd/options/CMakeLists.txt +@@ -0,0 +1,5 @@ ++# get current directory sources files ++aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} top_srcs) ++ ++set(OPT_SRCS ${top_srcs} PARENT_SCOPE) ++set(OPT_INCS ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE) +diff --git a/src/cmd/options/opt_ulimit.c b/src/cmd/options/opt_ulimit.c +new file mode 100644 +index 0000000..1a9c616 +--- /dev/null ++++ b/src/cmd/options/opt_ulimit.c +@@ -0,0 +1,190 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. 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: lifeng ++ * Create: 2020-09-28 ++ * Description: provide ulimit options parse function ++ ******************************************************************************/ ++#include "opt_ulimit.h" ++ ++#include ++#include ++#include ++#include ++ ++#include "isula_libutils/log.h" ++#include "utils.h" ++#include "utils_array.h" ++#include "utils_convert.h" ++#include "utils_string.h" ++ ++static int check_ulimit_input(const char *val) ++{ ++ int ret = 0; ++ if (val == NULL || strcmp(val, "") == 0) { ++ COMMAND_ERROR("ulimit argument can't be empty"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (val[0] == '=' || val[strlen(val) - 1] == '=') { ++ COMMAND_ERROR("Invalid ulimit argument: \"%s\", delimiter '=' can't" ++ " be the first or the last character", ++ val); ++ ret = -1; ++ } ++ ++out: ++ return ret; ++} ++ ++static void get_ulimit_split_parts(const char *val, char ***parts, size_t *parts_len, char deli) ++{ ++ *parts = util_string_split_multi(val, deli); ++ if (*parts == NULL) { ++ COMMAND_ERROR("Out of memory"); ++ return; ++ } ++ *parts_len = util_array_len((const char **)(*parts)); ++} ++ ++static int parse_soft_hard_ulimit(const char *val, char **limitvals, size_t limitvals_len, int64_t *soft, int64_t *hard) ++{ ++ int ret = 0; ++ // parse soft ++ ret = util_safe_llong(limitvals[0], (long long *)soft); ++ if (ret < 0) { ++ COMMAND_ERROR("Invalid ulimit soft value: \"%s\", parse int64 failed: %s", val, strerror(-ret)); ++ ret = -1; ++ goto out; ++ } ++ ++ // parse hard if exists ++ if (limitvals_len > 1) { ++ ret = util_safe_llong(limitvals[1], (long long *)hard); ++ if (ret < 0) { ++ COMMAND_ERROR("Invalid ulimit hard value: \"%s\", parse int64 failed: %s", val, strerror(-ret)); ++ ret = -1; ++ goto out; ++ } ++ ++ if (*soft > *hard) { ++ COMMAND_ERROR("Ulimit soft limit must be less than or equal to hard limit: %lld > %lld", ++ (long long int)(*soft), (long long int)(*hard)); ++ ret = -1; ++ goto out; ++ } ++ } else { ++ *hard = *soft; // default to soft in case no hard was set ++ } ++out: ++ return ret; ++} ++ ++int check_opt_ulimit_type(const char *type) ++{ ++ int ret = 0; ++ char **tmptype = NULL; ++ char *ulimit_valid_type[] = { ++ // "as", // Disabled since this doesn't seem usable with the way Docker inits a container. ++ "core", "cpu", "data", "fsize", "locks", "memlock", "msgqueue", "nice", ++ "nofile", "nproc", "rss", "rtprio", "rttime", "sigpending", "stack", NULL ++ }; ++ ++ for (tmptype = ulimit_valid_type; *tmptype != NULL; tmptype++) { ++ if (strcmp(type, *tmptype) == 0) { ++ break; ++ } ++ } ++ ++ if (*tmptype == NULL) { ++ COMMAND_ERROR("Invalid ulimit type: %s", type); ++ ret = -1; ++ } ++ return ret; ++} ++ ++host_config_ulimits_element *parse_opt_ulimit(const char *val) ++{ ++ int ret = 0; ++ int64_t soft = 0; ++ int64_t hard = 0; ++ size_t parts_len = 0; ++ size_t limitvals_len = 0; ++ char **parts = NULL; ++ char **limitvals = NULL; ++ host_config_ulimits_element *ulimit = NULL; ++ ++ ret = check_ulimit_input(val); ++ if (ret != 0) { ++ return NULL; ++ } ++ ++ get_ulimit_split_parts(val, &parts, &parts_len, '='); ++ if (parts == NULL) { ++ ERROR("Out of memory"); ++ return NULL; ++ } else if (parts_len != 2) { ++ COMMAND_ERROR("Invalid ulimit argument: %s", val); ++ ret = -1; ++ goto out; ++ } ++ ++ ret = check_opt_ulimit_type(parts[0]); ++ if (ret != 0) { ++ ret = -1; ++ goto out; ++ } ++ ++ if (parts[1][0] == ':' || parts[1][strlen(parts[1]) - 1] == ':') { ++ COMMAND_ERROR("Invalid ulimit value: \"%s\", delimiter ':' can't be the first" ++ " or the last character", ++ val); ++ ret = -1; ++ goto out; ++ } ++ ++ // parse value ++ get_ulimit_split_parts(parts[1], &limitvals, &limitvals_len, ':'); ++ if (limitvals == NULL) { ++ ret = -1; ++ goto out; ++ } ++ ++ if (limitvals_len > 2) { ++ COMMAND_ERROR("Too many limit value arguments - %s, can only have up to two, `soft[:hard]`", parts[1]); ++ ret = -1; ++ goto out; ++ } ++ ++ ret = parse_soft_hard_ulimit(val, limitvals, limitvals_len, &soft, &hard); ++ if (ret < 0) { ++ goto out; ++ } ++ ++ ulimit = util_common_calloc_s(sizeof(host_config_ulimits_element)); ++ if (ulimit == NULL) { ++ ret = -1; ++ goto out; ++ } ++ ulimit->name = util_strdup_s(parts[0]); ++ ulimit->hard = hard; ++ ulimit->soft = soft; ++ ++out: ++ util_free_array(parts); ++ util_free_array(limitvals); ++ if (ret != 0) { ++ free_host_config_ulimits_element(ulimit); ++ ulimit = NULL; ++ } ++ ++ return ulimit; ++} +\ No newline at end of file +diff --git a/src/client/connect/pack_config.h b/src/cmd/options/opt_ulimit.h +similarity index 65% +rename from src/client/connect/pack_config.h +rename to src/cmd/options/opt_ulimit.h +index c1062fa..657955d 100644 +--- a/src/client/connect/pack_config.h ++++ b/src/cmd/options/opt_ulimit.h +@@ -8,27 +8,28 @@ + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. +- * Author: tanyifeng +- * Create: 2018-11-08 +- * Description: provide container package configure definition ++ * Author: lifeng ++ * Create: 2020-09-28 ++ * Description: provide ulimit options parse function + ******************************************************************************/ +-#ifndef CLIENT_CONNECT_PACK_CONFIG_H +-#define CLIENT_CONNECT_PACK_CONFIG_H ++#ifndef CMD_OPTIONS_ULIMIT_H ++#define CMD_OPTIONS_ULIMIT_H + +-#include "libisula.h" ++#include ++#include ++#include ++ ++#include "isula_libutils/host_config.h" + + #ifdef __cplusplus + extern "C" { + #endif + +-int generate_hostconfig(const isula_host_config_t *srcconfig, char **hostconfigstr); +- +-int generate_container_config(const isula_container_config_t *custom_conf, +- char **container_config_str); ++int check_opt_ulimit_type(const char *type); ++host_config_ulimits_element *parse_opt_ulimit(const char *val); + + #ifdef __cplusplus + } + #endif + + #endif +- +diff --git a/src/common/constants.h b/src/common/constants.h +index 5aca48e..457e242 100644 +--- a/src/common/constants.h ++++ b/src/common/constants.h +@@ -26,6 +26,8 @@ extern "C" { + + #define DEFAULT_SECURE_DIRECTORY_MODE 0750 + ++#define ISULA_CLIENT_DIRECTORY_MODE 0770 ++ + #define USER_REMAP_DIRECTORY_MODE 0751 + + #define ROOTFS_MNT_DIRECTORY_MODE 0640 +@@ -42,7 +44,7 @@ extern "C" { + + #define LOG_DIRECTORY_MODE 0750 + +-#define TEMP_DIRECTORY_MODE 0750 ++#define TEMP_DIRECTORY_MODE 0700 + + #define CONSOLE_FIFO_DIRECTORY_MODE 0770 + +@@ -113,9 +115,6 @@ extern "C" { + + #define AUTH_PLUGIN "authz-broker" + +-#define ISULAD_ISULA_ADAPTER "isula-adapter" +-#define ISULAD_ISULA_ACCEL_ARGS "isulad.accel.args" +-#define ISULAD_ISULA_ACCEL_ARGS_SEPERATOR ";" + #define ISULAD_ENABLE_PLUGINS "ISULAD_ENABLE_PLUGINS" + #define ISULAD_ENABLE_PLUGINS_SEPERATOR "," + #define ISULAD_ENABLE_PLUGINS_SEPERATOR_CHAR ',' +diff --git a/src/contrib/config/config.json b/src/contrib/config/config.json +index e87420d..cfcdc37 100644 +--- a/src/contrib/config/config.json ++++ b/src/contrib/config/config.json +@@ -49,7 +49,6 @@ + "path": "rootfs", + "readonly": false + }, +- "hostname": "ubuntu", + "mounts": [ + { + "destination": "/proc", +@@ -266,6 +265,7 @@ + "/proc/pagealloc_statistics", + "/proc/pagealloc_module", + "/proc/pagealloc_bt", ++ "/proc/pin_memory", + "/proc/slaballoc_statistics", + "/proc/slaballoc_module", + "/proc/slaballoc_bt", +diff --git a/src/contrib/config/daemon.json b/src/contrib/config/daemon.json +index 2eac55e..9ffb08e 100644 +--- a/src/contrib/config/daemon.json ++++ b/src/contrib/config/daemon.json +@@ -1,5 +1,5 @@ + { +- "group": "isulad", ++ "group": "isula", + "default-runtime": "lcr", + "graph": "/var/lib/isulad", + "state": "/var/run/isulad", +diff --git a/src/contrib/config/iSulad.sysconfig b/src/contrib/config/iSulad.sysconfig +index 580d6de..43ba7cb 100644 +--- a/src/contrib/config/iSulad.sysconfig ++++ b/src/contrib/config/iSulad.sysconfig +@@ -20,3 +20,7 @@ + #SYSMONITOR_OPTIONS='-H unix:///var/run/isulad.sock' + #SYSMONITOR_OPTIONS='-H tcp://127.0.0.1:2375' + #SYSMONITOR_OPTIONS='-H tcp://127.0.0.1:2375 --tlsverify --tlscacert=/root/.iSulad/ca.pem --tlscert=/root/.iSulad/cert.pem --tlskey=/root/.iSulad/key.pem' ++ ++# Location used for temporary files, such as those created by isula load and pull operations. ++# Default is /var/tmp. Can be overridden by setting the following env variable. ++# ISULAD_TMPDIR=/var/tmp +diff --git a/src/contrib/config/systemcontainer_config.json b/src/contrib/config/systemcontainer_config.json +index b9e6e8c..8ebce8c 100644 +--- a/src/contrib/config/systemcontainer_config.json ++++ b/src/contrib/config/systemcontainer_config.json +@@ -49,7 +49,6 @@ + "path": "rootfs", + "readonly": false + }, +- "hostname": "ubuntu", + "mounts": [ + { + "destination": "/proc", +@@ -311,6 +310,7 @@ + "/proc/pagealloc_statistics", + "/proc/pagealloc_module", + "/proc/pagealloc_bt", ++ "/proc/pin_memory", + "/proc/slaballoc_statistics", + "/proc/slaballoc_module", + "/proc/slaballoc_bt", +diff --git a/src/daemon/common/CMakeLists.txt b/src/daemon/common/CMakeLists.txt +index f84830a..bd1badc 100644 +--- a/src/daemon/common/CMakeLists.txt ++++ b/src/daemon/common/CMakeLists.txt +@@ -1,13 +1,18 @@ + # get current directory sources files +-aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/ daemon_common_top_srcs) ++aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} daemon_common_top_srcs) ++ ++if (NOT ENABLE_SELINUX) ++ list(REMOVE_ITEM daemon_common_top_srcs "${CMAKE_CURRENT_SOURCE_DIR}/selinux_label.c") ++endif() ++ + set(local_daemon_common_srcs ${daemon_common_top_srcs}) +-set(local_daemon_common_incs ${CMAKE_CURRENT_SOURCE_DIR}) + + set(DAEMON_COMMON_SRCS + ${local_daemon_common_srcs} + PARENT_SCOPE + ) ++ + set(DAEMON_COMMON_INCS +- ${local_daemon_common_incs} ++ ${CMAKE_CURRENT_SOURCE_DIR} + PARENT_SCOPE + ) +diff --git a/src/daemon/common/selinux_label.c b/src/daemon/common/selinux_label.c +index b97e07f..33c06a8 100644 +--- a/src/daemon/common/selinux_label.c ++++ b/src/daemon/common/selinux_label.c +@@ -219,7 +219,7 @@ static int read_con(const char *fpath, char **content) + return -1; + } + +- tmp = isula_utils_read_file(fpath); ++ tmp = util_read_content_from_file(fpath); + if (tmp == NULL) { + ERROR("Failed to read file: %s", fpath); + ret = -1; +diff --git a/src/daemon/common/sysinfo.c b/src/daemon/common/sysinfo.c +index f147aee..87ea47f 100644 +--- a/src/daemon/common/sysinfo.c ++++ b/src/daemon/common/sysinfo.c +@@ -12,15 +12,16 @@ + * Create: 2017-11-22 + * Description: provide system information functions + ******************************************************************************/ ++#include "sysinfo.h" + #include + #include + #include + #include + #include + #include ++#include + + #include "err_msg.h" +-#include "sysinfo.h" + #include "isula_libutils/log.h" + #include "utils.h" + #include "utils_array.h" +@@ -106,7 +107,7 @@ static int add_null_to_list(void ***list) + } + newsize = (index + 2) * sizeof(void **); + oldsize = index * sizeof(void **); +- ret = mem_realloc((void **)&newlist, newsize, (*list), oldsize); ++ ret = util_mem_realloc((void **)&newlist, newsize, (*list), oldsize); + if (ret < 0) { + ERROR("Out of memory"); + return -1; +@@ -798,7 +799,7 @@ static void check_cgroup_cpuset_info(struct layer **layers, bool quiet, cgroup_c + goto error; + } + +- cpusetinfo->cpus = isula_utils_read_file(cpuset_cpus_path); ++ cpusetinfo->cpus = util_read_content_from_file(cpuset_cpus_path); + if (cpusetinfo->cpus == NULL) { + ERROR("Failed to read the file: %s", cpuset_cpus_path); + goto error; +@@ -810,7 +811,7 @@ static void check_cgroup_cpuset_info(struct layer **layers, bool quiet, cgroup_c + goto error; + } + +- cpusetinfo->mems = isula_utils_read_file(cpuset_mems_path); ++ cpusetinfo->mems = util_read_content_from_file(cpuset_mems_path); + if (cpusetinfo->mems == NULL) { + ERROR("Failed to read the file: %s", cpuset_mems_path); + goto error; +@@ -1170,6 +1171,8 @@ sysinfo_t *get_sys_info(bool quiet) + goto out; + } + ++ sysinfo->ncpus = get_nprocs(); ++ + check_cgroup_mem(layers, quiet, &sysinfo->cgmeminfo); + check_cgroup_cpu(layers, quiet, &sysinfo->cgcpuinfo); + check_cgroup_hugetlb(layers, quiet, &sysinfo->hugetlbinfo); +diff --git a/src/daemon/common/sysinfo.h b/src/daemon/common/sysinfo.h +index 7089c4e..8468e00 100644 +--- a/src/daemon/common/sysinfo.h ++++ b/src/daemon/common/sysinfo.h +@@ -71,6 +71,7 @@ typedef struct { + } cgroup_files_info_t; + + typedef struct { ++ int ncpus; + cgroup_mem_info_t cgmeminfo; + cgroup_cpu_info_t cgcpuinfo; + cgroup_hugetlb_info_t hugetlbinfo; +@@ -143,4 +144,3 @@ void free_mounts_info(mountinfo_t **minfos); + #endif + + #endif // DAEMON_COMMON_SYSINFO_H +- +diff --git a/src/daemon/config/daemon_arguments.c b/src/daemon/config/daemon_arguments.c +index 63e525b..ef28764 100644 +--- a/src/daemon/config/daemon_arguments.c ++++ b/src/daemon/config/daemon_arguments.c +@@ -109,7 +109,7 @@ int service_arguments_init(struct service_arguments *args) + goto free_out; + } + args->json_confs->engine = util_strdup_s("lcr"); +- args->json_confs->group = util_strdup_s("isulad"); ++ args->json_confs->group = util_strdup_s("isula"); + args->json_confs->graph = util_strdup_s(ISULAD_ROOT_PATH); + args->json_confs->state = util_strdup_s(ISULAD_STATE_PATH); + args->json_confs->log_level = util_strdup_s("INFO"); +@@ -279,7 +279,7 @@ int ulimit_array_append(host_config_ulimits_element ***ulimit_array, const host_ + new_size = (len + 2) * sizeof(host_config_ulimits_element *); + old_size = len * sizeof(host_config_ulimits_element *); + +- ret = mem_realloc((void **)(&new_ulimit_array), new_size, (void *)*ulimit_array, old_size); ++ ret = util_mem_realloc((void **)(&new_ulimit_array), new_size, (void *)*ulimit_array, old_size); + if (ret != 0) { + ERROR("Failed to realloc memory for append ulimit"); + return -1; +diff --git a/src/daemon/config/isulad_config.c b/src/daemon/config/isulad_config.c +index dac0332..f6e5ffd 100644 +--- a/src/daemon/config/isulad_config.c ++++ b/src/daemon/config/isulad_config.c +@@ -12,8 +12,8 @@ + * Create: 2018-11-08 + * Description: provide container configure definition + ******************************************************************************/ ++#include "isulad_config.h" + #include +-#include + #include + #include + #include +@@ -31,7 +31,6 @@ + #include "constants.h" + #include "isula_libutils/log.h" + #include "utils.h" +-#include "isulad_config.h" + #include "sysinfo.h" + #include "err_msg.h" + #include "daemon_arguments.h" +@@ -223,6 +222,30 @@ free_out: + return epath; + } + ++int conf_get_cgroup_cpu_rt(int64_t *cpu_rt_period, int64_t *cpu_rt_runtime) ++{ ++ struct service_arguments *conf = NULL; ++ ++ if (isulad_server_conf_rdlock() != 0) { ++ return -1; ++ } ++ ++ conf = conf_get_server_conf(); ++ if (conf == NULL) { ++ (void)isulad_server_conf_unlock(); ++ return -1; ++ } ++ ++ *cpu_rt_period = conf->json_confs->cpu_rt_period; ++ *cpu_rt_runtime = conf->json_confs->cpu_rt_runtime; ++ ++ if (isulad_server_conf_unlock() != 0) { ++ return -1; ++ } ++ ++ return 0; ++} ++ + /* conf get graph checked flag file path */ + char *conf_get_graph_check_flag_file() + { +@@ -857,16 +880,16 @@ out: + return check_flag; + } + +-#define OCI_STR_ARRAY_DUP(src, dest, srclen, destlen, ret) \ +- do { \ +- if ((src) != NULL) { \ +- (dest) = str_array_dup((const char **)(src), (srclen)); \ +- if ((dest) == NULL) { \ +- (ret) = -1; \ +- goto out; \ +- } \ +- (destlen) = (srclen); \ +- } \ ++#define OCI_STR_ARRAY_DUP(src, dest, srclen, destlen, ret) \ ++ do { \ ++ if ((src) != NULL) { \ ++ (dest) = util_str_array_dup((const char **)(src), (srclen)); \ ++ if ((dest) == NULL) { \ ++ (ret) = -1; \ ++ goto out; \ ++ } \ ++ (destlen) = (srclen); \ ++ } \ + } while (0) + + #define HOOKS_ELEM_DUP_DEF(item) \ +@@ -1049,7 +1072,7 @@ char *conf_get_default_runtime() + goto out; + } + +- result = strings_to_lower(conf->json_confs->default_runtime); ++ result = util_strings_to_lower(conf->json_confs->default_runtime); + + out: + (void)isulad_server_conf_unlock(); +@@ -1133,34 +1156,6 @@ out: + return ret; + } + +-/* set path group */ +-static int set_path_group(const char *rpath, const char *group) +-{ +- struct group *grp = NULL; +- gid_t gid; +- +- grp = getgrnam(group); +- +- if (grp != NULL) { +- gid = grp->gr_gid; +- DEBUG("Group %s found, gid: %d", group, gid); +- if (chown(rpath, -1, gid) != 0) { +- DEBUG("Failed to chown %s to gid: %d", rpath, gid); +- return -1; +- } +- } else { +- if (strcmp(group, "docker") == 0 || strcmp(group, "isulad") == 0) { +- DEBUG("Warning: could not change group %s to %s", rpath, group); +- } else { +- ERROR("Group %s not found", group); +- isulad_set_error_message("Group %s not found", group); +- return -1; +- } +- } +- +- return 0; +-} +- + /* set socket group */ + int set_unix_socket_group(const char *socket, const char *group) + { +@@ -1181,7 +1176,7 @@ int set_unix_socket_group(const char *socket, const char *group) + goto out; + } + INFO("set socket: %s with group: %s", socket, group); +- nret = set_path_group(rpath, group); ++ nret = util_set_file_group(rpath, group); + if (nret < 0) { + ERROR("set group of the path: %s failed", rpath); + ret = -1; +@@ -1202,172 +1197,6 @@ out: + return ret; + } + +-/* maybe create cpu realtime file */ +-static int maybe_create_cpu_realtime_file(bool present, int64_t value, const char *file, const char *path) +-{ +- int ret; +- int fd = 0; +- ssize_t nwrite; +- char fpath[PATH_MAX] = { 0 }; +- char buf[ISULAD_NUMSTRLEN64] = { 0 }; +- +- if (!present || value == 0) { +- return 0; +- } +- +- ret = util_mkdir_p(path, CONFIG_DIRECTORY_MODE); +- if (ret != 0) { +- ERROR("Failed to mkdir: %s", path); +- return -1; +- } +- +- int nret = snprintf(fpath, sizeof(fpath), "%s/%s", path, file); +- if (nret < 0 || nret >= sizeof(fpath)) { +- ERROR("Failed to print string"); +- return -1; +- } +- nret = snprintf(buf, sizeof(buf), "%lld", (long long int)value); +- if (nret < 0 || (size_t)nret >= sizeof(buf)) { +- ERROR("Failed to print string"); +- return -1; +- } +- +- fd = util_open(fpath, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0700); +- if (fd < 0) { +- ERROR("Failed to open file: %s: %s", fpath, strerror(errno)); +- isulad_set_error_message("Failed to open file: %s: %s", fpath, strerror(errno)); +- return -1; +- } +- nwrite = util_write_nointr(fd, buf, strlen(buf)); +- if (nwrite < 0) { +- ERROR("Failed to write %s to %s: %s", buf, fpath, strerror(errno)); +- isulad_set_error_message("Failed to write '%s' to '%s': %s", buf, fpath, strerror(errno)); +- close(fd); +- return -1; +- } +- close(fd); +- +- return 0; +-} +- +-static int get_cgroup_cpu_rt(int64_t *cpu_rt_period, int64_t *cpu_rt_runtime) +-{ +- struct service_arguments *conf = NULL; +- +- if (isulad_server_conf_rdlock() != 0) { +- return -1; +- } +- +- conf = conf_get_server_conf(); +- if (conf == NULL) { +- (void)isulad_server_conf_unlock(); +- return -1; +- } +- +- *cpu_rt_period = conf->json_confs->cpu_rt_period; +- *cpu_rt_runtime = conf->json_confs->cpu_rt_runtime; +- +- if (isulad_server_conf_unlock() != 0) { +- return -1; +- } +- +- return 0; +-} +- +-static int recursively_create_cgroup(const char *path, int recursive_depth, int64_t cpu_rt_period, +- int64_t cpu_rt_runtime) +-{ +- int ret = 0; +- sysinfo_t *sysinfo = NULL; +- char *dup = NULL; +- char *dirpath = NULL; +- char *mnt = NULL; +- char *root = NULL; +- char fpath[PATH_MAX] = { 0 }; +- +- dup = util_strdup_s(path); +- dirpath = dirname(dup); +- ret = init_cgroups_path(dirpath, (recursive_depth + 1)); +- free(dup); +- if (ret != 0) { +- return ret; +- } +- +- ret = find_cgroup_mountpoint_and_root("cpu", &mnt, &root); +- if (ret != 0 || mnt == NULL || root == NULL) { +- ERROR("Can not find cgroup mnt and root path for subsystem 'cpu'"); +- isulad_set_error_message("Can not find cgroup mnt and root path for subsystem 'cpu'"); +- ret = -1; +- goto out; +- } +- +- // When iSulad is run inside iSulad/docker, the root is based of the host cgroup. +- // Replace root to "/" +- if (strncmp(root, "/lxc/", strlen("/lxc/")) != 0) { +- root[1] = '\0'; +- } +- +- int nret = snprintf(fpath, sizeof(fpath), "%s/%s/%s", mnt, root, path); +- if (nret < 0 || (size_t)nret >= sizeof(fpath)) { +- ERROR("Failed to print string"); +- ret = -1; +- goto out; +- } +- +- sysinfo = get_sys_info(true); +- if (sysinfo == NULL) { +- ERROR("Can not get system info"); +- ret = -1; +- goto out; +- } +- +- ret = maybe_create_cpu_realtime_file(sysinfo->cgcpuinfo.cpu_rt_period, cpu_rt_period, "cpu.rt_period_us", fpath); +- if (ret != 0) { +- goto out; +- } +- ret = maybe_create_cpu_realtime_file(sysinfo->cgcpuinfo.cpu_rt_runtime, cpu_rt_runtime, "cpu.rt_runtime_us", fpath); +- if (ret != 0) { +- goto out; +- } +-out: +- free(mnt); +- free(root); +- free_sysinfo(sysinfo); +- return ret; +-} +- +-/* init cgroups path */ +-int init_cgroups_path(const char *path, int recursive_depth) +-{ +- int64_t cpu_rt_period = 0; +- int64_t cpu_rt_runtime = 0; +- +- if ((recursive_depth + 1) > MAX_PATH_DEPTH) { +- ERROR("Reach the max cgroup depth:%s", path); +- return -1; +- } +- +- if (path == NULL || strcmp(path, "/") == 0 || strcmp(path, ".") == 0) { +- return 0; +- } +- +- if (get_cgroup_cpu_rt(&cpu_rt_period, &cpu_rt_runtime)) { +- return -1; +- } +- +- if (cpu_rt_period == 0 && cpu_rt_runtime == 0) { +- return 0; +- } +- +- // Recursively create cgroup to ensure that the system and all parent cgroups have values set +- // for the period and runtime as this limits what the children can be set to. +- if (recursively_create_cgroup(path, recursive_depth, cpu_rt_period, cpu_rt_runtime)) { +- return -1; +- } +- +- return 0; +-} +- + #define OVERRIDE_STRING_VALUE(dst, src) \ + do { \ + if ((src) != NULL && strlen((src)) != 0) { \ +@@ -1658,7 +1487,9 @@ int merge_json_confs_into_global(struct service_arguments *args) + goto out; + } + ++#ifdef ENABLE_SELINUX + args->json_confs->selinux_enabled = tmp_json_confs->selinux_enabled; ++#endif + + out: + free(err); +diff --git a/src/daemon/config/isulad_config.h b/src/daemon/config/isulad_config.h +index c4dd8c1..b5c64c5 100644 +--- a/src/daemon/config/isulad_config.h ++++ b/src/daemon/config/isulad_config.h +@@ -49,6 +49,8 @@ char *conf_get_isulad_logdriver(); + int conf_get_daemon_log_config(char **loglevel, char **logdriver, char **engine_log_path); + char *conf_get_isulad_log_gather_fifo_path(); + ++int conf_get_cgroup_cpu_rt(int64_t *cpu_rt_period, int64_t *cpu_rt_runtime); ++ + char *conf_get_isulad_log_file(); + char *conf_get_engine_log_file(); + char *conf_get_enable_plugins(); +@@ -74,8 +76,6 @@ int conf_get_isulad_default_ulimit(host_config_ulimits_element ***ulimit); + + unsigned int conf_get_start_timeout(); + +-int init_cgroups_path(const char *path, int recursive_depth); +- + char **conf_get_insecure_registry_list(); + + char **conf_get_registry_list(); +diff --git a/src/daemon/entry/connect/CMakeLists.txt b/src/daemon/entry/connect/CMakeLists.txt +index 0220319..d960f6e 100644 +--- a/src/daemon/entry/connect/CMakeLists.txt ++++ b/src/daemon/entry/connect/CMakeLists.txt +@@ -15,17 +15,17 @@ endif() + + if (GRPC_CONNECTOR) + # GRPC +- aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/types CONNECT_API_TYPES) + aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/containers CONNECT_API_CONTAINERS) + aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/images CONNECT_API_IMAGES) ++ aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/volumes CONNECT_API_VOLUMES) + aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/cri CONNECT_API_CRI) +- set(CONNECT_API ${CONNECT_API_TYPES} ${CONNECT_API_CONTAINERS} ${CONNECT_API_IMAGES} ${CONNECT_API_CRI}) ++ set(CONNECT_API ${CONNECT_API_CONTAINERS} ${CONNECT_API_IMAGES} ${CONNECT_API_VOLUMES} ${CONNECT_API_CRI}) + list(APPEND local_server_connect_srcs ${CONNECT_API}) + + list(APPEND local_server_connect_incs +- ${CMAKE_BINARY_DIR}/grpc/src/api/types + ${CMAKE_BINARY_DIR}/grpc/src/api/services/containers + ${CMAKE_BINARY_DIR}/grpc/src/api/services/images ++ ${CMAKE_BINARY_DIR}/grpc/src/api/services/volumes + ${CMAKE_BINARY_DIR}/grpc/src/api/services/cri + ) + endif() +diff --git a/src/daemon/entry/connect/grpc/grpc_containers_service.cc b/src/daemon/entry/connect/grpc/grpc_containers_service.cc +index 54417c6..123fee8 100644 +--- a/src/daemon/entry/connect/grpc/grpc_containers_service.cc ++++ b/src/daemon/entry/connect/grpc/grpc_containers_service.cc +@@ -149,7 +149,7 @@ bool grpc_copy_to_container_read_function(void *reader, void *data) + + Status ContainerServiceImpl::Version(ServerContext *context, const VersionRequest *request, VersionResponse *reply) + { +- int ret, tret; ++ int tret; + service_executor_t *cb = nullptr; + container_version_request *container_req = nullptr; + container_version_response *container_res = nullptr; +@@ -170,22 +170,18 @@ Status ContainerServiceImpl::Version(ServerContext *context, const VersionReques + return Status::OK; + } + +- ret = cb->container.version(container_req, &container_res); +- tret = version_response_to_grpc(container_res, reply); ++ (void)cb->container.version(container_req, &container_res); ++ version_response_to_grpc(container_res, reply); + + free_container_version_request(container_req); + free_container_version_response(container_res); +- if (tret != 0) { +- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); +- reply->set_cc(ISULAD_ERR_INTERNAL); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + + Status ContainerServiceImpl::Info(ServerContext *context, const InfoRequest *request, InfoResponse *reply) + { +- int ret, tret; ++ int tret; + service_executor_t *cb = nullptr; + host_info_request *container_req = nullptr; + host_info_response *container_res = nullptr; +@@ -206,22 +202,18 @@ Status ContainerServiceImpl::Info(ServerContext *context, const InfoRequest *req + return Status::OK; + } + +- ret = cb->container.info(container_req, &container_res); +- tret = info_response_to_grpc(container_res, reply); ++ (void)cb->container.info(container_req, &container_res); ++ info_response_to_grpc(container_res, reply); + + free_host_info_request(container_req); + free_host_info_response(container_res); +- if (tret != 0) { +- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); +- reply->set_cc(ISULAD_ERR_INTERNAL); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + + Status ContainerServiceImpl::Create(ServerContext *context, const CreateRequest *request, CreateResponse *reply) + { +- int ret, tret; ++ int tret; + service_executor_t *cb = nullptr; + container_create_response *container_res = nullptr; + container_create_request *container_req = nullptr; +@@ -242,22 +234,18 @@ Status ContainerServiceImpl::Create(ServerContext *context, const CreateRequest + return Status::OK; + } + +- ret = cb->container.create(container_req, &container_res); +- tret = create_response_to_grpc(container_res, reply); ++ (void)cb->container.create(container_req, &container_res); ++ create_response_to_grpc(container_res, reply); + + free_container_create_request(container_req); + free_container_create_response(container_res); +- if (tret != 0) { +- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); +- reply->set_cc(ISULAD_ERR_INTERNAL); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + + Status ContainerServiceImpl::Start(ServerContext *context, const StartRequest *request, StartResponse *reply) + { +- int ret, tret; ++ int tret; + service_executor_t *cb = nullptr; + container_start_request *req = nullptr; + container_start_response *res = nullptr; +@@ -278,16 +266,12 @@ Status ContainerServiceImpl::Start(ServerContext *context, const StartRequest *r + return Status::CANCELLED; + } + +- ret = cb->container.start(req, &res, -1, nullptr, nullptr); +- tret = response_to_grpc(res, reply); ++ (void)cb->container.start(req, &res, -1, nullptr, nullptr); ++ response_to_grpc(res, reply); + + free_container_start_request(req); + free_container_start_response(res); +- if (tret != 0) { +- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); +- reply->set_cc(ISULAD_ERR_INTERNAL); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + +@@ -356,7 +340,6 @@ Status ContainerServiceImpl::RemoteStart(ServerContext *context, + + if (sem_init(&sem, 0, 0) != 0) { + return grpc::Status(grpc::StatusCode::UNKNOWN, "Semaphore initialization failed"); +- ; + } + + int read_pipe_fd[2]; +@@ -415,7 +398,7 @@ Status ContainerServiceImpl::RemoteStart(ServerContext *context, + + Status ContainerServiceImpl::Top(ServerContext *context, const TopRequest *request, TopResponse *reply) + { +- int ret, tret; ++ int tret; + service_executor_t *cb = nullptr; + container_top_request *req = nullptr; + container_top_response *res = nullptr; +@@ -436,22 +419,18 @@ Status ContainerServiceImpl::Top(ServerContext *context, const TopRequest *reque + return Status::CANCELLED; + } + +- ret = cb->container.top(req, &res); +- tret = top_response_to_grpc(res, reply); ++ (void)cb->container.top(req, &res); ++ top_response_to_grpc(res, reply); + + free_container_top_request(req); + free_container_top_response(res); +- if (tret != 0) { +- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); +- reply->set_cc(ISULAD_ERR_INTERNAL); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + + Status ContainerServiceImpl::Stop(ServerContext *context, const StopRequest *request, StopResponse *reply) + { +- int ret, tret; ++ int tret; + service_executor_t *cb = nullptr; + container_stop_request *container_req = nullptr; + container_stop_response *container_res = nullptr; +@@ -472,22 +451,18 @@ Status ContainerServiceImpl::Stop(ServerContext *context, const StopRequest *req + return Status::OK; + } + +- ret = cb->container.stop(container_req, &container_res); +- tret = response_to_grpc(container_res, reply); ++ (void)cb->container.stop(container_req, &container_res); ++ response_to_grpc(container_res, reply); + + free_container_stop_request(container_req); + free_container_stop_response(container_res); +- if (tret != 0) { +- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); +- reply->set_cc(ISULAD_ERR_INTERNAL); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + + Status ContainerServiceImpl::Restart(ServerContext *context, const RestartRequest *request, RestartResponse *reply) + { +- int ret, tret; ++ int tret; + service_executor_t *cb = nullptr; + container_restart_request *container_req = nullptr; + container_restart_response *container_res = nullptr; +@@ -508,22 +483,18 @@ Status ContainerServiceImpl::Restart(ServerContext *context, const RestartReques + return Status::OK; + } + +- ret = cb->container.restart(container_req, &container_res); +- tret = response_to_grpc(container_res, reply); ++ (void)cb->container.restart(container_req, &container_res); ++ response_to_grpc(container_res, reply); + + free_container_restart_request(container_req); + free_container_restart_response(container_res); +- if (tret != 0) { +- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); +- reply->set_cc(ISULAD_ERR_INTERNAL); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + + Status ContainerServiceImpl::Kill(ServerContext *context, const KillRequest *request, KillResponse *reply) + { +- int ret, tret; ++ int tret; + service_executor_t *cb = nullptr; + container_kill_request *container_req = nullptr; + container_kill_response *container_res = nullptr; +@@ -544,22 +515,18 @@ Status ContainerServiceImpl::Kill(ServerContext *context, const KillRequest *req + return Status::OK; + } + +- ret = cb->container.kill(container_req, &container_res); +- tret = response_to_grpc(container_res, reply); ++ (void)cb->container.kill(container_req, &container_res); ++ response_to_grpc(container_res, reply); + + free_container_kill_request(container_req); + free_container_kill_response(container_res); +- if (tret != 0) { +- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); +- reply->set_cc(ISULAD_ERR_INTERNAL); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + + Status ContainerServiceImpl::Delete(ServerContext *context, const DeleteRequest *request, DeleteResponse *reply) + { +- int ret, tret; ++ int tret; + service_executor_t *cb = nullptr; + container_delete_request *container_req = nullptr; + container_delete_response *container_res = nullptr; +@@ -580,22 +547,18 @@ Status ContainerServiceImpl::Delete(ServerContext *context, const DeleteRequest + return Status::OK; + } + +- ret = cb->container.remove(container_req, &container_res); +- tret = delete_response_to_grpc(container_res, reply); ++ (void)cb->container.remove(container_req, &container_res); ++ delete_response_to_grpc(container_res, reply); + + free_container_delete_request(container_req); + free_container_delete_response(container_res); +- if (tret != 0) { +- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); +- reply->set_cc(ISULAD_ERR_INTERNAL); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + + Status ContainerServiceImpl::Exec(ServerContext *context, const ExecRequest *request, ExecResponse *reply) + { +- int ret, tret; ++ int tret; + service_executor_t *cb = nullptr; + container_exec_request *container_req = nullptr; + container_exec_response *container_res = nullptr; +@@ -616,16 +579,12 @@ Status ContainerServiceImpl::Exec(ServerContext *context, const ExecRequest *req + return Status::CANCELLED; + } + +- ret = cb->container.exec(container_req, &container_res, -1, nullptr, nullptr); +- tret = exec_response_to_grpc(container_res, reply); ++ (void)cb->container.exec(container_req, &container_res, -1, nullptr, nullptr); ++ exec_response_to_grpc(container_res, reply); + + free_container_exec_request(container_req); + free_container_exec_response(container_res); +- if (tret != 0) { +- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); +- reply->set_cc(ISULAD_ERR_INTERNAL); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + +@@ -776,11 +735,16 @@ Status ContainerServiceImpl::RemoteExec(ServerContext *context, + Status ContainerServiceImpl::Inspect(ServerContext *context, const InspectContainerRequest *request, + InspectContainerResponse *reply) + { +- int ret, tret; ++ int tret; + service_executor_t *cb = nullptr; + container_inspect_request *container_req = nullptr; + container_inspect_response *container_res = nullptr; + ++ Status status = GrpcServerTlsAuth::auth(context, "container_inspect"); ++ if (!status.ok()) { ++ return status; ++ } ++ + cb = get_service_executor(); + if (cb == nullptr || cb->container.inspect == nullptr) { + return Status(StatusCode::UNIMPLEMENTED, "Unimplemented callback"); +@@ -793,27 +757,18 @@ Status ContainerServiceImpl::Inspect(ServerContext *context, const InspectContai + return Status::OK; + } + +- Status status = GrpcServerTlsAuth::auth(context, "container_inspect"); +- if (!status.ok()) { +- return status; +- } +- +- ret = cb->container.inspect(container_req, &container_res); +- tret = inspect_response_to_grpc(container_res, reply); ++ (void)cb->container.inspect(container_req, &container_res); ++ inspect_response_to_grpc(container_res, reply); + + free_container_inspect_request(container_req); + free_container_inspect_response(container_res); +- if (tret != 0) { +- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); +- reply->set_cc(ISULAD_ERR_INTERNAL); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + + Status ContainerServiceImpl::List(ServerContext *context, const ListRequest *request, ListResponse *reply) + { +- int ret, tret; ++ int tret; + service_executor_t *cb = nullptr; + container_list_request *container_req = nullptr; + container_list_response *container_res = nullptr; +@@ -834,16 +789,12 @@ Status ContainerServiceImpl::List(ServerContext *context, const ListRequest *req + return Status::OK; + } + +- ret = cb->container.list(container_req, &container_res); +- tret = list_response_to_grpc(container_res, reply); ++ (void)cb->container.list(container_req, &container_res); ++ list_response_to_grpc(container_res, reply); + + free_container_list_request(container_req); + free_container_list_response(container_res); +- if (tret != 0) { +- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); +- reply->set_cc(ISULAD_ERR_INTERNAL); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + +@@ -915,7 +866,6 @@ Status ContainerServiceImpl::AttachInit(ServerContext *context, service_executor + if (sem_init(sem_stderr, 0, 0) != 0) { + free_container_attach_request(*req); + return grpc::Status(grpc::StatusCode::UNKNOWN, "Semaphore initialization failed"); +- ; + } + + if ((pipe2(pipefd, O_NONBLOCK | O_CLOEXEC)) < 0) { +@@ -990,7 +940,7 @@ Status ContainerServiceImpl::Attach(ServerContext *context, ServerReaderWritercontainer.pause(container_req, &container_res); +- tret = response_to_grpc(container_res, reply); ++ (void)cb->container.pause(container_req, &container_res); ++ response_to_grpc(container_res, reply); + + free_container_pause_request(container_req); + free_container_pause_response(container_res); +- if (tret != 0) { +- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); +- reply->set_cc(ISULAD_ERR_INTERNAL); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + + Status ContainerServiceImpl::Resume(ServerContext *context, const ResumeRequest *request, ResumeResponse *reply) + { +- int ret, tret; ++ int tret; + service_executor_t *cb = nullptr; + container_resume_request *container_req = nullptr; + container_resume_response *container_res = nullptr; +@@ -1047,22 +993,18 @@ Status ContainerServiceImpl::Resume(ServerContext *context, const ResumeRequest + return Status::OK; + } + +- ret = cb->container.resume(container_req, &container_res); +- tret = response_to_grpc(container_res, reply); ++ (void)cb->container.resume(container_req, &container_res); ++ response_to_grpc(container_res, reply); + + free_container_resume_request(container_req); + free_container_resume_response(container_res); +- if (tret != 0) { +- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); +- reply->set_cc(ISULAD_ERR_INTERNAL); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + + Status ContainerServiceImpl::Export(ServerContext *context, const ExportRequest *request, ExportResponse *reply) + { +- int ret, tret; ++ int tret; + service_executor_t *cb = nullptr; + container_export_request *container_req = nullptr; + container_export_response *container_res = nullptr; +@@ -1083,22 +1025,18 @@ Status ContainerServiceImpl::Export(ServerContext *context, const ExportRequest + return Status::OK; + } + +- ret = cb->container.export_rootfs(container_req, &container_res); +- tret = response_to_grpc(container_res, reply); ++ (void)cb->container.export_rootfs(container_req, &container_res); ++ response_to_grpc(container_res, reply); + + free_container_export_request(container_req); + free_container_export_response(container_res); +- if (tret != 0) { +- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); +- reply->set_cc(ISULAD_ERR_INTERNAL); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + + Status ContainerServiceImpl::Rename(ServerContext *context, const RenameRequest *request, RenameResponse *reply) + { +- int ret, tret; ++ int tret; + service_executor_t *cb = nullptr; + struct isulad_container_rename_request *isuladreq = nullptr; + struct isulad_container_rename_response *isuladres = nullptr; +@@ -1120,22 +1058,18 @@ Status ContainerServiceImpl::Rename(ServerContext *context, const RenameRequest + return Status::OK; + } + +- ret = cb->container.rename(isuladreq, &isuladres); +- tret = container_rename_response_to_grpc(isuladres, reply); ++ (void)cb->container.rename(isuladreq, &isuladres); ++ container_rename_response_to_grpc(isuladres, reply); + + isulad_container_rename_request_free(isuladreq); + isulad_container_rename_response_free(isuladres); +- if (tret != 0) { +- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); +- reply->set_cc(ISULAD_ERR_INTERNAL); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + + Status ContainerServiceImpl::Resize(ServerContext *context, const ResizeRequest *request, ResizeResponse *reply) + { +- int ret, tret; ++ int tret; + service_executor_t *cb = nullptr; + struct isulad_container_resize_request *isuladreq = nullptr; + struct isulad_container_resize_response *isuladres = nullptr; +@@ -1157,22 +1091,18 @@ Status ContainerServiceImpl::Resize(ServerContext *context, const ResizeRequest + return Status::OK; + } + +- ret = cb->container.resize(isuladreq, &isuladres); +- tret = container_resize_response_to_grpc(isuladres, reply); ++ (void)cb->container.resize(isuladreq, &isuladres); ++ container_resize_response_to_grpc(isuladres, reply); + + isulad_container_resize_request_free(isuladreq); + isulad_container_resize_response_free(isuladres); +- if (tret != 0) { +- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); +- reply->set_cc(ISULAD_ERR_INTERNAL); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + + Status ContainerServiceImpl::Update(ServerContext *context, const UpdateRequest *request, UpdateResponse *reply) + { +- int ret, tret; ++ int tret; + service_executor_t *cb = nullptr; + container_update_request *container_req = nullptr; + container_update_response *container_res = nullptr; +@@ -1193,22 +1123,18 @@ Status ContainerServiceImpl::Update(ServerContext *context, const UpdateRequest + return Status::OK; + } + +- ret = cb->container.update(container_req, &container_res); +- tret = update_response_to_grpc(container_res, reply); ++ (void)cb->container.update(container_req, &container_res); ++ update_response_to_grpc(container_res, reply); + + free_container_update_request(container_req); + free_container_update_response(container_res); +- if (tret != 0) { +- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); +- reply->set_cc(ISULAD_ERR_INTERNAL); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + + Status ContainerServiceImpl::Stats(ServerContext *context, const StatsRequest *request, StatsResponse *reply) + { +- int ret, tret; ++ int tret; + service_executor_t *cb = nullptr; + container_stats_request *container_req = nullptr; + container_stats_response *container_res = nullptr; +@@ -1229,22 +1155,18 @@ Status ContainerServiceImpl::Stats(ServerContext *context, const StatsRequest *r + return Status::OK; + } + +- ret = cb->container.stats(container_req, &container_res); +- tret = stats_response_to_grpc(container_res, reply); ++ (void)cb->container.stats(container_req, &container_res); ++ stats_response_to_grpc(container_res, reply); + + free_container_stats_request(container_req); + free_container_stats_response(container_res); +- if (tret != 0) { +- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); +- reply->set_cc(ISULAD_ERR_INTERNAL); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + + Status ContainerServiceImpl::Wait(ServerContext *context, const WaitRequest *request, WaitResponse *reply) + { +- int ret, tret; ++ int tret; + service_executor_t *cb = nullptr; + container_wait_request *container_req = nullptr; + container_wait_response *container_res = nullptr; +@@ -1265,22 +1187,18 @@ Status ContainerServiceImpl::Wait(ServerContext *context, const WaitRequest *req + return Status::OK; + } + +- ret = cb->container.wait(container_req, &container_res); +- tret = wait_response_to_grpc(container_res, reply); ++ (void)cb->container.wait(container_req, &container_res); ++ wait_response_to_grpc(container_res, reply); + + free_container_wait_request(container_req); + free_container_wait_response(container_res); +- if (tret != 0) { +- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); +- reply->set_cc(ISULAD_ERR_INTERNAL); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + + Status ContainerServiceImpl::Events(ServerContext *context, const EventsRequest *request, ServerWriter *writer) + { +- int ret, tret; ++ int tret; + service_executor_t *cb = nullptr; + isulad_events_request *isuladreq = nullptr; + stream_func_wrapper stream = { 0 }; +@@ -1305,9 +1223,9 @@ Status ContainerServiceImpl::Events(ServerContext *context, const EventsRequest + stream.write_func = &grpc_event_write_function; + stream.writer = (void *)writer; + +- ret = cb->container.events(isuladreq, &stream); ++ tret = cb->container.events(isuladreq, &stream); + isulad_events_request_free(isuladreq); +- if (ret != 0) { ++ if (tret != 0) { + return Status(StatusCode::INTERNAL, "Failed to execute events callback"); + } + +@@ -1317,7 +1235,7 @@ Status ContainerServiceImpl::Events(ServerContext *context, const EventsRequest + Status ContainerServiceImpl::CopyFromContainer(ServerContext *context, const CopyFromContainerRequest *request, + ServerWriter *writer) + { +- int ret, tret; ++ int tret; + service_executor_t *cb = nullptr; + isulad_copy_from_container_request *isuladreq = nullptr; + +@@ -1344,11 +1262,11 @@ Status ContainerServiceImpl::CopyFromContainer(ServerContext *context, const Cop + stream.writer = (void *)writer; + + char *err = nullptr; +- ret = cb->container.copy_from_container(isuladreq, &stream, &err); ++ tret = cb->container.copy_from_container(isuladreq, &stream, &err); + isulad_copy_from_container_request_free(isuladreq); + std::string errmsg = (err != nullptr) ? err : "Failed to execute copy_from_container callback"; + free(err); +- if (ret != 0) { ++ if (tret != 0) { + return Status(StatusCode::UNKNOWN, errmsg); + } + return Status::OK; +diff --git a/src/daemon/entry/connect/grpc/grpc_containers_service.h b/src/daemon/entry/connect/grpc/grpc_containers_service.h +index 30de091..4865c41 100644 +--- a/src/daemon/entry/connect/grpc/grpc_containers_service.h ++++ b/src/daemon/entry/connect/grpc/grpc_containers_service.h +@@ -106,36 +106,36 @@ public: + + private: + template +- int response_to_grpc(const T1 *response, T2 *gresponse) ++ void response_to_grpc(const T1 *response, T2 *gresponse) + { + if (response == nullptr) { + gresponse->set_cc(ISULAD_ERR_MEMOUT); +- return 0; ++ return; + } + gresponse->set_cc(response->cc); + if (response->errmsg != nullptr) { + gresponse->set_errmsg(response->errmsg); + } +- return 0; ++ return; + } + + int version_request_from_grpc(const VersionRequest *grequest, container_version_request **request); + +- int version_response_to_grpc(const container_version_response *response, VersionResponse *gresponse); ++ void version_response_to_grpc(const container_version_response *response, VersionResponse *gresponse); + + int info_request_from_grpc(const InfoRequest *grequest, host_info_request **request); + +- int info_response_to_grpc(const host_info_response *response, InfoResponse *gresponse); ++ void info_response_to_grpc(const host_info_response *response, InfoResponse *gresponse); + + int create_request_from_grpc(const CreateRequest *grequest, container_create_request **request); + +- int create_response_to_grpc(const container_create_response *response, CreateResponse *gresponse); ++ void create_response_to_grpc(const container_create_response *response, CreateResponse *gresponse); + + int start_request_from_grpc(const StartRequest *grequest, container_start_request **request); + + int top_request_from_grpc(const TopRequest *grequest, container_top_request **request); + +- int top_response_to_grpc(const container_top_response *response, TopResponse *gresponse); ++ void top_response_to_grpc(const container_top_response *response, TopResponse *gresponse); + + int stop_request_from_grpc(const StopRequest *grequest, container_stop_request **request); + +@@ -145,19 +145,19 @@ private: + + int delete_request_from_grpc(const DeleteRequest *grequest, container_delete_request **request); + +- int delete_response_to_grpc(const container_delete_response *response, DeleteResponse *gresponse); ++ void delete_response_to_grpc(const container_delete_response *response, DeleteResponse *gresponse); + + int exec_request_from_grpc(const ExecRequest *grequest, container_exec_request **request); + +- int exec_response_to_grpc(const container_exec_response *response, ExecResponse *gresponse); ++ void exec_response_to_grpc(const container_exec_response *response, ExecResponse *gresponse); + + int inspect_request_from_grpc(const InspectContainerRequest *grequest, container_inspect_request **request); + +- int inspect_response_to_grpc(const container_inspect_response *response, InspectContainerResponse *gresponse); ++ void inspect_response_to_grpc(const container_inspect_response *response, InspectContainerResponse *gresponse); + + int list_request_from_grpc(const ListRequest *grequest, container_list_request **request); + +- int list_response_to_grpc(const container_list_response *response, ListResponse *gresponse); ++ void list_response_to_grpc(const container_list_response *response, ListResponse *gresponse); + + int pause_request_from_grpc(const PauseRequest *grequest, container_pause_request **request); + +@@ -166,26 +166,26 @@ private: + int container_rename_request_from_grpc(const RenameRequest *grequest, + struct isulad_container_rename_request **request); + +- int container_rename_response_to_grpc(const struct isulad_container_rename_response *response, +- RenameResponse *gresponse); ++ void container_rename_response_to_grpc(const struct isulad_container_rename_response *response, ++ RenameResponse *gresponse); + + int container_resize_request_from_grpc(const ResizeRequest *grequest, + struct isulad_container_resize_request **request); + +- int container_resize_response_to_grpc(const struct isulad_container_resize_response *response, +- ResizeResponse *gresponse); ++ void container_resize_response_to_grpc(const struct isulad_container_resize_response *response, ++ ResizeResponse *gresponse); + + int update_request_from_grpc(const UpdateRequest *grequest, container_update_request **request); + +- int update_response_to_grpc(const container_update_response *response, UpdateResponse *gresponse); ++ void update_response_to_grpc(const container_update_response *response, UpdateResponse *gresponse); + + int stats_request_from_grpc(const StatsRequest *grequest, container_stats_request **request); + +- int stats_response_to_grpc(const container_stats_response *response, StatsResponse *gresponse); ++ void stats_response_to_grpc(const container_stats_response *response, StatsResponse *gresponse); + + int wait_request_from_grpc(const WaitRequest *grequest, container_wait_request **request); + +- int wait_response_to_grpc(const container_wait_response *response, WaitResponse *gresponse); ++ void wait_response_to_grpc(const container_wait_response *response, WaitResponse *gresponse); + + int events_request_from_grpc(const EventsRequest *grequest, struct isulad_events_request **request); + +@@ -211,11 +211,11 @@ private: + + int export_request_from_grpc(const ExportRequest *grequest, container_export_request **request); + +- int pack_os_info_to_grpc(const host_info_response *response, InfoResponse *gresponse); ++ void pack_os_info_to_grpc(const host_info_response *response, InfoResponse *gresponse); + +- int pack_proxy_info_to_grpc(const host_info_response *response, InfoResponse *gresponse); ++ void pack_proxy_info_to_grpc(const host_info_response *response, InfoResponse *gresponse); + +- int pack_driver_info_to_grpc(const host_info_response *response, InfoResponse *gresponse); ++ void pack_driver_info_to_grpc(const host_info_response *response, InfoResponse *gresponse); + + int logs_request_from_grpc(const LogsRequest *grequest, struct isulad_logs_request **request); + }; +diff --git a/src/daemon/entry/connect/grpc/grpc_containers_service_private.cc b/src/daemon/entry/connect/grpc/grpc_containers_service_private.cc +index 4d1f657..c09021c 100644 +--- a/src/daemon/entry/connect/grpc/grpc_containers_service_private.cc ++++ b/src/daemon/entry/connect/grpc/grpc_containers_service_private.cc +@@ -30,12 +30,12 @@ int ContainerServiceImpl::version_request_from_grpc(const VersionRequest *greque + return 0; + } + +-int ContainerServiceImpl::version_response_to_grpc(const container_version_response *response, +- VersionResponse *gresponse) ++void ContainerServiceImpl::version_response_to_grpc(const container_version_response *response, ++ VersionResponse *gresponse) + { + if (response == nullptr) { + gresponse->set_cc(ISULAD_ERR_MEMOUT); +- return 0; ++ return; + } + gresponse->set_cc(response->cc); + if (response->errmsg != nullptr) { +@@ -54,7 +54,7 @@ int ContainerServiceImpl::version_response_to_grpc(const container_version_respo + gresponse->set_root_path(response->root_path); + } + +- return 0; ++ return; + } + + int ContainerServiceImpl::info_request_from_grpc(const InfoRequest *grequest, host_info_request **request) +@@ -68,11 +68,11 @@ int ContainerServiceImpl::info_request_from_grpc(const InfoRequest *grequest, ho + return 0; + } + +-int ContainerServiceImpl::info_response_to_grpc(const host_info_response *response, InfoResponse *gresponse) ++void ContainerServiceImpl::info_response_to_grpc(const host_info_response *response, InfoResponse *gresponse) + { + if (response == nullptr) { + gresponse->set_cc(ISULAD_ERR_MEMOUT); +- return 0; ++ return; + } + + gresponse->set_cc(response->cc); +@@ -92,9 +92,8 @@ int ContainerServiceImpl::info_response_to_grpc(const host_info_response *respon + + gresponse->set_images_num(response->images_num); + +- if (pack_os_info_to_grpc(response, gresponse)) { +- return -1; +- } ++ ++ pack_os_info_to_grpc(response, gresponse); + + if (response->logging_driver != nullptr) { + gresponse->set_logging_driver(response->logging_driver); +@@ -106,15 +105,11 @@ int ContainerServiceImpl::info_response_to_grpc(const host_info_response *respon + + gresponse->set_total_mem(response->total_mem); + +- if (pack_proxy_info_to_grpc(response, gresponse)) { +- return -1; +- } ++ pack_proxy_info_to_grpc(response, gresponse); + +- if (pack_driver_info_to_grpc(response, gresponse)) { +- return -1; +- } ++ pack_driver_info_to_grpc(response, gresponse); + +- return 0; ++ return; + } + + int ContainerServiceImpl::create_request_from_grpc(const CreateRequest *grequest, container_create_request **request) +@@ -151,11 +146,11 @@ int ContainerServiceImpl::create_request_from_grpc(const CreateRequest *grequest + } + + +-int ContainerServiceImpl::create_response_to_grpc(const container_create_response *response, CreateResponse *gresponse) ++void ContainerServiceImpl::create_response_to_grpc(const container_create_response *response, CreateResponse *gresponse) + { + if (response == nullptr) { + gresponse->set_cc(ISULAD_ERR_MEMOUT); +- return 0; ++ return; + } + gresponse->set_cc(response->cc); + if (response->errmsg != nullptr) { +@@ -164,7 +159,7 @@ int ContainerServiceImpl::create_response_to_grpc(const container_create_respons + if (response->id != nullptr) { + gresponse->set_id(response->id); + } +- return 0; ++ return; + } + + int ContainerServiceImpl::start_request_from_grpc(const StartRequest *grequest, container_start_request **request) +@@ -234,11 +229,11 @@ int ContainerServiceImpl::top_request_from_grpc(const TopRequest *grequest, cont + return 0; + } + +-int ContainerServiceImpl::top_response_to_grpc(const container_top_response *response, TopResponse *gresponse) ++void ContainerServiceImpl::top_response_to_grpc(const container_top_response *response, TopResponse *gresponse) + { + if (response == nullptr) { + gresponse->set_cc(ISULAD_ERR_MEMOUT); +- return 0; ++ return; + } + gresponse->set_cc(response->cc); + if (response->errmsg != nullptr) { +@@ -253,7 +248,7 @@ int ContainerServiceImpl::top_response_to_grpc(const container_top_response *res + gresponse->add_processes(response->processes[i]); + } + +- return 0; ++ return; + } + + int ContainerServiceImpl::stop_request_from_grpc(const StopRequest *grequest, container_stop_request **request) +@@ -328,11 +323,11 @@ int ContainerServiceImpl::delete_request_from_grpc(const DeleteRequest *grequest + return 0; + } + +-int ContainerServiceImpl::delete_response_to_grpc(const container_delete_response *response, DeleteResponse *gresponse) ++void ContainerServiceImpl::delete_response_to_grpc(const container_delete_response *response, DeleteResponse *gresponse) + { + if (response == nullptr) { + gresponse->set_cc(ISULAD_ERR_MEMOUT); +- return 0; ++ return; + } + gresponse->set_cc(response->cc); + if (response->id != nullptr) { +@@ -341,7 +336,7 @@ int ContainerServiceImpl::delete_response_to_grpc(const container_delete_respons + if (response->errmsg != nullptr) { + gresponse->set_errmsg(response->errmsg); + } +- return 0; ++ return; + } + + int ContainerServiceImpl::exec_request_from_grpc(const ExecRequest *grequest, container_exec_request **request) +@@ -418,11 +413,11 @@ int ContainerServiceImpl::exec_request_from_grpc(const ExecRequest *grequest, co + return 0; + } + +-int ContainerServiceImpl::exec_response_to_grpc(const container_exec_response *response, ExecResponse *gresponse) ++void ContainerServiceImpl::exec_response_to_grpc(const container_exec_response *response, ExecResponse *gresponse) + { + if (response == nullptr) { + gresponse->set_cc(ISULAD_ERR_MEMOUT); +- return 0; ++ return; + } + + gresponse->set_cc(response->cc); +@@ -430,7 +425,7 @@ int ContainerServiceImpl::exec_response_to_grpc(const container_exec_response *r + if (response->errmsg != nullptr) { + gresponse->set_errmsg(response->errmsg); + } +- return 0; ++ return; + } + + int ContainerServiceImpl::inspect_request_from_grpc(const InspectContainerRequest *grequest, +@@ -454,12 +449,12 @@ int ContainerServiceImpl::inspect_request_from_grpc(const InspectContainerReques + return 0; + } + +-int ContainerServiceImpl::inspect_response_to_grpc(const container_inspect_response *response, +- InspectContainerResponse *gresponse) ++void ContainerServiceImpl::inspect_response_to_grpc(const container_inspect_response *response, ++ InspectContainerResponse *gresponse) + { + if (response == nullptr) { + gresponse->set_cc(ISULAD_ERR_MEMOUT); +- return 0; ++ return; + } + + gresponse->set_cc(response->cc); +@@ -469,7 +464,7 @@ int ContainerServiceImpl::inspect_response_to_grpc(const container_inspect_respo + if (response->errmsg != nullptr) { + gresponse->set_errmsg(response->errmsg); + } +- return 0; ++ return; + } + + int ContainerServiceImpl::list_request_from_grpc(const ListRequest *grequest, container_list_request **request) +@@ -534,11 +529,11 @@ cleanup: + return -1; + } + +-int ContainerServiceImpl::list_response_to_grpc(const container_list_response *response, ListResponse *gresponse) ++void ContainerServiceImpl::list_response_to_grpc(const container_list_response *response, ListResponse *gresponse) + { + if (response == nullptr) { + gresponse->set_cc(ISULAD_ERR_MEMOUT); +- return 0; ++ return; + } + + gresponse->set_cc(response->cc); +@@ -579,7 +574,7 @@ int ContainerServiceImpl::list_response_to_grpc(const container_list_response *r + } + container->set_created(response->containers[i]->created); + } +- return 0; ++ return; + } + + int ContainerServiceImpl::pause_request_from_grpc(const PauseRequest *grequest, container_pause_request **request) +@@ -637,12 +632,12 @@ int ContainerServiceImpl::container_rename_request_from_grpc(const RenameRequest + return 0; + } + +-int ContainerServiceImpl::container_rename_response_to_grpc(const struct isulad_container_rename_response *response, +- RenameResponse *gresponse) ++void ContainerServiceImpl::container_rename_response_to_grpc(const struct isulad_container_rename_response *response, ++ RenameResponse *gresponse) + { + if (response == nullptr) { + gresponse->set_cc(ISULAD_ERR_MEMOUT); +- return 0; ++ return; + } + + gresponse->set_cc(response->cc); +@@ -653,7 +648,7 @@ int ContainerServiceImpl::container_rename_response_to_grpc(const struct isulad_ + gresponse->set_id(response->id); + } + +- return 0; ++ return; + } + + int ContainerServiceImpl::container_resize_request_from_grpc(const ResizeRequest *grequest, +@@ -682,12 +677,12 @@ int ContainerServiceImpl::container_resize_request_from_grpc(const ResizeRequest + return 0; + } + +-int ContainerServiceImpl::container_resize_response_to_grpc(const struct isulad_container_resize_response *response, +- ResizeResponse *gresponse) ++void ContainerServiceImpl::container_resize_response_to_grpc(const struct isulad_container_resize_response *response, ++ ResizeResponse *gresponse) + { + if (response == nullptr) { + gresponse->set_cc(ISULAD_ERR_MEMOUT); +- return 0; ++ return; + } + + gresponse->set_cc(response->cc); +@@ -698,7 +693,7 @@ int ContainerServiceImpl::container_resize_response_to_grpc(const struct isulad_ + gresponse->set_id(response->id); + } + +- return 0; ++ return; + } + + int ContainerServiceImpl::update_request_from_grpc(const UpdateRequest *grequest, container_update_request **request) +@@ -722,11 +717,11 @@ int ContainerServiceImpl::update_request_from_grpc(const UpdateRequest *grequest + return 0; + } + +-int ContainerServiceImpl::update_response_to_grpc(const container_update_response *response, UpdateResponse *gresponse) ++void ContainerServiceImpl::update_response_to_grpc(const container_update_response *response, UpdateResponse *gresponse) + { + if (response == nullptr) { + gresponse->set_cc(ISULAD_ERR_MEMOUT); +- return 0; ++ return; + } + + gresponse->set_cc(response->cc); +@@ -736,7 +731,7 @@ int ContainerServiceImpl::update_response_to_grpc(const container_update_respons + if (response->errmsg != nullptr) { + gresponse->set_errmsg(response->errmsg); + } +- return 0; ++ return; + } + + int ContainerServiceImpl::stats_request_from_grpc(const StatsRequest *grequest, container_stats_request **request) +@@ -766,11 +761,11 @@ int ContainerServiceImpl::stats_request_from_grpc(const StatsRequest *grequest, + return 0; + } + +-int ContainerServiceImpl::stats_response_to_grpc(const container_stats_response *response, StatsResponse *gresponse) ++void ContainerServiceImpl::stats_response_to_grpc(const container_stats_response *response, StatsResponse *gresponse) + { + if (response == nullptr) { + gresponse->set_cc(ISULAD_ERR_MEMOUT); +- return 0; ++ return; + } + + if (response->container_stats && response->container_stats_len) { +@@ -803,7 +798,7 @@ int ContainerServiceImpl::stats_response_to_grpc(const container_stats_response + if (response->errmsg != nullptr) { + gresponse->set_errmsg(response->errmsg); + } +- return 0; ++ return; + } + + int ContainerServiceImpl::wait_request_from_grpc(const WaitRequest *grequest, container_wait_request **request) +@@ -824,11 +819,11 @@ int ContainerServiceImpl::wait_request_from_grpc(const WaitRequest *grequest, co + return 0; + } + +-int ContainerServiceImpl::wait_response_to_grpc(const container_wait_response *response, WaitResponse *gresponse) ++void ContainerServiceImpl::wait_response_to_grpc(const container_wait_response *response, WaitResponse *gresponse) + { + if (response == nullptr) { + gresponse->set_cc(ISULAD_ERR_MEMOUT); +- return 0; ++ return; + } + + gresponse->set_cc(response->cc); +@@ -836,7 +831,7 @@ int ContainerServiceImpl::wait_response_to_grpc(const container_wait_response *r + if (response->errmsg != nullptr) { + gresponse->set_errmsg(response->errmsg); + } +- return 0; ++ return; + } + + int ContainerServiceImpl::events_request_from_grpc(const EventsRequest *grequest, +@@ -1059,11 +1054,11 @@ int ContainerServiceImpl::export_request_from_grpc(const ExportRequest *grequest + return 0; + } + +-int ContainerServiceImpl::pack_os_info_to_grpc(const host_info_response *response, InfoResponse *gresponse) ++void ContainerServiceImpl::pack_os_info_to_grpc(const host_info_response *response, InfoResponse *gresponse) + { + if (response == nullptr) { + gresponse->set_cc(ISULAD_ERR_MEMOUT); +- return 0; ++ return; + } + + if (response->kversion != nullptr) { +@@ -1096,14 +1091,14 @@ int ContainerServiceImpl::pack_os_info_to_grpc(const host_info_response *respons + gresponse->set_huge_page_size(response->huge_page_size); + } + +- return 0; ++ return; + } + +-int ContainerServiceImpl::pack_proxy_info_to_grpc(const host_info_response *response, InfoResponse *gresponse) ++void ContainerServiceImpl::pack_proxy_info_to_grpc(const host_info_response *response, InfoResponse *gresponse) + { + if (response == nullptr) { + gresponse->set_cc(ISULAD_ERR_MEMOUT); +- return 0; ++ return; + } + + if (response->http_proxy != nullptr) { +@@ -1118,14 +1113,14 @@ int ContainerServiceImpl::pack_proxy_info_to_grpc(const host_info_response *resp + gresponse->set_no_proxy(response->no_proxy); + } + +- return 0; ++ return; + } + +-int ContainerServiceImpl::pack_driver_info_to_grpc(const host_info_response *response, InfoResponse *gresponse) ++void ContainerServiceImpl::pack_driver_info_to_grpc(const host_info_response *response, InfoResponse *gresponse) + { + if (response == nullptr) { + gresponse->set_cc(ISULAD_ERR_MEMOUT); +- return 0; ++ return; + } + + if (response->driver_name != nullptr) { +@@ -1136,5 +1131,5 @@ int ContainerServiceImpl::pack_driver_info_to_grpc(const host_info_response *res + gresponse->set_driver_status(response->driver_status); + } + +- return 0; ++ return; + } +diff --git a/src/daemon/entry/connect/grpc/grpc_images_service.cc b/src/daemon/entry/connect/grpc/grpc_images_service.cc +index 533467c..57a51ee 100644 +--- a/src/daemon/entry/connect/grpc/grpc_images_service.cc ++++ b/src/daemon/entry/connect/grpc/grpc_images_service.cc +@@ -88,11 +88,11 @@ cleanup: + return -1; + } + +-int ImagesServiceImpl::image_list_response_to_grpc(image_list_images_response *response, ListImagesResponse *gresponse) ++void ImagesServiceImpl::image_list_response_to_grpc(image_list_images_response *response, ListImagesResponse *gresponse) + { + if (response == nullptr) { + gresponse->set_cc(ISULAD_ERR_MEMOUT); +- return 0; ++ return; + } + + gresponse->set_cc(response->cc); +@@ -109,7 +109,8 @@ int ImagesServiceImpl::image_list_response_to_grpc(image_list_images_response *r + target = new (std::nothrow) Descriptor; + if (target == nullptr) { + ERROR("Out of memory"); +- return -1; ++ gresponse->set_cc(ISULAD_ERR_MEMOUT); ++ return; + } + if (response->images[i]->target->digest != nullptr) { + target->set_digest(response->images[i]->target->digest); +@@ -117,8 +118,8 @@ int ImagesServiceImpl::image_list_response_to_grpc(image_list_images_response *r + Timestamp *timestamp = image->mutable_created_at(); + if (timestamp == nullptr) { + delete target; +- ERROR("Out of memory"); +- return -1; ++ gresponse->set_cc(ISULAD_ERR_MEMOUT); ++ return; + } + timestamp->set_seconds(response->images[i]->created_at->seconds); + timestamp->set_nanos(response->images[i]->created_at->nanos); +@@ -129,7 +130,7 @@ int ImagesServiceImpl::image_list_response_to_grpc(image_list_images_response *r + image->set_allocated_target(target); + } + +- return 0; ++ return; + } + + int ImagesServiceImpl::image_remove_request_from_grpc(const DeleteImageRequest *grequest, +@@ -232,11 +233,12 @@ int ImagesServiceImpl::inspect_request_from_grpc(const InspectImageRequest *greq + return 0; + } + +-int ImagesServiceImpl::inspect_response_to_grpc(const image_inspect_response *response, InspectImageResponse *gresponse) ++void ImagesServiceImpl::inspect_response_to_grpc(const image_inspect_response *response, ++ InspectImageResponse *gresponse) + { + if (response == nullptr) { + gresponse->set_cc(ISULAD_ERR_MEMOUT); +- return 0; ++ return; + } + + gresponse->set_cc(response->cc); +@@ -246,7 +248,7 @@ int ImagesServiceImpl::inspect_response_to_grpc(const image_inspect_response *re + if (response->errmsg != nullptr) { + gresponse->set_errmsg(response->errmsg); + } +- return 0; ++ return; + } + + Status ImagesServiceImpl::List(ServerContext *context, const ListImagesRequest *request, ListImagesResponse *reply) +@@ -269,16 +271,12 @@ Status ImagesServiceImpl::List(ServerContext *context, const ListImagesRequest * + } + + image_list_images_response *image_res = nullptr; +- int ret = cb->image.list(image_req, &image_res); +- tret = image_list_response_to_grpc(image_res, reply); ++ (void)cb->image.list(image_req, &image_res); ++ image_list_response_to_grpc(image_res, reply); + + free_image_list_images_request(image_req); + free_image_list_images_response(image_res); +- if (tret != 0) { +- reply->set_errmsg(util_strdup_s(errno_to_error_message(ISULAD_ERR_INTERNAL))); +- reply->set_cc(ISULAD_ERR_INPUT); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + +@@ -302,16 +300,12 @@ Status ImagesServiceImpl::Delete(ServerContext *context, const DeleteImageReques + } + + image_delete_image_response *image_res = nullptr; +- int ret = cb->image.remove(image_req, &image_res); +- tret = response_to_grpc(image_res, reply); ++ (void)cb->image.remove(image_req, &image_res); ++ response_to_grpc(image_res, reply); + + free_image_delete_image_request(image_req); + free_image_delete_image_response(image_res); +- if (tret != 0) { +- reply->set_errmsg(util_strdup_s(errno_to_error_message(ISULAD_ERR_INTERNAL))); +- reply->set_cc(ISULAD_ERR_INPUT); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + +@@ -335,24 +329,20 @@ Status ImagesServiceImpl::Tag(ServerContext *context, const TagImageRequest *req + } + + image_tag_image_response *image_res = nullptr; +- int ret = cb->image.tag(image_req, &image_res); +- tret = response_to_grpc(image_res, reply); ++ (void)cb->image.tag(image_req, &image_res); ++ response_to_grpc(image_res, reply); + + free_image_tag_image_request(image_req); + free_image_tag_image_response(image_res); +- if (tret != 0) { +- reply->set_errmsg(util_strdup_s(errno_to_error_message(ISULAD_ERR_INTERNAL))); +- reply->set_cc(ISULAD_ERR_INPUT); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + +-int ImagesServiceImpl::import_response_to_grpc(const image_import_response *response, ImportResponse *gresponse) ++void ImagesServiceImpl::import_response_to_grpc(const image_import_response *response, ImportResponse *gresponse) + { + if (response == nullptr) { + gresponse->set_cc(ISULAD_ERR_MEMOUT); +- return 0; ++ return; + } + + gresponse->set_cc(response->cc); +@@ -362,7 +352,7 @@ int ImagesServiceImpl::import_response_to_grpc(const image_import_response *resp + if (response->errmsg != nullptr) { + gresponse->set_errmsg(response->errmsg); + } +- return 0; ++ return; + } + + Status ImagesServiceImpl::Import(ServerContext *context, const ImportRequest *request, ImportResponse *reply) +@@ -385,16 +375,11 @@ Status ImagesServiceImpl::Import(ServerContext *context, const ImportRequest *re + } + + image_import_response *image_res = nullptr; +- int ret = cb->image.import(image_req, &image_res); +- tret = import_response_to_grpc(image_res, reply); ++ (void)cb->image.import(image_req, &image_res); ++ import_response_to_grpc(image_res, reply); + + free_image_import_request(image_req); + free_image_import_response(image_res); +- if (tret != 0) { +- reply->set_errmsg(util_strdup_s(errno_to_error_message(ISULAD_ERR_INTERNAL))); +- reply->set_cc(ISULAD_ERR_INPUT); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } + + return Status::OK; + } +@@ -419,16 +404,11 @@ Status ImagesServiceImpl::Load(ServerContext *context, const LoadImageRequest *r + } + + image_load_image_response *image_res = nullptr; +- int ret = cb->image.load(image_req, &image_res); +- tret = response_to_grpc(image_res, reply); ++ (void)cb->image.load(image_req, &image_res); ++ response_to_grpc(image_res, reply); + + free_image_load_image_request(image_req); + free_image_load_image_response(image_res); +- if (tret != 0) { +- reply->set_errmsg(util_strdup_s(errno_to_error_message(ISULAD_ERR_INTERNAL))); +- reply->set_cc(ISULAD_ERR_INPUT); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } + + return Status::OK; + } +@@ -436,7 +416,7 @@ Status ImagesServiceImpl::Load(ServerContext *context, const LoadImageRequest *r + Status ImagesServiceImpl::Inspect(ServerContext *context, const InspectImageRequest *request, + InspectImageResponse *reply) + { +- int ret, tret; ++ int tret; + service_executor_t *cb = nullptr; + image_inspect_request *image_req = nullptr; + image_inspect_response *image_res = nullptr; +@@ -458,16 +438,12 @@ Status ImagesServiceImpl::Inspect(ServerContext *context, const InspectImageRequ + return Status::OK; + } + +- ret = cb->image.inspect(image_req, &image_res); +- tret = inspect_response_to_grpc(image_res, reply); ++ (void)cb->image.inspect(image_req, &image_res); ++ inspect_response_to_grpc(image_res, reply); + + free_image_inspect_request(image_req); + free_image_inspect_response(image_res); +- if (tret != 0) { +- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); +- reply->set_cc(ISULAD_ERR_INTERNAL); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } ++ + return Status::OK; + } + +@@ -535,16 +511,11 @@ Status ImagesServiceImpl::Login(ServerContext *context, const LoginRequest *requ + } + + image_login_response *image_res = nullptr; +- int ret = cb->image.login(image_req, &image_res); +- tret = response_to_grpc(image_res, reply); ++ (void)cb->image.login(image_req, &image_res); ++ response_to_grpc(image_res, reply); + + free_image_login_request(image_req); + free_image_login_response(image_res); +- if (tret != 0) { +- reply->set_errmsg(util_strdup_s(errno_to_error_message(ISULAD_ERR_INTERNAL))); +- reply->set_cc(ISULAD_ERR_INPUT); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } + + return Status::OK; + } +@@ -569,16 +540,11 @@ Status ImagesServiceImpl::Logout(ServerContext *context, const LogoutRequest *re + } + + image_logout_response *image_res = nullptr; +- int ret = cb->image.logout(image_req, &image_res); +- tret = response_to_grpc(image_res, reply); ++ (void)cb->image.logout(image_req, &image_res); ++ response_to_grpc(image_res, reply); + + free_image_logout_request(image_req); + free_image_logout_response(image_res); +- if (tret != 0) { +- reply->set_errmsg(util_strdup_s(errno_to_error_message(ISULAD_ERR_INTERNAL))); +- reply->set_cc(ISULAD_ERR_INPUT); +- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); +- } + + return Status::OK; + } +diff --git a/src/daemon/entry/connect/grpc/grpc_images_service.h b/src/daemon/entry/connect/grpc/grpc_images_service.h +index 3c498f4..92334b5 100644 +--- a/src/daemon/entry/connect/grpc/grpc_images_service.h ++++ b/src/daemon/entry/connect/grpc/grpc_images_service.h +@@ -33,7 +33,6 @@ using grpc::StatusCode; + using google::protobuf::Timestamp; + + using namespace images; +-using namespace containerd::types; + + // Implement of images service + class ImagesServiceImpl final : public ImagesService::Service { +@@ -55,29 +54,27 @@ public: + + Status Inspect(ServerContext *context, const InspectImageRequest *request, InspectImageResponse *reply) override; + +- Status Login(ServerContext *context, const LoginRequest *request, +- LoginResponse *reply) override; ++ Status Login(ServerContext *context, const LoginRequest *request, LoginResponse *reply) override; + +- Status Logout(ServerContext *context, const LogoutRequest *request, +- LogoutResponse *reply) override; ++ Status Logout(ServerContext *context, const LogoutRequest *request, LogoutResponse *reply) override; + + private: + template +- int response_to_grpc(const T1 *response, T2 *gresponse) ++ void response_to_grpc(const T1 *response, T2 *gresponse) + { + if (response == nullptr) { + gresponse->set_cc(ISULAD_ERR_MEMOUT); +- return 0; ++ return; + } + gresponse->set_cc(response->cc); + if (response->errmsg != nullptr) { + gresponse->set_errmsg(response->errmsg); + } +- return 0; ++ return; + } + int image_list_request_from_grpc(const ListImagesRequest *grequest, image_list_images_request **request); + +- int image_list_response_to_grpc(image_list_images_response *response, ListImagesResponse *gresponse); ++ void image_list_response_to_grpc(image_list_images_response *response, ListImagesResponse *gresponse); + + int image_remove_request_from_grpc(const DeleteImageRequest *grequest, image_delete_image_request **request); + +@@ -85,13 +82,13 @@ private: + + int image_import_request_from_grpc(const ImportRequest *grequest, image_import_request **request); + +- int import_response_to_grpc(const image_import_response *response, ImportResponse *gresponse); ++ void import_response_to_grpc(const image_import_response *response, ImportResponse *gresponse); + + int image_load_request_from_grpc(const LoadImageRequest *grequest, image_load_image_request **request); + + int inspect_request_from_grpc(const InspectImageRequest *grequest, image_inspect_request **request); + +- int inspect_response_to_grpc(const image_inspect_response *response, InspectImageResponse *gresponse); ++ void inspect_response_to_grpc(const image_inspect_response *response, InspectImageResponse *gresponse); + + int image_login_request_from_grpc(const LoginRequest *grequest, image_login_request **request); + +@@ -99,4 +96,3 @@ private: + }; + + #endif // DAEMON_ENTRY_CONNECT_GRPC_GRPC_IMAGES_SERVICE_H +- +diff --git a/src/daemon/entry/connect/grpc/grpc_server_tls_auth.cc b/src/daemon/entry/connect/grpc/grpc_server_tls_auth.cc +index 18f2719..1bb1b92 100644 +--- a/src/daemon/entry/connect/grpc/grpc_server_tls_auth.cc ++++ b/src/daemon/entry/connect/grpc/grpc_server_tls_auth.cc +@@ -28,7 +28,7 @@ Status auth(ServerContext *context, std::string action) + const std::multimap init_metadata = context->client_metadata(); + auto tls_mode_kv = init_metadata.find("tls_mode"); + if (tls_mode_kv == init_metadata.end()) { +- return Status(StatusCode::UNKNOWN, "unkown error"); ++ return Status(StatusCode::UNKNOWN, "unknown error"); + } + std::string tls_mode = std::string(tls_mode_kv->second.data(), tls_mode_kv->second.length()); + if (tls_mode == "0") { +@@ -39,7 +39,7 @@ Status auth(ServerContext *context, std::string action) + } else if (AuthorizationPluginConfig::auth_plugin == "authz-broker") { + auto username_kv = init_metadata.find("username"); + if (username_kv == init_metadata.end()) { +- return Status(StatusCode::UNKNOWN, "unkown error"); ++ return Status(StatusCode::UNKNOWN, "unknown error"); + } + std::string username = std::string(username_kv->second.data(), username_kv->second.length()); + char *errmsg = nullptr; +diff --git a/src/daemon/entry/connect/grpc/grpc_service.cc b/src/daemon/entry/connect/grpc/grpc_service.cc +index 0a7f3be..ab3e32a 100644 +--- a/src/daemon/entry/connect/grpc/grpc_service.cc ++++ b/src/daemon/entry/connect/grpc/grpc_service.cc +@@ -22,6 +22,7 @@ + #include + #include "grpc_containers_service.h" + #include "grpc_images_service.h" ++#include "grpc_volumes_service.h" + #include "runtime_runtime_service.h" + #include "runtime_image_service.h" + #include "isula_libutils/log.h" +@@ -70,6 +71,7 @@ public: + // clients. In this case it corresponds to an *synchronous* service. + m_builder.RegisterService(&m_containerService); + m_builder.RegisterService(&m_imagesService); ++ m_builder.RegisterService(&m_volumeService); + m_builder.RegisterService(&m_runtimeRuntimeService); + m_builder.RegisterService(&m_runtimeImageService); + +@@ -181,6 +183,7 @@ private: + Network::NetworkPluginConf m_conf; + ContainerServiceImpl m_containerService; + ImagesServiceImpl m_imagesService; ++ VolumeServiceImpl m_volumeService; + RuntimeRuntimeServiceImpl m_runtimeRuntimeService; + RuntimeImageServiceImpl m_runtimeImageService; + ServerBuilder m_builder; +diff --git a/src/daemon/entry/connect/grpc/grpc_volumes_service.cc b/src/daemon/entry/connect/grpc/grpc_volumes_service.cc +new file mode 100644 +index 0000000..fcc7210 +--- /dev/null ++++ b/src/daemon/entry/connect/grpc/grpc_volumes_service.cc +@@ -0,0 +1,218 @@ ++/****************************************************************************** ++ * 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-09-02 ++ * Description: provide grpc volume functions ++ ******************************************************************************/ ++ ++#include "grpc_volumes_service.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "isula_libutils/log.h" ++#include "utils.h" ++#include "grpc_server_tls_auth.h" ++ ++int VolumeServiceImpl::volume_list_request_from_grpc(const ListVolumeRequest *grequest, ++ volume_list_volume_request **request) ++{ ++ volume_list_volume_request *tmpreq = ++ static_cast(util_common_calloc_s(sizeof(volume_list_volume_request))); ++ if (tmpreq == nullptr) { ++ ERROR("Out of memory"); ++ return -1; ++ } ++ *request = tmpreq; ++ ++ return 0; ++} ++ ++int VolumeServiceImpl::volume_list_response_to_grpc(volume_list_volume_response *response, ++ ListVolumeResponse *gresponse) ++{ ++ if (response == nullptr) { ++ gresponse->set_cc(ISULAD_ERR_MEMOUT); ++ return 0; ++ } ++ ++ gresponse->set_cc(response->cc); ++ if (response->errmsg != nullptr) { ++ gresponse->set_errmsg(response->errmsg); ++ } ++ ++ for (size_t i {}; i < response->volumes_len; i++) { ++ auto volume = gresponse->add_volumes(); ++ if (response->volumes[i]->driver != nullptr) { ++ volume->set_driver(response->volumes[i]->driver); ++ } ++ if (response->volumes[i]->name != nullptr) { ++ volume->set_name(response->volumes[i]->name); ++ } ++ } ++ ++ return 0; ++} ++ ++int VolumeServiceImpl::volume_remove_request_from_grpc(const RemoveVolumeRequest *grequest, ++ volume_remove_volume_request **request) ++{ ++ volume_remove_volume_request *tmpreq = ++ static_cast(util_common_calloc_s(sizeof(volume_remove_volume_request))); ++ if (tmpreq == nullptr) { ++ ERROR("Out of memory"); ++ return -1; ++ } ++ ++ if (!grequest->name().empty()) { ++ tmpreq->name = util_strdup_s(grequest->name().c_str()); ++ } ++ *request = tmpreq; ++ ++ return 0; ++} ++ ++int VolumeServiceImpl::volume_prune_request_from_grpc(const PruneVolumeRequest *grequest, ++ volume_prune_volume_request **request) ++{ ++ volume_prune_volume_request *tmpreq = ++ static_cast(util_common_calloc_s(sizeof(volume_prune_volume_request))); ++ if (tmpreq == nullptr) { ++ ERROR("Out of memory"); ++ return -1; ++ } ++ *request = tmpreq; ++ ++ return 0; ++} ++ ++int VolumeServiceImpl::volume_prune_response_to_grpc(volume_prune_volume_response *response, ++ PruneVolumeResponse *gresponse) ++{ ++ if (response == nullptr) { ++ gresponse->set_cc(ISULAD_ERR_MEMOUT); ++ return 0; ++ } ++ ++ gresponse->set_cc(response->cc); ++ if (response->errmsg != nullptr) { ++ gresponse->set_errmsg(response->errmsg); ++ } ++ ++ for (size_t i {}; i < response->volumes_len; i++) { ++ gresponse->add_volumes(response->volumes[i]); ++ } ++ ++ return 0; ++} ++ ++ ++Status VolumeServiceImpl::List(ServerContext *context, const ListVolumeRequest *request, ListVolumeResponse *reply) ++{ ++ auto status = GrpcServerTlsAuth::auth(context, "volume_list"); ++ if (!status.ok()) { ++ return status; ++ } ++ auto cb = get_service_executor(); ++ if (cb == nullptr || cb->volume.list == nullptr) { ++ return Status(StatusCode::UNIMPLEMENTED, "Unimplemented callback"); ++ } ++ ++ volume_list_volume_request *volume_req = nullptr; ++ int tret = volume_list_request_from_grpc(request, &volume_req); ++ if (tret != 0) { ++ ERROR("Failed to transform grpc request"); ++ reply->set_cc(ISULAD_ERR_INPUT); ++ return Status::OK; ++ } ++ ++ volume_list_volume_response *volume_res = nullptr; ++ int ret = cb->volume.list(volume_req, &volume_res); ++ tret = volume_list_response_to_grpc(volume_res, reply); ++ free_volume_list_volume_request(volume_req); ++ free_volume_list_volume_response(volume_res); ++ if (tret != 0) { ++ reply->set_errmsg(util_strdup_s(errno_to_error_message(ISULAD_ERR_INTERNAL))); ++ reply->set_cc(ISULAD_ERR_INPUT); ++ ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); ++ } ++ ++ return Status::OK; ++} ++ ++Status VolumeServiceImpl::Remove(ServerContext *context, const RemoveVolumeRequest *request, ++ RemoveVolumeResponse *reply) ++{ ++ auto status = GrpcServerTlsAuth::auth(context, "volume_remove"); ++ if (!status.ok()) { ++ return status; ++ } ++ service_executor_t *cb = get_service_executor(); ++ if (cb == nullptr || cb->volume.remove == nullptr) { ++ return Status(StatusCode::UNIMPLEMENTED, "Unimplemented callback"); ++ } ++ ++ volume_remove_volume_request *volume_req = nullptr; ++ int tret = volume_remove_request_from_grpc(request, &volume_req); ++ if (tret != 0) { ++ ERROR("Failed to transform grpc request"); ++ reply->set_cc(ISULAD_ERR_INPUT); ++ return Status::OK; ++ } ++ ++ volume_remove_volume_response *volume_res = nullptr; ++ int ret = cb->volume.remove(volume_req, &volume_res); ++ tret = response_to_grpc(volume_res, reply); ++ free_volume_remove_volume_request(volume_req); ++ free_volume_remove_volume_response(volume_res); ++ if (tret != 0) { ++ reply->set_errmsg(util_strdup_s(errno_to_error_message(ISULAD_ERR_INTERNAL))); ++ reply->set_cc(ISULAD_ERR_INPUT); ++ ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); ++ } ++ ++ return Status::OK; ++} ++ ++Status VolumeServiceImpl::Prune(ServerContext *context, const PruneVolumeRequest *request, PruneVolumeResponse *reply) ++{ ++ auto status = GrpcServerTlsAuth::auth(context, "volume_prune"); ++ if (!status.ok()) { ++ return status; ++ } ++ service_executor_t *cb = get_service_executor(); ++ if (cb == nullptr || cb->volume.prune == nullptr) { ++ return Status(StatusCode::UNIMPLEMENTED, "Unimplemented callback"); ++ } ++ volume_prune_volume_request *volume_req = nullptr; ++ int tret = volume_prune_request_from_grpc(request, &volume_req); ++ if (tret != 0) { ++ ERROR("Failed to transform grpc request"); ++ reply->set_cc(ISULAD_ERR_INPUT); ++ return Status::OK; ++ } ++ ++ volume_prune_volume_response *volume_res = nullptr; ++ int ret = cb->volume.prune(volume_req, &volume_res); ++ tret = volume_prune_response_to_grpc(volume_res, reply); ++ free_volume_prune_volume_request(volume_req); ++ free_volume_prune_volume_response(volume_res); ++ if (tret != 0) { ++ reply->set_errmsg(util_strdup_s(errno_to_error_message(ISULAD_ERR_INTERNAL))); ++ reply->set_cc(ISULAD_ERR_INPUT); ++ ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); ++ } ++ ++ return Status::OK; ++} +diff --git a/src/daemon/entry/connect/grpc/grpc_volumes_service.h b/src/daemon/entry/connect/grpc/grpc_volumes_service.h +new file mode 100644 +index 0000000..59dd03d +--- /dev/null ++++ b/src/daemon/entry/connect/grpc/grpc_volumes_service.h +@@ -0,0 +1,71 @@ ++/****************************************************************************** ++ * 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-09-02 ++ * Description: provide grpc volume functions ++ ******************************************************************************/ ++ ++#ifndef DAEMON_ENTRY_CONNECT_GRPC_GRPC_VOLUMES_SERVICE_H ++#define DAEMON_ENTRY_CONNECT_GRPC_GRPC_VOLUMES_SERVICE_H ++ ++#include ++ ++#include "volumes.grpc.pb.h" ++#include "callback.h" ++#include "error.h" ++ ++using grpc::ServerContext; ++using grpc::Status; ++ ++using namespace volume; ++ ++// Implement of volume service ++class VolumeServiceImpl final : public VolumeService::Service { ++public: ++ VolumeServiceImpl() = default; ++ VolumeServiceImpl(const VolumeServiceImpl &) = delete; ++ VolumeServiceImpl &operator=(const VolumeServiceImpl &) = delete; ++ virtual ~VolumeServiceImpl() = default; ++ ++ Status List(ServerContext *context, const ListVolumeRequest *request, ListVolumeResponse *reply) override; ++ ++ Status Remove(ServerContext *context, const RemoveVolumeRequest *request, RemoveVolumeResponse *reply) override; ++ ++ Status Prune(ServerContext *context, const PruneVolumeRequest *request, PruneVolumeResponse *reply) override; ++ ++private: ++ template ++ int response_to_grpc(const T1 *response, T2 *gresponse) ++ { ++ if (response == nullptr) { ++ gresponse->set_cc(ISULAD_ERR_MEMOUT); ++ return 0; ++ } ++ gresponse->set_cc(response->cc); ++ if (response->errmsg != nullptr) { ++ gresponse->set_errmsg(response->errmsg); ++ } ++ return 0; ++ } ++ ++ int volume_list_request_from_grpc(const volume::ListVolumeRequest*, volume_list_volume_request**); ++ ++ int volume_list_response_to_grpc(volume_list_volume_response *response, ListVolumeResponse *gresponse); ++ ++ int volume_remove_request_from_grpc(const RemoveVolumeRequest *grequest, volume_remove_volume_request **request); ++ ++ int volume_prune_request_from_grpc(const PruneVolumeRequest *grequest, volume_prune_volume_request **request); ++ ++ int volume_prune_response_to_grpc(volume_prune_volume_response *response, PruneVolumeResponse *gresponse); ++}; ++ ++#endif // DAEMON_ENTRY_CONNECT_GRPC_GRPC_VOLUMES_SERVICE_H ++ +diff --git a/src/daemon/entry/connect/rest/rest_containers_service.c b/src/daemon/entry/connect/rest/rest_containers_service.c +index 4f38e8a..74ba482 100644 +--- a/src/daemon/entry/connect/rest/rest_containers_service.c ++++ b/src/daemon/entry/connect/rest/rest_containers_service.c +@@ -12,6 +12,7 @@ + * Create: 2018-11-08 + * Description: provide container restful service functions + ******************************************************************************/ ++#include "rest_containers_service.h" + #include + #include + +@@ -21,7 +22,6 @@ + #include "callback.h" + #include "container.rest.h" + #include "rest_service_common.h" +-#include "rest_containers_service.h" + + struct rest_handle_st { + const char *name; +diff --git a/src/daemon/entry/connect/rest/rest_images_service.c b/src/daemon/entry/connect/rest/rest_images_service.c +index 6675357..6058359 100644 +--- a/src/daemon/entry/connect/rest/rest_images_service.c ++++ b/src/daemon/entry/connect/rest/rest_images_service.c +@@ -12,13 +12,13 @@ + * Create: 2018-11-08 + * Description: provide image restful service functions + ******************************************************************************/ ++#include "rest_images_service.h" + #include + + #include "isula_libutils/log.h" + #include "callback.h" + #include "image.rest.h" + #include "rest_service_common.h" +-#include "rest_images_service.h" + + /* image load request check */ + static int image_load_request_check(image_load_image_request *req) +diff --git a/src/daemon/entry/connect/rest/rest_service_common.c b/src/daemon/entry/connect/rest/rest_service_common.c +index 6e06273..e011c7c 100644 +--- a/src/daemon/entry/connect/rest/rest_service_common.c ++++ b/src/daemon/entry/connect/rest/rest_service_common.c +@@ -12,13 +12,13 @@ + * Create: 2018-11-08 + * Description: provide container restful service common functions + ******************************************************************************/ ++#include "rest_service_common.h" + #include + #include + #include + + #include "isula_libutils/log.h" + #include "utils.h" +-#include "rest_service_common.h" + + #define UNIX_PATH_MAX 128 + #define MAX_BODY_SIZE 8192 +diff --git a/src/daemon/entry/cri/cni_network_plugin.cc b/src/daemon/entry/cri/cni_network_plugin.cc +index 3442560..9cb5722 100644 +--- a/src/daemon/entry/cri/cni_network_plugin.cc ++++ b/src/daemon/entry/cri/cni_network_plugin.cc +@@ -42,7 +42,7 @@ static auto GetLoNetwork(std::vector binDirs) -> std::unique_ptr char ** + { + char **paths = CRIHelpers::StringVectorToCharArray(m_path); + if (paths == nullptr) { +- err.SetError("Get char ** path failed"); ++ err.SetError("Get cni network paths failed"); + } + return paths; + } +@@ -102,8 +102,8 @@ void CniNetworkPlugin::SetLoNetwork(std::unique_ptr lo) + } + } + +-void CniNetworkPlugin::SetDefaultNetwork(std::unique_ptr network, +- std::vector &binDirs, Errors &err) ++void CniNetworkPlugin::SetDefaultNetwork(std::unique_ptr network, std::vector &binDirs, ++ Errors &err) + { + if (network == nullptr) { + return; +@@ -124,6 +124,26 @@ void CniNetworkPlugin::SetDefaultNetwork(std::unique_ptr network, + } + } + ++void CniNetworkPlugin::UpdateMutlNetworks(std::vector> &multNets, ++ std::vector &binDirs, Errors &err) ++{ ++ if (multNets.size() == 0) { ++ return; ++ } ++ WLockNetworkMap(err); ++ if (err.NotEmpty()) { ++ return; ++ } ++ ++ m_mutlNetworks.clear(); ++ for (auto iter = multNets.begin(); iter != multNets.end(); ++iter) { ++ (*iter)->SetPaths(binDirs); ++ m_mutlNetworks[(*iter)->GetName()] = std::move(*iter); ++ } ++ ++ UnlockNetworkMap(err); ++} ++ + CniNetworkPlugin::CniNetworkPlugin(std::vector &binDirs, const std::string &confDir, + const std::string &podCidr) + : m_confDir(confDir) +@@ -139,6 +159,7 @@ CniNetworkPlugin::~CniNetworkPlugin() + if (m_syncThread.joinable()) { + m_syncThread.join(); + } ++ m_mutlNetworks.clear(); + } + + void CniNetworkPlugin::PlatformInit(Errors &error) +@@ -154,8 +175,8 @@ void CniNetworkPlugin::PlatformInit(Errors &error) + free(tpath); + } + +-auto CniNetworkPlugin::GetCNIConfFiles(const std::string &pluginDir, std::vector &vect_files, +- Errors &err) -> int ++auto CniNetworkPlugin::GetCNIConfFiles(const std::string &pluginDir, std::vector &vect_files, Errors &err) ++-> int + { + int ret { 0 }; + std::string usePluginDir { pluginDir }; +@@ -259,7 +280,9 @@ out: + void CniNetworkPlugin::GetDefaultCNINetwork(const std::string &confDir, std::vector &binDirs, Errors &err) + { + std::vector files; +- bool found = false; ++ std::vector> mutlNets; ++ char *default_net_name = nullptr; ++ std::string message = { "" }; + + if (GetCNIConfFiles(confDir, files, err) != 0) { + goto free_out; +@@ -279,16 +302,33 @@ void CniNetworkPlugin::GetDefaultCNINetwork(const std::string &confDir, std::vec + n_list = nullptr; + continue; + } ++ DEBUG("parse cni network: %s", n_list->name); + +- SetDefaultNetwork(std::unique_ptr(new (std::nothrow) CNINetwork(n_list->name, n_list)), binDirs, err); +- found = true; +- break; ++ if (default_net_name == nullptr) { ++ SetDefaultNetwork(std::unique_ptr(new (std::nothrow) CNINetwork(n_list->name, n_list)), binDirs, err); ++ default_net_name = util_strdup_s(n_list->name); ++ message += default_net_name; ++ continue; ++ } ++ if (strcmp(default_net_name, n_list->name) == 0) { ++ WARN("Use same name of default net: %s", default_net_name); ++ continue; ++ } ++ mutlNets.push_back(std::unique_ptr(new (std::nothrow) CNINetwork(n_list->name, n_list))); ++ message += ", " + std::string(n_list->name); + } +- if (!found) { ++ if (default_net_name == nullptr) { + err.Errorf("No valid networks found in %s", confDir.c_str()); ++ goto free_out; ++ } ++ UpdateMutlNetworks(mutlNets, binDirs, err); ++ if (err.NotEmpty()) { ++ goto free_out; + } ++ INFO("Loaded cni plugins successfully, [ %s ]", message.c_str()); + + free_out: ++ free(default_net_name); + return; + } + +@@ -349,9 +389,73 @@ void CniNetworkPlugin::Status(Errors &err) + CheckInitialized(err); + } + +-void CniNetworkPlugin::SetUpPod(const std::string &ns, const std::string &name, +- const std::string &interfaceName, const std::string &id, +- const std::map &annotations, ++ ++bool CniNetworkPlugin::SetupMultNetworks(const std::string &ns, const std::string &defaultInterface, ++ const std::string &name, ++ const std::string &netnsPath, const std::string &podSandboxID, ++ const std::map &annotations, ++ const std::map &options, Errors &err) ++{ ++ bool ret = false; ++ int defaultIdx = -1; ++ size_t len = 0; ++ cri_pod_network_element **networks = CRIHelpers::GetNetworkPlaneFromPodAnno(annotations, &len, err); ++ if (err.NotEmpty()) { ++ ERROR("Couldn't get network plane from pod annotations: %s", err.GetCMessage()); ++ err.Errorf("Couldn't get network plane from pod annotations: %s", err.GetCMessage()); ++ goto cleanup; ++ } ++ ++ for (size_t i = 0; i < len; i++) { ++ if (networks[i] == nullptr || networks[i]->name == nullptr || networks[i]->interface == nullptr) { ++ continue; ++ } ++ struct result *preResult = nullptr; ++ auto netIter = m_mutlNetworks.find(networks[i]->name); ++ if (netIter == m_mutlNetworks.end()) { ++ err.Errorf("Cannot found user defined net: %s", networks[i]->name); ++ break; ++ } ++ if (defaultInterface == networks[i]->interface) { ++ defaultIdx = i; ++ continue; ++ } ++ AddToNetwork((netIter->second).get(), name, ns, networks[i]->interface, podSandboxID, netnsPath, annotations, options, ++ &preResult, err); ++ free_result(preResult); ++ if (err.NotEmpty()) { ++ ERROR("Do setup user defined net: %s, failed: %s", networks[i]->name, err.GetCMessage()); ++ break; ++ } ++ INFO("Setup user defained net: %s success", networks[i]->name); ++ } ++ ++ // mask default network pod, if user defined net use same interface ++ if (defaultIdx >= 0) { ++ auto netIter = m_mutlNetworks.find(networks[defaultIdx]->name); ++ if (netIter == m_mutlNetworks.end()) { ++ err.Errorf("Cannot found user defined net: %s", networks[defaultIdx]->name); ++ goto cleanup; ++ } ++ ++ struct result *preResult = nullptr; ++ AddToNetwork((netIter->second).get(), name, ns, networks[defaultIdx]->interface, podSandboxID, netnsPath, annotations, ++ options, &preResult, err); ++ free_result(preResult); ++ if (err.NotEmpty()) { ++ ERROR("Do setup user defined net: %s, failed: %s", networks[defaultIdx]->name, err.GetCMessage()); ++ goto cleanup; ++ } ++ INFO("Setup default net: %s success", networks[defaultIdx]->name); ++ ret = true; ++ } ++cleanup: ++ free_cri_pod_network(networks, len); ++ return ret; ++} ++ ++void CniNetworkPlugin::SetUpPod(const std::string &ns, const std::string &name, const std::string &interfaceName, ++ const std::string &id, const std::map &annotations, + const std::map &options, Errors &err) + { + CheckInitialized(err); +@@ -381,25 +485,92 @@ void CniNetworkPlugin::SetUpPod(const std::string &ns, const std::string &name, + return; + } + +- AddToNetwork(m_defaultNetwork.get(), name, ns, interfaceName, id, netnsPath, annotations, options, &preResult, err); ++ bool setedDefaultNet = SetupMultNetworks(ns, interfaceName, name, netnsPath, id, annotations, options, err); ++ if (err.NotEmpty()) { ++ goto unlock; ++ } ++ ++ if (setedDefaultNet) { ++ goto unlock; ++ } + ++ AddToNetwork(m_defaultNetwork.get(), name, ns, interfaceName, id, netnsPath, annotations, options, &preResult, err); + free_result(preResult); +- preResult = nullptr; + if (err.NotEmpty()) { + ERROR("Error while adding to cni network: %s", err.GetCMessage()); + } + ++unlock: + UnlockNetworkMap(err); + } + ++bool CniNetworkPlugin::TearDownMultNetworks(const std::string &ns, const std::string &defaultInterface, ++ const std::string &name, ++ const std::string &netnsPath, const std::string &podSandboxID, const std::map &annotations, ++ Errors &err) ++{ ++ bool ret = false; ++ int defaultIdx = -1; ++ size_t len = 0; ++ cri_pod_network_element **networks = CRIHelpers::GetNetworkPlaneFromPodAnno(annotations, &len, err); ++ if (err.NotEmpty()) { ++ ERROR("Couldn't get network plane from pod annotations: %s", err.GetCMessage()); ++ err.Errorf("Couldn't get network plane from pod annotations: %s", err.GetCMessage()); ++ goto cleanup; ++ } ++ ++ for (size_t i = 0; i < len; i++) { ++ if (networks[i] == nullptr || networks[i]->name == nullptr || networks[i]->interface == nullptr) { ++ continue; ++ } ++ auto netIter = m_mutlNetworks.find(networks[i]->name); ++ if (netIter == m_mutlNetworks.end()) { ++ WARN("Cannot found user defined net: %s", networks[i]->name); ++ continue; ++ } ++ if (defaultInterface == networks[i]->interface) { ++ defaultIdx = i; ++ continue; ++ } ++ DeleteFromNetwork((netIter->second).get(), name, ns, networks[i]->interface, podSandboxID, netnsPath, annotations, err); ++ if (err.NotEmpty()) { ++ ERROR("Do teardown user defined net: %s, failed: %s", networks[i]->name, err.GetCMessage()); ++ break; ++ } ++ INFO("Teardown user defained net: %s success", networks[i]->name); ++ } ++ ++ // mask default network pod, if user defined net use same interface ++ if (defaultIdx >= 0) { ++ auto netIter = m_mutlNetworks.find(networks[defaultIdx]->name); ++ if (netIter == m_mutlNetworks.end()) { ++ err.Errorf("Cannot found user defined net: %s", networks[defaultIdx]->name); ++ goto cleanup; ++ } ++ ++ DeleteFromNetwork((netIter->second).get(), name, ns, networks[defaultIdx]->interface, podSandboxID, netnsPath, ++ annotations, err); ++ if (err.NotEmpty()) { ++ ERROR("Do teardown user defined net: %s, failed: %s", networks[defaultIdx]->name, err.GetCMessage()); ++ goto cleanup; ++ } ++ INFO("Teardown default net: %s success", networks[defaultIdx]->name); ++ ret = true; ++ } ++cleanup: ++ free_cri_pod_network(networks, len); ++ return ret; ++} ++ + void CniNetworkPlugin::TearDownPod(const std::string &ns, const std::string &name, const std::string &interfaceName, +- const std::string &id, +- const std::map &annotations, Errors &err) ++ const std::string &id, const std::map &annotations, ++ Errors &err) + { + CheckInitialized(err); + if (err.NotEmpty()) { + return; + } ++ Errors tmpErr; + + std::string netnsPath = m_criImpl->GetNetNS(id, err); + if (err.NotEmpty()) { +@@ -413,8 +584,21 @@ void CniNetworkPlugin::TearDownPod(const std::string &ns, const std::string &nam + return; + } + +- DeleteFromNetwork(m_defaultNetwork.get(), name, ns, interfaceName, id, netnsPath, annotations, err); ++ bool defaultNetDone = TearDownMultNetworks(ns, interfaceName, name, netnsPath, id, annotations, err); ++ if (defaultNetDone) { ++ goto unlock; ++ } ++ if (err.NotEmpty()) { ++ WARN("Teardown user defined networks failed: %s", err.GetCMessage()); ++ } ++ ++ DeleteFromNetwork(m_defaultNetwork.get(), name, ns, interfaceName, id, netnsPath, annotations, tmpErr); ++ if (tmpErr.NotEmpty()) { ++ WARN("Teardown default network failed: %s", tmpErr.GetCMessage()); ++ err.AppendError(tmpErr.GetMessage()); ++ } + ++unlock: + UnlockNetworkMap(err); + } + +@@ -464,7 +648,7 @@ void CniNetworkPlugin::GetPodNetworkStatus(const std::string & /*ns*/, const std + PodNetworkStatus &status, Errors &err) + { + std::string netnsPath; +- std::string ip; ++ std::vector ips; + Errors tmpErr; + + if (podSandboxID.empty()) { +@@ -482,23 +666,23 @@ void CniNetworkPlugin::GetPodNetworkStatus(const std::string & /*ns*/, const std + podSandboxID.c_str()); + goto out; + } +- ip = GetPodIP(m_nsenterPath, netnsPath, interfaceName, err); ++ GetPodIP(m_nsenterPath, netnsPath, interfaceName, ips, err); + if (err.NotEmpty()) { + ERROR("GetPodIP failed: %s", err.GetCMessage()); + goto out; + } +- status.SetIP(ip); ++ status.SetIPs(ips); + + out: +- INFO("get_pod_network_status: %s", podSandboxID.c_str()); ++ INFO("Get pod: %s network status success", podSandboxID.c_str()); + } + +-void CniNetworkPlugin::AddToNetwork(CNINetwork *snetwork, const std::string &podName, +- const std::string &podNamespace, const std::string &interfaceName, +- const std::string &podSandboxID, const std::string &podNetnsPath, ++void CniNetworkPlugin::AddToNetwork(CNINetwork *snetwork, const std::string &podName, const std::string &podNamespace, ++ const std::string &interfaceName, const std::string &podSandboxID, ++ const std::string &podNetnsPath, + const std::map &annotations, +- const std::map &options, +- struct result **presult, Errors &err) ++ const std::map &options, struct result **presult, ++ Errors &err) + { + struct runtime_conf *rc { + nullptr +@@ -510,7 +694,8 @@ void CniNetworkPlugin::AddToNetwork(CNINetwork *snetwork, const std::string &pod + return; + } + +- BuildCNIRuntimeConf(podName, podNamespace, interfaceName, podSandboxID, podNetnsPath, annotations, options, &rc, err); ++ BuildCNIRuntimeConf(podName, podNamespace, interfaceName, podSandboxID, podNetnsPath, annotations, options, &rc, ++ err); + if (err.NotEmpty()) { + ERROR("Error adding network when building cni runtime conf: %s", err.GetCMessage()); + return; +@@ -536,12 +721,10 @@ void CniNetworkPlugin::AddToNetwork(CNINetwork *snetwork, const std::string &pod + free(serr); + } + +-void CniNetworkPlugin::DeleteFromNetwork(CNINetwork *network, +- const std::string &podName, const std::string &podNamespace, +- const std::string &interfaceName, const std::string &podSandboxID, +- const std::string &podNetnsPath, +- const std::map &annotations, +- Errors &err) ++void CniNetworkPlugin::DeleteFromNetwork(CNINetwork *network, const std::string &podName, ++ const std::string &podNamespace, const std::string &interfaceName, ++ const std::string &podSandboxID, const std::string &podNetnsPath, ++ const std::map &annotations, Errors &err) + { + struct runtime_conf *rc { + nullptr +@@ -553,7 +736,8 @@ void CniNetworkPlugin::DeleteFromNetwork(CNINetwork *network, + return; + } + std::map options; +- BuildCNIRuntimeConf(podName, podNamespace, interfaceName, podSandboxID, podNetnsPath, annotations, options, &rc, err); ++ BuildCNIRuntimeConf(podName, podNamespace, interfaceName, podSandboxID, podNetnsPath, annotations, options, &rc, ++ err); + if (err.NotEmpty()) { + ERROR("Error deleting network when building cni runtime conf: %s", err.GetCMessage()); + return; +@@ -579,68 +763,115 @@ void CniNetworkPlugin::DeleteFromNetwork(CNINetwork *network, + free(serr); + } + +-static void PrepareRuntimeConf(const std::string &podName, +- const std::string &podNs, const std::string &interfaceName, ++static bool CheckCNIArgValue(const std::string &val) ++{ ++ if (val.find(';') != std::string::npos) { ++ return false; ++ } ++ if (std::count(val.begin(), val.end(), '=') != 1) { ++ return false; ++ } ++ return true; ++} ++ ++static void GetExtensionCNIArgs(const std::map &annotations, ++ std::map &args) ++{ ++ // get cni multinetwork extension ++ auto iter = annotations.find(CRIHelpers::Constants::CNI_MUTL_NET_EXTENSION_KEY); ++ if (iter != annotations.end()) { ++ if (!CheckCNIArgValue(iter->second)) { ++ WARN("Ignore: invalid multinetwork cni args: %s", iter->second.c_str()); ++ } else { ++ args[CRIHelpers::Constants::CNI_MUTL_NET_EXTENSION_ARGS_KEY] = iter->second; ++ } ++ } ++ ++ for (const auto &work : annotations) { ++ if (work.first.find(CRIHelpers::Constants::CNI_ARGS_EXTENSION_PREFIX_KEY) != 0) { ++ continue; ++ } ++ if (!CheckCNIArgValue(work.second)) { ++ WARN("Ignore: invalid extension cni args: %s", work.second.c_str()); ++ continue; ++ } ++ auto strs = CXXUtils::Split(work.second, '='); ++ iter = annotations.find(work.first); ++ if (iter != annotations.end()) { ++ WARN("Ignore: Same key cni args: %s", work.first.c_str()); ++ continue; ++ } ++ args[strs[0]] = strs[1]; ++ } ++} ++ ++static void PrepareRuntimeConf(const std::string &podName, const std::string &podNs, const std::string &interfaceName, + const std::string &podSandboxID, const std::string &podNetnsPath, +- const std::map &options, +- struct runtime_conf **cni_rc, Errors &err) ++ const std::map &annotations, ++ const std::map &options, struct runtime_conf **cni_rc, ++ Errors &err) + { +- const size_t defaultLen = 5; ++ size_t workLen = 5; ++ std::map cniArgs; ++ + if (cni_rc == nullptr) { + err.Errorf("Invalid arguments"); + ERROR("Invalid arguments"); + return; + } + +- auto iter = options.find("UID"); +- std::string podUID; +- if (iter != options.end()) { +- podUID = iter->second; +- } +- + struct runtime_conf *rt = (struct runtime_conf *)util_common_calloc_s(sizeof(struct runtime_conf)); + if (rt == nullptr) { + ERROR("Out of memory"); + err.SetError("Out of memory"); + return; + } +- + rt->container_id = util_strdup_s(podSandboxID.c_str()); + rt->netns = util_strdup_s(podNetnsPath.c_str()); + rt->ifname = util_strdup_s(interfaceName.c_str()); + +- rt->args = (char *(*)[2])util_common_calloc_s(sizeof(char *) * 2 * defaultLen); ++ auto iter = options.find("UID"); ++ std::string podUID; ++ if (iter != options.end()) { ++ podUID = iter->second; ++ } ++ ++ cniArgs["K8S_POD_UID"] = podUID; ++ cniArgs["IgnoreUnknown"] = "1"; ++ cniArgs["K8S_POD_NAMESPACE"] = podNs; ++ cniArgs["K8S_POD_NAME"] = podName; ++ cniArgs["K8S_POD_INFRA_CONTAINER_ID"] = podSandboxID; ++ ++ GetExtensionCNIArgs(annotations, cniArgs); ++ workLen = cniArgs.size(); ++ ++ rt->args = (char *(*)[2])util_common_calloc_s(sizeof(char *) * 2 * workLen); + if (rt->args == nullptr) { + ERROR("Out of memory"); + err.SetError("Out of memory"); +- goto free_out; ++ free_runtime_conf(rt); ++ return; ++ } ++ rt->args_len = workLen; ++ ++ workLen = 0; ++ for (const auto &work : cniArgs) { ++ rt->args[workLen][0] = util_strdup_s(work.first.c_str()); ++ rt->args[workLen][1] = util_strdup_s(work.second.c_str()); ++ workLen++; + } +- rt->args_len = defaultLen; +- rt->args[0][0] = util_strdup_s("IgnoreUnknown"); +- rt->args[0][1] = util_strdup_s("1"); +- rt->args[1][0] = util_strdup_s("K8S_POD_NAMESPACE"); +- rt->args[1][1] = util_strdup_s(podNs.c_str()); +- rt->args[2][0] = util_strdup_s("K8S_POD_NAME"); +- rt->args[2][1] = util_strdup_s(podName.c_str()); +- rt->args[3][0] = util_strdup_s("K8S_POD_INFRA_CONTAINER_ID"); +- rt->args[3][1] = util_strdup_s(podSandboxID.c_str()); +- rt->args[4][0] = util_strdup_s("K8S_POD_UID"); +- rt->args[4][1] = util_strdup_s(podUID.c_str()); + + *cni_rc = rt; +- return; +-free_out: +- free_runtime_conf(rt); + } + +-void CniNetworkPlugin::BuildCNIRuntimeConf(const std::string &podName, +- const std::string &podNs, const std::string &interfaceName, +- const std::string &podSandboxID, const std::string &podNetnsPath, ++void CniNetworkPlugin::BuildCNIRuntimeConf(const std::string &podName, const std::string &podNs, ++ const std::string &interfaceName, const std::string &podSandboxID, ++ const std::string &podNetnsPath, + const std::map &annotations, + const std::map &options, + struct runtime_conf **cni_rc, Errors &err) + { +- PrepareRuntimeConf(podName, podNs, interfaceName, podSandboxID, podNetnsPath, options, cni_rc, err); ++ PrepareRuntimeConf(podName, podNs, interfaceName, podSandboxID, podNetnsPath, annotations, options, cni_rc, err); + if (err.NotEmpty()) { + return; + } +@@ -697,7 +928,7 @@ void CniNetworkPlugin::BuildCNIRuntimeConf(const std::string &podName, + rt->p_mapping[rt->p_mapping_len]->container_port = *(portMapping.GetContainerPort()); + } + if (portMapping.GetProtocol() != nullptr) { +- rt->p_mapping[rt->p_mapping_len]->protocol = strings_to_lower(portMapping.GetProtocol()->c_str()); ++ rt->p_mapping[rt->p_mapping_len]->protocol = util_strings_to_lower(portMapping.GetProtocol()->c_str()); + } + // ignore hostip, because GetPodPortMappings() don't set + (rt->p_mapping_len)++; +@@ -714,7 +945,8 @@ void CniNetworkPlugin::RLockNetworkMap(Errors &error) + { + int ret = pthread_rwlock_rdlock(&m_netsLock); + if (ret != 0) { +- error.Errorf("Get read lock failed: %s", strerror(ret)); ++ error.Errorf("Failed to get read lock"); ++ ERROR("Get read lock failed: %s", strerror(ret)); + } + } + +@@ -722,7 +954,8 @@ void CniNetworkPlugin::WLockNetworkMap(Errors &error) + { + int ret = pthread_rwlock_wrlock(&m_netsLock); + if (ret != 0) { +- error.Errorf("Get write lock failed: %s", strerror(ret)); ++ error.Errorf("Failed to get write lock"); ++ ERROR("Get write lock failed: %s", strerror(ret)); + } + } + +@@ -730,7 +963,8 @@ void CniNetworkPlugin::UnlockNetworkMap(Errors &error) + { + int ret = pthread_rwlock_unlock(&m_netsLock); + if (ret != 0) { +- error.Errorf("Unlock failed: %s", strerror(ret)); ++ error.Errorf("Failed to unlock"); ++ ERROR("Unlock failed: %s", strerror(ret)); + } + } + +diff --git a/src/daemon/entry/cri/cni_network_plugin.h b/src/daemon/entry/cri/cni_network_plugin.h +index 02c95fb..c59c200 100644 +--- a/src/daemon/entry/cri/cni_network_plugin.h ++++ b/src/daemon/entry/cri/cni_network_plugin.h +@@ -146,6 +146,9 @@ private: + void RLockNetworkMap(Errors &error); + void WLockNetworkMap(Errors &error); + void UnlockNetworkMap(Errors &error); ++ ++ void UpdateMutlNetworks(std::vector> &multNets, std::vector &binDirs, ++ Errors &err); + void SetDefaultNetwork(std::unique_ptr network, std::vector &binDirs, Errors &err); + void SetPodCidr(const std::string &podCidr); + static auto GetCNIConfFiles(const std::string &pluginDir, std::vector &vect_files, Errors &err) -> int; +@@ -155,10 +158,19 @@ private: + void ResetCNINetwork(std::map> &newNets, Errors &err); + void UpdateDefaultNetwork(); + ++ bool SetupMultNetworks(const std::string &ns, const std::string &defaultInterface, const std::string &name, ++ const std::string &netnsPath, const std::string &podSandboxID, const std::map &annotations, ++ const std::map &options, Errors &err); ++ ++ bool TearDownMultNetworks(const std::string &ns, const std::string &defaultInterface, const std::string &name, ++ const std::string &netnsPath, const std::string &podSandboxID, const std::map &annotations, ++ Errors &err); ++ + NoopNetworkPlugin m_noop; + std::unique_ptr m_loNetwork { nullptr }; +- + std::unique_ptr m_defaultNetwork { nullptr }; ++ std::map> m_mutlNetworks; ++ + CRIRuntimeServiceImpl *m_criImpl { nullptr }; + std::string m_nsenterPath; + std::string m_confDir; +diff --git a/src/daemon/entry/cri/cri_container.cc b/src/daemon/entry/cri/cri_container.cc +index f6a2558..e23e59e 100644 +--- a/src/daemon/entry/cri/cri_container.cc ++++ b/src/daemon/entry/cri/cri_container.cc +@@ -37,8 +37,7 @@ + #include "url.h" + #include "ws_server.h" + +-auto CRIRuntimeServiceImpl::GetRealContainerOrSandboxID(const std::string &id, bool isSandbox, +- Errors &error) -> std::string ++std::string CRIRuntimeServiceImpl::GetRealContainerOrSandboxID(const std::string &id, bool isSandbox, Errors &error) + { + std::string realID; + +@@ -121,20 +120,20 @@ void CRIRuntimeServiceImpl::GetContainerTimeStamps(container_inspect *inspect, i + return; + } + if (createdAt != nullptr) { +- if (to_unix_nanos_from_str(inspect->created, createdAt) != 0) { ++ if (util_to_unix_nanos_from_str(inspect->created, createdAt) != 0) { + err.Errorf("Parse createdAt failed: %s", inspect->created); + return; + } + } + if (inspect->state != nullptr) { + if (startedAt != nullptr) { +- if (to_unix_nanos_from_str(inspect->state->started_at, startedAt) != 0) { ++ if (util_to_unix_nanos_from_str(inspect->state->started_at, startedAt) != 0) { + err.Errorf("Parse startedAt failed: %s", inspect->state->started_at); + return; + } + } + if (finishedAt != nullptr) { +- if (to_unix_nanos_from_str(inspect->state->finished_at, finishedAt) != 0) { ++ if (util_to_unix_nanos_from_str(inspect->state->finished_at, finishedAt) != 0) { + err.Errorf("Parse finishedAt failed: %s", inspect->state->finished_at); + return; + } +@@ -169,14 +168,15 @@ auto CRIRuntimeServiceImpl::GenerateCreateContainerCustomConfig( + if (!podSandboxConfig.log_directory().empty() || !containerConfig.log_path().empty()) { + std::string logpath = podSandboxConfig.log_directory() + "/" + containerConfig.log_path(); + char real_logpath[PATH_MAX] { 0 }; +- if (cleanpath(logpath.c_str(), real_logpath, sizeof(real_logpath)) == nullptr) { ++ if (util_clean_path(logpath.c_str(), real_logpath, sizeof(real_logpath)) == nullptr) { + ERROR("Failed to clean path: %s", logpath.c_str()); + error.Errorf("Failed to clean path: %s", logpath.c_str()); + goto cleanup; + } + + if (append_json_map_string_string(custom_config->labels, +- CRIHelpers::Constants::CONTAINER_LOGPATH_LABEL_KEY.c_str(), real_logpath) != 0) { ++ CRIHelpers::Constants::CONTAINER_LOGPATH_LABEL_KEY.c_str(), ++ real_logpath) != 0) { + error.SetError("Append map string string failed"); + goto cleanup; + } +@@ -269,7 +269,7 @@ auto CRIRuntimeServiceImpl::PackCreateContainerHostConfigSecurityContext( + } + size_t newSize = (hostconfig->security_opt_len + securityOpts.size()) * sizeof(char *); + size_t oldSize = hostconfig->security_opt_len * sizeof(char *); +- int ret = mem_realloc((void **)(&tmp_security_opt), newSize, (void *)hostconfig->security_opt, oldSize); ++ int ret = util_mem_realloc((void **)(&tmp_security_opt), newSize, (void *)hostconfig->security_opt, oldSize); + if (ret != 0) { + error.Errorf("Out of memory"); + return -1; +@@ -322,10 +322,11 @@ cleanup: + return nullptr; + } + +-auto CRIRuntimeServiceImpl::GenerateCreateContainerRequest(const std::string &realPodSandboxID, +- const runtime::v1alpha2::ContainerConfig &containerConfig, +- const runtime::v1alpha2::PodSandboxConfig &podSandboxConfig, +- const std::string &podSandboxRuntime, Errors &error) -> container_create_request * ++container_create_request * ++CRIRuntimeServiceImpl::GenerateCreateContainerRequest(const std::string &realPodSandboxID, ++ const runtime::v1alpha2::ContainerConfig &containerConfig, ++ const runtime::v1alpha2::PodSandboxConfig &podSandboxConfig, ++ const std::string &podSandboxRuntime, Errors &error) + { + struct parser_context ctx { + OPT_GEN_SIMPLIFY, 0 +@@ -393,10 +394,10 @@ cleanup: + return request; + } + +-auto CRIRuntimeServiceImpl::CreateContainer(const std::string &podSandboxID, +- const runtime::v1alpha2::ContainerConfig &containerConfig, +- const runtime::v1alpha2::PodSandboxConfig &podSandboxConfig, +- Errors &error) -> std::string ++std::string CRIRuntimeServiceImpl::CreateContainer(const std::string &podSandboxID, ++ const runtime::v1alpha2::ContainerConfig &containerConfig, ++ const runtime::v1alpha2::PodSandboxConfig &podSandboxConfig, ++ Errors &error) + { + std::string response_id; + std::string podSandboxRuntime; +@@ -787,6 +788,12 @@ void CRIRuntimeServiceImpl::ListContainersFromGRPC(const runtime::v1alpha2::Cont + error.SetError("Out of memory"); + return; + } ++ // Add filter to get only non-sandbox containers ++ if (CRIHelpers::FiltersAddLabel((*request)->filters, CRIHelpers::Constants::CONTAINER_TYPE_LABEL_KEY, ++ CRIHelpers::Constants::CONTAINER_TYPE_LABEL_CONTAINER) != 0) { ++ error.SetError("Failed to add filter"); ++ return; ++ } + + if (filter != nullptr) { + if (!filter->id().empty()) { +@@ -810,12 +817,6 @@ void CRIRuntimeServiceImpl::ListContainersFromGRPC(const runtime::v1alpha2::Cont + } + } + +- // Add some label +- if (CRIHelpers::FiltersAddLabel((*request)->filters, CRIHelpers::Constants::CONTAINER_TYPE_LABEL_KEY, +- CRIHelpers::Constants::CONTAINER_TYPE_LABEL_CONTAINER) != 0) { +- error.SetError("Failed to add filter"); +- return; +- } + for (auto &iter : filter->label_selector()) { + if (CRIHelpers::FiltersAddLabel((*request)->filters, iter.first, iter.second) != 0) { + error.SetError("Failed to add filter"); +@@ -1186,8 +1187,8 @@ void CRIRuntimeServiceImpl::ContainerStatusToGRPC(container_inspect *inspect, + ConvertMountsToStatus(inspect, contStatus); + } + +-auto CRIRuntimeServiceImpl::ContainerStatus(const std::string &containerID, +- Errors &error) -> std::unique_ptr ++std::unique_ptr ++CRIRuntimeServiceImpl::ContainerStatus(const std::string &containerID, Errors &error) + { + if (containerID.empty()) { + error.SetError("Empty pod sandbox id"); +diff --git a/src/daemon/entry/cri/cri_helpers.cc b/src/daemon/entry/cri/cri_helpers.cc +index bfb1d4a..34d32e5 100644 +--- a/src/daemon/entry/cri/cri_helpers.cc ++++ b/src/daemon/entry/cri/cri_helpers.cc +@@ -51,19 +51,22 @@ const std::string Constants::CONTAINER_TYPE_ANNOTATION_SANDBOX { "sandbox" }; + const std::string Constants::SANDBOX_ID_ANNOTATION_KEY { "io.kubernetes.cri.sandbox-id" }; + const std::string Constants::NET_PLUGIN_EVENT_POD_CIDR_CHANGE { "pod-cidr-change" }; + const std::string Constants::NET_PLUGIN_EVENT_POD_CIDR_CHANGE_DETAIL_CIDR { "pod-cidr" }; ++const std::string Constants::CNI_MUTL_NET_EXTENSION_KEY { "extension.network.kubernetes.io/cni" }; ++const std::string Constants::CNI_MUTL_NET_EXTENSION_ARGS_KEY { "CNI_MUTLINET_EXTENSION" }; ++const std::string Constants::CNI_ARGS_EXTENSION_PREFIX_KEY { "extension.network.kubernetes.io/cniargs/" }; + +-const char *InternalLabelKeys[] = { +- CRIHelpers::Constants::CONTAINER_TYPE_LABEL_KEY.c_str(), +- CRIHelpers::Constants::CONTAINER_LOGPATH_LABEL_KEY.c_str(), +- CRIHelpers::Constants::SANDBOX_ID_LABEL_KEY.c_str(), nullptr +-}; ++const char *InternalLabelKeys[] = { CRIHelpers::Constants::CONTAINER_TYPE_LABEL_KEY.c_str(), ++ CRIHelpers::Constants::CONTAINER_LOGPATH_LABEL_KEY.c_str(), ++ CRIHelpers::Constants::SANDBOX_ID_LABEL_KEY.c_str(), nullptr ++ }; + + auto GetDefaultSandboxImage(Errors &err) -> std::string + { + const std::string defaultPodSandboxImageName { "pause" }; + const std::string defaultPodSandboxImageVersion { "3.0" }; + std::string machine; +- struct utsname uts {}; ++ struct utsname uts { ++ }; + + if (uname(&uts) < 0) { + err.SetError("Failed to read host arch."); +@@ -85,8 +88,8 @@ auto GetDefaultSandboxImage(Errors &err) -> std::string + return defaultPodSandboxImageName + "-" + machine + ":" + defaultPodSandboxImageVersion; + } + +-auto MakeLabels(const google::protobuf::Map &mapLabels, +- Errors &error) -> json_map_string_string * ++auto MakeLabels(const google::protobuf::Map &mapLabels, Errors &error) ++-> json_map_string_string * + { + json_map_string_string *labels = (json_map_string_string *)util_common_calloc_s(sizeof(json_map_string_string)); + if (labels == nullptr) { +@@ -112,8 +115,8 @@ cleanup: + return nullptr; + } + +-auto MakeAnnotations(const google::protobuf::Map &mapAnnotations, +- Errors &error) -> json_map_string_string * ++auto MakeAnnotations(const google::protobuf::Map &mapAnnotations, Errors &error) ++-> json_map_string_string * + { + json_map_string_string *annotations = + (json_map_string_string *)util_common_calloc_s(sizeof(json_map_string_string)); +@@ -386,8 +389,8 @@ auto sha256(const char *val) -> std::string + return outputBuffer; + } + +-auto GetNetworkPlaneFromPodAnno(const google::protobuf::Map &annotations, +- size_t *len, Errors &error) -> cri_pod_network_element ** ++auto GetNetworkPlaneFromPodAnno(const std::map &annotations, size_t *len, ++ Errors &error) -> cri_pod_network_element ** + { + auto iter = annotations.find(CRIHelpers::Constants::POD_NETWORK_ANNOTATION_KEY); + +@@ -396,7 +399,7 @@ auto GetNetworkPlaneFromPodAnno(const google::protobuf::Mapsecond.c_str(), nullptr, &err, len); + if (result == nullptr) { +- error.Errorf("parse pod network json failed: %s", err); ++ error.Errorf("parse pod network json: %s failed: %s", iter->second.c_str(), err); + } + free(err); + } +@@ -404,8 +407,8 @@ auto GetNetworkPlaneFromPodAnno(const google::protobuf::Map std::unique_ptr ++auto CheckpointToSandbox(const std::string &id, const cri::PodSandboxCheckpoint &checkpoint) ++-> std::unique_ptr + { + std::unique_ptr result(new (std::nothrow) runtime::v1alpha2::PodSandbox); + if (result == nullptr) { +@@ -507,8 +510,8 @@ void GenerateMountBindings(const google::protobuf::RepeatedPtrField &envs) -> std::vector ++auto GenerateEnvList(const ::google::protobuf::RepeatedPtrField<::runtime::v1alpha2::KeyValue> &envs) ++-> std::vector + { + std::vector vect; + std::for_each(envs.begin(), envs.end(), [&vect](const ::runtime::v1alpha2::KeyValue & elem) { +@@ -568,7 +571,8 @@ auto GetSeccompiSuladOpts(const std::string &seccompProfile, Errors &error) -> s + if (seccompProfile.empty() || seccompProfile == "unconfined") { + return std::vector { { "seccomp", "unconfined", "" } }; + } +- if (seccompProfile == "iSulad/default" || seccompProfile == "docker/default" || seccompProfile == "runtime/default") { ++ if (seccompProfile == "iSulad/default" || seccompProfile == "docker/default" || ++ seccompProfile == "runtime/default") { + // return nil so docker will load the default seccomp profile + return std::vector {}; + } +@@ -578,7 +582,7 @@ auto GetSeccompiSuladOpts(const std::string &seccompProfile, Errors &error) -> s + } + std::string fname = seccompProfile.substr(std::string("localhost/").length(), seccompProfile.length()); + char dstpath[PATH_MAX] { 0 }; +- if (cleanpath(fname.c_str(), dstpath, sizeof(dstpath)) == nullptr) { ++ if (util_clean_path(fname.c_str(), dstpath, sizeof(dstpath)) == nullptr) { + error.Errorf("failed to get clean path"); + return std::vector {}; + } +@@ -609,8 +613,8 @@ auto GetSeccompiSuladOpts(const std::string &seccompProfile, Errors &error) -> s + return ret; + } + +-auto GetSeccompSecurityOpts(const std::string &seccompProfile, const char &separator, +- Errors &error) -> std::vector ++auto GetSeccompSecurityOpts(const std::string &seccompProfile, const char &separator, Errors &error) ++-> std::vector + { + std::vector seccompOpts = GetSeccompiSuladOpts(seccompProfile, error); + if (error.NotEmpty()) { +@@ -620,8 +624,8 @@ auto GetSeccompSecurityOpts(const std::string &seccompProfile, const char &separ + return fmtiSuladOpts(seccompOpts, separator); + } + +-auto GetSecurityOpts(const std::string &seccompProfile, const char &separator, +- Errors &error) -> std::vector ++auto GetSecurityOpts(const std::string &seccompProfile, const char &separator, Errors &error) ++-> std::vector + { + std::vector seccompSecurityOpts = GetSeccompSecurityOpts(seccompProfile, separator, error); + if (error.NotEmpty()) { +diff --git a/src/daemon/entry/cri/cri_helpers.h b/src/daemon/entry/cri/cri_helpers.h +index 9dd3630..b9fb153 100644 +--- a/src/daemon/entry/cri/cri_helpers.h ++++ b/src/daemon/entry/cri/cri_helpers.h +@@ -56,6 +56,9 @@ public: + + static const std::string NET_PLUGIN_EVENT_POD_CIDR_CHANGE; + static const std::string NET_PLUGIN_EVENT_POD_CIDR_CHANGE_DETAIL_CIDR; ++ static const std::string CNI_MUTL_NET_EXTENSION_KEY; ++ static const std::string CNI_MUTL_NET_EXTENSION_ARGS_KEY; ++ static const std::string CNI_ARGS_EXTENSION_PREFIX_KEY; + }; + + auto GetDefaultSandboxImage(Errors &err) -> std::string; +@@ -91,7 +94,7 @@ auto IsImageNotFoundError(const std::string &err) -> bool; + + auto sha256(const char *val) -> std::string; + +-auto GetNetworkPlaneFromPodAnno(const google::protobuf::Map &annotations, ++auto GetNetworkPlaneFromPodAnno(const std::map &annotations, + size_t *len, Errors &error) -> cri_pod_network_element **; + + auto CheckpointToSandbox(const std::string &id, +diff --git a/src/daemon/entry/cri/cri_runtime_service.h b/src/daemon/entry/cri/cri_runtime_service.h +index 66837e9..1a0f601 100644 +--- a/src/daemon/entry/cri/cri_runtime_service.h ++++ b/src/daemon/entry/cri/cri_runtime_service.h +@@ -210,9 +210,12 @@ private: + void ConstructPodSandboxCheckpoint(const runtime::v1alpha2::PodSandboxConfig &config, + cri::PodSandboxCheckpoint &checkpoint); + +- auto GetIP(const std::string &podSandboxID, container_inspect *inspect, const std::string &networkInterface, +- Errors &error) -> std::string; +- auto GetIPFromPlugin(container_inspect *inspect, const std::string &networkInterface, Errors &error) -> std::string; ++ void GetIPs(const std::string &podSandboxID, container_inspect *inspect, const std::string &networkInterface, ++ std::vector &ips, Errors &error); ++ void GetFormatIPsForMultNet(container_inspect *inspect, const std::string &defaultInterface, ++ const runtime::v1alpha2::PodSandboxMetadata &metadata, std::vector &result, Errors &error); ++ auto GetIPsFromPlugin(container_inspect *inspect, const std::string &networkInterface, ++ Errors &error) -> std::vector; + auto GetNetworkReady(const std::string &podSandboxID, Errors &error) -> bool; + void SetNetworkReady(const std::string &podSandboxID, bool ready, Errors &error); + void ClearNetworkReady(const std::string &podSandboxID); +@@ -247,9 +250,6 @@ private: + + void SetupSandboxNetwork(const runtime::v1alpha2::PodSandboxConfig &config, const std::string &response_id, + const std::string &jsonCheckpoint, Errors &error); +- void SetupUserDefinedNetworkPlane(const runtime::v1alpha2::PodSandboxConfig &config, const std::string &response_id, +- container_inspect *inspect_data, std::map &stdAnnos, +- std::map &options, Errors &error); + void StartSandboxContainer(const std::string &response_id, Errors &error); + auto CreateSandboxContainer(const runtime::v1alpha2::PodSandboxConfig &config, const std::string &image, + std::string &jsonCheckpoint, const std::string &runtimeHandler, +@@ -273,6 +273,7 @@ private: + auto ClearCniNetwork(const std::string &realSandboxID, bool hostNetwork, const std::string &ns, + const std::string &name, std::vector &errlist, + std::map &stdAnnos, Errors &error) -> int; ++ + auto RemoveAllContainersInSandbox(const std::string &realSandboxID, std::vector &errors) -> int; + auto DoRemovePodSandbox(const std::string &realSandboxID, std::vector &errors) -> int; + static void MergeSecurityContextToHostConfig(const runtime::v1alpha2::PodSandboxConfig &c, host_config *hc, +diff --git a/src/daemon/entry/cri/cri_sandbox.cc b/src/daemon/entry/cri/cri_sandbox.cc +index 540e8b3..b44c86c 100644 +--- a/src/daemon/entry/cri/cri_sandbox.cc ++++ b/src/daemon/entry/cri/cri_sandbox.cc +@@ -116,16 +116,14 @@ void CRIRuntimeServiceImpl::ConstructPodSandboxCheckpoint(const runtime::v1alpha + } + + void CRIRuntimeServiceImpl::ApplySandboxResources(const runtime::v1alpha2::LinuxPodSandboxConfig * /*lc*/, +- host_config *hc, +- Errors & /*error*/) ++ host_config *hc, Errors & /*error*/) + { + hc->memory_swap = CRIRuntimeService::Constants::DefaultMemorySwap; + hc->cpu_shares = CRIRuntimeService::Constants::DefaultSandboxCPUshares; + } + + void CRIRuntimeServiceImpl::ApplySandboxLinuxOptions(const runtime::v1alpha2::LinuxPodSandboxConfig &lc, +- host_config *hc, container_config *custom_config, +- Errors &error) ++ host_config *hc, container_config *custom_config, Errors &error) + { + CRISecurity::ApplySandboxSecurityContext(lc, custom_config, hc, error); + if (error.NotEmpty()) { +@@ -184,7 +182,7 @@ void CRIRuntimeServiceImpl::MergeSecurityContextToHostConfig(const runtime::v1al + } + size_t newSize = (hc->security_opt_len + securityOpts.size()) * sizeof(char *); + size_t oldSize = hc->security_opt_len * sizeof(char *); +- int ret = mem_realloc((void **)(&tmp_security_opt), newSize, (void *)hc->security_opt, oldSize); ++ int ret = util_mem_realloc((void **)(&tmp_security_opt), newSize, (void *)hc->security_opt, oldSize); + if (ret != 0) { + error.Errorf("Out of memory"); + return; +@@ -258,7 +256,7 @@ void CRIRuntimeServiceImpl::MakeSandboxIsuladConfig(const runtime::v1alpha2::Pod + } + size_t newSize = (hc->security_opt_len + securityOpts.size()) * sizeof(char *); + size_t oldSize = hc->security_opt_len * sizeof(char *); +- int ret = mem_realloc((void **)(&tmp_security_opt), newSize, (void *)hc->security_opt, oldSize); ++ int ret = util_mem_realloc((void **)(&tmp_security_opt), newSize, (void *)hc->security_opt, oldSize); + if (ret != 0) { + error.Errorf("Out of memory"); + return; +@@ -292,9 +290,9 @@ void CRIRuntimeServiceImpl::SetupSandboxFiles(const std::string &resolvPath, + resolvContentStrs.push_back("nameserver " + CXXUtils::StringsJoin(servers, "\nnameserver ")); + } + +- std::vector searchs(config.dns_config().searches().begin(), config.dns_config().searches().end()); +- if (!searchs.empty()) { +- resolvContentStrs.push_back("search " + CXXUtils::StringsJoin(searchs, " ")); ++ std::vector searches(config.dns_config().searches().begin(), config.dns_config().searches().end()); ++ if (!searches.empty()) { ++ resolvContentStrs.push_back("search " + CXXUtils::StringsJoin(searches, " ")); + } + + std::vector options(config.dns_config().options().begin(), config.dns_config().options().end()); +@@ -304,17 +302,16 @@ void CRIRuntimeServiceImpl::SetupSandboxFiles(const std::string &resolvPath, + + if (!resolvContentStrs.empty()) { + std::string resolvContent = CXXUtils::StringsJoin(resolvContentStrs, "\n") + "\n"; +- if (util_write_file(resolvPath.c_str(), resolvContent.c_str(), resolvContent.size(), DEFAULT_SECURE_FILE_MODE) != 0) { ++ if (util_write_file(resolvPath.c_str(), resolvContent.c_str(), resolvContent.size(), ++ DEFAULT_SECURE_FILE_MODE) != 0) { + error.SetError("Failed to write resolv content"); + } + } + } + +-auto CRIRuntimeServiceImpl::PackCreateContainerRequest( +- const runtime::v1alpha2::PodSandboxConfig &config, +- const std::string &image, host_config *hostconfig, +- container_config *custom_config, +- const std::string &runtimeHandler, Errors &error) -> container_create_request * ++container_create_request *CRIRuntimeServiceImpl::PackCreateContainerRequest( ++ const runtime::v1alpha2::PodSandboxConfig &config, const std::string &image, host_config *hostconfig, ++ container_config *custom_config, const std::string &runtimeHandler, Errors &error) + { + struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 }; + parser_error perror = nullptr; +@@ -353,11 +350,10 @@ error_out: + return nullptr; + } + +-auto CRIRuntimeServiceImpl::GenerateSandboxCreateContainerRequest( +- const runtime::v1alpha2::PodSandboxConfig &config, +- const std::string &image, std::string &jsonCheckpoint, +- const std::string &runtimeHandler, +- Errors &error) -> container_create_request * ++container_create_request * ++CRIRuntimeServiceImpl::GenerateSandboxCreateContainerRequest(const runtime::v1alpha2::PodSandboxConfig &config, ++ const std::string &image, std::string &jsonCheckpoint, ++ const std::string &runtimeHandler, Errors &error) + { + container_create_request *create_request = nullptr; + host_config *hostconfig = nullptr; +@@ -415,8 +411,7 @@ cleanup: + + auto CRIRuntimeServiceImpl::CreateSandboxContainer(const runtime::v1alpha2::PodSandboxConfig &config, + const std::string &image, std::string &jsonCheckpoint, +- const std::string &runtimeHandler, +- Errors &error) -> std::string ++ const std::string &runtimeHandler, Errors &error) -> std::string + { + std::string response_id; + container_create_request *create_request = +@@ -463,44 +458,6 @@ void CRIRuntimeServiceImpl::StartSandboxContainer(const std::string &response_id + free_container_start_response(start_response); + } + +-void CRIRuntimeServiceImpl::SetupUserDefinedNetworkPlane(const runtime::v1alpha2::PodSandboxConfig &config, +- const std::string &response_id, +- container_inspect *inspect_data, +- std::map &stdAnnos, +- std::map &options, Errors &error) +-{ +- google::protobuf::Map annotations; +- CRIHelpers::ExtractAnnotations(inspect_data->config->annotations, annotations); +- +- size_t len = 0; +- cri_pod_network_element **networks = CRIHelpers::GetNetworkPlaneFromPodAnno(annotations, &len, error); +- if (error.NotEmpty()) { +- ERROR("Couldn't get network plane from pod annotations: %s", error.GetCMessage()); +- error.Errorf("Couldn't get network plane from pod annotations: %s", error.GetCMessage()); +- goto cleanup; +- } +- for (size_t i = 0; i < len; i++) { +- if ((networks[i] != nullptr) && (networks[i]->name != nullptr) && (networks[i]->interface != nullptr) && +- strcmp(networks[i]->name, Network::DEFAULT_NETWORK_PLANE_NAME.c_str()) != 0) { +- INFO("SetupPod net: %s", networks[i]->name); +- m_pluginManager->SetUpPod(config.metadata().namespace_(), config.metadata().name(), networks[i]->interface, response_id, +- stdAnnos, options, error); +- if (error.Empty()) { +- continue; +- } +- Errors tmpErr; +- StopContainerHelper(response_id, tmpErr); +- if (tmpErr.NotEmpty()) { +- WARN("Failed to stop sandbox container %s for pod %s: %s", response_id.c_str(), networks[i]->name, +- tmpErr.GetCMessage()); +- } +- goto cleanup; +- } +- } +-cleanup: +- free_cri_pod_network(networks, len); +-} +- + void CRIRuntimeServiceImpl::SetupSandboxNetwork(const runtime::v1alpha2::PodSandboxConfig &config, + const std::string &response_id, const std::string &jsonCheckpoint, + Errors &error) +@@ -545,8 +502,7 @@ cleanup: + } + + auto CRIRuntimeServiceImpl::RunPodSandbox(const runtime::v1alpha2::PodSandboxConfig &config, +- const std::string &runtimeHandler, +- Errors &error) -> std::string ++ const std::string &runtimeHandler, Errors &error) -> std::string + { + std::string response_id; + std::string jsonCheckpoint; +@@ -597,8 +553,7 @@ cleanup: + } + + auto CRIRuntimeServiceImpl::GetRealSandboxIDToStop(const std::string &podSandboxID, bool &hostNetwork, +- std::string &name, +- std::string &ns, std::string &realSandboxID, ++ std::string &name, std::string &ns, std::string &realSandboxID, + std::map &stdAnnos, Errors &error) -> int + { + Errors statusErr; +@@ -692,55 +647,18 @@ cleanup: + return ret; + } + +-auto CRIRuntimeServiceImpl::TearDownPodCniNetwork(const std::string &realSandboxID, std::vector &errlist, +- std::map &stdAnnos, const std::string &ns, +- const std::string &name, Errors &error) -> int +-{ +- int ret = 0; +- cri_pod_network_element **networks = nullptr; +- container_inspect *inspect_data = InspectContainer(realSandboxID, error); +- if (inspect_data == nullptr) { +- return -1; +- } +- +- google::protobuf::Map annotations; +- CRIHelpers::ExtractAnnotations(inspect_data->config->annotations, annotations); +- size_t len = 0; +- +- networks = CRIHelpers::GetNetworkPlaneFromPodAnno(annotations, &len, error); +- if (error.NotEmpty()) { +- ERROR("Couldn't get network plane from pod annotations: %s", error.GetCMessage()); +- error.Errorf("Couldn't get network plane from pod annotations: %s", error.GetCMessage()); +- ret = -1; +- goto cleanup; +- } +- for (size_t i = 0; i < len; i++) { +- if ((networks[i] != nullptr) && (networks[i]->name != nullptr) && (networks[i]->interface != nullptr) && +- strcmp(networks[i]->name, Network::DEFAULT_NETWORK_PLANE_NAME.c_str()) != 0) { +- Errors tmpErr; +- m_pluginManager->TearDownPod(ns, name, networks[i]->interface, inspect_data->id, stdAnnos, tmpErr); +- if (tmpErr.NotEmpty()) { +- WARN("TearDownPod cni network failed: %s", tmpErr.GetCMessage()); +- errlist.push_back(tmpErr.GetMessage()); +- } +- } +- } +-cleanup: +- free_cri_pod_network(networks, len); +- free_container_inspect(inspect_data); +- return ret; +-} +- + auto CRIRuntimeServiceImpl::ClearCniNetwork(const std::string &realSandboxID, bool hostNetwork, const std::string &ns, + const std::string &name, std::vector &errlist, +- std::map &stdAnnos, Errors & /*error*/) -> int ++ std::map &stdAnnos, Errors & ++ /*error*/) -> int + { + Errors networkErr; + + bool ready = GetNetworkReady(realSandboxID, networkErr); + if (!hostNetwork && (ready || networkErr.NotEmpty())) { + Errors pluginErr; +- m_pluginManager->TearDownPod(ns, name, Network::DEFAULT_NETWORK_INTERFACE_NAME, realSandboxID, stdAnnos, pluginErr); ++ m_pluginManager->TearDownPod(ns, name, Network::DEFAULT_NETWORK_INTERFACE_NAME, realSandboxID, stdAnnos, ++ pluginErr); + if (pluginErr.NotEmpty()) { + WARN("TearDownPod cni network failed: %s", pluginErr.GetCMessage()); + errlist.push_back(pluginErr.GetMessage()); +@@ -828,8 +746,7 @@ cleanup: + free_container_stop_response(response); + } + +-auto CRIRuntimeServiceImpl::DoRemovePodSandbox(const std::string &realSandboxID, +- std::vector &errors) -> int ++int CRIRuntimeServiceImpl::DoRemovePodSandbox(const std::string &realSandboxID, std::vector &errors) + { + int ret = 0; + container_delete_request *remove_request { nullptr }; +@@ -972,8 +889,19 @@ void CRIRuntimeServiceImpl::SetSandboxStatusNetwork(container_inspect *inspect, + std::unique_ptr &podStatus, + Errors &error) + { +- std::string interfaceIP = GetIP(podSandboxID, inspect, Network::DEFAULT_NETWORK_INTERFACE_NAME, error); +- podStatus->mutable_network()->set_ip(interfaceIP); ++ std::vector ips; ++ size_t i; ++ ++ GetIPs(podSandboxID, inspect, Network::DEFAULT_NETWORK_INTERFACE_NAME, ips, error); ++ if (ips.size() == 0) { ++ return; ++ } ++ podStatus->mutable_network()->set_ip(ips[0]); ++ ++ for (i = 1; i < ips.size(); i++) { ++ auto tPoint = podStatus->mutable_network()->add_additional_ips(); ++ tPoint->set_ip(ips[i]); ++ } + } + + void CRIRuntimeServiceImpl::PodSandboxStatusToGRPC(container_inspect *inspect, const std::string &podSandboxID, +@@ -1025,70 +953,130 @@ void CRIRuntimeServiceImpl::PodSandboxStatusToGRPC(container_inspect *inspect, c + } + } + +-auto CRIRuntimeServiceImpl::GetIPFromPlugin(container_inspect *inspect, const std::string &networkInterface, +- Errors &error) -> std::string ++void CRIRuntimeServiceImpl::GetFormatIPsForMultNet(container_inspect *inspect, const std::string &defaultInterface, ++ const runtime::v1alpha2::PodSandboxMetadata &metadata, std::vector &result, Errors &error) + { +- if (inspect == nullptr || inspect->id == nullptr || inspect->name == nullptr) { +- error.SetError("Empty arguments"); +- return ""; ++ size_t len = 0; ++ cri_pod_network_element **elems { nullptr }; ++ parser_error jerr { nullptr }; ++ ++ if (inspect->config == nullptr || inspect->config->annotations == nullptr) { ++ return; ++ } ++ ++ for (size_t i = 0; i < inspect->config->annotations->len; i++) { ++ if (strcmp(inspect->config->annotations->keys[i], CRIHelpers::Constants::POD_NETWORK_ANNOTATION_KEY.c_str()) != 0) { ++ continue; ++ } ++ elems = cri_pod_network_parse_data(inspect->config->annotations->values[i], nullptr, &jerr, &len); ++ if (elems == nullptr) { ++ ERROR("parse mutlnetwork config failed: %s", jerr); ++ error.SetError("parse mutlnetwork config failed"); ++ goto out; ++ } ++ break; ++ } ++ ++ for (size_t i = 0; i < len; i++) { ++ if (elems[i]->interface == nullptr || strcmp(elems[i]->interface, defaultInterface.c_str()) == 0) { ++ continue; ++ } ++ Network::PodNetworkStatus status; ++ m_pluginManager->GetPodNetworkStatus(metadata.namespace_(), metadata.name(), elems[i]->interface, inspect->id, status, ++ error); ++ if (error.NotEmpty()) { ++ goto out; ++ } ++ // add a sentry to make ips of mutlnetwork store from position 2 ++ if (result.size() < 2) { ++ result.push_back(""); ++ } ++ ++ result.push_back(std::string(elems[i]->name) + "@" + std::string(elems[i]->interface) + "@[" + CXXUtils::StringsJoin( ++ status.GetIPs(), ", ") + "]"); ++ } ++out: ++ for (size_t i = 0; i < len; i++) { ++ free_cri_pod_network_element(elems[i]); ++ elems[i] = nullptr; + } ++ free(elems); ++ free(jerr); ++} + ++auto CRIRuntimeServiceImpl::GetIPsFromPlugin(container_inspect *inspect, const std::string &networkInterface, ++ Errors &error) -> std::vector ++{ ++ std::vector ret; + runtime::v1alpha2::PodSandboxMetadata metadata; ++ std::string defaultInterface = networkInterface; ++ ++ if (inspect == nullptr || inspect->id == nullptr || inspect->name == nullptr) { ++ error.SetError("Empty arguments"); ++ return ret; ++ } + CRINaming::ParseSandboxName(inspect->name, metadata, error); + if (error.NotEmpty()) { +- return ""; ++ return ret; + } +- std::string cid = inspect->id; +- Network::PodNetworkStatus status; +- if (networkInterface.empty()) { +- m_pluginManager->GetPodNetworkStatus(metadata.namespace_(), metadata.name(), +- Network::DEFAULT_NETWORK_INTERFACE_NAME, cid, status, error); +- } else { +- m_pluginManager->GetPodNetworkStatus(metadata.namespace_(), metadata.name(), networkInterface, cid, status, +- error); ++ if (defaultInterface.empty()) { ++ defaultInterface = Network::DEFAULT_NETWORK_INTERFACE_NAME; + } ++ ++ // step 1: get ips of default network ++ Network::PodNetworkStatus status; ++ m_pluginManager->GetPodNetworkStatus(metadata.namespace_(), metadata.name(), defaultInterface, inspect->id, status, ++ error); + if (error.NotEmpty()) { +- return ""; ++ return ret; ++ } ++ for (auto &iter : status.GetIPs()) { ++ ret.push_back(iter); + } + +- return status.GetIP(); ++ // step 2: get ips of mutl networks ++ GetFormatIPsForMultNet(inspect, defaultInterface, metadata, ret, error); ++ ++ return ret; + } + +-auto CRIRuntimeServiceImpl::GetIP(const std::string &podSandboxID, container_inspect *inspect, +- const std::string &networkInterface, Errors &error) -> std::string ++void CRIRuntimeServiceImpl::GetIPs(const std::string &podSandboxID, container_inspect *inspect, ++ const std::string &networkInterface, std::vector &ips, Errors &error) + { + if (inspect == nullptr || inspect->network_settings == nullptr) { +- return ""; ++ return; + } + if (SharesHostNetwork(inspect) != 0) { + // For sandboxes using host network, the shim is not responsible for reporting the IP. +- return ""; ++ return; + } + + bool ready = GetNetworkReady(podSandboxID, error); + if (error.Empty() && !ready) { + WARN("Network %s do not ready", podSandboxID.c_str()); +- return ""; ++ return; + } + + error.Clear(); +- auto ip = GetIPFromPlugin(inspect, networkInterface, error); ++ auto tmpIPs = GetIPsFromPlugin(inspect, networkInterface, error); + if (error.Empty()) { +- return ip; ++ for (const auto &iter : tmpIPs) { ++ ips.push_back(iter); ++ } ++ return; + } + + if (inspect->network_settings->ip_address != nullptr) { + WARN("Use container inspect ip info: %s", error.GetCMessage()); + error.Clear(); +- return inspect->network_settings->ip_address; ++ ips.push_back(inspect->network_settings->ip_address); + } + + WARN("Failed to read pod IP from plugin/docker: %s", error.GetCMessage()); +- return ""; + } + +-auto CRIRuntimeServiceImpl::PodSandboxStatus( +- const std::string &podSandboxID, Errors &error) -> std::unique_ptr ++std::unique_ptr ++CRIRuntimeServiceImpl::PodSandboxStatus(const std::string &podSandboxID, Errors &error) + { + container_inspect *inspect { nullptr }; + std::unique_ptr podStatus(new runtime::v1alpha2::PodSandboxStatus); +diff --git a/src/daemon/entry/cri/cri_security_context.cc b/src/daemon/entry/cri/cri_security_context.cc +index 3b05e2c..634e53a 100644 +--- a/src/daemon/entry/cri/cri_security_context.cc ++++ b/src/daemon/entry/cri/cri_security_context.cc +@@ -19,8 +19,7 @@ + #include + + namespace CRISecurity { +-static void ModifyContainerConfig(const runtime::v1alpha2::LinuxContainerSecurityContext &sc, +- container_config *config) ++static void ModifyContainerConfig(const runtime::v1alpha2::LinuxContainerSecurityContext &sc, container_config *config) + { + if (sc.has_run_as_user()) { + free(config->user); +@@ -89,7 +88,7 @@ static void ModifyHostConfigNoNewPrivs(const runtime::v1alpha2::LinuxContainerSe + + size_t oldSize = hostConfig->security_opt_len * sizeof(char *); + size_t newSize = oldSize + sizeof(char *); +- int ret = mem_realloc((void **)(&tmp_security_opt), newSize, (void *)hostConfig->security_opt, oldSize); ++ int ret = util_mem_realloc((void **)(&tmp_security_opt), newSize, (void *)hostConfig->security_opt, oldSize); + if (ret != 0) { + error.Errorf("Out of memory"); + return; +diff --git a/src/daemon/entry/cri/network_plugin.cc b/src/daemon/entry/cri/network_plugin.cc +index 0cab31a..311ebb6 100644 +--- a/src/daemon/entry/cri/network_plugin.cc ++++ b/src/daemon/entry/cri/network_plugin.cc +@@ -65,25 +65,58 @@ static void runGetIP(void *cmdArgs) + execvp(tmpArgs[0], args); + } + +-static std::string GetOnePodIP(std::string nsenterPath, std::string netnsPath, std::string interfaceName, +- std::string addrType, Errors &error) ++static std::string ParseIPFromLine(const char *line, const char *stdout_str) + { +- char *stderr_str { nullptr }; +- char *stdout_str { nullptr }; +- char *strErr { nullptr }; +- char **lines { nullptr }; ++ char *cIP { nullptr }; + char **fields { nullptr }; ++ char *strErr { nullptr }; + struct ipnet *ipnet_val { + nullptr + }; ++ std::string ret; ++ ++ fields = util_string_split(line, ' '); ++ if (fields == nullptr) { ++ ERROR("Out of memory"); ++ goto out; ++ } ++ if (util_array_len((const char **)fields) < 4) { ++ ERROR("Unexpected address output %s ", line); ++ goto out; ++ } ++ ++ if (parse_cidr(fields[3], &ipnet_val, &strErr) != 0) { ++ ERROR("CNI failed to parse ip from output %s due to %s", stdout_str, strErr); ++ goto out; ++ } ++ cIP = ip_to_string(ipnet_val->ip, ipnet_val->ip_len); ++ if (cIP == nullptr) { ++ ERROR("Out of memory"); ++ goto out; ++ } ++ ++ ret = cIP; ++out: ++ free(cIP); ++ free(strErr); ++ free_ipnet_type(ipnet_val); ++ util_free_array(fields); ++ return ret; ++} ++ ++static void GetOnePodIP(std::string nsenterPath, std::string netnsPath, std::string interfaceName, ++ std::string addrType, std::vector &ips, Errors &error) ++{ ++ char *stderr_str { nullptr }; ++ char *stdout_str { nullptr }; ++ char **lines { nullptr }; + char **args { nullptr }; +- std::string result { "" }; +- char *cIP { nullptr }; ++ size_t i; + + args = (char **)util_common_calloc_s(sizeof(char *) * 5); + if (args == nullptr) { + error.SetError("Out of memory"); +- return result; ++ return; + } + + args[0] = util_strdup_s(nsenterPath.c_str()); +@@ -102,52 +135,55 @@ static std::string GetOnePodIP(std::string nsenterPath, std::string netnsPath, s + error.SetError("Out of memory"); + goto free_out; + } +- if (util_array_len((const char **)lines) < 1) { +- error.Errorf("Unexpected command output %s", stdout_str); +- goto free_out; +- } + +- fields = util_string_split(lines[0], ' '); +- if (fields == nullptr) { +- error.SetError("Out of memory"); +- goto free_out; +- } +- if (util_array_len((const char **)fields) < 4) { +- error.Errorf("Unexpected address output %s ", lines[0]); ++ if (util_array_len((const char **)lines) == 0) { ++ error.Errorf("Unexpected command output %s", stdout_str); + goto free_out; + } + +- if (parse_cidr(fields[3], &ipnet_val, &strErr) != 0) { +- error.Errorf("CNI failed to parse ip from output %s due to %s", stdout_str, strErr); +- goto free_out; +- } +- cIP = ip_to_string(ipnet_val->ip, ipnet_val->ip_len); +- if (cIP == nullptr) { +- error.SetError("Out of memory"); +- goto free_out; ++ for (i = 0; i < util_array_len((const char **)lines); i++) { ++ // ip string min length must bigger than 4 ++ if (lines[i] == nullptr || strlen(lines[i]) < 4) { ++ continue; ++ } ++ std::string tIP = ParseIPFromLine(lines[i], stdout_str); ++ if (tIP.empty()) { ++ error.Errorf("parse %s to ip failed", lines[i]); ++ break; ++ } ++ ips.push_back(tIP); + } +- result = cIP; +- free(cIP); + + free_out: +- free_ipnet_type(ipnet_val); + free(stdout_str); + free(stderr_str); + util_free_array(args); + util_free_array(lines); +- util_free_array(fields); +- return result; + } + +-std::string GetPodIP(const std::string &nsenterPath, const std::string &netnsPath, const std::string &interfaceName, +- Errors &error) ++void GetPodIP(const std::string &nsenterPath, const std::string &netnsPath, const std::string &interfaceName, ++ std::vector &getIPs, Errors &error) + { +- std::string ip = GetOnePodIP(nsenterPath, netnsPath, interfaceName, "-4", error); ++ Errors tmpErr; ++ ++ GetOnePodIP(nsenterPath, netnsPath, interfaceName, "-4", getIPs, tmpErr); ++ if (tmpErr.NotEmpty()) { ++ WARN("Get ipv4 failed: %s", tmpErr.GetCMessage()); ++ } ++ ++ GetOnePodIP(nsenterPath, netnsPath, interfaceName, "-6", getIPs, error); + if (error.NotEmpty()) { +- return GetOnePodIP(nsenterPath, netnsPath, interfaceName, "-6", error); ++ WARN("Get ipv6 failed: %s", tmpErr.GetCMessage()); + } + +- return ip; ++ if (getIPs.size() > 0) { ++ error.Clear(); ++ return; ++ } ++ ++ if (tmpErr.NotEmpty()) { ++ error.AppendError(tmpErr.GetMessage()); ++ } + } + + void InitNetworkPlugin(std::vector> *plugins, std::string networkPluginName, +@@ -290,14 +326,14 @@ void PodNetworkStatus::SetAPIVersion(const std::string &version) + m_apiVersion = version; + } + +-const std::string &PodNetworkStatus::GetIP() const ++const std::vector &PodNetworkStatus::GetIPs() const + { +- return m_ip; ++ return m_ips; + } + +-void PodNetworkStatus::SetIP(const std::string &ip) ++void PodNetworkStatus::SetIPs(std::vector &ips) + { +- m_ip = ip; ++ m_ips = ips; + } + + void PluginManager::Lock(const std::string &fullPodName, Errors &error) +diff --git a/src/daemon/entry/cri/network_plugin.h b/src/daemon/entry/cri/network_plugin.h +index 5a46eb8..24afd71 100644 +--- a/src/daemon/entry/cri/network_plugin.h ++++ b/src/daemon/entry/cri/network_plugin.h +@@ -82,13 +82,13 @@ public: + void SetKind(const std::string &kind); + const std::string &GetAPIVersion() const; + void SetAPIVersion(const std::string &version); +- const std::string &GetIP() const; +- void SetIP(const std::string &ip); ++ const std::vector &GetIPs() const; ++ void SetIPs(std::vector &ips); + + private: + std::string m_kind; + std::string m_apiVersion; +- std::string m_ip; ++ std::vector m_ips; + }; + + class NetworkPlugin { +@@ -227,8 +227,8 @@ void InitNetworkPlugin(std::vector> *plugins, std + void ProbeNetworkPlugins(const std::string &pluginDir, const std::string &binDir, + std::vector> *plugins); + +-std::string GetPodIP(const std::string &nsenterPath, const std::string &netnsPath, const std::string &interfaceName, +- Errors &error); ++void GetPodIP(const std::string &nsenterPath, const std::string &netnsPath, const std::string &interfaceName, ++ std::vector &getIPs, Errors &error); + + const std::string &GetInterfaceName(); + } // namespace Network +diff --git a/src/daemon/entry/cri/sysctl_tools.c b/src/daemon/entry/cri/sysctl_tools.c +index 98f7ee1..9883f9f 100644 +--- a/src/daemon/entry/cri/sysctl_tools.c ++++ b/src/daemon/entry/cri/sysctl_tools.c +@@ -15,13 +15,13 @@ + #ifndef _GNU_SOURCE + #define _GNU_SOURCE + #endif ++#include "sysctl_tools.h" + #include + #include + #include + #include + #include + +-#include "sysctl_tools.h" + #include "utils.h" + + int get_sysctl(const char *sysctl, char **err) +diff --git a/src/daemon/executor/CMakeLists.txt b/src/daemon/executor/CMakeLists.txt +index 13afcc0..01b0d4c 100644 +--- a/src/daemon/executor/CMakeLists.txt ++++ b/src/daemon/executor/CMakeLists.txt +@@ -11,6 +11,10 @@ add_subdirectory(image_cb) + list(APPEND local_executor_srcs ${IMAGE_CB_SRCS}) + list(APPEND local_executor_incs ${IMAGE_CB_INCS}) + ++add_subdirectory(volume_cb) ++list(APPEND local_executor_srcs ${VOLUME_CB_SRCS}) ++list(APPEND local_executor_incs ${VOLUME_CB_INCS}) ++ + set(EXECUTOR_SRCS + ${local_executor_srcs} + PARENT_SCOPE +diff --git a/src/daemon/executor/callback.c b/src/daemon/executor/callback.c +index 392a899..903492e 100644 +--- a/src/daemon/executor/callback.c ++++ b/src/daemon/executor/callback.c +@@ -18,6 +18,7 @@ + + #include "image_cb.h" + #include "execution.h" ++#include "volume_cb.h" + + service_executor_t g_isulad_service_executor; + +@@ -155,6 +156,7 @@ int service_callback_init(void) + { + container_callback_init(&g_isulad_service_executor.container); + image_callback_init(&g_isulad_service_executor.image); ++ volume_callback_init(&g_isulad_service_executor.volume); + return 0; + } + +diff --git a/src/daemon/executor/callback.h b/src/daemon/executor/callback.h +index 9946b22..f3445c8 100644 +--- a/src/daemon/executor/callback.h ++++ b/src/daemon/executor/callback.h +@@ -79,6 +79,12 @@ + #include "isula_libutils/image_login_response.h" + #include "isula_libutils/image_logout_request.h" + #include "isula_libutils/image_logout_response.h" ++#include "isula_libutils/volume_list_volume_request.h" ++#include "isula_libutils/volume_list_volume_response.h" ++#include "isula_libutils/volume_remove_volume_request.h" ++#include "isula_libutils/volume_remove_volume_response.h" ++#include "isula_libutils/volume_prune_volume_request.h" ++#include "isula_libutils/volume_prune_volume_response.h" + #include "events_format.h" + #include "stream_wrapper.h" + #include "utils_timestamp.h" +@@ -258,9 +264,18 @@ typedef struct { + int (*tag)(const image_tag_image_request *request, image_tag_image_response **response); + } service_image_callback_t; + ++typedef struct { ++ int (*list)(const volume_list_volume_request *request, volume_list_volume_response **response); ++ ++ int (*remove)(const volume_remove_volume_request *request, volume_remove_volume_response **response); ++ ++ int (*prune)(const volume_prune_volume_request *request, volume_prune_volume_response **response); ++} service_volume_callback_t; ++ + typedef struct { + service_container_callback_t container; + service_image_callback_t image; ++ service_volume_callback_t volume; + } service_executor_t; + + int service_callback_init(void); +diff --git a/src/daemon/executor/container_cb/execution.c b/src/daemon/executor/container_cb/execution.c +index 44ae32e..db17b86 100644 +--- a/src/daemon/executor/container_cb/execution.c ++++ b/src/daemon/executor/container_cb/execution.c +@@ -13,6 +13,7 @@ + * Description: provide container list callback function definition + ********************************************************************************/ + ++#include "execution.h" + #include + #include + #include +@@ -38,7 +39,6 @@ + #include + + #include "isula_libutils/log.h" +-#include "execution.h" + #include "container_api.h" + #include "execution_extend.h" + #include "execution_information.h" +@@ -403,7 +403,7 @@ static int restart_container(container_t *cont) + goto out; + } + +- (void)get_now_time_buffer(timebuffer, sizeof(timebuffer)); ++ (void)util_get_now_time_buffer(timebuffer, sizeof(timebuffer)); + + params.rootpath = rootpath; + +@@ -706,7 +706,7 @@ static int container_kill_cb(const container_kill_request *request, container_ki + goto pack_response; + } + +- if (!util_check_signal_valid((int)signal)) { ++ if (!util_valid_signal((int)signal)) { + isulad_set_error_message("Not supported signal %d", signal); + ERROR("Not supported signal %d", signal); + cc = ISULAD_ERR_EXEC; +diff --git a/src/daemon/executor/container_cb/execution_create.c b/src/daemon/executor/container_cb/execution_create.c +index 91c9692..188d58b 100644 +--- a/src/daemon/executor/container_cb/execution_create.c ++++ b/src/daemon/executor/container_cb/execution_create.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + + #include "isula_libutils/log.h" + #include "isulad_config.h" +@@ -57,6 +58,9 @@ + #include "utils_verify.h" + #include "selinux_label.h" + ++static int do_init_cpurt_cgroups_path(const char *path, int recursive_depth, const char *mnt_root, ++ int64_t cpu_rt_period, int64_t cpu_rt_runtime); ++ + static int runtime_check(const char *name, bool *runtime_res) + { + int ret = 0; +@@ -157,7 +161,6 @@ static host_config *get_host_spec_from_request(const container_create_request *r + if (host_spec == NULL) { + ERROR("Failed to parse host config data:%s", err); + } +- + free(err); + return host_spec; + } +@@ -479,7 +482,7 @@ static int register_new_container(const char *id, const char *runtime, host_conf + container_config_v2_common_config **v2_spec) + { + int ret = -1; +- bool registed = false; ++ bool registered = false; + char *runtime_root = NULL; + char *runtime_stat = NULL; + char *image_id = NULL; +@@ -511,8 +514,8 @@ static int register_new_container(const char *id, const char *runtime, host_conf + goto out; + } + +- registed = containers_store_add(id, cont); +- if (!registed) { ++ registered = containers_store_add(id, cont); ++ if (!registered) { + ERROR("Failed to register container '%s'", id); + goto out; + } +@@ -576,7 +579,7 @@ out: + + static char *get_runtime_from_request(const container_create_request *request) + { +- return strings_to_lower(request->runtime); ++ return util_strings_to_lower(request->runtime); + } + + static void pack_create_response(container_create_response *response, const char *id, uint32_t cc) +@@ -916,12 +919,13 @@ static int pack_security_config_to_v2_spec(const host_config *host_spec, contain + v2_spec->seccomp_profile = seccomp_profile; + seccomp_profile = NULL; + v2_spec->no_new_privileges = no_new_privileges; +- ++#ifdef ENABLE_SELINUX + if (init_label((const char **)label_opts, label_opts_len, &process_label, &mount_label) != 0) { + ERROR("Failed to append label"); + ret = -1; + goto out; + } ++#endif + + v2_spec->mount_label = mount_label; + mount_label = NULL; +@@ -944,7 +948,7 @@ static void v2_spec_fill_basic_info(const char *id, const char *name, const char + v2_spec->name = name ? util_strdup_s(name) : NULL; + v2_spec->image = image_name ? util_strdup_s(image_name) : util_strdup_s("none"); + v2_spec->image_type = image_type ? util_strdup_s(image_type) : NULL; +- (void)get_now_time_buffer(timebuffer, sizeof(timebuffer)); ++ (void)util_get_now_time_buffer(timebuffer, sizeof(timebuffer)); + free(v2_spec->created); + v2_spec->created = util_strdup_s(timebuffer); + v2_spec->config = container_spec; +@@ -1022,6 +1026,204 @@ static int save_container_config_before_create(const char *id, const char *runti + return 0; + } + ++/* maybe create cpu realtime file */ ++static int maybe_create_cpu_realtime_file(int64_t value, const char *file, const char *path) ++{ ++ int ret; ++ int fd = 0; ++ ssize_t nwrite; ++ char fpath[PATH_MAX] = { 0 }; ++ char buf[ISULAD_NUMSTRLEN64] = { 0 }; ++ ++ if (value == 0) { ++ return 0; ++ } ++ ++ ret = util_mkdir_p(path, CONFIG_DIRECTORY_MODE); ++ if (ret != 0) { ++ ERROR("Failed to mkdir: %s", path); ++ return -1; ++ } ++ ++ int nret = snprintf(fpath, sizeof(fpath), "%s/%s", path, file); ++ if (nret < 0 || nret >= sizeof(fpath)) { ++ ERROR("Failed to print string"); ++ return -1; ++ } ++ nret = snprintf(buf, sizeof(buf), "%lld", (long long int)value); ++ if (nret < 0 || (size_t)nret >= sizeof(buf)) { ++ ERROR("Failed to print string"); ++ return -1; ++ } ++ ++ fd = util_open(fpath, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0700); ++ if (fd < 0) { ++ ERROR("Failed to open file: %s: %s", fpath, strerror(errno)); ++ isulad_set_error_message("Failed to open file: %s: %s", fpath, strerror(errno)); ++ return -1; ++ } ++ nwrite = util_write_nointr(fd, buf, strlen(buf)); ++ if (nwrite < 0) { ++ ERROR("Failed to write %s to %s: %s", buf, fpath, strerror(errno)); ++ isulad_set_error_message("Failed to write '%s' to '%s': %s", buf, fpath, strerror(errno)); ++ close(fd); ++ return -1; ++ } ++ close(fd); ++ ++ return 0; ++} ++ ++static int recursively_create_cgroup(const char *path, const char *mnt_root, int recursive_depth, int64_t cpu_rt_period, ++ int64_t cpu_rt_runtime) ++{ ++ int ret = 0; ++ char *dup = NULL; ++ char *dirpath = NULL; ++ char fpath[PATH_MAX] = { 0 }; ++ ++ dup = util_strdup_s(path); ++ dirpath = dirname(dup); ++ ret = do_init_cpurt_cgroups_path(dirpath, (recursive_depth + 1), mnt_root, cpu_rt_period, cpu_rt_runtime); ++ free(dup); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ int nret = snprintf(fpath, sizeof(fpath), "%s/%s", mnt_root, path); ++ if (nret < 0 || (size_t)nret >= sizeof(fpath)) { ++ ERROR("Failed to print string"); ++ ret = -1; ++ goto out; ++ } ++ ++ ret = maybe_create_cpu_realtime_file(cpu_rt_period, "cpu.rt_period_us", fpath); ++ if (ret != 0) { ++ goto out; ++ } ++ ++ ret = maybe_create_cpu_realtime_file(cpu_rt_runtime, "cpu.rt_runtime_us", fpath); ++ if (ret != 0) { ++ goto out; ++ } ++ ++out: ++ return ret; ++} ++ ++/* init cgroups path */ ++static int do_init_cpurt_cgroups_path(const char *path, int recursive_depth, const char *mnt_root, ++ int64_t cpu_rt_period, int64_t cpu_rt_runtime) ++{ ++ if ((recursive_depth + 1) > MAX_PATH_DEPTH) { ++ ERROR("Reach the max cgroup depth:%s", path); ++ return -1; ++ } ++ ++ if (path == NULL || strcmp(path, "/") == 0 || strcmp(path, ".") == 0) { ++ return 0; ++ } ++ ++ // Recursively create cgroup to ensure that the system and all parent cgroups have values set ++ // for the period and runtime as this limits what the children can be set to. ++ if (recursively_create_cgroup(path, mnt_root, recursive_depth, cpu_rt_period, cpu_rt_runtime)) { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static char *get_cpurt_controller_mnt_path() ++{ ++ char *res = NULL; ++ int nret = 0; ++ char *mnt = NULL; ++ char *root = NULL; ++ char fpath[PATH_MAX] = { 0 }; ++ ++ nret = find_cgroup_mountpoint_and_root("cpu", &mnt, &root); ++ if (nret != 0 || mnt == NULL || root == NULL) { ++ ERROR("Can not find cgroup mnt and root path for subsystem 'cpu'"); ++ isulad_set_error_message("Can not find cgroup mnt and root path for subsystem 'cpu'"); ++ goto out; ++ } ++ ++ // When iSulad is run inside docker, the root is based of the host cgroup. ++ // Replace root to "/" ++ if (strncmp(root, "/docker/", strlen("/docker/")) == 0) { ++ root[1] = '\0'; ++ } ++ ++ nret = snprintf(fpath, sizeof(fpath), "%s/%s", mnt, root); ++ if (nret < 0 || (size_t)nret >= sizeof(fpath)) { ++ ERROR("Failed to print string"); ++ goto out; ++ } ++ ++ res = util_strdup_s(fpath); ++ ++out: ++ free(mnt); ++ free(root); ++ return res; ++} ++ ++static int cpurt_controller_init(const char *cgroups_path) ++{ ++ int ret = 0; ++ char *dup = NULL; ++ char *dirpath = NULL; ++ int64_t cpu_rt_period = 0; ++ int64_t cpu_rt_runtime = 0; ++ sysinfo_t *sysinfo = NULL; ++ char *mnt_root = NULL; ++ ++ if (cgroups_path == NULL || strcmp(cgroups_path, "/") == 0 || strcmp(cgroups_path, ".") == 0) { ++ return 0; ++ } ++ ++ if (conf_get_cgroup_cpu_rt(&cpu_rt_period, &cpu_rt_runtime)) { ++ return -1; ++ } ++ ++ if (cpu_rt_period == 0 && cpu_rt_runtime == 0) { ++ return 0; ++ } ++ ++ sysinfo = get_sys_info(true); ++ if (sysinfo == NULL) { ++ ERROR("Can not get system info"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (!(sysinfo->cgcpuinfo.cpu_rt_period)) { ++ ERROR("Daemon-scoped cpu-rt-period and cpu-rt-runtime are not supported by kernel"); ++ isulad_set_error_message("Daemon-scoped cpu-rt-period and cpu-rt-runtime are not supported by kernel"); ++ ret = -1; ++ goto out; ++ } ++ ++ mnt_root = get_cpurt_controller_mnt_path(); ++ if (mnt_root == NULL) { ++ ERROR("Failed to get cpu rt controller mnt root path"); ++ isulad_set_error_message("Failed to get cpu rt controller mnt root path"); ++ ret = -1; ++ goto out; ++ } ++ ++ dup = util_strdup_s(cgroups_path); ++ dirpath = dirname(dup); ++ ++ ret = do_init_cpurt_cgroups_path(dirpath, 0, mnt_root, cpu_rt_period, cpu_rt_runtime); ++ ++out: ++ free_sysinfo(sysinfo); ++ free(mnt_root); ++ free(dup); ++ return ret; ++} ++ + /* + * request -> host_spec + container_spec + * container_spec + image config +@@ -1127,11 +1329,6 @@ int container_create_cb(const container_create_request *request, container_creat + goto umount_shm; + } + +- ret = merge_oci_cgroups_path(id, oci_spec, host_spec); +- if (ret < 0) { +- goto umount_shm; +- } +- + if (merge_config_for_syscontainer(request, host_spec, v2_spec->config, oci_spec) != 0) { + ERROR("Failed to merge config for syscontainer"); + cc = ISULAD_ERR_EXEC; +@@ -1165,6 +1362,13 @@ int container_create_cb(const container_create_request *request, container_creat + goto umount_channel; + } + ++ // init cgroup path for cpu_rt_runtime and cpu_rt_period ++ if (cpurt_controller_init(oci_spec->linux->cgroups_path) != 0) { ++ ERROR("Unable to init CPU RT controller %s", oci_spec->linux->cgroups_path); ++ cc = ISULAD_ERR_EXEC; ++ goto umount_channel; ++ } ++ + if (container_v2_spec_merge_contaner_spec(v2_spec) != 0) { + ERROR("Failed to merge container settings"); + cc = ISULAD_ERR_EXEC; +@@ -1192,6 +1396,8 @@ umount_channel: + umount_shm: + umount_shm_by_configs(host_spec, v2_spec); + ++ (void)release_volumes(v2_spec->mount_points, id, false); ++ + clean_rootfs: + (void)im_remove_container_rootfs(image_type, id); + +diff --git a/src/daemon/executor/container_cb/execution_extend.c b/src/daemon/executor/container_cb/execution_extend.c +index df4655d..e63ec54 100644 +--- a/src/daemon/executor/container_cb/execution_extend.c ++++ b/src/daemon/executor/container_cb/execution_extend.c +@@ -834,8 +834,41 @@ static void host_config_restore_unlocking(container_t *cont, host_config *backup + } + } + +-static void update_container_cpu(const host_config *hostconfig, host_config *chostconfig) ++static int update_container_cpu(const host_config *hostconfig, host_config *chostconfig) + { ++ int ret = 0; ++ ++ if (hostconfig->nano_cpus > 0 && chostconfig->cpu_period > 0) { ++ ERROR("Conflicting options: Nano CPUs cannot be updated as CPU Period has already been set"); ++ isulad_set_error_message("Conflicting options: Nano CPUs cannot be updated as CPU Period has already been set"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (hostconfig->nano_cpus > 0 && chostconfig->cpu_quota > 0) { ++ ERROR("Conflicting options: Nano CPUs cannot be updated as CPU Quota has already been set"); ++ isulad_set_error_message("Conflicting options: Nano CPUs cannot be updated as CPU Quota has already been set"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (hostconfig->cpu_period > 0 && chostconfig->nano_cpus > 0) { ++ ERROR("Conflicting options: CPU Period cannot be updated as NanoCPUs has already been set"); ++ isulad_set_error_message("Conflicting options: CPU Period cannot be updated as NanoCPUs has already been set"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (hostconfig->cpu_quota > 0 && chostconfig->nano_cpus > 0) { ++ ERROR("Conflicting options: CPU Quota cannot be updated as NanoCPUs has already been set"); ++ isulad_set_error_message("Conflicting options: CPU Quota cannot be updated as NanoCPUs has already been set"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (hostconfig->nano_cpus != 0) { ++ chostconfig->nano_cpus = hostconfig->nano_cpus; ++ } + if (hostconfig->cpu_shares != 0) { + chostconfig->cpu_shares = hostconfig->cpu_shares; + } +@@ -853,6 +886,15 @@ static void update_container_cpu(const host_config *hostconfig, host_config *cho + free(chostconfig->cpuset_mems); + chostconfig->cpuset_mems = util_strdup_s(hostconfig->cpuset_mems); + } ++ if (hostconfig->cpu_realtime_period != 0) { ++ chostconfig->cpu_realtime_period = hostconfig->cpu_realtime_period; ++ } ++ if (hostconfig->cpu_realtime_runtime != 0) { ++ chostconfig->cpu_realtime_runtime = hostconfig->cpu_realtime_runtime; ++ } ++ ++out: ++ return ret; + } + + static int update_container_memory(const char *id, const host_config *hostconfig, host_config *chostconfig) +@@ -926,7 +968,11 @@ static int update_container(const container_t *cont, const host_config *hostconf + chostconfig->blkio_weight = hostconfig->blkio_weight; + } + +- update_container_cpu(hostconfig, chostconfig); ++ ret = update_container_cpu(hostconfig, chostconfig); ++ if (ret != 0) { ++ ret = -1; ++ goto out; ++ } + + ret = update_container_memory(id, hostconfig, chostconfig); + if (ret != 0) { +diff --git a/src/daemon/executor/container_cb/execution_information.c b/src/daemon/executor/container_cb/execution_information.c +index 4dd8166..cc43a24 100644 +--- a/src/daemon/executor/container_cb/execution_information.c ++++ b/src/daemon/executor/container_cb/execution_information.c +@@ -13,6 +13,7 @@ + * Description: provide container information callback function definition + *********************************************************************************/ + ++#include "execution_information.h" + #include + #include + #include +@@ -49,7 +50,6 @@ + #include "image_api.h" + #include "isula_libutils/container_inspect.h" + #include "container_api.h" +-#include "execution_information.h" + #include "sysinfo.h" + #include "runtime_api.h" + #include "list.h" +@@ -183,7 +183,7 @@ static int get_proxy_env(char **proxy, const char *type) + + *proxy = getenv(type); + if (*proxy == NULL) { +- tmp = strings_to_upper(type); ++ tmp = util_strings_to_upper(type); + if (tmp == NULL) { + ERROR("Failed to upper string!"); + ret = -1; +@@ -1007,13 +1007,13 @@ static int dup_container_config_cmd_and_entrypoint(const container_config *src, + return 0; + } + +- ret = dup_array_of_strings((const char **)(src->cmd), src->cmd_len, &(dest->cmd), &(dest->cmd_len)); ++ ret = util_dup_array_of_strings((const char **)(src->cmd), src->cmd_len, &(dest->cmd), &(dest->cmd_len)); + if (ret != 0) { + goto out; + } + +- ret = dup_array_of_strings((const char **)(src->entrypoint), src->entrypoint_len, &(dest->entrypoint), +- &(dest->entrypoint_len)); ++ ret = util_dup_array_of_strings((const char **)(src->entrypoint), src->entrypoint_len, &(dest->entrypoint), ++ &(dest->entrypoint_len)); + out: + return ret; + } +@@ -1038,6 +1038,21 @@ out: + return ret; + } + ++static int dup_container_config_volumes(const container_config *src, container_inspect_config *dest) ++{ ++ int ret = 0; ++ ++ if (src->volumes != NULL) { ++ dest->volumes = dup_map_string_empty_object(src->volumes); ++ if (dest->volumes == 0) { ++ ret = -1; ++ goto out; ++ } ++ } ++out: ++ return ret; ++} ++ + static int dup_container_config_annotations(const container_config *src, container_inspect_config *dest) + { + int ret = 0; +@@ -1086,6 +1101,11 @@ static int dup_container_config(const char *image, const container_config *src, + goto out; + } + ++ if (dup_container_config_volumes(src, dest) != 0) { ++ ret = -1; ++ goto out; ++ } ++ + if (dup_container_config_annotations(src, dest) != 0) { + ret = -1; + goto out; +@@ -1126,6 +1146,7 @@ static int mount_point_to_inspect(const container_t *cont, container_inspect *in + ERROR("Out of memory"); + return -1; + } ++ inspect->mounts[i]->type = util_strdup_s(mp->type); + inspect->mounts[i]->source = util_strdup_s(mp->source); + inspect->mounts[i]->destination = util_strdup_s(mp->destination); + inspect->mounts[i]->name = util_strdup_s(mp->name); +diff --git a/src/daemon/executor/container_cb/execution_network.c b/src/daemon/executor/container_cb/execution_network.c +index 7bb0c36..2c662bc 100644 +--- a/src/daemon/executor/container_cb/execution_network.c ++++ b/src/daemon/executor/container_cb/execution_network.c +@@ -46,7 +46,7 @@ static int write_hostname_to_file(const char *rootfs, const char *hostname) + goto out; + } + +- if (realpath_in_scope(rootfs, "/etc/hostname", &file_path) < 0) { ++ if (util_realpath_in_scope(rootfs, "/etc/hostname", &file_path) < 0) { + SYSERROR("Failed to get real path '/etc/hostname' under rootfs '%s'", rootfs); + isulad_set_error_message("Failed to get real path '/etc/hostname' under rootfs '%s'", rootfs); + goto out; +@@ -76,7 +76,7 @@ out: + + static int fopen_network(FILE **fp, char **file_path, const char *rootfs, const char *filename) + { +- if (realpath_in_scope(rootfs, filename, file_path) < 0) { ++ if (util_realpath_in_scope(rootfs, filename, file_path) < 0) { + SYSERROR("Failed to get real path '%s' under rootfs '%s'", filename, rootfs); + isulad_set_error_message("Failed to get real path '%s' under rootfs '%s'", filename, rootfs); + return -1; +@@ -163,14 +163,28 @@ static int write_content_to_file(const char *file_path, const char *content) + return ret; + } + ++static bool is_exist_in_map(const char *key, const json_map_string_bool *map) ++{ ++ bool is_exist = false; ++ size_t j; ++ ++ for (j = 0; j < map->len; j++) { ++ if (strcmp(key, map->keys[j]) == 0) { ++ is_exist = true; ++ break; ++ } ++ } ++ ++ return is_exist; ++} ++ + static int merge_hosts_content(const host_config *host_spec, char **content, json_map_string_bool *hosts_map) + { +- size_t i, j; ++ size_t i; + char *tmp = NULL; + char *saveptr = NULL; + + for (i = 0; i < host_spec->extra_hosts_len; i++) { +- bool need_to_add = true; + char *host_name = NULL; + char *host_ip = NULL; + char *hosts = NULL; +@@ -193,13 +207,7 @@ static int merge_hosts_content(const host_config *host_spec, char **content, jso + ERROR("Out of memory"); + return -1; + } +- for (j = 0; j < hosts_map->len; j++) { +- if (strcmp(host_key, hosts_map->keys[j]) == 0) { +- need_to_add = false; +- break; +- } +- } +- if (need_to_add) { ++ if (!is_exist_in_map(host_key, hosts_map)) { + tmp = util_string_append(host_ip, *content); + free(*content); + *content = tmp; +@@ -267,7 +275,7 @@ error_out: + static int merge_dns_search(const host_config *host_spec, char **content, const char *token, char *saveptr) + { + int ret = 0; +- size_t i, j; ++ size_t i; + size_t content_len = strlen(*content); + char *tmp = NULL; + json_map_string_bool *dns_search_map = NULL; +@@ -289,14 +297,7 @@ static int merge_dns_search(const host_config *host_spec, char **content, const + } + } + for (i = 0; i < host_spec->dns_search_len; i++) { +- bool need_to_add = true; +- for (j = 0; j < dns_search_map->len; j++) { +- if (strcmp(host_spec->dns_search[i], dns_search_map->keys[j]) == 0) { +- need_to_add = false; +- break; +- } +- } +- if (need_to_add) { ++ if (!is_exist_in_map(host_spec->dns_search[i], dns_search_map)) { + if (strlen(*content) > 0) { + (*content)[strlen(*content) - 1] = ' '; + } +@@ -325,7 +326,7 @@ error_out: + static int merge_dns_options(const host_config *host_spec, char **content, const char *token, char *saveptr) + { + int ret = 0; +- size_t i, j; ++ size_t i; + size_t content_len = strlen(*content); + char *tmp = NULL; + json_map_string_bool *dns_options_map = NULL; +@@ -347,14 +348,7 @@ static int merge_dns_options(const host_config *host_spec, char **content, const + } + } + for (i = 0; i < host_spec->dns_options_len; i++) { +- bool need_to_add = true; +- for (j = 0; j < dns_options_map->len; j++) { +- if (strcmp(host_spec->dns_options[i], dns_options_map->keys[j]) == 0) { +- need_to_add = false; +- break; +- } +- } +- if (need_to_add) { ++ if (!is_exist_in_map(host_spec->dns_options[i], dns_options_map)) { + if (strlen(*content) > 0) { + (*content)[strlen(*content) - 1] = ' '; + } +@@ -382,18 +376,11 @@ error_out: + + static int merge_dns(const host_config *host_spec, char **content, json_map_string_bool *dns_map) + { +- size_t i, j; ++ size_t i; + char *tmp = NULL; + + for (i = 0; i < host_spec->dns_len; i++) { +- bool need_to_add = true; +- for (j = 0; j < dns_map->len; j++) { +- if (strcmp(host_spec->dns[i], dns_map->keys[j]) == 0) { +- need_to_add = false; +- break; +- } +- } +- if (need_to_add) { ++ if (!is_exist_in_map(host_spec->dns[i], dns_map)) { + tmp = util_string_append("nameserver ", *content); + free(*content); + *content = tmp; +@@ -412,117 +399,118 @@ static int merge_dns(const host_config *host_spec, char **content, json_map_stri + return 0; + } + +-static bool is_need_add(const char *dns_search, const json_map_string_bool *dns_search_map) +-{ +- bool need_to_add = true; +- size_t j; +- +- for (j = 0; j < dns_search_map->len; j++) { +- if (strcmp(dns_search, dns_search_map->keys[j]) == 0) { +- need_to_add = false; +- break; +- } +- } +- +- return need_to_add; +-} +- +-static int generate_new_search(const host_config *host_spec, json_map_string_bool *dns_search_map, char **content, +- bool search) ++static int do_append_host_spec_search_to_content(const host_config *host_spec, json_map_string_bool *dns_search_map, ++ char **content) + { + char *tmp = NULL; ++ size_t i; + +- if (!search && host_spec->dns_search_len > 0) { +- size_t i; +- tmp = util_string_append("search ", *content); ++ tmp = util_string_append("search ", *content); ++ free(*content); ++ *content = tmp; ++ for (i = 0; i < host_spec->dns_search_len; i++) { ++ if (is_exist_in_map(host_spec->dns_search[i], dns_search_map)) { ++ continue; ++ } ++ if (append_json_map_string_bool(dns_search_map, host_spec->dns_search[i], true)) { ++ ERROR("append data to dns search map failed"); ++ return -1; ++ } ++ tmp = util_string_append(host_spec->dns_search[i], *content); + free(*content); + *content = tmp; +- for (i = 0; i < host_spec->dns_search_len; i++) { +- if (!is_need_add(host_spec->dns_search[i], dns_search_map)) { +- continue; +- } +- +- if (append_json_map_string_bool(dns_search_map, host_spec->dns_search[i], true)) { +- ERROR("append data to dns search map failed"); +- return -1; +- } +- tmp = util_string_append(host_spec->dns_search[i], *content); +- free(*content); +- *content = tmp; +- tmp = util_string_append(" ", *content); +- free(*content); +- *content = tmp; +- } +- tmp = util_string_append("\n", *content); ++ tmp = util_string_append(" ", *content); + free(*content); + *content = tmp; + } ++ tmp = util_string_append("\n", *content); ++ free(*content); ++ *content = tmp; ++ + return 0; + } + +-static int generate_new_options(const host_config *host_spec, json_map_string_bool *dns_options_map, char **content, +- bool options) ++static int do_append_host_spec_options_to_content(const host_config *host_spec, json_map_string_bool *dns_options_map, ++ char **content) + { + char *tmp = NULL; ++ size_t i; + +- if (!options && host_spec->dns_options_len > 0) { +- size_t i; +- tmp = util_string_append("options ", *content); +- free(*content); +- *content = tmp; +- for (i = 0; i < host_spec->dns_options_len; i++) { +- if (!is_need_add(host_spec->dns_options[i], dns_options_map)) { +- continue; +- } ++ tmp = util_string_append("options ", *content); ++ free(*content); ++ *content = tmp; ++ for (i = 0; i < host_spec->dns_options_len; i++) { ++ if (is_exist_in_map(host_spec->dns_options[i], dns_options_map)) { ++ continue; ++ } + +- if (append_json_map_string_bool(dns_options_map, host_spec->dns_options[i], true)) { +- ERROR("append data to dns options map failed"); +- return -1; +- } +- tmp = util_string_append(host_spec->dns_options[i], *content); +- free(*content); +- *content = tmp; +- tmp = util_string_append(" ", *content); +- free(*content); +- *content = tmp; ++ if (append_json_map_string_bool(dns_options_map, host_spec->dns_options[i], true)) { ++ ERROR("append data to dns options map failed"); ++ return -1; + } +- tmp = util_string_append("\n", *content); ++ tmp = util_string_append(host_spec->dns_options[i], *content); ++ free(*content); ++ *content = tmp; ++ tmp = util_string_append(" ", *content); + free(*content); + *content = tmp; + } ++ tmp = util_string_append("\n", *content); ++ free(*content); ++ *content = tmp; ++ + return 0; + } + +-static int generate_new_search_and_options(const host_config *host_spec, char **content, bool search, bool options) ++static int append_host_spec_options_to_content(const host_config *host_spec, char **content) + { + int ret = 0; +- json_map_string_bool *dns_search_map = NULL; + json_map_string_bool *dns_options_map = NULL; + +- dns_search_map = (json_map_string_bool *)util_common_calloc_s(sizeof(json_map_string_bool)); +- if (dns_search_map == NULL) { +- ERROR("Out of memory"); +- ret = -1; +- goto error_out; ++ if (host_spec->dns_options_len == 0) { ++ return 0; + } ++ + dns_options_map = (json_map_string_bool *)util_common_calloc_s(sizeof(json_map_string_bool)); + if (dns_options_map == NULL) { + ERROR("Out of memory"); + ret = -1; + goto error_out; + } +- ret = generate_new_search(host_spec, dns_search_map, content, search); ++ ++ ret = do_append_host_spec_options_to_content(host_spec, dns_options_map, content); + if (ret) { + goto error_out; + } +- ret = generate_new_options(host_spec, dns_options_map, content, options); ++ ++error_out: ++ free_json_map_string_bool(dns_options_map); ++ return ret; ++} ++ ++static int append_host_spec_search_to_content(const host_config *host_spec, char **content) ++{ ++ int ret = 0; ++ json_map_string_bool *dns_search_map = NULL; ++ ++ if (host_spec->dns_search_len == 0) { ++ return 0; ++ } ++ ++ dns_search_map = (json_map_string_bool *)util_common_calloc_s(sizeof(json_map_string_bool)); ++ if (dns_search_map == NULL) { ++ ERROR("Out of memory"); ++ ret = -1; ++ goto error_out; ++ } ++ ++ ret = do_append_host_spec_search_to_content(host_spec, dns_search_map, content); + if (ret) { + goto error_out; + } + + error_out: + free_json_map_string_bool(dns_search_map); +- free_json_map_string_bool(dns_options_map); + return ret; + } + +@@ -603,8 +591,8 @@ static int merge_resolv(const host_config *host_spec, const char *rootfs, const + { + int ret = 0; + size_t length = 0; +- bool search = false; +- bool options = false; ++ bool handle_search = false; ++ bool handle_options = false; + char *pline = NULL; + char *content = NULL; + char *file_path = NULL; +@@ -628,19 +616,39 @@ static int merge_resolv(const host_config *host_spec, const char *rootfs, const + ret = -1; + goto error_out; + } +- ret = resolve_handle_content(pline, host_spec, &content, dns_map, &search, &options); ++ char *tmp_content = util_strdup_s(content); ++ ret = resolve_handle_content(pline, host_spec, &tmp_content, dns_map, &handle_search, &handle_options); + if (ret != 0) { +- goto error_out; ++ WARN("Failed to handle resolv config %s, skip", pline); ++ free(tmp_content); ++ ret = 0; ++ } else { ++ free(content); ++ content = tmp_content; + } + } ++ + ret = merge_dns(host_spec, &content, dns_map); + if (ret) { + goto error_out; + } +- ret = generate_new_search_and_options(host_spec, &content, search, options); +- if (ret) { +- goto error_out; ++ ++ // if we handle search aleady in resolve_handle_content, skip append_host_spec_search_to_content ++ if (!handle_search) { ++ if (append_host_spec_search_to_content(host_spec, &content) != 0) { ++ ret = -1; ++ goto error_out; ++ } + } ++ ++ // if we handle options aleady in resolve_handle_content, skip append_host_spec_options_to_content ++ if (!handle_options) { ++ if (append_host_spec_options_to_content(host_spec, &content) != 0) { ++ ret = -1; ++ goto error_out; ++ } ++ } ++ + ret = write_content_to_file(file_path, content); + if (ret) { + goto error_out; +@@ -674,7 +682,7 @@ static int chown_network(const char *user_remap, const char *rootfs, const char + ret = -1; + goto out; + } +- if (realpath_in_scope(rootfs, filename, &file_path) < 0) { ++ if (util_realpath_in_scope(rootfs, filename, &file_path) < 0) { + SYSERROR("Failed to get real path '%s' under rootfs '%s'", filename, rootfs); + isulad_set_error_message("Failed to get real path '%s' under rootfs '%s'", filename, rootfs); + ret = -1; +@@ -965,7 +973,6 @@ out: + static int write_default_resolve(const char *file_path) + { + const char *default_ipv4_dns = "\nnameserver 8.8.8.8\nnameserver 8.8.4.4\n"; +- ; + + return util_write_file(file_path, default_ipv4_dns, strlen(default_ipv4_dns), NETWORK_MOUNT_FILE_MODE); + } +@@ -1004,10 +1011,10 @@ int init_container_network_confs(const char *id, const char *rootpath, const hos + container_config_v2_common_config *v2_spec) + { + int ret = 0; +- bool share_host = is_host(hc->network_mode); ++ bool share_host = namespace_is_host(hc->network_mode); + + // is container mode +- if (is_container(hc->network_mode)) { ++ if (namespace_is_container(hc->network_mode)) { + return init_container_network_confs_container(id, hc, v2_spec); + } + +diff --git a/src/daemon/executor/container_cb/execution_stream.c b/src/daemon/executor/container_cb/execution_stream.c +index c897624..7e2ac38 100644 +--- a/src/daemon/executor/container_cb/execution_stream.c ++++ b/src/daemon/executor/container_cb/execution_stream.c +@@ -381,18 +381,18 @@ static int archive_and_send_copy_data(const stream_func_wrapper *stream, + return -1; + } + +- if (cleanpath(resolvedpath, cleaned, sizeof(cleaned)) == NULL) { ++ if (util_clean_path(resolvedpath, cleaned, sizeof(cleaned)) == NULL) { + ERROR("Can not clean path: %s", resolvedpath); + goto cleanup; + } + +- nret = split_dir_and_base_name(cleaned, &srcdir, &srcbase); ++ nret = util_split_dir_and_base_name(cleaned, &srcdir, &srcbase); + if (nret != 0) { + ERROR("split %s failed", cleaned); + goto cleanup; + } + +- nret = split_dir_and_base_name(abspath, NULL, &absbase); ++ nret = util_split_dir_and_base_name(abspath, NULL, &absbase); + if (nret != 0) { + ERROR("split %s failed", abspath); + goto cleanup; +@@ -453,7 +453,7 @@ static container_path_stat *do_container_stat_path(const char *rootpath, const c + + if (S_ISLNK(st.st_mode)) { + char *p = NULL; +- hostpath = get_resource_path(rootpath, abspath); ++ hostpath = util_get_resource_path(rootpath, abspath); + if (hostpath == NULL) { + ERROR("Failed to get resource path"); + goto cleanup; +@@ -481,7 +481,7 @@ static container_path_stat *do_container_stat_path(const char *rootpath, const c + ERROR("Out of memory"); + goto cleanup; + } +- nret = split_dir_and_base_name(abspath, NULL, &stat->name); ++ nret = util_split_dir_and_base_name(abspath, NULL, &stat->name); + if (nret != 0) { + ERROR("split %s failed", abspath); + goto cleanup; +@@ -538,7 +538,7 @@ static container_path_stat *resolve_and_stat_path(const char *rootpath, const ch + char *abs = NULL; + container_path_stat *stat = NULL; + +- nret = resolve_path(rootpath, srcpath, &resolved, &abs); ++ nret = util_resolve_path(rootpath, srcpath, &resolved, &abs); + if (nret < 0) { + ERROR("Can not resolve path: %s", srcpath); + return NULL; +@@ -844,17 +844,17 @@ static int copy_to_container_resolve_path(const container_t *cont, const char *d + ERROR("Can not join path"); + return -1; + } +- if (cleanpath(joined, cleaned, sizeof(cleaned)) == NULL) { ++ if (util_clean_path(joined, cleaned, sizeof(cleaned)) == NULL) { + ERROR("Can not clean path: %s", dstdir); + goto cleanup; + } +- *abspath = preserve_trailing_dot_or_separator(cleaned, dstdir); ++ *abspath = util_preserve_trailing_dot_or_separator(cleaned, dstdir); + if (*abspath == NULL) { + ERROR("Can not preserve path"); + goto cleanup; + } + +- *resolvedpath = get_resource_path(cont->common_config->base_fs, *abspath); ++ *resolvedpath = util_get_resource_path(cont->common_config->base_fs, *abspath); + if (*resolvedpath == NULL) { + ERROR("Can not get resource path"); + goto cleanup; +@@ -1062,7 +1062,7 @@ static int64_t do_read_log_file(const char *path, int64_t require_line, long pos + break; + } + /* fopen is too fast, need wait rename operator finish */ +- usleep_nointerupt(1000); ++ util_usleep_nointerupt(1000); + } + if (fp == NULL) { + ERROR("open file: %s failed: %s", path, strerror(errno)); +@@ -1079,7 +1079,7 @@ static int64_t do_read_log_file(const char *path, int64_t require_line, long pos + (*last_pos) += (long)strlen(buffer); + + if (do_decode_write_log_entry(buffer, stream) != 0) { +- /* read a incomplete json object, try agin */ ++ /* read a incomplete json object, try again */ + decode_retries++; + if (decode_retries < MAX_JSON_DECODE_RETRY) { + continue; +@@ -1341,7 +1341,7 @@ static int handle_rotate(int fd, int wd, const char *path) + if (watch_fd >= 0) { + break; + } +- usleep_nointerupt(1000); ++ util_usleep_nointerupt(1000); + } + if (watch_fd < 0) { + SYSERROR("Add watch %s failed", path); +@@ -1509,7 +1509,7 @@ static int do_follow_log_file(const char *cid, stream_func_wrapper *stream, stru + ret = -1; + break; + } +- usleep_nointerupt(10000); ++ util_usleep_nointerupt(10000); + } + + out: +diff --git a/src/daemon/executor/container_cb/list.c b/src/daemon/executor/container_cb/list.c +index feccebe..4c9c9ed 100644 +--- a/src/daemon/executor/container_cb/list.c ++++ b/src/daemon/executor/container_cb/list.c +@@ -13,6 +13,7 @@ + * Description: provide container list callback function definition + ********************************************************************************/ + ++#include "list.h" + #include + #include + #include +@@ -26,7 +27,6 @@ + + #include "isula_libutils/log.h" + #include "container_api.h" +-#include "list.h" + #include "filters.h" + #include "utils.h" + #include "error.h" +@@ -341,7 +341,7 @@ static int convert_common_config_info(const map_t *map_labels, const container_c + + dup_id_name(common_config, isuladinfo); + args_err = (common_config->created != NULL && +- to_unix_nanos_from_str(common_config->created, &isuladinfo->created) != 0); ++ util_to_unix_nanos_from_str(common_config->created, &isuladinfo->created) != 0); + if (args_err) { + ret = -1; + goto out; +@@ -439,7 +439,7 @@ static int fill_isuladinfo(container_container *isuladinfo, const container_conf + + isuladinfo->health_state = container_get_health_state(cont_state); + if (cont->common_config->created != NULL) { +- ret = to_unix_nanos_from_str(cont->common_config->created, &created_nanos); ++ ret = util_to_unix_nanos_from_str(cont->common_config->created, &created_nanos); + if (ret != 0) { + goto out; + } +diff --git a/src/daemon/executor/image_cb/image_cb.c b/src/daemon/executor/image_cb/image_cb.c +index 63a780b..fcacff8 100644 +--- a/src/daemon/executor/image_cb/image_cb.c ++++ b/src/daemon/executor/image_cb/image_cb.c +@@ -12,7 +12,7 @@ + * Create: 2018-11-1 + * Description: provide image functions + *********************************************************************************/ +- ++#include "image_cb.h" + #include + #include + #include +@@ -41,7 +41,6 @@ + #include + #include + +-#include "image_cb.h" + #include "utils.h" + #include "error.h" + #include "err_msg.h" +@@ -596,7 +595,7 @@ static int trans_one_image(image_list_images_response *response, size_t image_in + int64_t created_nanos = 0; + types_timestamp_t timestamp; + +- if (to_unix_nanos_from_str(im_image->created, &created_nanos) != 0) { ++ if (util_to_unix_nanos_from_str(im_image->created, &created_nanos) != 0) { + ERROR("Failed to translate created time to nanos"); + ret = -1; + goto out; +@@ -930,7 +929,7 @@ out: + return ret; + } + +-/* When inspect none image, we respone following string according hasen's request. */ ++/* When inspect none image, we respond following string according hasen's request. */ + #define INSPECT_NONE_IMAGE_RESP \ + "{ \ + \"ContainerConfig\": { \ +diff --git a/src/daemon/executor/volume_cb/CMakeLists.txt b/src/daemon/executor/volume_cb/CMakeLists.txt +new file mode 100644 +index 0000000..1f6352e +--- /dev/null ++++ b/src/daemon/executor/volume_cb/CMakeLists.txt +@@ -0,0 +1,12 @@ ++# get current directory sources files ++aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} local_volume_cb_srcs) ++ ++set(VOLUME_CB_SRCS ++ ${local_volume_cb_srcs} ++ PARENT_SCOPE ++ ) ++ ++set(VOLUME_CB_INCS ++ ${CMAKE_CURRENT_SOURCE_DIR} ++ PARENT_SCOPE ++ ) +diff --git a/src/daemon/executor/volume_cb/volume_cb.c b/src/daemon/executor/volume_cb/volume_cb.c +new file mode 100644 +index 0000000..8efddad +--- /dev/null ++++ b/src/daemon/executor/volume_cb/volume_cb.c +@@ -0,0 +1,207 @@ ++/****************************************************************************** ++ * 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-09-03 ++ * Description: provide volume functions ++ *********************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include "isula_libutils/volume_list_volume_request.h" ++#include "isula_libutils/volume_list_volume_response.h" ++#include "isula_libutils/volume_remove_volume_request.h" ++#include "isula_libutils/volume_remove_volume_response.h" ++#include "isula_libutils/volume_prune_volume_request.h" ++#include "isula_libutils/volume_prune_volume_response.h" ++#include "isula_libutils/volume_volume.h" ++#include ++#include ++#include ++#include ++ ++#include "volume_cb.h" ++#include "utils.h" ++#include "error.h" ++#include "err_msg.h" ++#include "isula_libutils/log.h" ++#include "volume_api.h" ++ ++/* volume list cb */ ++static int volume_list_cb(const volume_list_volume_request *request, volume_list_volume_response **response) ++{ ++ uint32_t cc = ISULAD_SUCCESS; ++ struct volumes *list = NULL; ++ size_t i = 0; ++ volume_volume *vol = NULL; ++ ++ DAEMON_CLEAR_ERRMSG(); ++ ++ if (request == NULL || response == NULL) { ++ ERROR("Invalid input arguments"); ++ return EINVALIDARGS; ++ } ++ ++ *response = util_common_calloc_s(sizeof(volume_list_volume_response)); ++ if (*response == NULL) { ++ ERROR("Out of memory"); ++ cc = ISULAD_ERR_MEMOUT; ++ goto err_out; ++ } ++ ++ EVENT("Volume Event: {Object: list volumes, Type: listing}"); ++ ++ list = volume_list(); ++ if (list == NULL) { ++ cc = ISULAD_ERR_EXEC; ++ goto err_out; ++ } ++ ++ if (list->vols_len == 0) { ++ goto out; ++ } ++ ++ (*response)->volumes = util_common_calloc_s(sizeof(volume_volume *) * list->vols_len); ++ if ((*response)->volumes == NULL) { ++ ERROR("out of memory"); ++ cc = ISULAD_ERR_MEMOUT; ++ goto err_out; ++ } ++ ++ for (i = 0; i < list->vols_len; i++) { ++ vol = util_common_calloc_s(sizeof(volume_volume)); ++ if (vol == NULL) { ++ ERROR("out of memory"); ++ cc = ISULAD_ERR_MEMOUT; ++ goto err_out; ++ } ++ vol->driver = util_strdup_s(list->vols[i]->driver); ++ vol->name = util_strdup_s(list->vols[i]->name); ++ (*response)->volumes[i] = vol; ++ (*response)->volumes_len++; ++ } ++ ++out: ++ EVENT("Volume Event: {Object: list volumes, Type: listed"); ++ ++err_out: ++ if (*response != NULL) { ++ (*response)->cc = cc; ++ if (g_isulad_errmsg != NULL) { ++ (*response)->errmsg = util_strdup_s(g_isulad_errmsg); ++ DAEMON_CLEAR_ERRMSG(); ++ } ++ } ++ free_volumes(list); ++ ++ return (cc != ISULAD_SUCCESS) ? ECOMMON : 0; ++} ++ ++/* volume remove cb */ ++static int volume_remove_cb(const volume_remove_volume_request *request, volume_remove_volume_response **response) ++{ ++ uint32_t cc = ISULAD_SUCCESS; ++ ++ DAEMON_CLEAR_ERRMSG(); ++ ++ if (request == NULL || request->name == NULL || response == NULL) { ++ ERROR("Invalid input arguments"); ++ return EINVALIDARGS; ++ } ++ ++ *response = util_common_calloc_s(sizeof(volume_remove_volume_response)); ++ if (*response == NULL) { ++ ERROR("Out of memory"); ++ cc = ISULAD_ERR_MEMOUT; ++ goto out; ++ } ++ ++ EVENT("Volume Event: {Object: %s, Type: Deleting}", request->name); ++ ++ if (volume_remove(request->name) != 0) { ++ cc = ISULAD_ERR_EXEC; ++ goto out; ++ } ++ ++ EVENT("Volume Event: {Object: %s, Type: Deleted}", request->name); ++ ++out: ++ if (*response != NULL) { ++ (*response)->cc = cc; ++ if (g_isulad_errmsg != NULL) { ++ (*response)->errmsg = util_strdup_s(g_isulad_errmsg); ++ DAEMON_CLEAR_ERRMSG(); ++ } ++ } ++ ++ return (cc != ISULAD_SUCCESS) ? ECOMMON : 0; ++} ++ ++/* volume prune cb */ ++static int volume_prune_cb(const volume_prune_volume_request *request, volume_prune_volume_response **response) ++{ ++ uint32_t cc = ISULAD_SUCCESS; ++ struct volume_names *pruned = NULL; ++ ++ DAEMON_CLEAR_ERRMSG(); ++ ++ if (request == NULL || response == NULL) { ++ ERROR("Invalid input arguments"); ++ return EINVALIDARGS; ++ } ++ ++ *response = util_common_calloc_s(sizeof(volume_prune_volume_response)); ++ if (*response == NULL) { ++ ERROR("Out of memory"); ++ cc = ISULAD_ERR_MEMOUT; ++ goto out; ++ } ++ ++ EVENT("Volume Event: {Object: prune volumes, Type: Prune}"); ++ ++ if (volume_prune(&pruned) != 0) { ++ cc = ISULAD_ERR_EXEC; ++ goto out; ++ } ++ ++ (*response)->volumes = pruned->names; ++ pruned->names = NULL; ++ (*response)->volumes_len = pruned->names_len; ++ pruned->names_len = 0; ++ ++ EVENT("Volume Event: {Object: prune volumes, Type: Pruned"); ++ ++out: ++ if (*response != NULL) { ++ (*response)->cc = cc; ++ if (g_isulad_errmsg != NULL) { ++ (*response)->errmsg = util_strdup_s(g_isulad_errmsg); ++ DAEMON_CLEAR_ERRMSG(); ++ } ++ } ++ free_volume_names(pruned); ++ ++ return (cc != ISULAD_SUCCESS) ? ECOMMON : 0; ++} ++ ++/* volume callback init */ ++void volume_callback_init(service_volume_callback_t *cb) ++{ ++ if (cb == NULL) { ++ ERROR("Invalid input arguments"); ++ return; ++ } ++ ++ cb->list = volume_list_cb; ++ cb->remove = volume_remove_cb; ++ cb->prune = volume_prune_cb; ++} +diff --git a/src/daemon/executor/volume_cb/volume_cb.h b/src/daemon/executor/volume_cb/volume_cb.h +new file mode 100644 +index 0000000..465af00 +--- /dev/null ++++ b/src/daemon/executor/volume_cb/volume_cb.h +@@ -0,0 +1,32 @@ ++/****************************************************************************** ++ * 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-09-03 ++ * Description: provide volume function definition ++ ********************************************************************************/ ++ ++#ifndef DAEMON_EXECUTOR_VOLUME_CB_VOLUME_CB_H ++#define DAEMON_EXECUTOR_VOLUME_CB_VOLUME_CB_H ++ ++#include "callback.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++void volume_callback_init(service_volume_callback_t *cb); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif ++ +diff --git a/src/daemon/modules/CMakeLists.txt b/src/daemon/modules/CMakeLists.txt +index 229ccfd..c5b6987 100644 +--- a/src/daemon/modules/CMakeLists.txt ++++ b/src/daemon/modules/CMakeLists.txt +@@ -11,6 +11,7 @@ add_subdirectory(events) + add_subdirectory(events_sender) + add_subdirectory(service) + add_subdirectory(api) ++add_subdirectory(volume) + + set(local_modules_srcs + ${modules_top_srcs} +@@ -23,6 +24,7 @@ set(local_modules_srcs + ${EVENTS_SRCS} + ${EVENTS_SENDER_SRCS} + ${SERVICE_SRCS} ++ ${VOLUME_SRCS} + ) + + set(local_modules_incs +@@ -37,6 +39,7 @@ set(local_modules_incs + ${EVENTS_SENDER_INCS} + ${SERVICE_INCS} + ${MODULES_API_INCS} ++ ${VOLUME_INCS} + ) + + set(MODULES_SRCS +diff --git a/src/daemon/modules/api/service_container_api.h b/src/daemon/modules/api/service_container_api.h +index 387a042..587b71e 100644 +--- a/src/daemon/modules/api/service_container_api.h ++++ b/src/daemon/modules/api/service_container_api.h +@@ -35,6 +35,9 @@ void umount_host_channel(const host_config_host_channel *host_channel); + + void umount_share_shm(container_t *cont); + ++int release_volumes(container_config_v2_common_config_mount_points *mount_points, ++ char *id, bool rm_anonymous_volumes); ++ + int kill_container(container_t *cont, uint32_t signal); + + int set_container_to_removal(const container_t *cont); +diff --git a/src/daemon/modules/api/volume_api.h b/src/daemon/modules/api/volume_api.h +new file mode 100644 +index 0000000..2b976ad +--- /dev/null ++++ b/src/daemon/modules/api/volume_api.h +@@ -0,0 +1,93 @@ ++/****************************************************************************** ++* 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-09-07 ++* Description: provide isula volume definition ++*******************************************************************************/ ++#ifndef DAEMON_MODULES_API_VOLUME_API_H ++#define DAEMON_MODULES_API_VOLUME_API_H ++ ++#include ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#define VOLUME_DEFAULT_DRIVER_NAME "local" ++#define VOLUME_DEFAULT_NAME_LEN 64 ++#define VOLUME_ERR_NOT_EXIST -2 ++ ++typedef struct { ++ struct volume * (*create)(char *name); ++ ++ struct volume * (*get)(char *name); ++ ++ int (*mount)(char *name); ++ ++ int (*umount)(char *name); ++ ++ struct volumes * (*list)(void); ++ ++ int (*remove)(char *name); ++} volume_driver; ++ ++struct volume { ++ char *driver; ++ char *name; ++ char *path; ++ // volume mount point, valid only when mounted ++ char *mount_point; ++}; ++ ++struct volumes { ++ struct volume **vols; ++ size_t vols_len; ++}; ++ ++struct volume_names { ++ char **names; ++ size_t names_len; ++}; ++ ++struct volume_options { ++ char *ref; ++}; ++ ++int volume_init(char *root_dir); ++ ++int register_driver(char *name, volume_driver *driver); ++ ++struct volume * volume_create(char *driver_name, char *name, struct volume_options *opts); ++ ++int volume_mount(char *name); ++ ++int volume_umount(char *name); ++ ++struct volumes * volume_list(void); ++ ++int volume_add_ref(char *name, char *ref); ++ ++int volume_del_ref(char *name, char *ref); ++ ++int volume_remove(char *name); ++ ++int volume_prune(struct volume_names **pruned); ++ ++void free_volume_names(struct volume_names *pruned); ++ ++void free_volume(struct volume *vol); ++ ++void free_volumes(struct volumes *vols); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif // DAEMON_MODULES_API_VOLUME_API_H +diff --git a/src/daemon/modules/container/container_events_handler.c b/src/daemon/modules/container/container_events_handler.c +index b227541..59023df 100644 +--- a/src/daemon/modules/container/container_events_handler.c ++++ b/src/daemon/modules/container/container_events_handler.c +@@ -12,6 +12,7 @@ + * Create: 2020-06-22 + * Description: provide container events handler definition + ******************************************************************************/ ++#include "container_events_handler.h" + #include + #include + #include +@@ -21,7 +22,6 @@ + #include + + #include "isula_libutils/log.h" +-#include "container_events_handler.h" + #include "utils.h" + #include "container_api.h" + #include "service_container_api.h" +@@ -141,7 +141,7 @@ static int container_state_changed(container_t *cont, const struct isulad_events + + should_restart = restart_manager_should_restart(id, events->exit_status, + cont->common_config->has_been_manually_stopped, +- time_seconds_since(started_at), &timeout); ++ util_time_seconds_since(started_at), &timeout); + free(started_at); + started_at = NULL; + +diff --git a/src/daemon/modules/container/container_gc/containers_gc.c b/src/daemon/modules/container/container_gc/containers_gc.c +index dbf2077..b5a4fd9 100644 +--- a/src/daemon/modules/container/container_gc/containers_gc.c ++++ b/src/daemon/modules/container/container_gc/containers_gc.c +@@ -12,6 +12,7 @@ + * Create: 2017-11-22 + * Description: provide container gc functions + ******************************************************************************/ ++#include "containers_gc.h" + #include + #include + #include +@@ -27,7 +28,6 @@ + #include + + #include "constants.h" +-#include "containers_gc.h" + #include "isulad_config.h" + #include "isula_libutils/container_garbage_config.h" + #include "isula_libutils/log.h" +@@ -130,7 +130,7 @@ out: + return ret; + } + +-/* notes: this funciton must be called with gc_containers_lock */ ++/* notes: this function must be called with gc_containers_lock */ + static int gc_containers_to_disk() + { + int ret = 0; +@@ -356,7 +356,7 @@ static void apply_restart_policy_after_gc(const char *id) + exit_code = container_state_get_exitcode(cont->state); + + should_restart = restart_manager_should_restart(id, exit_code, cont->common_config->has_been_manually_stopped, +- time_seconds_since(started_at), &timeout); ++ util_time_seconds_since(started_at), &timeout); + free(started_at); + + if (should_restart) { +@@ -535,7 +535,7 @@ static void *gchandler(void *arg) + do_gc_container(it); + + wait_continue: +- usleep_nointerupt(100 * 1000); /* wait 100 millisecond to check next gc container */ ++ util_usleep_nointerupt(100 * 1000); /* wait 100 millisecond to check next gc container */ + } + error: + return NULL; +diff --git a/src/daemon/modules/container/container_state.c b/src/daemon/modules/container/container_state.c +index 47f12ac..21f435b 100644 +--- a/src/daemon/modules/container/container_state.c ++++ b/src/daemon/modules/container/container_state.c +@@ -12,6 +12,7 @@ + * Create: 2017-11-22 + * Description: provide container state functions + ******************************************************************************/ ++#include "container_state.h" + #include + #include + #include +@@ -20,7 +21,6 @@ + #include + #include + +-#include "container_state.h" + #include "isula_libutils/log.h" + #include "utils.h" + #include "constants.h" +@@ -167,7 +167,7 @@ void container_state_set_running(container_state_t *s, const pid_ppid_info_t *pi + state->p_start_time = 0; + } + +- (void)get_now_time_buffer(timebuffer, sizeof(timebuffer)); ++ (void)util_get_now_time_buffer(timebuffer, sizeof(timebuffer)); + free(state->started_at); + state->started_at = util_strdup_s(timebuffer); + +@@ -198,7 +198,7 @@ void container_state_set_stopped(container_state_t *s, int exit_code) + state->p_pid = 0; + state->p_start_time = 0; + +- (void)get_now_time_buffer(timebuffer, sizeof(timebuffer)); ++ (void)util_get_now_time_buffer(timebuffer, sizeof(timebuffer)); + free(state->finished_at); + state->finished_at = util_strdup_s(timebuffer); + +@@ -259,7 +259,7 @@ void container_restart_update_start_and_finish_time(container_state_t *s, const + state->paused = false; + state->exit_code = 0; + +- (void)get_now_time_buffer(timebuffer, sizeof(timebuffer)); ++ (void)util_get_now_time_buffer(timebuffer, sizeof(timebuffer)); + free(state->finished_at); + state->finished_at = util_strdup_s(finish_at); + free(state->started_at); +@@ -294,7 +294,7 @@ void container_state_set_restarting(container_state_t *s, int exit_code) + state->p_start_time = 0; + state->exit_code = exit_code; + +- (void)get_now_time_buffer(timebuffer, sizeof(timebuffer)); ++ (void)util_get_now_time_buffer(timebuffer, sizeof(timebuffer)); + free(state->finished_at); + state->finished_at = util_strdup_s(timebuffer); + +diff --git a/src/daemon/modules/container/container_unix.c b/src/daemon/modules/container/container_unix.c +index a37ea94..9d4a76e 100644 +--- a/src/daemon/modules/container/container_unix.c ++++ b/src/daemon/modules/container/container_unix.c +@@ -12,6 +12,7 @@ + * Create: 2017-11-22 + * Description: provide container unix functions + ******************************************************************************/ ++#include "container_unix.h" + #include + #include + #include +@@ -28,7 +29,6 @@ + #include + + #include "constants.h" +-#include "container_unix.h" + #include "isula_libutils/log.h" + #include "container_state.h" + #include "restartmanager.h" +@@ -44,6 +44,7 @@ + #include "utils_convert.h" + #include "utils_file.h" + #include "utils_string.h" ++#include "volume_api.h" + + static int parse_container_log_configs(container_t *cont); + +@@ -344,6 +345,7 @@ static int container_wait_rm_cond_wait(container_t *cont, int timeout) + int container_wait_rm_locking(container_t *cont, int timeout) + { + int ret = 0; ++ container_t *cont_tmp = NULL; + + if (cont == NULL) { + return -1; +@@ -351,8 +353,17 @@ int container_wait_rm_locking(container_t *cont, int timeout) + + container_lock(cont); + ++ /* check if container was deregistered by previous rm already */ ++ cont_tmp = containers_store_get(cont->common_config->id); ++ if (cont_tmp == NULL) { ++ ret = 0; ++ goto unlock; ++ } ++ container_unref(cont_tmp); ++ + ret = container_wait_rm_cond_wait(cont, timeout); + ++unlock: + container_unlock(cont); + + return ret; +@@ -740,6 +751,38 @@ out: + return ret; + } + ++static int restore_volumes(container_config_v2_common_config_mount_points *mount_points, char *id) ++{ ++ int ret = 0; ++ size_t i = 0; ++ ++ // no mount point is valid ++ if (mount_points == NULL || mount_points->len == 0) { ++ return 0; ++ } ++ ++ if (id == NULL) { ++ ERROR("invalid null container id found when restore volumes"); ++ return -1; ++ } ++ ++ for (i = 0; i < mount_points->len; i++) { ++ // only volume have name ++ if (mount_points->values[i]->name == NULL) { ++ continue; ++ } ++ ++ // add reference to this volume ++ if (volume_add_ref(mount_points->values[i]->name, id) != 0) { ++ ERROR("add reference %s to volume %s failed", id, mount_points->values[i]->name); ++ ret = -1; ++ break; ++ } ++ } ++ ++ return ret; ++} ++ + /* container load */ + container_t *container_load(const char *runtime, const char *rootpath, const char *statepath, const char *id) + { +@@ -748,6 +791,7 @@ container_t *container_load(const char *runtime, const char *rootpath, const cha + host_config *hostconfig = NULL; + const char *image_id = NULL; + container_t *cont = NULL; ++ container_config_v2_common_config_mount_points *mount_points = NULL; + + if (rootpath == NULL || statepath == NULL || id == NULL || runtime == NULL) { + return NULL; +@@ -770,6 +814,9 @@ container_t *container_load(const char *runtime, const char *rootpath, const cha + goto error_out; + } + ++ if (v2config->common_config != NULL) { ++ mount_points = v2config->common_config->mount_points; ++ } + common_config = v2config->common_config; + v2config->common_config = NULL; + image_id = v2config->image; +@@ -780,6 +827,10 @@ container_t *container_load(const char *runtime, const char *rootpath, const cha + goto error_out; + } + ++ if (restore_volumes(mount_points, (char*)id) != 0) { ++ goto error_out; ++ } ++ + /* replace cont->state->state with v2config->state */ + free_container_config_v2_state(cont->state->state); + +@@ -1127,4 +1178,4 @@ int container_module_init(char **msg) + + out: + return ret; +-} +\ No newline at end of file ++} +diff --git a/src/daemon/modules/container/health_check/health_check.c b/src/daemon/modules/container/health_check/health_check.c +index 8905f90..6b1f19c 100644 +--- a/src/daemon/modules/container/health_check/health_check.c ++++ b/src/daemon/modules/container/health_check/health_check.c +@@ -13,6 +13,7 @@ + * Description: provide health check functions + *********************************************************************************/ + #define _GNU_SOURCE ++#include "health_check.h" + #include + #include + #include +@@ -27,7 +28,6 @@ + + #include "isula_libutils/log.h" + #include "utils.h" +-#include "health_check.h" + #include "service_container_api.h" + #include "log_gather_api.h" + #include "container_state.h" +@@ -297,8 +297,8 @@ static int append_last_log_result(defs_health *health, const defs_health_log_ele + return -1; + } + +- ret = mem_realloc((void **)(&tmp_log), (health->log_len + 1) * sizeof(defs_health_log_element *), health->log, +- health->log_len * sizeof(defs_health_log_element *)); ++ ret = util_mem_realloc((void **)(&tmp_log), (health->log_len + 1) * sizeof(defs_health_log_element *), health->log, ++ health->log_len * sizeof(defs_health_log_element *)); + if (ret != 0) { + ERROR("failed to realloc memory"); + return -1; +@@ -356,12 +356,12 @@ static int handle_unhealthy_case(container_t *cont, const defs_health_log_elemen + DEFAULT_START_PERIOD : + cont->common_config->config->healthcheck->start_period; + int64_t first, last; +- if (to_unix_nanos_from_str(cont->state->state->started_at, &first)) { ++ if (util_to_unix_nanos_from_str(cont->state->state->started_at, &first)) { + ERROR("Parse container started time failed: %s", cont->state->state->started_at); + ret = -1; + goto out; + } +- if (to_unix_nanos_from_str(result->start, &last)) { ++ if (util_to_unix_nanos_from_str(result->start, &last)) { + ERROR("Parse last health check start time failed: %s", result->start); + ret = -1; + goto out; +@@ -560,7 +560,7 @@ void *health_check_run(void *arg) + cmd_slice = NULL; + EVENT("EVENT: {Object: %s, Type: Health checking}", cont->common_config->id); + +- (void)get_now_time_buffer(timebuffer, sizeof(timebuffer)); ++ (void)util_get_now_time_buffer(timebuffer, sizeof(timebuffer)); + result = util_common_calloc_s(sizeof(defs_health_log_element)); + if (result == NULL) { + ERROR("Out of memory"); +@@ -581,7 +581,7 @@ void *health_check_run(void *arg) + health_check_exec_success_handle(container_res, result, output); + } + +- (void)get_now_time_buffer(timebuffer, sizeof(timebuffer)); ++ (void)util_get_now_time_buffer(timebuffer, sizeof(timebuffer)); + result->end = util_strdup_s(timebuffer); + + if (handle_probe_result(cont->common_config->id, result) != 0) { +@@ -644,7 +644,7 @@ static int do_monitor_interval(const char *container_id, health_check_manager_t + goto out; + } + set_monitor_idle_status(health_check); +- if (get_now_time_stamp(start_timestamp) == false) { ++ if (util_get_now_time_stamp(start_timestamp) == false) { + ERROR("Failed to get time stamp"); + ret = -1; + goto out; +@@ -658,12 +658,12 @@ static int do_monitor_default(int64_t probe_interval, health_check_manager_t *he + { + int64_t time_interval = 0; + +- if (get_now_time_stamp(last_timestamp) == false) { ++ if (util_get_now_time_stamp(last_timestamp) == false) { + ERROR("Failed to get time stamp"); + return -1; + } + +- if (get_time_interval(*start_timestamp, *last_timestamp, &time_interval)) { ++ if (util_get_time_interval(*start_timestamp, *last_timestamp, &time_interval)) { + ERROR("Failed to get time interval"); + return -1; + } +@@ -671,7 +671,7 @@ static int do_monitor_default(int64_t probe_interval, health_check_manager_t *he + if (time_interval >= probe_interval) { + set_monitor_interval_timeout_status(health_check); + } +- usleep_nointerupt(500); ++ util_usleep_nointerupt(500); + + return 0; + } +@@ -697,7 +697,7 @@ static void *health_check_monitor(void *arg) + goto out; + } + +- if (get_now_time_stamp(&start_timestamp) == false) { ++ if (util_get_now_time_stamp(&start_timestamp) == false) { + ERROR("Failed to monitor start time stamp"); + goto out; + } +diff --git a/src/daemon/modules/container/restore/restore.c b/src/daemon/modules/container/restore/restore.c +index 372d4bd..be7caed 100644 +--- a/src/daemon/modules/container/restore/restore.c ++++ b/src/daemon/modules/container/restore/restore.c +@@ -12,7 +12,7 @@ + * Create: 2017-11-22 + * Description: provide container list callback function definition + ********************************************************************************/ +- ++#include "restore.h" + #include + #include + #include +@@ -25,7 +25,6 @@ + + #include "isulad_config.h" + #include "isula_libutils/log.h" +-#include "restore.h" + #include "container_api.h" + #include "supervisor.h" + #include "containers_gc.h" +@@ -348,7 +347,7 @@ static void restored_restart_container(container_t *cont) + + started_at = container_state_get_started_at(cont->state); + if (restart_manager_should_restart(id, container_state_get_exitcode(cont->state), +- cont->common_config->has_been_manually_stopped, time_seconds_since(started_at), ++ cont->common_config->has_been_manually_stopped, util_time_seconds_since(started_at), + &timeout)) { + cont->common_config->restart_count++; + INFO("Restart container %s after 5 second", id); +diff --git a/src/daemon/modules/container/supervisor/supervisor.c b/src/daemon/modules/container/supervisor/supervisor.c +index ac49f6a..3aee08c 100644 +--- a/src/daemon/modules/container/supervisor/supervisor.c ++++ b/src/daemon/modules/container/supervisor/supervisor.c +@@ -13,6 +13,7 @@ + * Description: provide container supervisor functions + ******************************************************************************/ + #define _GNU_SOURCE ++#include "supervisor.h" + #include + #include + #include +@@ -29,7 +30,6 @@ + + #include "isula_libutils/log.h" + #include "utils.h" +-#include "supervisor.h" + #include "mainloop.h" + #include "err_msg.h" + #include "events_sender_api.h" +@@ -189,7 +189,7 @@ retry: + } + + if (retry_count < max_retry) { +- usleep_nointerupt(100 * 1000); /* 100 millisecond */ ++ util_usleep_nointerupt(100 * 1000); /* 100 millisecond */ + retry_count++; + goto retry; + } +diff --git a/src/daemon/modules/events/collector.c b/src/daemon/modules/events/collector.c +index 1165972..3e587ae 100644 +--- a/src/daemon/modules/events/collector.c ++++ b/src/daemon/modules/events/collector.c +@@ -598,7 +598,7 @@ out: + static int check_since_time(const types_timestamp_t *since, const struct isulad_events_format *event) + { + if (since != NULL && (since->has_seconds || since->has_nanos)) { +- if (types_timestamp_cmp(&event->timestamp, since) < 0) { ++ if (util_types_timestamp_cmp(&event->timestamp, since) < 0) { + return -1; + } + } +@@ -608,7 +608,7 @@ static int check_since_time(const types_timestamp_t *since, const struct isulad_ + static int check_util_time(const types_timestamp_t *until, const struct isulad_events_format *event) + { + if (until != NULL && (until->has_seconds || until->has_nanos)) { +- if (types_timestamp_cmp(&event->timestamp, until) > 0) { ++ if (util_types_timestamp_cmp(&event->timestamp, until) > 0) { + return -1; + } + } +@@ -684,7 +684,7 @@ int events_subscribe(const char *name, const types_timestamp_t *since, const typ + + if (since != NULL && (since->has_seconds || since->has_nanos) && until != NULL && + (until->has_seconds || until->has_nanos)) { +- if (types_timestamp_cmp(since, until) > 0) { ++ if (util_types_timestamp_cmp(since, until) > 0) { + ERROR("'since' time cannot be after 'until' time"); + return -1; + } +@@ -717,7 +717,7 @@ static void events_forward(struct isulad_events_format *r) + name = context_info->name; + + if (context_info->since != NULL) { +- if (types_timestamp_cmp(&r->timestamp, context_info->since) < 0) { ++ if (util_types_timestamp_cmp(&r->timestamp, context_info->since) < 0) { + continue; + } + } +@@ -806,7 +806,7 @@ static void *event_should_exit(void *arg) + t_now.has_nanos = true; + t_now.nanos = (int32_t)ts_now.tv_nsec; + +- if (types_timestamp_cmp(&t_now, context_info->until) > 0) { ++ if (util_types_timestamp_cmp(&t_now, context_info->until) > 0) { + INFO("Finish response for RPC, client should exit"); + linked_list_del(it); + sem_post(&context_info->context_sem); +@@ -988,15 +988,15 @@ out: + return ret; + } + +-static int start_monitord() ++static int start_monitored() + { + int ret = 0; +- int monitord_exitcode = 0; ++ int monitored_exitcode = 0; + sem_t monitord_sem; + struct monitord_sync_data msync = { 0 }; + + msync.monitord_sem = &monitord_sem; +- msync.exit_code = &monitord_exitcode; ++ msync.exit_code = &monitored_exitcode; + if (sem_init(msync.monitord_sem, 0, 0)) { + isulad_set_error_message("Failed to init monitor sem"); + ret = -1; +@@ -1004,7 +1004,7 @@ static int start_monitord() + } + + if (new_monitord(&msync)) { +- isulad_set_error_message("Create monitord thread failed"); ++ isulad_set_error_message("Create monitored thread failed"); + ret = -1; + sem_destroy(msync.monitord_sem); + goto out; +@@ -1012,8 +1012,8 @@ static int start_monitord() + + sem_wait(msync.monitord_sem); + sem_destroy(msync.monitord_sem); +- if (monitord_exitcode) { +- isulad_set_error_message("Monitord start failed"); ++ if (monitored_exitcode) { ++ isulad_set_error_message("Monitored start failed"); + ret = -1; + goto out; + } +@@ -1032,7 +1032,7 @@ int events_module_init(char **msg) + goto out; + } + +- if (start_monitord()) { ++ if (start_monitored()) { + *msg = g_isulad_errmsg ? g_isulad_errmsg : "Failed to init cgroups path"; + ret = -1; + goto out; +diff --git a/src/daemon/modules/events/monitord.c b/src/daemon/modules/events/monitord.c +index 70ab4eb..69c23aa 100644 +--- a/src/daemon/modules/events/monitord.c ++++ b/src/daemon/modules/events/monitord.c +@@ -10,10 +10,10 @@ + * See the Mulan PSL v2 for more details. + * Author: tanyifeng + * Create: 2017-11-22 +- * Description: provide container monitord functions ++ * Description: provide container monitored functions + ******************************************************************************/ + #define _GNU_SOURCE +- ++#include "monitord.h" + #include + #include + #include +@@ -26,14 +26,13 @@ + #include + + #include "isula_libutils/log.h" +-#include "monitord.h" + #include "mainloop.h" + #include "isulad_config.h" + #include "events_collector_api.h" + #include "event_type.h" + #include "utils_file.h" + +-struct monitord_handler { ++struct monitored_handler { + struct epoll_descr *pdescr; + int fifo_fd; + char *fifo_path; +@@ -61,8 +60,8 @@ out: + return 0; + } + +-/* free monitord */ +-static void free_monitord(struct monitord_handler *mhandler) ++/* free monitored */ ++static void free_monitored(struct monitored_handler *mhandler) + { + if (mhandler->fifo_fd != -1) { + epoll_loop_del_handler(mhandler->pdescr, mhandler->fifo_fd); +@@ -76,16 +75,16 @@ static void free_monitord(struct monitord_handler *mhandler) + mhandler->fifo_path = NULL; + } + +- DEBUG("Clean monitord data..."); ++ DEBUG("Clean monitored data..."); + } + + #define EVENTS_FIFO_SIZE (1024 * 1024) +-/* monitord */ +-static void *monitord(void *arg) ++/* monitored */ ++static void *monitored(void *arg) + { + int ret = 0; + char *fifo_file_path = NULL; +- struct monitord_handler mhandler = { 0 }; ++ struct monitored_handler mhandler = { 0 }; + struct flock mlock; + struct monitord_sync_data *msync = arg; + struct epoll_descr descr; +@@ -97,7 +96,7 @@ static void *monitord(void *arg) + goto pexit; + } + +- prctl(PR_SET_NAME, "Monitord"); ++ prctl(PR_SET_NAME, "Monitored"); + + ret = epoll_loop_open(&descr); + if (ret != 0) { +@@ -114,13 +113,13 @@ static void *monitord(void *arg) + mhandler.fifo_path = fifo_file_path; + + if (mknod(fifo_file_path, S_IFIFO | S_IRUSR | S_IWUSR, (dev_t)0) && errno != EEXIST) { +- ERROR("Create monitord fifo file failed: %s", strerror(errno)); ++ ERROR("Create monitored fifo file failed: %s", strerror(errno)); + goto err; + } + + mhandler.fifo_fd = util_open(fifo_file_path, O_RDWR | O_NONBLOCK | O_CLOEXEC, 0); + if (mhandler.fifo_fd == -1) { +- ERROR("Open monitord fifo file failed: %s", strerror(errno)); ++ ERROR("Open monitored fifo file failed: %s", strerror(errno)); + goto err; + } + +@@ -134,7 +133,7 @@ static void *monitord(void *arg) + mlock.l_start = 0; + mlock.l_len = 0; + if (fcntl(mhandler.fifo_fd, F_SETLK, &mlock)) { +- INFO("Monitord already running on path: %s", fifo_file_path); ++ INFO("Monitored already running on path: %s", fifo_file_path); + goto err; + } + +@@ -146,7 +145,7 @@ static void *monitord(void *arg) + + sem_post(msync->monitord_sem); + +- /* loop forever except error occured */ ++ /* loop forever except error occurred */ + do { + ret = epoll_loop(&descr, -1); + } while (ret == 0); +@@ -158,22 +157,22 @@ err: + *(msync->exit_code) = -1; + sem_post(msync->monitord_sem); + err2: +- free_monitord(&mhandler); ++ free_monitored(&mhandler); + epoll_loop_close(&descr); + + pexit: + return NULL; + } + +-/* new monitord */ ++/* new monitored */ + int new_monitord(struct monitord_sync_data *msync) + { + int ret = 0; + char *statedir = NULL; +- pthread_t monitord_thread; ++ pthread_t monitored_thread; + + if (msync == NULL || msync->monitord_sem == NULL) { +- ERROR("Monitord sem is NULL"); ++ ERROR("Monitored sem is NULL"); + ret = -1; + goto out; + } +@@ -185,15 +184,15 @@ int new_monitord(struct monitord_sync_data *msync) + goto out; + } + +- if (setenv("ISULAD_MONITORD_PATH", statedir, 1)) { +- ERROR("Setenv monitord path failed"); ++ if (setenv("ISULAD_MONITORED_PATH", statedir, 1)) { ++ ERROR("Setenv monitored path failed"); + ret = -1; + goto out; + } + +- INFO("Starting monitord..."); +- if (pthread_create(&monitord_thread, NULL, monitord, msync) != 0) { +- ERROR("Create monitord thread failed"); ++ INFO("Starting monitored..."); ++ if (pthread_create(&monitored_thread, NULL, monitored, msync) != 0) { ++ ERROR("Create monitored thread failed"); + ret = -1; + } + +diff --git a/src/daemon/modules/events/monitord.h b/src/daemon/modules/events/monitord.h +index 00a09ca..beace80 100644 +--- a/src/daemon/modules/events/monitord.h ++++ b/src/daemon/modules/events/monitord.h +@@ -10,10 +10,10 @@ + * See the Mulan PSL v2 for more details. + * Author: maoweiyong + * Create: 2017-11-22 +- * Description: provide monitord definition ++ * Description: provide monitored definition + ******************************************************************************/ +-#ifndef DAEMON_MODULES_EVENTS_MONITORD_H +-#define DAEMON_MODULES_EVENTS_MONITORD_H ++#ifndef DAEMON_MODULES_EVENTS_MONITORED_H ++#define DAEMON_MODULES_EVENTS_MONITORED_H + #include + #include + #include +diff --git a/src/daemon/modules/events_sender/event_sender.c b/src/daemon/modules/events_sender/event_sender.c +index 63c8c26..03dcbbf 100644 +--- a/src/daemon/modules/events_sender/event_sender.c ++++ b/src/daemon/modules/events_sender/event_sender.c +@@ -59,7 +59,7 @@ static void isulad_monitor_fifo_send(const struct monitord_msg *msg) + do { + ret = util_write_nointr(fd, msg, sizeof(struct monitord_msg)); + if (ret != sizeof(struct monitord_msg)) { +- usleep_nointerupt(1000); ++ util_usleep_nointerupt(1000); + } + } while (ret != sizeof(struct monitord_msg)); + +diff --git a/src/daemon/modules/image/CMakeLists.txt b/src/daemon/modules/image/CMakeLists.txt +index a4d569e..a92799a 100644 +--- a/src/daemon/modules/image/CMakeLists.txt ++++ b/src/daemon/modules/image/CMakeLists.txt +@@ -100,5 +100,7 @@ target_link_libraries(${LIB_ISULAD_IMG} + ${SELINUX_LIBRARY} + -lpthread -lcrypto -larchive -lz libhttpclient) + ++target_compile_definitions(${LIB_ISULAD_IMG} PRIVATE LIB_ISULAD_IMG_SO) ++ + install(TARGETS ${LIB_ISULAD_IMG} + LIBRARY DESTINATION ${LIB_INSTALL_DIR_DEFAULT} PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE) +diff --git a/src/daemon/modules/image/embedded/db/db_all.c b/src/daemon/modules/image/embedded/db/db_all.c +index 185eb75..9a61158 100644 +--- a/src/daemon/modules/image/embedded/db/db_all.c ++++ b/src/daemon/modules/image/embedded/db/db_all.c +@@ -12,6 +12,7 @@ + * Create: 2018-11-07 + * Description: provide image functions + ******************************************************************************/ ++#include "db_all.h" + #include + #include + #include +@@ -20,7 +21,6 @@ + #include "utils.h" + #include "db_common.h" + #include "sqlite_common.h" +-#include "db_all.h" + + + #define IMAGE_INFO_TABLE_COLUMS_NUM 11 +@@ -299,7 +299,7 @@ static int db_save_image_info_sql(struct db_image *image) + sqlite3_bind_text(stmt, 12, image->config_digest, -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 13, image->config_path, -1, SQLITE_STATIC); + if (sqlite3_step(stmt) != SQLITE_DONE) { +- ERROR("Insert image info into the image infomation table failed!"); ++ ERROR("Insert image info into the image information table failed!"); + ret = DB_FAIL; + } + +@@ -373,7 +373,7 @@ int db_save_image(struct db_image *image) + ret = db_add_image_name_sql(image->image_name, + image->config_digest, image->config_path); + if (ret) { +- /* Should not error when add image name. If error occured, ++ /* Should not error when add image name. If error occurred, + * database is abnormal, so do not rollback. */ + goto out; + } +@@ -699,8 +699,8 @@ static int read_all_images_info(sqlite3_stmt *stmt, void **data) + } + oldsize = (*imagesinfo)->imagesnum * sizeof(struct db_image *); + newsize = ((*imagesinfo)->imagesnum + 1) * sizeof(struct db_image *); +- ret = mem_realloc((void **)(&(*imagesinfo)->images_info), newsize, +- (*imagesinfo)->images_info, oldsize); ++ ret = util_mem_realloc((void **)(&(*imagesinfo)->images_info), newsize, ++ (*imagesinfo)->images_info, oldsize); + if (ret < 0) { + ERROR("Out of memory!"); + goto cleanup; +diff --git a/src/daemon/modules/image/embedded/db/db_all.h b/src/daemon/modules/image/embedded/db/db_all.h +index 4975c34..9fbe272 100644 +--- a/src/daemon/modules/image/embedded/db/db_all.h ++++ b/src/daemon/modules/image/embedded/db/db_all.h +@@ -15,6 +15,9 @@ + #ifndef __DB_ALL_H_ + #define __DB_ALL_H_ + ++#include ++#include ++#include + #include "db_common.h" + + struct db_sninfo { +diff --git a/src/daemon/modules/image/embedded/db/sqlite_common.c b/src/daemon/modules/image/embedded/db/sqlite_common.c +index f8c7c2a..42fdf6d 100644 +--- a/src/daemon/modules/image/embedded/db/sqlite_common.c ++++ b/src/daemon/modules/image/embedded/db/sqlite_common.c +@@ -25,10 +25,10 @@ + + // Waiting at most (10 * 1000ms) when database is busy + // to avoid concurrent write or read. +-#define SQLITE_BUSY_TIMEOUT 120000 ++#define ISULA_SQLITE_BUSY_TIMEOUT 120000 + +-#define SQLITE_PAGECACHE_SIZE 4096 +-#define SQLITE_PAGECACHE_NUM 8 ++#define ISULA_SQLITE_PAGECACHE_SIZE 4096 ++#define ISULA_SQLITE_PAGECACHE_NUM 8 + + sqlite3 *g_db = NULL; + +@@ -74,7 +74,7 @@ int db_sqlite_request(const char *stmt) + char *errmsg = NULL; + int ret; + +- ret = sqlite3_busy_timeout(g_db, SQLITE_BUSY_TIMEOUT); ++ ret = sqlite3_busy_timeout(g_db, ISULA_SQLITE_BUSY_TIMEOUT); + if (ret != SQLITE_OK) { + ERROR("Falied to set sqlite busy timeout"); + return ret; +@@ -94,7 +94,7 @@ int db_sqlite_request_callback(const char *stmt, + char *errmsg = NULL; + int ret; + +- ret = sqlite3_busy_timeout(g_db, SQLITE_BUSY_TIMEOUT); ++ ret = sqlite3_busy_timeout(g_db, ISULA_SQLITE_BUSY_TIMEOUT); + if (ret != SQLITE_OK) { + ERROR("Falied to set sqlite busy timeout"); + return ret; +@@ -163,8 +163,8 @@ int db_common_init(const char *rootpath) + ERROR("Failed to print string"); + return -1; + } +- ret = sqlite3_config(SQLITE_CONFIG_PAGECACHE, NULL, SQLITE_PAGECACHE_SIZE, +- SQLITE_PAGECACHE_NUM); ++ ret = sqlite3_config(SQLITE_CONFIG_PAGECACHE, NULL, ISULA_SQLITE_PAGECACHE_SIZE, ++ ISULA_SQLITE_PAGECACHE_NUM); + if (ret != SQLITE_OK) { + goto open_new_db; + } +diff --git a/src/daemon/modules/image/embedded/embedded_config_merge.c b/src/daemon/modules/image/embedded/embedded_config_merge.c +index c60bbcc..29878a4 100644 +--- a/src/daemon/modules/image/embedded/embedded_config_merge.c ++++ b/src/daemon/modules/image/embedded/embedded_config_merge.c +@@ -13,6 +13,7 @@ + * Description: provide embedded image merge config + ******************************************************************************/ + #define _GNU_SOURCE /* See feature_test_macros(7) */ ++#include "embedded_config_merge.h" + #include /* Obtain O_* constant definitions */ + #include + #include +@@ -28,13 +29,13 @@ + #include "specs_mount.h" + #include "lim.h" + #include "mediatype.h" +-#include "embedded_config_merge.h" ++#include "image_spec_merge.h" + + static int embedded_merge_entrypoint(embedded_config *config, container_config *container_spec) + { + if (config->entrypoint && container_spec->entrypoint_len == 0) { +- int ret = dup_array_of_strings((const char **)config->entrypoint, config->entrypoint_len, +- &(container_spec->entrypoint), &(container_spec->entrypoint_len)); ++ int ret = util_dup_array_of_strings((const char **)config->entrypoint, config->entrypoint_len, ++ &(container_spec->entrypoint), &(container_spec->entrypoint_len)); + if (ret != 0) { + ERROR("Failed to duplicate entrypoint from manifest"); + return -1; +@@ -47,64 +48,16 @@ static int embedded_merge_entrypoint(embedded_config *config, container_config * + static int embedded_merge_env(const embedded_config *config, container_config *container_spec) + { + int ret = 0; +- size_t new_size = 0; +- size_t old_size = 0; +- size_t i = 0; +- size_t j = 0; +- char **temp = NULL; +- char **im_kv = NULL; +- char **custom_kv = NULL; + + if (config->env == NULL || config->env_len == 0) { + return 0; + } + +- if (config->env_len > LIST_ENV_SIZE_MAX - container_spec->env_len) { +- ERROR("The length of envionment variables is too long, the limit is %lld", LIST_ENV_SIZE_MAX); +- isulad_set_error_message("The length of envionment variables is too long, the limit is %lld", +- LIST_ENV_SIZE_MAX); ++ if (image_spec_merge_env((const char **)config->env, config->env_len, container_spec) != 0) { + ret = -1; + goto out; + } +- new_size = (container_spec->env_len + config->env_len) * sizeof(char *); +- old_size = container_spec->env_len * sizeof(char *); +- ret = mem_realloc((void **)&temp, new_size, container_spec->env, old_size); +- if (ret != 0) { +- ERROR("Failed to realloc memory for envionment variables"); +- ret = -1; +- goto out; +- } +- +- container_spec->env = temp; +- for (i = 0; i < config->env_len; i++) { +- bool found = false; +- im_kv = util_string_split(config->env[i], '='); +- if (im_kv == NULL) { +- continue; +- } + +- for (j = 0; j < container_spec->env_len; j++) { +- custom_kv = util_string_split(container_spec->env[j], '='); +- if (custom_kv == NULL) { +- continue; +- } +- if (strcmp(im_kv[0], custom_kv[0]) == 0) { +- found = true; +- } +- util_free_array(custom_kv); +- custom_kv = NULL; +- if (found) { +- break; +- } +- } +- +- if (!found) { +- container_spec->env[container_spec->env_len] = util_strdup_s(config->env[i]); +- container_spec->env_len++; +- } +- util_free_array(im_kv); +- im_kv = NULL; +- } + out: + return ret; + } +diff --git a/src/daemon/modules/image/embedded/embedded_config_merge.h b/src/daemon/modules/image/embedded/embedded_config_merge.h +index db0a15e..d2fd734 100644 +--- a/src/daemon/modules/image/embedded/embedded_config_merge.h ++++ b/src/daemon/modules/image/embedded/embedded_config_merge.h +@@ -15,7 +15,7 @@ + #ifndef __EMBEDDED_IMAGE_MERGE_CONFIG_H_ + #define __EMBEDDED_IMAGE_MERGE_CONFIG_H_ + +-#include "isula_libutils/oci_image_spec.h" ++#include "isula_libutils/container_config.h" + + #ifdef __cplusplus + extern "C" { +@@ -28,4 +28,3 @@ int embedded_image_merge_config(const char *image_config, container_config *cont + #endif + + #endif +- +diff --git a/src/daemon/modules/image/embedded/embedded_image.c b/src/daemon/modules/image/embedded/embedded_image.c +index a73b3d3..02d8d7a 100644 +--- a/src/daemon/modules/image/embedded/embedded_image.c ++++ b/src/daemon/modules/image/embedded/embedded_image.c +@@ -12,6 +12,7 @@ + * Create: 2018-11-08 + * Explanation: provide image functions + ******************************************************************************/ ++#include "embedded_image.h" + #include + #include + #include +@@ -23,7 +24,6 @@ + + #include "image_rootfs_handler.h" + #include "isula_libutils/log.h" +-#include "embedded_image.h" + #include "lim.h" + #include "embedded_config_merge.h" + #include "db_all.h" +diff --git a/src/daemon/modules/image/embedded/lim.c b/src/daemon/modules/image/embedded/lim.c +index 8de60d9..a3834d3 100644 +--- a/src/daemon/modules/image/embedded/lim.c ++++ b/src/daemon/modules/image/embedded/lim.c +@@ -12,13 +12,13 @@ + * Create: 2018-11-08 + * Description: provide image list functions + ******************************************************************************/ ++#include "lim.h" + #include + #include + #include + + #include "error.h" + #include "isula_libutils/log.h" +-#include "lim.h" + #include "err_msg.h" + #include "mediatype.h" + #include "snapshot.h" +@@ -249,7 +249,7 @@ static bool validate_layer_path_in_host(size_t layer_index, const char *location + UTIL_FREE_AND_SET_NULL(tmp_path); + return false; + } +- tmp_path = follow_symlink_in_scope(abs_path, parent_location); ++ tmp_path = util_follow_symlink_in_scope(abs_path, parent_location); + if (tmp_path == NULL || !strncmp(tmp_path, "..", 2)) { + ERROR("invalid layer path %s", path_in_host); + isulad_try_set_error_message("Invalid content in manifest: layer not exists"); +@@ -312,7 +312,7 @@ static bool validate_layer_digest(size_t layer_index, char *path, uint32_t fmod, + /* If layer is a directory, digest must be empty */ + if ((int)fmod == S_IFDIR) { + ERROR("Invalid digest %s, digest must be empty if media type is %s", digest, MediaTypeEmbeddedLayerDir); +- isulad_try_set_error_message("Invalid content in mainfest: layer digest must be empty if mediaType is %s", ++ isulad_try_set_error_message("Invalid content in manifest: layer digest must be empty if mediaType is %s", + MediaTypeEmbeddedLayerDir); + return false; + } +@@ -320,13 +320,13 @@ static bool validate_layer_digest(size_t layer_index, char *path, uint32_t fmod, + /* check if digest format is valid */ + if (!util_valid_digest(digest)) { + ERROR("invalid digest %s for layer", digest); +- isulad_try_set_error_message("Invalid content in mainfest: layer(except first layer) has invalid digest"); ++ isulad_try_set_error_message("Invalid content in manifest: layer(except first layer) has invalid digest"); + return false; + } + + /* calc and check digest */ + if (!sha256_valid_digest_file(path, digest)) { +- isulad_try_set_error_message("Invalid content in mainfest: layer(except first layer) has invalid digest"); ++ isulad_try_set_error_message("Invalid content in manifest: layer(except first layer) has invalid digest"); + return false; + } + +@@ -386,7 +386,7 @@ static bool validate_image_name(char *image_name) + { + if (image_name == NULL) { + ERROR("image name not exist"); +- isulad_try_set_error_message("Invalid content in manfiest: image name not exist"); ++ isulad_try_set_error_message("Invalid content in manifest: image name not exist"); + return false; + } + +@@ -399,7 +399,7 @@ static bool validate_image_name(char *image_name) + + if (!util_valid_embedded_image_name(image_name)) { + ERROR("invalid image name %s", image_name); +- isulad_try_set_error_message("Invalid content in manfiest: invalid image name"); ++ isulad_try_set_error_message("Invalid content in manifest: invalid image name"); + return false; + } + return true; +@@ -410,7 +410,7 @@ static bool validate_image_layers_number(size_t layers_len) + { + if (layers_len > LAYER_NUM_MAX || layers_len < 1) { + ERROR("invalid layers number %ld maxium is %d", layers_len, LAYER_NUM_MAX); +- isulad_try_set_error_message("Invalid content in mainfest: layer empty or max depth exceeded"); ++ isulad_try_set_error_message("Invalid content in manifest: layer empty or max depth exceeded"); + return false; + } + return true; +diff --git a/src/daemon/modules/image/embedded/lim.h b/src/daemon/modules/image/embedded/lim.h +index 7a0f7b8..cb21884 100644 +--- a/src/daemon/modules/image/embedded/lim.h ++++ b/src/daemon/modules/image/embedded/lim.h +@@ -33,7 +33,7 @@ struct image_creator { + struct image_info { + char *image_name; /* image name */ + char *image_type; /* image type. docker or embedded */ +- int64_t size; /* image sieze */ ++ int64_t size; /* image size */ + char *chain_id; /* chain id of image's top layer */ + char *config_digest; /* sha256 digest of image's config */ + }; +diff --git a/src/daemon/modules/image/external/ext_image.c b/src/daemon/modules/image/external/ext_image.c +index feb2351..d918f4c 100644 +--- a/src/daemon/modules/image/external/ext_image.c ++++ b/src/daemon/modules/image/external/ext_image.c +@@ -12,6 +12,7 @@ + * Create: 2018-11-08 + * Description: provide image functions + ******************************************************************************/ ++#include "ext_image.h" + #include + #include + #include +@@ -20,7 +21,6 @@ + + #include "isula_libutils/log.h" + #include "utils.h" +-#include "ext_image.h" + #include "image_rootfs_handler.h" + #include "err_msg.h" + #include "utils_file.h" +diff --git a/src/daemon/modules/image/image.c b/src/daemon/modules/image/image.c +index 87025ad..551c630 100644 +--- a/src/daemon/modules/image/image.c ++++ b/src/daemon/modules/image/image.c +@@ -245,7 +245,7 @@ static const struct bim_type *bim_query(const char *image_name) + } + temp = g_bims[i].ops->resolve_image_name(image_name); + if (temp == NULL) { +- isulad_append_error_message("Failed to resovle image name%s", image_name); ++ isulad_append_error_message("Failed to resolve image name%s", image_name); + return NULL; + } + int r = g_bims[i].ops->detect(temp); +@@ -325,7 +325,7 @@ static struct bim *bim_get(const char *image_type, const char *image_name, const + if (image_name != NULL) { + bim->image_name = bim->ops->resolve_image_name(image_name); + if (bim->image_name == NULL) { +- isulad_append_error_message("Failed to resovle image name%s", image_name); ++ isulad_append_error_message("Failed to resolve image name%s", image_name); + bim_put(bim); + return NULL; + } +@@ -808,7 +808,7 @@ static int append_images_to_response(im_list_response *response, imagetool_image + + new_size = (old_num + images_num) * sizeof(imagetool_image *); + old_size = old_num * sizeof(imagetool_image *); +- ret = mem_realloc((void **)(&tmp), new_size, response->images->images, old_size); ++ ret = util_mem_realloc((void **)(&tmp), new_size, response->images->images, old_size); + if (ret != 0) { + ERROR("Failed to realloc memory for append images"); + ret = -1; +@@ -962,17 +962,17 @@ void free_im_pull_request(im_pull_request *req) + req->type = NULL; + free(req->image); + req->image = NULL; +- free_sensitive_string(req->username); ++ util_free_sensitive_string(req->username); + req->username = NULL; +- free_sensitive_string(req->password); ++ util_free_sensitive_string(req->password); + req->password = NULL; +- free_sensitive_string(req->auth); ++ util_free_sensitive_string(req->auth); + req->auth = NULL; +- free_sensitive_string(req->server_address); ++ util_free_sensitive_string(req->server_address); + req->server_address = NULL; +- free_sensitive_string(req->registry_token); ++ util_free_sensitive_string(req->registry_token); + req->registry_token = NULL; +- free_sensitive_string(req->identity_token); ++ util_free_sensitive_string(req->identity_token); + req->identity_token = NULL; + free(req); + } +@@ -1235,16 +1235,16 @@ void free_im_login_request(im_login_request *ptr) + return; + } + +- free_sensitive_string(ptr->username); ++ util_free_sensitive_string(ptr->username); + ptr->username = NULL; + +- free_sensitive_string(ptr->password); ++ util_free_sensitive_string(ptr->password); + ptr->password = NULL; + + free(ptr->type); + ptr->type = NULL; + +- free_sensitive_string(ptr->server); ++ util_free_sensitive_string(ptr->server); + ptr->server = NULL; + + free(ptr); +diff --git a/src/daemon/modules/image/image_rootfs_handler.c b/src/daemon/modules/image/image_rootfs_handler.c +index dd30535..19735f6 100644 +--- a/src/daemon/modules/image/image_rootfs_handler.c ++++ b/src/daemon/modules/image/image_rootfs_handler.c +@@ -41,43 +41,6 @@ + #define UnixPasswdPath "/etc/passwd" + #define UnixGroupPath "/etc/group" + +-static void parse_user_group(const char *username, char **user, char **group, char **tmp_dup) +-{ +- char *tmp = NULL; +- char *pdot = NULL; +- +- if (user == NULL || group == NULL || tmp_dup == NULL) { +- return; +- } +- +- if (username != NULL) { +- tmp = util_strdup_s(username); +- +- // for free tmp in caller +- *tmp_dup = tmp; +- +- pdot = strstr(tmp, ":"); +- if (pdot != NULL) { +- *pdot = '\0'; +- if (pdot != tmp) { +- // User found +- *user = tmp; +- } +- if (*(pdot + 1) != '\0') { +- // group found +- *group = pdot + 1; +- } +- } else { +- // No : found +- if (*tmp != '\0') { +- *user = tmp; +- } +- } +- } +- +- return; +-} +- + static void uids_gids_range_err_log() + { + ERROR("uids and gids must be in range 0-%lld", MAXUID); +@@ -189,7 +152,7 @@ static int append_additional_gids(gid_t gid, gid_t **additional_gids, size_t *le + } + } + +- ret = mem_realloc((void **)&new_gids, new_len * sizeof(gid_t), *additional_gids, (*len) * sizeof(gid_t)); ++ ret = util_mem_realloc((void **)&new_gids, new_len * sizeof(gid_t), *additional_gids, (*len) * sizeof(gid_t)); + if (ret != 0) { + ERROR("Out of memory"); + return -1; +@@ -310,7 +273,7 @@ static int append_additional_groups(const struct group *grp, struct group **grou + struct group *new_groups = NULL; + size_t new_len = *len + 1; + +- ret = mem_realloc((void **)&new_groups, new_len * sizeof(struct group), *groups, (*len) * sizeof(struct group)); ++ ret = util_mem_realloc((void **)&new_groups, new_len * sizeof(struct group), *groups, (*len) * sizeof(struct group)); + if (ret != 0) { + ERROR("Out of memory"); + return -1; +@@ -432,7 +395,7 @@ static int read_user_file(const char *basefs, const char *user_path, FILE **stre + int64_t filesize = 0; + char *real_path = NULL; + +- if (realpath_in_scope(basefs, user_path, &real_path) < 0) { ++ if (util_realpath_in_scope(basefs, user_path, &real_path) < 0) { + ERROR("user target file '%s' real path must be under '%s'", user_path, basefs); + isulad_set_error_message("user target file '%s' real path must be under '%s'", user_path, basefs); + ret = -1; +@@ -492,7 +455,7 @@ static int get_exec_user(const char *username, FILE *f_passwd, FILE *f_group, de + char *matched_username = NULL; + + // parse user and group by username +- parse_user_group(username, &user, &group, &tmp); ++ util_parse_user_group(username, &user, &group, &tmp); + + // proc by f_passwd + ret = proc_by_fpasswd(f_passwd, user, puser, &matched_username); +diff --git a/src/daemon/modules/image/image_spec_merge.c b/src/daemon/modules/image/image_spec_merge.c +new file mode 100644 +index 0000000..a5d7501 +--- /dev/null ++++ b/src/daemon/modules/image/image_spec_merge.c +@@ -0,0 +1,84 @@ ++/****************************************************************************** ++* 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: lifeng ++* Create: 2020-10-10 ++* Description: provide oci image operator definition ++*******************************************************************************/ ++#include "image_spec_merge.h" ++ ++#include "utils.h" ++#include "isula_libutils/log.h" ++#include "err_msg.h" ++ ++int image_spec_merge_env(const char **env, size_t env_len, container_config *container_spec) ++{ ++ int ret = 0; ++ size_t new_size = 0; ++ size_t old_size = 0; ++ size_t i = 0; ++ size_t j = 0; ++ char **temp = NULL; ++ char **im_kv = NULL; ++ char **custom_kv = NULL; ++ ++ if (env == NULL || env_len == 0) { ++ return 0; ++ } ++ ++ if (env_len > LIST_ENV_SIZE_MAX - container_spec->env_len) { ++ ERROR("The length of envionment variables is too long, the limit is %lld", LIST_ENV_SIZE_MAX); ++ isulad_set_error_message("The length of envionment variables is too long, the limit is %lld", ++ LIST_ENV_SIZE_MAX); ++ ret = -1; ++ goto out; ++ } ++ new_size = (container_spec->env_len + env_len) * sizeof(char *); ++ old_size = container_spec->env_len * sizeof(char *); ++ ret = util_mem_realloc((void **)&temp, new_size, container_spec->env, old_size); ++ if (ret != 0) { ++ ERROR("Failed to realloc memory for envionment variables"); ++ ret = -1; ++ goto out; ++ } ++ ++ container_spec->env = temp; ++ for (i = 0; i < env_len; i++) { ++ bool found = false; ++ im_kv = util_string_split(env[i], '='); ++ if (im_kv == NULL) { ++ continue; ++ } ++ ++ for (j = 0; j < container_spec->env_len; j++) { ++ custom_kv = util_string_split(container_spec->env[j], '='); ++ if (custom_kv == NULL) { ++ continue; ++ } ++ if (strcmp(im_kv[0], custom_kv[0]) == 0) { ++ found = true; ++ } ++ util_free_array(custom_kv); ++ custom_kv = NULL; ++ if (found) { ++ break; ++ } ++ } ++ ++ if (!found) { ++ container_spec->env[container_spec->env_len] = util_strdup_s(env[i]); ++ container_spec->env_len++; ++ } ++ util_free_array(im_kv); ++ im_kv = NULL; ++ } ++out: ++ return ret; ++} +\ No newline at end of file +diff --git a/src/daemon/modules/image/image_spec_merge.h b/src/daemon/modules/image/image_spec_merge.h +new file mode 100644 +index 0000000..3cc91b0 +--- /dev/null ++++ b/src/daemon/modules/image/image_spec_merge.h +@@ -0,0 +1,30 @@ ++/****************************************************************************** ++* 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: lifeng ++* Create: 2020-10-10 ++* Description: provide isula image rootfs handler definition ++*******************************************************************************/ ++#ifndef DAEMON_MODULES_IMAGE_SPEC_MERGE_H ++#define DAEMON_MODULES_IMAGE_SPEC_MERGE_H ++ ++#include "isula_libutils/container_config.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++int image_spec_merge_env(const char **env, size_t env_len, container_config *container_spec); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif // DAEMON_MODULES_IMAGE_SPEC_MERGE_H +diff --git a/src/daemon/modules/image/oci/oci_common_operators.c b/src/daemon/modules/image/oci/oci_common_operators.c +index 6b95e86..967894b 100644 +--- a/src/daemon/modules/image/oci/oci_common_operators.c ++++ b/src/daemon/modules/image/oci/oci_common_operators.c +@@ -125,7 +125,7 @@ static int do_image_time_filter(map_itor *itor, bool is_before_filter, int64_t * + goto out; + } + +- if (to_unix_nanos_from_str(image_info->created, &tmp_nanos) != 0) { ++ if (util_to_unix_nanos_from_str(image_info->created, &tmp_nanos) != 0) { + ERROR("Failed to get unix nano from string"); + ret = -1; + goto out; +@@ -176,7 +176,7 @@ static bool image_time_filter(const imagetool_image *src, const struct filters_a + } + } + +- if (to_unix_nanos_from_str(src->created, &tmp_nanos) != 0) { ++ if (util_to_unix_nanos_from_str(src->created, &tmp_nanos) != 0) { + ERROR("Failed to get unix nano from string"); + goto out; + } +@@ -316,7 +316,7 @@ static int dup_oci_image_info_by_filters(const imagetool_image *src, const struc + new_size = (images_list->images_len + 1) * sizeof(imagetool_image *); + old_size = images_list->images_len * sizeof(imagetool_image *); + +- ret = mem_realloc((void **)(&tmp_images), new_size, images_list->images, old_size); ++ ret = util_mem_realloc((void **)(&tmp_images), new_size, images_list->images, old_size); + if (ret != 0) { + ERROR("Failed to realloc memory for append images"); + ret = -1; +@@ -434,8 +434,8 @@ int oci_status_image(im_status_request *request, im_status_response **response) + + resolved_name = oci_resolve_image_name(image_ref); + if (resolved_name == NULL) { +- ERROR("Failed to reslove image name %s", image_ref); +- isulad_set_error_message("Failed to reslove image name %s", image_ref); ++ ERROR("Failed to resolve image name %s", image_ref); ++ isulad_set_error_message("Failed to resolve image name %s", image_ref); + ret = -1; + goto pack_response; + } +diff --git a/src/daemon/modules/image/oci/oci_config_merge.c b/src/daemon/modules/image/oci/oci_config_merge.c +index 9b5050f..57e1884 100644 +--- a/src/daemon/modules/image/oci/oci_config_merge.c ++++ b/src/daemon/modules/image/oci/oci_config_merge.c +@@ -31,6 +31,7 @@ + #include "err_msg.h" + #include "utils_array.h" + #include "utils_string.h" ++#include "image_spec_merge.h" + + static void oci_image_merge_working_dir(const char *working_dir, container_config *container_spec) + { +@@ -44,63 +45,16 @@ static void oci_image_merge_working_dir(const char *working_dir, container_confi + static int oci_image_merge_env(const oci_image_spec_config *config, container_config *container_spec) + { + int ret = 0; +- size_t new_size = 0; +- size_t old_size = 0; +- size_t i = 0; +- size_t j = 0; +- char **temp = NULL; +- char **im_kv = NULL; +- char **custom_kv = NULL; + + if (config->env == NULL || config->env_len == 0) { + return 0; + } + +- if (config->env_len > LIST_ENV_SIZE_MAX - container_spec->env_len) { +- ERROR("The length of envionment variables is too long, the limit is %lld", LIST_ENV_SIZE_MAX); +- isulad_set_error_message("The length of envionment variables is too long, the limit is %d", LIST_ENV_SIZE_MAX); ++ if (image_spec_merge_env((const char **)config->env, config->env_len, container_spec) != 0) { + ret = -1; + goto out; + } +- new_size = (container_spec->env_len + config->env_len) * sizeof(char *); +- old_size = container_spec->env_len * sizeof(char *); +- ret = mem_realloc((void **)&temp, new_size, container_spec->env, old_size); +- if (ret != 0) { +- ERROR("Failed to realloc memory for envionment variables"); +- ret = -1; +- goto out; +- } +- +- container_spec->env = temp; +- for (i = 0; i < config->env_len; i++) { +- bool found = false; +- im_kv = util_string_split(config->env[i], '='); +- if (im_kv == NULL) { +- continue; +- } +- +- for (j = 0; j < container_spec->env_len; j++) { +- custom_kv = util_string_split(container_spec->env[j], '='); +- if (custom_kv == NULL) { +- continue; +- } +- if (strcmp(im_kv[0], custom_kv[0]) == 0) { +- found = true; +- } +- util_free_array(custom_kv); +- custom_kv = NULL; +- if (found) { +- break; +- } +- } + +- if (!found) { +- container_spec->env[container_spec->env_len] = util_strdup_s(config->env[i]); +- container_spec->env_len++; +- } +- util_free_array(im_kv); +- im_kv = NULL; +- } + out: + return ret; + } +@@ -237,6 +191,28 @@ out: + return ret; + } + ++static int oci_image_merge_anonymous_volumes(const oci_image_spec_config *config, container_config *container_spec) ++{ ++ if (container_spec == NULL) { ++ ERROR("Invalid NULL container spec"); ++ return -1; ++ } ++ ++ // no image config found ++ if (config == NULL || config->volumes == NULL || config->volumes->len == 0) { ++ return 0; ++ } ++ ++ // container's config contains image's anonymous volumes only right now, so just dump. ++ container_spec->volumes = dup_map_string_empty_object(config->volumes); ++ if (container_spec->volumes == NULL) { ++ ERROR("dup anonymous volumes failed"); ++ return -1; ++ } ++ ++ return 0; ++} ++ + static void oci_image_merge_user(const char *user, container_config *container_spec) + { + if (container_spec->user != NULL) { +@@ -377,7 +353,12 @@ int oci_image_merge_config(imagetool_image *image_conf, container_config *contai + goto out; + } + +- // ignore volumes now ++ // Merge image's anonymous volumes to container_spec, here we do not check conflict. ++ // We will check conflict after all volumes/binds merged. ++ if (oci_image_merge_anonymous_volumes(image_conf->spec->config, container_spec) != 0) { ++ ret = -1; ++ goto out; ++ } + } + + if (oci_image_merge_health_check(image_conf->healthcheck, container_spec) != 0) { +diff --git a/src/daemon/modules/image/oci/oci_export.c b/src/daemon/modules/image/oci/oci_export.c +index ca4b827..4b9d518 100644 +--- a/src/daemon/modules/image/oci/oci_export.c ++++ b/src/daemon/modules/image/oci/oci_export.c +@@ -12,11 +12,11 @@ + * Create: 2020-06-01 + * Description: isula image export operator implement + *******************************************************************************/ ++#include "oci_export.h" + #include + #include + + #include "storage.h" +-#include "oci_export.h" + #include "isula_libutils/log.h" + #include "err_msg.h" + #include "util_archive.h" +diff --git a/src/daemon/modules/image/oci/oci_image.c b/src/daemon/modules/image/oci/oci_image.c +index b9331c3..f0ba19c 100644 +--- a/src/daemon/modules/image/oci/oci_image.c ++++ b/src/daemon/modules/image/oci/oci_image.c +@@ -53,6 +53,7 @@ static char *format_driver_name(const char *driver) + } + } + ++#ifndef LIB_ISULAD_IMG_SO + static int do_integration_of_images_check(bool image_layer_check, struct storage_module_init_options *opts) + { + char *check_file = NULL; +@@ -89,6 +90,7 @@ out: + free(check_file); + return ret; + } ++#endif // LIB_ISULAD_IMG_SO + + static int storage_module_init_helper(const isulad_daemon_configs *args) + { +@@ -123,17 +125,19 @@ static int storage_module_init_helper(const isulad_daemon_configs *args) + goto out; + } + +- if (dup_array_of_strings((const char **)args->storage_opts, args->storage_opts_len, &storage_opts->driver_opts, +- &storage_opts->driver_opts_len) != 0) { ++ if (util_dup_array_of_strings((const char **)args->storage_opts, args->storage_opts_len, &storage_opts->driver_opts, ++ &storage_opts->driver_opts_len) != 0) { + ERROR("Failed to get storage storage opts"); + ret = -1; + goto out; + } + ++#ifndef LIB_ISULAD_IMG_SO + if (do_integration_of_images_check(args->image_layer_check, storage_opts) != 0) { + ret = -1; + goto out; + } ++#endif // LIB_ISULAD_IMG_SO + + if (storage_module_init(storage_opts) != 0) { + ERROR("Failed to init storage module"); +@@ -148,13 +152,22 @@ out: + + static void cleanup_image_tmpdir() + { +- if (util_recursive_rmdir(IMAGE_TMP_PATH, 0)) { +- ERROR("failed to remove directory %s", IMAGE_TMP_PATH); ++ char *image_tmp_path = NULL; ++ ++ image_tmp_path = get_image_tmp_path(); ++ if (image_tmp_path == NULL) { ++ ERROR("failed to get image tmp path"); ++ return; ++ } ++ ++ if (util_recursive_rmdir(image_tmp_path, 0)) { ++ ERROR("failed to remove directory %s", image_tmp_path); + } + +- if (util_mkdir_p(IMAGE_TMP_PATH, 0600)) { +- ERROR("failed to create directory %s", IMAGE_TMP_PATH); ++ if (util_mkdir_p(image_tmp_path, TEMP_DIRECTORY_MODE)) { ++ ERROR("failed to create directory %s", image_tmp_path); + } ++ free(image_tmp_path); + + return; + } +diff --git a/src/daemon/modules/image/oci/oci_import.c b/src/daemon/modules/image/oci/oci_import.c +index 0386372..e09a010 100644 +--- a/src/daemon/modules/image/oci/oci_import.c ++++ b/src/daemon/modules/image/oci/oci_import.c +@@ -12,6 +12,7 @@ + * Create: 2020-05-26 + * Description: isula image import operator implement + *******************************************************************************/ ++#include "oci_import.h" + #include + #include + #include +@@ -25,7 +26,6 @@ + #include + + #include "mediatype.h" +-#include "oci_import.h" + #include "isula_libutils/log.h" + #include "storage.h" + #include "err_msg.h" +@@ -41,7 +41,6 @@ + #define IMPORT_COMMENT "Imported from tarball" + #define ROOTFS_TYPE "layers" + #define MANIFEST_BIG_DATA_KEY "manifest" +-#define TIME_BUF_MAX_LEN 128 + + typedef struct { + char *manifest; +@@ -54,7 +53,7 @@ typedef struct { + types_timestamp_t now_time; + char *tag; + char *layer_file; +- char *layer_of_hold_flag; ++ char *layer_of_hold_refs; + } import_desc; + + static void free_import_desc(import_desc *desc) +@@ -81,8 +80,8 @@ static void free_import_desc(import_desc *desc) + desc->uncompressed_digest = NULL; + free(desc->layer_file); + desc->layer_file = NULL; +- free(desc->layer_of_hold_flag); +- desc->layer_of_hold_flag = NULL; ++ free(desc->layer_of_hold_refs); ++ desc->layer_of_hold_refs = NULL; + + free(desc); + +@@ -98,7 +97,7 @@ static int register_layer(import_desc *desc) + return -1; + } + +- id = without_sha256_prefix(desc->uncompressed_digest); ++ id = util_without_sha256_prefix(desc->uncompressed_digest); + if (id == NULL) { + ERROR("Invalid NULL param"); + return -1; +@@ -114,7 +113,7 @@ static int register_layer(import_desc *desc) + if (storage_layer_create(id, &copts) != 0) { + return -1; + } +- desc->layer_of_hold_flag = util_strdup_s(id); ++ desc->layer_of_hold_refs = util_strdup_s(id); + + return 0; + } +@@ -127,7 +126,7 @@ static int create_config(import_desc *desc) + char *host_arch = NULL; + char *host_variant = NULL; + parser_error err = NULL; +- char time_str[TIME_BUF_MAX_LEN] = { 0 }; ++ char time_str[TIME_STR_SIZE] = { 0 }; + + if (desc == NULL || desc->uncompressed_digest == NULL) { + ERROR("Invalid NULL param"); +@@ -140,7 +139,7 @@ static int create_config(import_desc *desc) + return -1; + } + +- ret = normalized_host_os_arch(&host_os, &host_arch, &host_variant); ++ ret = util_normalized_host_os_arch(&host_os, &host_arch, &host_variant); + if (ret != 0) { + ERROR("get host os and arch for import failed"); + isulad_try_set_error_message("get host os and arch for import failed"); +@@ -178,7 +177,7 @@ static int create_config(import_desc *desc) + goto out; + } + +- if (!get_time_buffer(&desc->now_time, time_str, TIME_BUF_MAX_LEN)) { ++ if (!util_get_time_buffer(&desc->now_time, time_str, TIME_STR_SIZE)) { + ERROR("get time string from timestamp failed"); + isulad_try_set_error_message("get time string from timestamp failed"); + ret = -1; +@@ -319,8 +318,8 @@ static int register_image(import_desc *desc) + opts.create_time = &desc->now_time; + opts.digest = desc->manifest_digest; + +- image_id = without_sha256_prefix(desc->config_digest); +- top_layer_id = without_sha256_prefix(desc->uncompressed_digest); ++ image_id = util_without_sha256_prefix(desc->config_digest); ++ top_layer_id = util_without_sha256_prefix(desc->uncompressed_digest); + ret = storage_img_create(image_id, top_layer_id, NULL, &opts); + if (ret != 0) { + pre_top_layer = storage_get_img_top_layer(image_id); +@@ -374,12 +373,11 @@ static int register_image(import_desc *desc) + } + + out: +- if (desc->layer_of_hold_flag != NULL && +- storage_set_hold_flag(desc->layer_of_hold_flag, false) != 0) { +- ERROR("clear hold flag failed for layer %s", desc->layer_of_hold_flag); ++ if (desc->layer_of_hold_refs != NULL && storage_dec_hold_refs(desc->layer_of_hold_refs) != 0) { ++ ERROR("decrease hold refs failed for layer %s", desc->layer_of_hold_refs); + } else { +- free(desc->layer_of_hold_flag); +- desc->layer_of_hold_flag = NULL; ++ free(desc->layer_of_hold_refs); ++ desc->layer_of_hold_refs = NULL; + } + + if (ret != 0 && image_created) { +@@ -420,7 +418,7 @@ static import_desc *prepre_import(char *file, char *tag) + goto out; + } + +- if (!get_now_time_stamp(&desc->now_time)) { ++ if (!util_get_now_time_stamp(&desc->now_time)) { + ERROR("get time stamp for import failed"); + isulad_try_set_error_message("get time stamp for import failed"); + ret = -1; +@@ -494,9 +492,8 @@ static int do_import(char *file, char *tag) + } + + out: +- if (desc->layer_of_hold_flag != NULL && +- storage_set_hold_flag(desc->layer_of_hold_flag, false) != 0) { +- ERROR("clear hold flag failed for layer %s", desc->layer_of_hold_flag); ++ if (desc->layer_of_hold_refs != NULL && storage_dec_hold_refs(desc->layer_of_hold_refs) != 0) { ++ ERROR("decrease hold refs failed for layer %s", desc->layer_of_hold_refs); + } + + free_import_desc(desc); +diff --git a/src/daemon/modules/image/oci/oci_load.c b/src/daemon/modules/image/oci/oci_load.c +index f7908b6..073ad55 100644 +--- a/src/daemon/modules/image/oci/oci_load.c ++++ b/src/daemon/modules/image/oci/oci_load.c +@@ -44,7 +44,6 @@ + + #define MANIFEST_BIG_DATA_KEY "manifest" + #define OCI_SCHEMA_VERSION 2 +-#define OCI_LOAD_TMP_DIR OCI_LOAD_TMP_WORK_DIR "/oci-image-load-XXXXXX" + + static image_manifest_items_element **load_manifest(const char *fname, size_t *length) + { +@@ -200,12 +199,25 @@ static void oci_load_free_image(load_image_t *im) + + free_oci_image_manifest(im->manifest); + +- free(im->layer_of_hold_flag); +- im->layer_of_hold_flag = NULL; ++ free(im->layer_of_hold_refs); ++ im->layer_of_hold_refs = NULL; + + free(im); + } + ++inline static void do_free_load_image(load_image_t *im) ++{ ++ if (im == NULL) { ++ return; ++ } ++ ++ if (im->layer_of_hold_refs != NULL && storage_dec_hold_refs(im->layer_of_hold_refs) != 0) { ++ ERROR("decrease hold refs failed for layer %s", im->layer_of_hold_refs); ++ } ++ ++ oci_load_free_image(im); ++} ++ + static char **str_array_copy(char **arr, size_t len) + { + char **str_arr = NULL; +@@ -224,25 +236,6 @@ static char **str_array_copy(char **arr, size_t len) + return str_arr; + } + +-static types_timestamp_t oci_load_get_timestamp(char *created) +-{ +- int64_t nanos = 0; +- types_timestamp_t timestamp = { 0 }; +- +- if (to_unix_nanos_from_str(created, &nanos) != 0) { +- ERROR("Failed to get created time from image config"); +- goto out; +- } +- +- timestamp.has_seconds = true; +- timestamp.seconds = nanos / Time_Second; +- timestamp.has_nanos = true; +- timestamp.nanos = nanos % Time_Second; +- +-out: +- return timestamp; +-} +- + static char *oci_load_calc_chain_id(char *parent_chain_id, char *diff_id) + { + int sret = 0; +@@ -299,21 +292,31 @@ static char *oci_load_without_sha256_prefix(char *digest) + return digest + strlen(SHA256_PREFIX); + } + +-static int oci_load_set_chain_id(load_image_t *image) ++static int registry_layer_from_tarball(const load_layer_blob_t *layer, const char *id, const char *parent) + { +- char *parent_chain_id = ""; +- size_t i = 0; ++ int ret = 0; + +- for (; i < image->layers_len; i++) { +- image->layers[i]->chain_id = oci_load_calc_chain_id(parent_chain_id, image->layers[i]->diff_id); +- if (image->layers[i]->chain_id == NULL) { +- ERROR("calc chain id failed, diff id %s, parent chain id %s", image->layers[i]->diff_id, parent_chain_id); +- return -1; +- } +- parent_chain_id = image->layers[i]->chain_id; ++ if (layer == NULL || id == NULL) { ++ ERROR("Invalid input params"); ++ return -1; + } + +- return 0; ++ storage_layer_create_opts_t copts = { ++ .parent = parent, ++ .uncompress_digest = layer->diff_id, ++ .compressed_digest = layer->compressed_digest, ++ .writable = false, ++ .layer_data_path = layer->fpath, ++ }; ++ ++ if (storage_layer_create(id, &copts) != 0) { ++ ERROR("create layer %s failed, parent %s, file %s", id, parent, layer->fpath); ++ ret = -1; ++ goto out; ++ } ++ ++out: ++ return ret; + } + + static int oci_load_register_layers(load_image_t *desc) +@@ -341,22 +344,22 @@ static int oci_load_register_layers(load_image_t *desc) + goto out; + } + +- storage_layer_create_opts_t copts = { +- .parent = parent, +- .uncompress_digest = desc->layers[i]->diff_id, +- .compressed_digest = desc->layers[i]->compressed_digest, +- .writable = false, +- .layer_data_path = desc->layers[i]->fpath, +- }; +- ret = storage_layer_create(id, &copts); +- if (ret != 0) { +- ERROR("create layer %s failed, parent %s, file %s", id, parent, desc->layers[i]->fpath); ++ if (desc->layers[i]->alread_exist) { ++ DEBUG("Layer:%s is already exist in storage, no need to registry", desc->layers[i]->fpath); ++ parent = id; ++ continue; ++ } ++ ++ if (registry_layer_from_tarball(desc->layers[i], id, parent) != 0) { ++ ERROR("Registry layer:%s from local tarball failed", desc->layers[i]->fpath); ++ ret = -1; + goto out; + } +- free(desc->layer_of_hold_flag); +- desc->layer_of_hold_flag = util_strdup_s(id); +- if (parent != NULL && storage_set_hold_flag(parent, false) != 0) { +- ERROR("clear hold flag failed for layer %s", parent); ++ ++ free(desc->layer_of_hold_refs); ++ desc->layer_of_hold_refs = util_strdup_s(id); ++ if (parent != NULL && storage_dec_hold_refs(parent) != 0) { ++ ERROR("decrease hold refs failed for layer %s", parent); + ret = -1; + goto out; + } +@@ -442,7 +445,7 @@ static int oci_load_create_image(load_image_t *desc, const char *dst_tag) + goto out; + } + +- timestamp = oci_load_get_timestamp(conf->created); ++ timestamp = util_to_timestamp_from_str(conf->created); + top_layer_index = desc->layers_len - 1; + opts.create_time = ×tamp; + opts.digest = desc->manifest_digest; +@@ -553,7 +556,7 @@ static int oci_load_set_loaded_time(char *image_id) + int ret = 0; + types_timestamp_t now = { 0 }; + +- if (!get_now_time_stamp(&now)) { ++ if (!util_get_now_time_stamp(&now)) { + ret = -1; + ERROR("get now time stamp failed"); + goto out; +@@ -623,12 +626,62 @@ out: + return ret; + } + ++static int check_and_set_digest_from_tarball(load_layer_blob_t *layer, const char *conf_diff_id) ++{ ++ int ret = 0; ++ bool gzip = false; ++ ++ if (layer == NULL || conf_diff_id == NULL) { ++ ERROR("Invalid input param"); ++ return -1; ++ } ++ ++ if (!util_file_exists(layer->fpath)) { ++ ERROR("Layer data file:%s is not exist", layer->fpath); ++ isulad_try_set_error_message("%s no such file", layer->fpath); ++ ret = -1; ++ goto out; ++ } ++ ++ layer->alread_exist = false; ++ layer->diff_id = oci_calc_diffid(layer->fpath); ++ if (layer->diff_id == NULL) { ++ ERROR("Calc layer:%s diff id failed", layer->fpath); ++ ret = -1; ++ goto out; ++ } ++ ++ if (util_gzip_compressed(layer->fpath, &gzip) != 0) { ++ ERROR("Judge layer file gzip attr err"); ++ ret = -1; ++ goto out; ++ } ++ ++ layer->compressed_digest = gzip ? sha256_full_file_digest(layer->fpath) : util_strdup_s(layer->diff_id); ++ if (layer->compressed_digest == NULL) { ++ ERROR("Calc layer %s compressed digest failed", layer->fpath); ++ ret = -1; ++ goto out; ++ } ++ ++ if (strcmp(layer->diff_id, conf_diff_id) != 0) { ++ ERROR("invalid diff id for layer:%s: expected %s, got %s", layer->chain_id, conf_diff_id, layer->diff_id); ++ ret = -1; ++ goto out; ++ } ++ ++out: ++ return ret; ++} ++ + static int oci_load_set_layers_info(load_image_t *im, const image_manifest_items_element *manifest, const char *dstdir) + { + int ret = 0; + size_t i = 0; +- bool gzip = false; +- char *layer_fpath = NULL; ++ oci_image_spec *conf = NULL; ++ char *parent_chain_id_sha256 = ""; ++ char *id = NULL; ++ char *parent_chain_id = NULL; + + if (im == NULL || manifest == NULL || dstdir == NULL) { + ERROR("Invalid input params image or manifest is null"); +@@ -638,12 +691,25 @@ static int oci_load_set_layers_info(load_image_t *im, const image_manifest_items + im->layers_len = manifest->layers_len; + im->layers = util_common_calloc_s(sizeof(load_layer_blob_t *) * manifest->layers_len); + if (im->layers == NULL) { +- ret = -1; + ERROR("Calloc memory failed"); ++ ret = -1; + goto out; + } + +- for (; i < im->layers_len; i++) { ++ conf = load_image_config(im->config_fpath); ++ if (conf == NULL || conf->rootfs == NULL) { ++ ERROR("Load image config file %s failed", im->config_fpath); ++ ret = -1; ++ goto out; ++ } ++ ++ if (conf->rootfs->diff_ids_len != im->layers_len) { ++ ERROR("Invalid manifest, layers length mismatch: expected %zu, got %zu", im->layers_len, conf->rootfs->diff_ids_len); ++ ret = -1; ++ goto out; ++ } ++ ++ for (; i < conf->rootfs->diff_ids_len; i++) { + im->layers[i] = util_common_calloc_s(sizeof(load_layer_blob_t)); + if (im->layers[i] == NULL) { + ERROR("Out of memory"); +@@ -651,47 +717,57 @@ static int oci_load_set_layers_info(load_image_t *im, const image_manifest_items + goto out; + } + +- layer_fpath = util_path_join(dstdir, manifest->layers[i]); +- if (layer_fpath == NULL) { ++ im->layers[i]->fpath = util_path_join(dstdir, manifest->layers[i]); ++ if (im->layers[i]->fpath == NULL) { + ERROR("Path join failed"); + ret = -1; + goto out; + } +- +- if (util_gzip_compressed(layer_fpath, &gzip) != 0) { +- ERROR("Judge layer file gzip attribute err"); ++ // The format is sha256:xxx ++ im->layers[i]->chain_id = oci_load_calc_chain_id(parent_chain_id_sha256, conf->rootfs->diff_ids[i]); ++ if (im->layers[i]->chain_id == NULL) { ++ ERROR("calc chain id failed, diff id %s, parent chain id %s", conf->rootfs->diff_ids[i], parent_chain_id_sha256); + ret = -1; + goto out; + } ++ parent_chain_id_sha256 = im->layers[i]->chain_id; + +- im->layers[i]->diff_id = oci_calc_diffid(layer_fpath); +- if (im->layers[i]->diff_id == NULL) { ++ id = oci_load_without_sha256_prefix(im->layers[i]->chain_id); ++ if (id == NULL) { ++ ERROR("Wipe out sha256 prefix failed from layer with chain id : %s", im->layers[i]->chain_id); + ret = -1; +- ERROR("Calc layer %s uncompressed digest failed", manifest->layers[i]); + goto out; + } + +- im->layers[i]->compressed_digest = gzip ? sha256_full_file_digest(layer_fpath) : +- util_strdup_s(im->layers[i]->diff_id); +- if (im->layers[i]->compressed_digest == NULL) { +- ret = -1; +- ERROR("Calc layer %s compressed digest failed", manifest->layers[i]); +- goto out; ++ if (storage_inc_hold_refs(id) == 0) { ++ free(im->layer_of_hold_refs); ++ im->layer_of_hold_refs = util_strdup_s(id); ++ if (parent_chain_id != NULL && storage_dec_hold_refs(parent_chain_id) != 0) { ++ ERROR("Decrease hold refs failed for layer with chain id:%s", parent_chain_id); ++ ret = -1; ++ goto out; ++ } ++ ++ im->layers[i]->diff_id = util_strdup_s(conf->rootfs->diff_ids[i]); ++ if (im->layers[i]->diff_id == NULL) { ++ ERROR("Dup layer diff id:%s from conf failed", conf->rootfs->diff_ids[i]); ++ ret = -1; ++ goto out; ++ } ++ im->layers[i]->alread_exist = true; ++ parent_chain_id = id; ++ continue; + } + +- im->layers[i]->fpath = util_strdup_s(layer_fpath); +- if (im->layers[i]->fpath == NULL) { ++ if (check_and_set_digest_from_tarball(im->layers[i], conf->rootfs->diff_ids[i]) != 0) { ++ ERROR("Check layer digest failed"); + ret = -1; +- ERROR("Image layer data file path is NULL"); + goto out; + } +- UTIL_FREE_AND_SET_NULL(layer_fpath); + } + + out: +- if (layer_fpath != NULL) { +- free(layer_fpath); +- } ++ free_oci_image_spec(conf); + return ret; + } + +@@ -743,11 +819,6 @@ static load_image_t *oci_load_process_manifest(const image_manifest_items_elemen + goto out; + } + +- if (oci_load_set_chain_id(im) != 0) { +- ret = -1; +- ERROR("Calc image chain id failed"); +- } +- + out: + free(config_fpath); + free(image_digest); +@@ -758,6 +829,38 @@ out: + return im; + } + ++static int64_t get_layer_size_from_storage(char *chain_id_pre) ++{ ++ char *id = NULL; ++ struct layer *l = NULL; ++ int64_t size = 0; ++ ++ if (chain_id_pre == NULL) { ++ ERROR("Invalid input param"); ++ return -1; ++ } ++ ++ id = oci_load_without_sha256_prefix(chain_id_pre); ++ if (id == NULL) { ++ ERROR("Get chain id failed from value:%s", chain_id_pre); ++ size = -1; ++ goto out; ++ } ++ ++ l = storage_layer_get(id); ++ if (l == NULL) { ++ ERROR("Layer with chain id:%s is not exist in store", id); ++ size = -1; ++ goto out; ++ } ++ ++ size = l->compress_size; ++ ++out: ++ free_layer(l); ++ return size; ++} ++ + static int oci_load_set_manifest_info(load_image_t *im) + { + int ret = 0; +@@ -811,14 +914,24 @@ static int oci_load_set_manifest_info(load_image_t *im) + ERROR("Out of memory"); + goto out; + } ++ + im->manifest->layers[i]->media_type = util_strdup_s(MediaTypeDockerSchema2LayerGzip); + im->manifest->layers[i]->digest = util_strdup_s(im->layers[i]->diff_id); + +- size = util_file_size(im->layers[i]->fpath); +- if (size < 0) { +- ERROR("Calc image layer %s size error", im->layers[i]->fpath); +- ret = -1; +- goto out; ++ if (im->layers[i]->alread_exist) { ++ size = get_layer_size_from_storage(im->layers[i]->chain_id); ++ if (size < 0) { ++ ERROR("Get image layer:%s size error from local store", im->layers[i]->chain_id); ++ ret = -1; ++ goto out; ++ } ++ } else { ++ size = util_file_size(im->layers[i]->fpath); ++ if (size < 0) { ++ ERROR("Calc image layer %s size error", im->layers[i]->fpath); ++ ret = -1; ++ goto out; ++ } + } + im->manifest->layers[i]->size = size; + } +@@ -831,38 +944,6 @@ out: + return ret; + } + +-static int oci_load_check_image_layers(load_image_t *im) +-{ +- int ret = 0; +- size_t i = 0; +- oci_image_spec *conf = NULL; +- +- conf = load_image_config(im->config_fpath); +- if (conf == NULL || conf->rootfs == NULL) { +- ERROR("Load image config file %s failed", im->config_fpath); +- ret = -1; +- goto out; +- } +- +- if (conf->rootfs->diff_ids_len != im->layers_len) { +- ret = -1; +- ERROR("Config file layer numbers are not equal to with image layer numbers"); +- goto out; +- } +- +- for (; i < im->layers_len; i++) { +- if (strcmp(im->layers[i]->diff_id, conf->rootfs->diff_ids[i]) != 0) { +- ERROR("Layer diff id %s check err", im->layers[i]->diff_id); +- ret = -1; +- goto out; +- } +- } +- +-out: +- free_oci_image_spec(conf); +- return ret; +-} +- + static size_t oci_tag_count(image_manifest_items_element **manifest, size_t manifest_len) + { + size_t cnt_tags = 0; +@@ -926,6 +1007,47 @@ out: + return res; + } + ++static char *oci_load_path_create() ++{ ++ int ret = 0; ++ int nret = 0; ++ char *oci_load_work_dir = NULL; ++ char tmp_dir[PATH_MAX] = { 0 }; ++ ++ oci_load_work_dir = storage_oci_load_work_dir(); ++ if (oci_load_work_dir == NULL) { ++ ERROR("Failed to get oci load work dir"); ++ isulad_try_set_error_message("Failed to get oci load work dir"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (util_mkdir_p(oci_load_work_dir, TEMP_DIRECTORY_MODE) != 0) { ++ ERROR("Unable to create oci image load tmp work dir:%s", oci_load_work_dir); ++ isulad_try_set_error_message("Unable to create oci image load tmp work dir:%s", oci_load_work_dir); ++ ret = -1; ++ goto out; ++ } ++ ++ nret = snprintf(tmp_dir, PATH_MAX, "%s/oci-image-load-XXXXXX", oci_load_work_dir); ++ if (nret < 0 || (size_t)nret >= sizeof(tmp_dir)) { ++ ERROR("Path is too long"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (mkdtemp(tmp_dir) == NULL) { ++ ERROR("make temporary dir failed: %s", strerror(errno)); ++ isulad_try_set_error_message("make temporary dir failed: %s", strerror(errno)); ++ ret = -1; ++ goto out; ++ } ++ ++out: ++ free(oci_load_work_dir); ++ return ret == 0 ? util_strdup_s(tmp_dir) : NULL; ++} ++ + int oci_do_load(const im_load_request *request) + { + int ret = 0; +@@ -937,23 +1059,16 @@ int oci_do_load(const im_load_request *request) + size_t manifest_len = 0; + load_image_t *im = NULL; + char *digest = NULL; +- char dstdir[] = OCI_LOAD_TMP_DIR; ++ char *dstdir = NULL; + + if (request == NULL || request->file == NULL) { + ERROR("Invalid input arguments, cannot load image"); + return -1; + } + +- if (util_mkdir_p(OCI_LOAD_TMP_WORK_DIR, TEMP_DIRECTORY_MODE) != 0) { +- ERROR("Unable to create oci image load tmp work dir:%s", OCI_LOAD_TMP_WORK_DIR); +- isulad_try_set_error_message("Unable to create oci image load tmp work dir:%s", OCI_LOAD_TMP_WORK_DIR); +- ret = -1; +- goto out; +- } +- +- if (mkdtemp(dstdir) == NULL) { +- ERROR("make temporary direcory failed: %s", strerror(errno)); +- isulad_try_set_error_message("make temporary direcory failed: %s", strerror(errno)); ++ dstdir = oci_load_path_create(); ++ if (dstdir == NULL) { ++ ERROR("create temporary direcory failed"); + ret = -1; + goto out; + } +@@ -1014,14 +1129,6 @@ int oci_do_load(const im_load_request *request) + + if (oci_load_set_manifest_info(im) != 0) { + ERROR("Image %s set manifest info err", im->im_id); +- isulad_try_set_error_message("Image %s set manifest info err", im->im_id); +- ret = -1; +- goto out; +- } +- +- if (oci_load_check_image_layers(im) != 0) { +- ERROR("Image %s check err", im->im_id); +- isulad_try_set_error_message("Image %s check err", im->im_id); + ret = -1; + goto out; + } +@@ -1033,7 +1140,8 @@ int oci_do_load(const im_load_request *request) + ret = -1; + goto out; + } +- oci_load_free_image(im); ++ ++ do_free_load_image(im); + im = NULL; + } + +@@ -1048,13 +1156,7 @@ out: + } + free(manifest); + +- if (im != NULL) { +- if (im->layer_of_hold_flag != NULL && storage_set_hold_flag(im->layer_of_hold_flag, false) != 0) { +- ERROR("clear hold flag failed for layer %s", im->layer_of_hold_flag); +- } +- +- oci_load_free_image(im); +- } ++ do_free_load_image(im); + + if (reader.close != NULL) { + reader.close(reader.context, NULL); +@@ -1063,5 +1165,6 @@ out: + if (util_recursive_rmdir(dstdir, 0)) { + WARN("failed to remove directory %s", dstdir); + } ++ free(dstdir); + return ret; + } +diff --git a/src/daemon/modules/image/oci/oci_load.h b/src/daemon/modules/image/oci/oci_load.h +index 5fdeb4c..e1e0906 100644 +--- a/src/daemon/modules/image/oci/oci_load.h ++++ b/src/daemon/modules/image/oci/oci_load.h +@@ -33,8 +33,11 @@ typedef struct { + char *diff_id; + // compressed digest + char *compressed_digest; ++ // with "sha256:" prefix + char *chain_id; + char *fpath; ++ // layer already exist in storage ++ bool alread_exist; + } load_layer_blob_t; + + typedef struct { +@@ -49,7 +52,7 @@ typedef struct { + char *manifest_digest; + types_timestamp_t create_time; + oci_image_manifest *manifest; +- char *layer_of_hold_flag; ++ char *layer_of_hold_refs; + } load_image_t; + + int oci_do_load(const im_load_request *request); +diff --git a/src/daemon/modules/image/oci/oci_pull.c b/src/daemon/modules/image/oci/oci_pull.c +index 21efd34..9d94b66 100644 +--- a/src/daemon/modules/image/oci/oci_pull.c ++++ b/src/daemon/modules/image/oci/oci_pull.c +@@ -63,7 +63,7 @@ static int decode_auth(const char *auth, char **username, char **password) + (void)memset(auth_parts[1], 0, strlen(auth_parts[1])); + + out: +- free_sensitive_string((char *)decoded); ++ util_free_sensitive_string((char *)decoded); + decoded = NULL; + util_free_array(auth_parts); + auth_parts = NULL; +@@ -194,8 +194,7 @@ int oci_do_pull_image(const im_pull_request *request, im_pull_response *response + image2 = storage_img_get(request->image); + if (image == NULL || image2 == NULL) { + ERROR("get image %s failed after pulling", request->image); +- isulad_set_error_message("Failed to pull image %s with error: image not found after pulling", +- request->image); ++ isulad_set_error_message("Failed to pull image %s with error: image not found after pulling", request->image); + ret = -1; + goto out; + } +diff --git a/src/daemon/modules/image/oci/registry/aes.c b/src/daemon/modules/image/oci/registry/aes.c +index ddf321a..b0f857f 100644 +--- a/src/daemon/modules/image/oci/registry/aes.c ++++ b/src/daemon/modules/image/oci/registry/aes.c +@@ -14,11 +14,11 @@ + ******************************************************************************/ + + #define _GNU_SOURCE /* See feature_test_macros(7) */ ++#include "aes.h" + #include + #include + + #include "isula_libutils/log.h" +-#include "aes.h" + #include "utils_aes.h" + #include "utils.h" + +diff --git a/src/daemon/modules/image/oci/registry/auths.c b/src/daemon/modules/image/oci/registry/auths.c +index a6c549c..710f5b2 100644 +--- a/src/daemon/modules/image/oci/registry/auths.c ++++ b/src/daemon/modules/image/oci/registry/auths.c +@@ -14,6 +14,7 @@ + ******************************************************************************/ + + #define _GNU_SOURCE /* See feature_test_macros(7) */ ++#include "auths.h" + #include + #include + #include +@@ -25,7 +26,6 @@ + + #include "isula_libutils/log.h" + #include "utils.h" +-#include "auths.h" + #include "aes.h" + #include "isula_libutils/registry_auths.h" + #include "err_msg.h" +@@ -35,12 +35,12 @@ + #include "utils_file.h" + #include "utils_string.h" + +-static char *g_auth_path = DEFAULT_AUTH_DIR"/"AUTH_FILE_NAME ; ++static char *g_auth_path = DEFAULT_AUTH_DIR "/" AUTH_FILE_NAME; + + void auths_set_dir(char *auth_dir) + { + int sret = 0; +- char path[PATH_MAX] = {0}; ++ char path[PATH_MAX] = { 0 }; + + if (auth_dir == NULL) { + return; +@@ -109,9 +109,9 @@ static int decode_auth_aes(char *encoded, char **username, char **password) + (void)memset(auth_parts[1], 0, strlen(auth_parts[1])); + + out: +- free_sensitive_string((char *)auth); ++ util_free_sensitive_string((char *)auth); + auth = NULL; +- free_sensitive_string((char *)decoded); ++ util_free_sensitive_string((char *)decoded); + decoded = NULL; + util_free_array(auth_parts); + auth_parts = NULL; +@@ -164,12 +164,12 @@ static char *encode_auth_aes(char *username, char *password) + + out: + (void)memset(plain_text, 0, strlen(plain_text)); +- free_sensitive_string((char*)aes); ++ util_free_sensitive_string((char *)aes); + aes = NULL; +- free_sensitive_string(plain_text_base64); ++ util_free_sensitive_string(plain_text_base64); + plain_text_base64 = NULL; + if (ret != 0) { +- free_sensitive_string(aes_base64); ++ util_free_sensitive_string(aes_base64); + aes_base64 = NULL; + } + return aes_base64; +@@ -307,7 +307,7 @@ out: + return ret; + } + +-static int write_auth_file(char *content) ++static int ensure_auth_dir_exist() + { + int ret = 0; + char *auths_dir = NULL; +@@ -319,17 +319,10 @@ static int write_auth_file(char *content) + goto out; + } + +- ret = util_mkdir_p(auths_dir, 0700); ++ ret = util_mkdir_p(auths_dir, DEFAULT_AUTH_DIR_MODE); + if (ret != 0) { +- ERROR("mkdir for aeskey failed"); +- isulad_try_set_error_message("create direcotry for auths failed"); +- goto out; +- } +- +- ret = util_atomic_write_file(g_auth_path, content, strlen(content), AUTH_FILE_MODE); +- if (ret != 0) { +- ERROR("failed to write auths json to file"); +- isulad_try_set_error_message("failed to write auths json to file"); ++ ERROR("mkdir for auths failed"); ++ isulad_try_set_error_message("create directory for auths failed"); + goto out; + } + +@@ -354,6 +347,11 @@ int auths_save(char *host, char *username, char *password) + return -1; + } + ++ ret = ensure_auth_dir_exist(); ++ if (ret != 0) { ++ goto out; ++ } ++ + auths = registry_auths_parse_file(g_auth_path, NULL, &err); + if (auths == NULL) { + auths = util_common_calloc_s(sizeof(registry_auths)); +@@ -392,7 +390,7 @@ int auths_save(char *host, char *username, char *password) + goto out; + } + +- ret = write_auth_file(json); ++ ret = util_atomic_write_file(g_auth_path, json, strlen(json), AUTH_FILE_MODE); + if (ret != 0) { + ERROR("failed to write auths json to file"); + goto out; +diff --git a/src/daemon/modules/image/oci/registry/auths.h b/src/daemon/modules/image/oci/registry/auths.h +index 263b80f..63969ed 100644 +--- a/src/daemon/modules/image/oci/registry/auths.h ++++ b/src/daemon/modules/image/oci/registry/auths.h +@@ -20,6 +20,7 @@ extern "C" { + #endif + + #define DEFAULT_AUTH_DIR "/root/.isulad" ++#define DEFAULT_AUTH_DIR_MODE 0700 + #define AUTH_FILE_NAME "auths.json" + #define AUTH_FILE_MODE 0600 + #define MAX_AUTHS_LEN 65536 +@@ -37,4 +38,3 @@ int auths_delete(char *host); + #endif + + #endif +- +diff --git a/src/daemon/modules/image/oci/registry/certs.c b/src/daemon/modules/image/oci/registry/certs.c +index 68ad549..6574d2b 100644 +--- a/src/daemon/modules/image/oci/registry/certs.c ++++ b/src/daemon/modules/image/oci/registry/certs.c +@@ -14,6 +14,7 @@ + ******************************************************************************/ + + #define _GNU_SOURCE /* See feature_test_macros(7) */ ++#include "certs.h" + #include + #include + #include +@@ -23,7 +24,6 @@ + + #include "isula_libutils/log.h" + #include "utils.h" +-#include "certs.h" + #include "utils_file.h" + #include "utils_string.h" + +@@ -79,7 +79,7 @@ static int load_certs(const char *path, const char *name, bool use_decrypted_key + return -1; + } + +- if (ca_file != NULL && util_has_suffix(name, CA_SUFFIX)) { ++ if (*ca_file == NULL && util_has_suffix(name, CA_SUFFIX)) { + *ca_file = util_path_join(path, name); + if (*ca_file == NULL) { + ret = -1; +@@ -87,7 +87,7 @@ static int load_certs(const char *path, const char *name, bool use_decrypted_key + goto out; + } + goto out; +- } else if (cert_file != NULL && *cert_file == NULL && util_has_suffix(name, CLIENT_CERT_SUFFIX)) { ++ } else if (*cert_file == NULL && *key_file == NULL && util_has_suffix(name, CLIENT_CERT_SUFFIX)) { + key_name = corresponding_key_name(name); + if (key_name == NULL) { + ERROR("find corresponding key name for cert failed"); +diff --git a/src/daemon/modules/image/oci/registry/http_request.c b/src/daemon/modules/image/oci/registry/http_request.c +index 3fcb9de..60644ed 100644 +--- a/src/daemon/modules/image/oci/registry/http_request.c ++++ b/src/daemon/modules/image/oci/registry/http_request.c +@@ -14,6 +14,7 @@ + ******************************************************************************/ + + #define _GNU_SOURCE /* See feature_test_macros(7) */ ++#include "http_request.h" + #include + #include + #include +@@ -26,7 +27,6 @@ + #include "isula_libutils/log.h" + #include "buffer.h" + #include "http.h" +-#include "http_request.h" + #include "utils.h" + #include "utils_images.h" + #include "certs.h" +@@ -431,7 +431,7 @@ static int setup_common_options(pull_descriptor *desc, struct http_get_options * + } + + if (custom_headers != NULL) { +- options->custom_headers = str_array_dup(custom_headers, util_array_len(custom_headers)); ++ options->custom_headers = util_str_array_dup(custom_headers, util_array_len(custom_headers)); + if (options->custom_headers == NULL) { + ERROR("dup headers failed"); + ret = -1; +diff --git a/src/daemon/modules/image/oci/registry/registry.c b/src/daemon/modules/image/oci/registry/registry.c +index 77b4d02..2656b9b 100644 +--- a/src/daemon/modules/image/oci/registry/registry.c ++++ b/src/daemon/modules/image/oci/registry/registry.c +@@ -14,6 +14,7 @@ + ******************************************************************************/ + + #define _GNU_SOURCE /* See feature_test_macros(7) */ ++#include "registry.h" + #include + #include + #include +@@ -30,7 +31,6 @@ + + #include "mediatype.h" + #include "isula_libutils/log.h" +-#include "registry.h" + #include "utils.h" + #include "registry_apiv2.h" + #include "certs.h" +@@ -73,13 +73,15 @@ typedef struct { + size_t file_list_len; + } cached_layer; + +-// Share infomation of downloading layers to avoid downloading the same layer. ++// Share information of downloading layers to avoid downloading the same layer. + typedef struct { + pthread_mutex_t mutex; + bool mutex_inited; + pthread_cond_t cond; + bool cond_inited; + map_t *cached_layers; ++ pthread_mutex_t image_mutex; ++ bool image_mutex_inited; + } registry_global; + + static registry_global *g_shared; +@@ -133,7 +135,7 @@ static int parse_manifest_schema1(pull_descriptor *desc) + desc->layers[index].empty_layer = v1config->throwaway; + free_image_manifest_v1_compatibility(v1config); + v1config = NULL; +- // Cann't download an empty layer, skip related infomation. ++ // Cann't download an empty layer, skip related information. + if (desc->layers[index].empty_layer) { + continue; + } +@@ -564,7 +566,7 @@ static int register_layers(pull_descriptor *desc) + continue; + } + +- id = without_sha256_prefix(desc->layers[i].chain_id); ++ id = util_without_sha256_prefix(desc->layers[i].chain_id); + if (id == NULL) { + ERROR("layer %zu have NULL digest for image %s", i, desc->image_name); + ret = -1; +@@ -609,9 +611,9 @@ static int register_layers(pull_descriptor *desc) + ERROR("create layer %s failed, parent %s, file %s", id, parent, desc->layers[i].file); + goto out; + } +- free(desc->layer_of_hold_flag); +- desc->layer_of_hold_flag = util_strdup_s(id); +- if (parent != NULL && storage_set_hold_flag(parent, false) != 0) { ++ free(desc->layer_of_hold_refs); ++ desc->layer_of_hold_refs = util_strdup_s(id); ++ if (parent != NULL && storage_dec_hold_refs(parent) != 0) { + ERROR("clear hold flag failed for layer %s", parent); + ret = -1; + goto out; +@@ -632,7 +634,7 @@ out: + + static int get_top_layer_index(pull_descriptor *desc, size_t *top_layer_index) + { +- size_t i = 0; ++ int i = 0; + + if (desc == NULL || top_layer_index == NULL) { + ERROR("Invalid NULL pointer"); +@@ -672,7 +674,7 @@ static int create_image(pull_descriptor *desc, char *image_id, bool *reuse) + + opts.create_time = &desc->config.create_time; + opts.digest = desc->manifest.digest; +- top_layer_id = without_sha256_prefix(desc->layers[top_layer_index].chain_id); ++ top_layer_id = util_without_sha256_prefix(desc->layers[top_layer_index].chain_id); + if (top_layer_id == NULL) { + ERROR("NULL top layer id found for image %s", desc->image_name); + ret = -1; +@@ -785,7 +787,7 @@ static int set_loaded_time(pull_descriptor *desc, char *image_id) + int ret = 0; + types_timestamp_t now = { 0 }; + +- if (!get_now_time_stamp(&now)) { ++ if (!util_get_now_time_stamp(&now)) { + ret = -1; + ERROR("get now time stamp failed"); + goto out; +@@ -863,7 +865,9 @@ static int register_image(pull_descriptor *desc) + goto out; + } + +- image_id = without_sha256_prefix(desc->config.digest); ++ // lock when create image to make sure image content all exist ++ mutex_lock(&g_shared->image_mutex); ++ image_id = util_without_sha256_prefix(desc->config.digest); + ret = create_image(desc, image_id, &reuse); + if (ret != 0) { + ERROR("create image %s failed", desc->image_name); +@@ -907,6 +911,7 @@ static int register_image(pull_descriptor *desc) + } + + out: ++ mutex_unlock(&g_shared->image_mutex); + + if (ret != 0 && image_created) { + if (storage_img_delete(image_id, true)) { +@@ -956,7 +961,7 @@ static int parse_docker_config(pull_descriptor *desc) + parent_chain_id = desc->layers[i].chain_id; + } + +- desc->config.create_time = created_to_timestamp(config->created); ++ desc->config.create_time = util_to_timestamp_from_str(config->created); + + out: + +@@ -1007,7 +1012,7 @@ static int parse_oci_config(pull_descriptor *desc) + parent_chain_id = desc->layers[i].chain_id; + } + +- desc->config.create_time = created_to_timestamp(config->created); ++ desc->config.create_time = util_to_timestamp_from_str(config->created); + + out: + free_oci_image_spec(config); +@@ -1212,6 +1217,8 @@ static int add_fetch_task(thread_fetch_info *info) + goto out; + } + } ++ // retry get cached layer after some time of unlock ++ cache = get_cached_layer(info->blob_digest); + } + + ret = add_cached_layer(info->blob_digest, info->file); +@@ -1395,15 +1402,15 @@ static int fetch_all(pull_descriptor *desc) + for (j = 0; j < list->layers_len; j++) { + if ((list->layers[j]->parent == NULL && i == 0) || + (parent_chain_id != NULL && list->layers[j]->parent != NULL && +- !strcmp(list->layers[j]->parent, without_sha256_prefix(parent_chain_id)) && ++ !strcmp(list->layers[j]->parent, util_without_sha256_prefix(parent_chain_id)) && + strcmp(list->layers[j]->uncompressed_digest, list->layers[j]->compressed_digest))) { +- // If can't set hold flag, it means it not exist anymore. +- if (storage_set_hold_flag(list->layers[j]->id, true) != 0) { ++ // If can't set hold refs, it means it not exist anymore. ++ if (storage_inc_hold_refs(list->layers[j]->id) != 0) { + continue; + } +- free(desc->layer_of_hold_flag); +- desc->layer_of_hold_flag = util_strdup_s(list->layers[j]->id); +- if (parent_chain_id != NULL && storage_set_hold_flag(parent_chain_id, false) != 0) { ++ free(desc->layer_of_hold_refs); ++ desc->layer_of_hold_refs = util_strdup_s(list->layers[j]->id); ++ if (parent_chain_id != NULL && storage_dec_hold_refs(parent_chain_id) != 0) { + continue; + } + desc->layers[i].already_exist = true; +@@ -1541,7 +1548,7 @@ static int create_config_from_v1config(pull_descriptor *desc) + goto out; + } + +- desc->config.create_time = created_to_timestamp(config->created); ++ desc->config.create_time = util_to_timestamp_from_str(config->created); + + free(err); + err = NULL; +@@ -1592,7 +1599,7 @@ static bool reuse_image(pull_descriptor *desc) + goto out; + } + +- id = without_sha256_prefix(desc->config.digest); ++ id = util_without_sha256_prefix(desc->config.digest); + if (id == NULL) { + goto out; + } +@@ -1675,8 +1682,9 @@ static int prepare_pull_desc(pull_descriptor *desc, registry_pull_options *optio + { + int ret = 0; + int sret = 0; +- char blobpath[] = REGISTRY_TMP_DIR; ++ char blobpath[PATH_MAX] = { 0 }; + char scope[PATH_MAX] = { 0 }; ++ char *image_tmp_path = NULL; + + if (desc == NULL || options == NULL) { + ERROR("Invalid NULL param"); +@@ -1710,6 +1718,20 @@ static int prepare_pull_desc(pull_descriptor *desc, registry_pull_options *optio + + update_host(desc); + ++ image_tmp_path = get_image_tmp_path(); ++ if (image_tmp_path == NULL) { ++ ERROR("failed to get image tmp work dir"); ++ ret = -1; ++ goto out; ++ } ++ ++ sret = snprintf(blobpath, PATH_MAX, "%s/registry-XXXXXX", image_tmp_path); ++ if (sret < 0 || (size_t)sret > PATH_MAX) { ++ ERROR("image tmp work path too long"); ++ ret = -1; ++ goto out; ++ } ++ + if (mkdtemp(blobpath) == NULL) { + ERROR("make temporary direcory failed: %s", strerror(errno)); + ret = -1; +@@ -1745,7 +1767,7 @@ static int prepare_pull_desc(pull_descriptor *desc, registry_pull_options *optio + } + + out: +- ++ free(image_tmp_path); + return ret; + } + +@@ -1795,9 +1817,8 @@ int registry_pull(registry_pull_options *options) + INFO("Pull images %s success", options->image_name); + + out: +- if (desc->layer_of_hold_flag != NULL && +- storage_set_hold_flag(desc->layer_of_hold_flag, false) != 0) { +- ERROR("clear hold flag failed for layer %s", desc->layer_of_hold_flag); ++ if (desc->layer_of_hold_refs != NULL && storage_dec_hold_refs(desc->layer_of_hold_refs) != 0) { ++ ERROR("decrease hold refs failed for layer %s", desc->layer_of_hold_refs); + } + + if (desc->blobpath != NULL) { +@@ -1838,10 +1859,18 @@ static void cached_layers_kvfree(void *key, void *value) + int registry_init(char *auths_dir, char *certs_dir) + { + int ret = 0; ++ char *image_tmp_path = NULL; ++ ++ image_tmp_path = get_image_tmp_path(); ++ if (image_tmp_path == NULL) { ++ ERROR("failed to get image tmp path"); ++ return -1; ++ } + +- if (util_mkdir_p(IMAGE_TMP_PATH, 0600)) { +- ERROR("failed to create directory %s", IMAGE_TMP_PATH); ++ if (util_mkdir_p(image_tmp_path, TEMP_DIRECTORY_MODE)) { ++ ERROR("failed to create directory %s", image_tmp_path); + } ++ free(image_tmp_path); + + auths_set_dir(auths_dir); + certs_set_dir(certs_dir); +@@ -1859,6 +1888,13 @@ int registry_init(char *auths_dir, char *certs_dir) + } + g_shared->mutex_inited = true; + ++ ret = pthread_mutex_init(&g_shared->image_mutex, NULL); ++ if (ret != 0) { ++ ERROR("Failed to init image mutex for create image"); ++ goto out; ++ } ++ g_shared->image_mutex_inited = true; ++ + ret = pthread_cond_init(&g_shared->cond, NULL); + if (ret != 0) { + ERROR("Failed to init cond for download info"); +@@ -1882,6 +1918,9 @@ out: + if (g_shared->mutex_inited) { + pthread_mutex_destroy(&g_shared->mutex); + } ++ if (g_shared->image_mutex_inited) { ++ pthread_mutex_destroy(&g_shared->image_mutex); ++ } + map_free(g_shared->cached_layers); + g_shared->cached_layers = NULL; + free(g_shared); +@@ -1941,9 +1980,9 @@ static void free_registry_auth(registry_auth *auth) + if (auth == NULL) { + return; + } +- free_sensitive_string(auth->username); ++ util_free_sensitive_string(auth->username); + auth->username = NULL; +- free_sensitive_string(auth->password); ++ util_free_sensitive_string(auth->password); + auth->password = NULL; + return; + } +diff --git a/src/daemon/modules/image/oci/registry/registry_apiv2.c b/src/daemon/modules/image/oci/registry/registry_apiv2.c +index 7abca9f..7d546d6 100644 +--- a/src/daemon/modules/image/oci/registry/registry_apiv2.c ++++ b/src/daemon/modules/image/oci/registry/registry_apiv2.c +@@ -14,6 +14,7 @@ + ******************************************************************************/ + + #define _GNU_SOURCE /* See feature_test_macros(7) */ ++#include "registry_apiv2.h" + #include + #include + #include +@@ -26,7 +27,6 @@ + #include "registry_type.h" + #include "isula_libutils/log.h" + #include "http.h" +-#include "registry_apiv2.h" + #include "http_request.h" + #include "utils.h" + #include "parser.h" +@@ -45,12 +45,22 @@ + #define MAX_ACCEPT_LEN 128 + // retry 5 times + #define RETRY_TIMES 5 ++#define BODY_DELIMITER "\r\n\r\n" ++ ++static void set_body_null_if_exist(char *message) ++{ ++ char *body = NULL; ++ ++ body = strstr(message, BODY_DELIMITER); ++ if (body != NULL) { ++ *(body + strlen(BODY_DELIMITER)) = 0; ++ } ++} + + static int parse_http_header(char *resp_buf, size_t buf_size, struct parsed_http_message *message) + { + char *real_message = NULL; + int ret = 0; +- size_t real_len = 0; + + if (resp_buf == NULL || message == NULL) { + ERROR("Invalid NULL param"); +@@ -64,8 +74,9 @@ static int parse_http_header(char *resp_buf, size_t buf_size, struct parsed_http + goto out; + } + +- real_len = buf_size - (real_message - resp_buf); +- ret = parse_http(real_message, real_len, message, HTTP_RESPONSE); ++ set_body_null_if_exist(real_message); ++ ++ ret = parse_http(real_message, strlen(real_message), message, HTTP_RESPONSE); + if (ret != 0) { + ERROR("Failed to parse response: %s", real_message); + ret = -1; +@@ -285,7 +296,7 @@ static int parse_ping_header(pull_descriptor *desc, char *http_head) + } + } + +- if (!strings_contains_word(version, "registry/2.0")) { ++ if (!util_strings_contains_word(version, "registry/2.0")) { + ERROR("Docker-Distribution-Api-Version does not contain registry/2.0, it's value is %s." + "Registry can not support registry API V2", + version); +@@ -339,7 +350,7 @@ int registry_pingv2(pull_descriptor *desc, char *protocol) + // Sending url + // https://registry.isula.org/v2/ + INFO("sending ping url: %s", url); +- ret = http_request_buf(desc, url, (const char **)headers, &output, HEAD_ONLY); ++ ret = http_request_buf(desc, url, (const char **)headers, &output, HEAD_BODY); + if (ret != 0) { + ERROR("http request failed"); + goto out; +@@ -425,7 +436,7 @@ static int registry_request(pull_descriptor *desc, char *path, char **custom_hea + goto out; + } + +- headers = str_array_dup((const char **)custom_headers, util_array_len((const char **)custom_headers)); ++ headers = util_str_array_dup((const char **)custom_headers, util_array_len((const char **)custom_headers)); + if (ret != 0) { + ERROR("duplicate custom headers failed"); + ret = -1; +@@ -717,6 +728,7 @@ static void try_log_resp_body(char *path, char *file) + if (size < LXC_LOG_BUFFER_SIZE) { // Max length not exactly, just avoid too long. + ERROR("Get %s response message body: %s", path, body); + } ++ free(body); + return; + } + +@@ -797,7 +809,7 @@ out: + + static bool is_variant_same(char *variant1, char *variant2) + { +- // Compatiable with manifests which didn't have variant ++ // Compatible with manifests which didn't have variant + if (variant1 == NULL || variant2 == NULL) { + return true; + } +@@ -819,7 +831,7 @@ static int select_oci_manifest(oci_image_index *index, char **content_type, char + return -1; + } + +- ret = normalized_host_os_arch(&host_os, &host_arch, &host_variant); ++ ret = util_normalized_host_os_arch(&host_os, &host_arch, &host_variant); + if (ret != 0) { + ret = -1; + goto out; +@@ -876,7 +888,7 @@ static int select_docker_manifest(registry_manifest_list *manifests, char **cont + return -1; + } + +- ret = normalized_host_os_arch(&host_os, &host_arch, &host_variant); ++ ret = util_normalized_host_os_arch(&host_os, &host_arch, &host_variant); + if (ret != 0) { + ret = -1; + goto out; +@@ -1201,7 +1213,7 @@ int login_to_registry(pull_descriptor *desc) + goto out; + } + +- ret = registry_request(desc, path, NULL, NULL, &resp_buffer, HEAD_ONLY, &errcode); ++ ret = registry_request(desc, path, NULL, NULL, &resp_buffer, HEAD_BODY, &errcode); + if (ret != 0) { + ERROR("registry: Get %s failed, resp: %s", path, resp_buffer); + isulad_try_set_error_message("login to registry for %s failed", desc->host); +diff --git a/src/daemon/modules/image/oci/registry_type.c b/src/daemon/modules/image/oci/registry_type.c +index cf7360b..c2b6bba 100644 +--- a/src/daemon/modules/image/oci/registry_type.c ++++ b/src/daemon/modules/image/oci/registry_type.c +@@ -78,9 +78,9 @@ void free_pull_desc(pull_descriptor *desc) + free(desc->tag); + desc->tag = NULL; + +- free_sensitive_string(desc->username); ++ util_free_sensitive_string(desc->username); + desc->username = NULL; +- free_sensitive_string(desc->password); ++ util_free_sensitive_string(desc->password); + desc->password = NULL; + free(desc->auths_dir); + desc->auths_dir = NULL; +@@ -140,8 +140,8 @@ void free_pull_desc(pull_descriptor *desc) + desc->layers = NULL; + desc->layers_len = 0; + +- free(desc->layer_of_hold_flag); +- desc->layer_of_hold_flag = NULL; ++ free(desc->layer_of_hold_refs); ++ desc->layer_of_hold_refs = NULL; + + free(desc); + +diff --git a/src/daemon/modules/image/oci/registry_type.h b/src/daemon/modules/image/oci/registry_type.h +index 349ddfc..e2047cb 100644 +--- a/src/daemon/modules/image/oci/registry_type.h ++++ b/src/daemon/modules/image/oci/registry_type.h +@@ -25,7 +25,6 @@ + // 8 is enough for challenge, usually only one challenge is provided. + #define CHALLENGE_MAX 8 + +-#define REGISTRY_TMP_DIR IMAGE_TMP_PATH "registry-XXXXXX" + + #define MAX_LAYER_NUM 125 + #define ROOTFS_TYPE "layers" +@@ -105,7 +104,7 @@ typedef struct { + // This is temporary field. Once http request is performed, it is cleared + char **headers; + +- char *layer_of_hold_flag; ++ char *layer_of_hold_refs; + + // Image blobs downloaded + manifest_blob manifest; +diff --git a/src/daemon/modules/image/oci/storage/image_store/image_store.c b/src/daemon/modules/image/oci/storage/image_store/image_store.c +index 1d4add9..0f613dd 100644 +--- a/src/daemon/modules/image/oci/storage/image_store/image_store.c ++++ b/src/daemon/modules/image/oci/storage/image_store/image_store.c +@@ -765,7 +765,7 @@ static int get_layers_from_manifest(const registry_manifest_schema1 *manifest, l + layers[index].empty_layer = v1config->throwaway; + free_image_manifest_v1_compatibility(v1config); + v1config = NULL; +- // Cann't download an empty layer, skip related infomation. ++ // Cann't download an empty layer, skip related information. + if (layers[index].empty_layer) { + continue; + } +@@ -777,7 +777,7 @@ static int get_layers_from_manifest(const registry_manifest_schema1 *manifest, l + for (j = 0; j < list->layers_len; j++) { + if ((list->layers[j]->parent == NULL && index == 0) || + (parent_chain_id != NULL && list->layers[j]->parent != NULL && +- !strcmp(list->layers[j]->parent, without_sha256_prefix(parent_chain_id)))) { ++ !strcmp(list->layers[j]->parent, util_without_sha256_prefix(parent_chain_id)))) { + layers[index].diff_id = util_strdup_s(list->layers[j]->uncompressed_digest); + layers[i].chain_id = util_string_append(list->layers[j]->id, SHA256_PREFIX); + parent_chain_id = layers[i].chain_id; +@@ -830,11 +830,11 @@ static int update_image_info(types_timestamp_t *created, const char *config_dige + free(img->id); + img->id = util_strdup_s(config_digest); + +- (void)get_now_time_buffer(timebuffer, sizeof(timebuffer)); ++ (void)util_get_now_time_buffer(timebuffer, sizeof(timebuffer)); + img->loaded = util_strdup_s(timebuffer); + + if (created != NULL && (created->has_seconds || created->has_nanos) && +- !get_time_buffer(created, timebuffer, sizeof(timebuffer))) { ++ !util_get_time_buffer(created, timebuffer, sizeof(timebuffer))) { + ERROR("Failed to get time buffer"); + return -1; + } +@@ -988,7 +988,7 @@ static int convert_to_v2_image_and_load(const char *path) + goto out; + } + +- created = created_to_timestamp(config->created); ++ created = util_to_timestamp_from_str(config->created); + if (update_image_info(&created, config_digest, img) != 0) { + ERROR("Failed to update image info"); + ret = -1; +@@ -1320,10 +1320,10 @@ static storage_image *new_storage_image(const char *id, const char *searchable_d + im->layer = util_strdup_s(layer); + im->metadata = util_strdup_s(metadata); + +- (void)get_now_time_buffer(timebuffer, sizeof(timebuffer)); ++ (void)util_get_now_time_buffer(timebuffer, sizeof(timebuffer)); + im->loaded = util_strdup_s(timebuffer); + if (time != NULL && (time->has_seconds || time->has_nanos) && +- !get_time_buffer(time, timebuffer, sizeof(timebuffer))) { ++ !util_get_time_buffer(time, timebuffer, sizeof(timebuffer))) { + ERROR("Failed to get time buffer"); + ret = -1; + goto out; +@@ -1338,91 +1338,6 @@ out: + return im; + } + +-char *image_store_create(const char *id, const char **names, size_t names_len, const char *layer, const char *metadata, +- const types_timestamp_t *time, const char *searchable_digest) +-{ +- int ret = 0; +- char *dst_id = NULL; +- char **unique_names = NULL; +- size_t unique_names_len = 0; +- image_t *img = NULL; +- storage_image *im = NULL; +- +- if (g_image_store == NULL) { +- ERROR("Image store is not ready"); +- return NULL; +- } +- +- if (!image_store_lock(EXCLUSIVE)) { +- ERROR("Failed to lock image store with exclusive lock, not allowed to create new images"); +- return NULL; +- } +- +- if (id == NULL) { +- dst_id = generate_random_image_id(); +- } else { +- dst_id = util_strdup_s(id); +- } +- +- if (dst_id == NULL) { +- ERROR("Out of memory or generate random image id failed"); +- ret = -1; +- goto out; +- } +- +- if (map_search(g_image_store->byid, (void *)dst_id) != NULL) { +- ERROR("ID is already in use: %s", dst_id); +- ret = -1; +- goto out; +- } +- +- if (util_string_array_unique(names, names_len, &unique_names, &unique_names_len) != 0) { +- ERROR("Failed to unique names"); +- ret = -1; +- goto out; +- } +- +- im = new_storage_image(dst_id, searchable_digest, &unique_names, &unique_names_len, time, layer, metadata); +- if (im == NULL) { +- ERROR("Failed to generate new storage image"); +- ret = -1; +- goto out; +- } +- +- img = new_image(im); +- if (img == NULL) { +- ERROR("Out of memory"); +- ret = -1; +- goto out; +- } +- im = NULL; +- +- if (image_store_append_image(dst_id, searchable_digest, img) != 0) { +- ERROR("Failed to append image to image store"); +- ret = -1; +- goto out; +- } +- +- if (save_image(img->simage) != 0) { +- ERROR("Failed to save image"); +- ret = -1; +- goto out; +- } +- +-out: +- if (ret != 0) { +- free(dst_id); +- dst_id = NULL; +- free_storage_image(im); +- im = NULL; +- free_image_t(img); +- img = NULL; +- } +- util_free_array_by_len(unique_names, unique_names_len); +- image_store_unlock(); +- return dst_id; +-} +- + static image_t *get_image_for_store_by_prefix(const char *id) + { + bool ret = true; +@@ -1494,40 +1409,6 @@ found: + return value; + } + +-char *image_store_lookup(const char *id) +-{ +- char *image_id = NULL; +- image_t *img = NULL; +- +- if (id == NULL) { +- ERROR("Invalid input parameter, id is NULL"); +- return NULL; +- } +- +- if (g_image_store == NULL) { +- ERROR("Image store is not ready"); +- return NULL; +- } +- +- if (!image_store_lock(SHARED)) { +- ERROR("Failed to lock image store with shared lock, not allowed to get image id assignments"); +- return NULL; +- } +- +- img = lookup(id); +- if (img == NULL) { +- ERROR("Image not known"); +- goto out; +- } +- +- image_id = util_strdup_s(img->simage->id); +- +-out: +- image_ref_dec(img); +- image_store_unlock(); +- return image_id; +-} +- + static char *get_value_from_json_map_string_string(json_map_string_string *map, const char *key) + { + size_t i; +@@ -1701,6 +1582,130 @@ out: + return ret; + } + ++char *image_store_create(const char *id, const char **names, size_t names_len, const char *layer, const char *metadata, ++ const types_timestamp_t *time, const char *searchable_digest) ++{ ++ int ret = 0; ++ char *dst_id = NULL; ++ char **unique_names = NULL; ++ size_t unique_names_len = 0; ++ image_t *img = NULL; ++ storage_image *im = NULL; ++ ++ if (g_image_store == NULL) { ++ ERROR("Image store is not ready"); ++ return NULL; ++ } ++ ++ if (!image_store_lock(EXCLUSIVE)) { ++ ERROR("Failed to lock image store with exclusive lock, not allowed to create new images"); ++ return NULL; ++ } ++ ++ if (id == NULL) { ++ dst_id = generate_random_image_id(); ++ } else { ++ dst_id = util_strdup_s(id); ++ } ++ ++ if (dst_id == NULL) { ++ ERROR("Out of memory or generate random image id failed"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (map_search(g_image_store->byid, (void *)dst_id) != NULL) { ++ ERROR("ID is already in use: %s", dst_id); ++ ret = -1; ++ goto out; ++ } ++ ++ if (util_string_array_unique(names, names_len, &unique_names, &unique_names_len) != 0) { ++ ERROR("Failed to unique names"); ++ ret = -1; ++ goto out; ++ } ++ ++ im = new_storage_image(dst_id, searchable_digest, &unique_names, &unique_names_len, time, layer, metadata); ++ if (im == NULL) { ++ ERROR("Failed to generate new storage image"); ++ ret = -1; ++ goto out; ++ } ++ ++ img = new_image(im); ++ if (img == NULL) { ++ ERROR("Out of memory"); ++ ret = -1; ++ goto out; ++ } ++ im = NULL; ++ ++ if (image_store_append_image(dst_id, searchable_digest, img) != 0) { ++ ERROR("Failed to append image to image store"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (save_image(img->simage) != 0) { ++ ERROR("Failed to save image"); ++ if (do_delete_image_info(dst_id) != 0) { ++ ERROR("Failed to delete image info"); ++ } ++ im = NULL; ++ img = NULL; ++ ret = -1; ++ goto out; ++ } ++ ++out: ++ if (ret != 0) { ++ free(dst_id); ++ dst_id = NULL; ++ free_storage_image(im); ++ im = NULL; ++ free_image_t(img); ++ img = NULL; ++ } ++ util_free_array_by_len(unique_names, unique_names_len); ++ image_store_unlock(); ++ return dst_id; ++} ++ ++char *image_store_lookup(const char *id) ++{ ++ char *image_id = NULL; ++ image_t *img = NULL; ++ ++ if (id == NULL) { ++ ERROR("Invalid input parameter, id is NULL"); ++ return NULL; ++ } ++ ++ if (g_image_store == NULL) { ++ ERROR("Image store is not ready"); ++ return NULL; ++ } ++ ++ if (!image_store_lock(SHARED)) { ++ ERROR("Failed to lock image store with shared lock, not allowed to get image id assignments"); ++ return NULL; ++ } ++ ++ img = lookup(id); ++ if (img == NULL) { ++ ERROR("Image not known"); ++ goto out; ++ } ++ ++ image_id = util_strdup_s(img->simage->id); ++ ++out: ++ image_ref_dec(img); ++ image_store_unlock(); ++ return image_id; ++} ++ + int image_store_delete(const char *id) + { + int ret = 0; +@@ -1812,7 +1817,7 @@ static int append_big_data_name(storage_image *im, const char *name) + old_size = im->big_data_names_len * sizeof(char *); + new_size = old_size + sizeof(char *); + +- if (mem_realloc((void **)&tmp_names, new_size, (void *)im->big_data_names, old_size) != 0) { ++ if (util_mem_realloc((void **)&tmp_names, new_size, (void *)im->big_data_names, old_size) != 0) { + ERROR("Failed to realloc memory"); + return -1; + } +@@ -2007,7 +2012,7 @@ static int append_name(char ***names, size_t *names_len, const char *name) + old_size = *names_len * sizeof(char *); + new_size = old_size + sizeof(char *); + +- if (mem_realloc((void **)&tmp_names, new_size, (void *)*names, old_size) != 0) { ++ if (util_mem_realloc((void **)&tmp_names, new_size, (void *)*names, old_size) != 0) { + ERROR("Failed to realloc memory"); + return -1; + } +@@ -2052,7 +2057,7 @@ int image_store_add_name(const char *id, const char *name) + goto out; + } + +- if (dup_array_of_strings((const char **)img->simage->names, img->simage->names_len, &names, &names_len) != 0) { ++ if (util_dup_array_of_strings((const char **)img->simage->names, img->simage->names_len, &names, &names_len) != 0) { + ERROR("Out of memory"); + ret = -1; + goto out; +@@ -2234,7 +2239,8 @@ int image_store_get_names(const char *id, char ***names, size_t *names_len) + goto out; + } + +- ret = dup_array_of_strings((const char **)img->simage->names, img->simage->names_len, &tmp_names, &tmp_names_len); ++ ret = util_dup_array_of_strings((const char **)img->simage->names, img->simage->names_len, &tmp_names, ++ &tmp_names_len); + if (ret != 0) { + ERROR("Out of memory"); + goto out; +@@ -2295,10 +2301,9 @@ out: + + int image_store_set_load_time(const char *id, const types_timestamp_t *time) + { +-#define MAX_TIMESTAMP_LEN 128 + int ret = 0; + image_t *img = NULL; +- char timebuffer[MAX_TIMESTAMP_LEN] = { 0x00 }; ++ char timebuffer[TIME_STR_SIZE] = { 0x00 }; + + if (id == NULL || time == NULL) { + ERROR("Invalid input paratemers"); +@@ -2322,7 +2327,7 @@ int image_store_set_load_time(const char *id, const types_timestamp_t *time) + goto out; + } + +- if (!get_time_buffer(time, timebuffer, sizeof(timebuffer))) { ++ if (!util_get_time_buffer(time, timebuffer, sizeof(timebuffer))) { + ERROR("Failed to get time buffer"); + ret = -1; + goto out; +@@ -2414,7 +2419,7 @@ char *image_store_big_data(const char *id, const char *key) + goto out; + } + +- content = isula_utils_read_file(filename); ++ content = util_read_content_from_file(filename); + + out: + image_ref_dec(img); +@@ -2620,8 +2625,8 @@ int image_store_big_data_names(const char *id, char ***names, size_t *names_len) + goto out; + } + +- if (dup_array_of_strings((const char **)img->simage->big_data_names, img->simage->big_data_names_len, names, +- names_len) != 0) { ++ if (util_dup_array_of_strings((const char **)img->simage->big_data_names, img->simage->big_data_names_len, names, ++ names_len) != 0) { + ERROR("Failed to dup image's names"); + ret = -1; + goto out; +@@ -3014,43 +3019,6 @@ out: + return ret; + } + +-static void parse_user_group(const char *username, char **user, char **group, char **tmp_dup) +-{ +- char *tmp = NULL; +- char *pdot = NULL; +- +- if (user == NULL || group == NULL || tmp_dup == NULL) { +- return; +- } +- +- if (username != NULL) { +- tmp = util_strdup_s(username); +- +- // for free tmp in caller +- *tmp_dup = tmp; +- +- pdot = strstr(tmp, ":"); +- if (pdot != NULL) { +- *pdot = '\0'; +- if (pdot != tmp) { +- // User found +- *user = tmp; +- } +- if (*(pdot + 1) != '\0') { +- // group found +- *group = pdot + 1; +- } +- } else { +- // No : found +- if (*tmp != '\0') { +- *user = tmp; +- } +- } +- } +- +- return; +-} +- + static int pack_health_check_from_image(const docker_image_config_v2 *config_v2, imagetool_image *info) + { + int ret = 0; +@@ -3106,7 +3074,7 @@ static int pack_user_info_from_image(const docker_image_config_v2 *config_v2, im + } + + // parse user and group by username +- parse_user_group(config_v2->config->user, &user, &group, &tmp); ++ util_parse_user_group(config_v2->config->user, &user, &group, &tmp); + + if (user == NULL) { + ERROR("Failed to parse user"); +@@ -3114,6 +3082,14 @@ static int pack_user_info_from_image(const docker_image_config_v2 *config_v2, im + goto out; + } + if (util_safe_llong(user, &converted) == 0) { ++ if (info->uid == NULL) { ++ info->uid = (imagetool_image_uid *)util_common_calloc_s(sizeof(imagetool_image_uid)); ++ if (info->uid == NULL) { ++ ERROR("Out of memory"); ++ ret = -1; ++ goto out; ++ } ++ } + info->uid->value = (int64_t)converted; + } else { + info->username = util_strdup_s(user); +@@ -3366,7 +3342,7 @@ int image_store_get_fs_info(imagetool_fs_info *fs_info) + goto out; + } + +- fs_usage_tmp->timestamp = get_now_time_nanos(); ++ fs_usage_tmp->timestamp = util_get_now_time_nanos(); + + fs_usage_tmp->fs_id = util_common_calloc_s(sizeof(imagetool_fs_info_image_filesystems_fs_id)); + if (fs_usage_tmp->fs_id == NULL) { +diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.c +index 11523a3..3d3dcad 100644 +--- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.c ++++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.c +@@ -1145,9 +1145,10 @@ static int pool_has_free_space(struct device_set *devset) + ERROR("devmapper: Thin Pool has %lu free data blocks which is less than minimum required " + "%lu free data blocks. Create more free space in thin pool or use dm.min_free_space option to change behavior", + data_total - data_used, min_free_data); +- isulad_set_error_message("devmapper: Thin Pool has %lu free data blocks which is less than minimum required " +- "%lu free data blocks. Create more free space in thin pool or use dm.min_free_space option to change behavior", +- data_total - data_used, min_free_data); ++ isulad_set_error_message( ++ "devmapper: Thin Pool has %lu free data blocks which is less than minimum required " ++ "%lu free data blocks. Create more free space in thin pool or use dm.min_free_space option to change behavior", ++ data_total - data_used, min_free_data); + ret = -1; + goto out; + } +@@ -1163,10 +1164,11 @@ static int pool_has_free_space(struct device_set *devset) + "which is less than minimum required %lu free metadata blocks. " + "Create more free metadata space in thin pool or use dm.min_free_space option to change behavior", + metadata_total - metadata_used, min_free_metadata); +- isulad_set_error_message("devmapper: Thin Pool has %lu free metadata blocks " +- "which is less than minimum required %lu free metadata blocks. " +- "Create more free metadata space in thin pool or use dm.min_free_space option to change behavior", +- metadata_total - metadata_used, min_free_metadata); ++ isulad_set_error_message( ++ "devmapper: Thin Pool has %lu free metadata blocks " ++ "which is less than minimum required %lu free metadata blocks. " ++ "Create more free metadata space in thin pool or use dm.min_free_space option to change behavior", ++ metadata_total - metadata_used, min_free_metadata); + ret = -1; + goto out; + } +@@ -1652,7 +1654,8 @@ static int take_snapshot(struct device_set *devset, const char *hash, image_devm + if (dinfo.deferred_remove != 0) { + nret = cancel_deferred_removal(devset, base_info->hash); + if (nret != 0) { +- ERROR("devmapper: cancel deferred remove for device with hash:%s failed, err:%s", base_info->hash, dev_strerror(nret)); ++ ERROR("devmapper: cancel deferred remove for device with hash:%s failed, err:%s", base_info->hash, ++ dev_strerror(nret)); + if (nret != ERR_ENXIO) { + ERROR("devmapper: cancel device(id:%s) deferred remove failed", base_info->hash); + ret = -1; +@@ -1721,7 +1724,8 @@ static int cancel_deferred_removal_if_needed(struct device_set *devset, image_de + + nret = cancel_deferred_removal(devset, info->hash); + if (nret != 0 && nret != ERR_BUSY) { +- ERROR("devmapper: cancel deferred remove for device with hash:%s failed, err:%s", info->hash, dev_strerror(nret)); ++ ERROR("devmapper: cancel deferred remove for device with hash:%s failed, err:%s", info->hash, ++ dev_strerror(nret)); + ret = -1; + goto out; + } +@@ -2563,7 +2567,8 @@ static int determine_driver_capabilities(const char *version, struct device_set + + if (major < 4) { + ERROR("devicamapper driver version:(%ld.xxx) < 4.27.0, do not surpport deferred removal", major); +- isulad_set_error_message("devicamapper driver version:(%ld.xxx) < 4.27.0, do not surpport deferred removal", major); ++ isulad_set_error_message("devicamapper driver version:(%ld.xxx) < 4.27.0, do not surpport deferred removal", ++ major); + ret = -1; + goto out; + } +@@ -2584,7 +2589,8 @@ static int determine_driver_capabilities(const char *version, struct device_set + */ + if (minor < 27) { + ERROR("devicamapper driver version (4.%ld) < 4.27.0, , do not surpport deferred removal", minor); +- isulad_set_error_message("devicamapper driver version (4.%ld) < 4.27.0, , do not surpport deferred removal", minor); ++ isulad_set_error_message("devicamapper driver version (4.%ld) < 4.27.0, , do not surpport deferred removal", ++ minor); + ret = -1; + goto out; + } +@@ -2842,10 +2848,12 @@ free_out: + static char *generate_mount_options(const struct driver_mount_opts *moptions, const char *dev_options) + { + char *res_str = NULL; +- char *tmp = NULL; + + append_mount_options(&res_str, dev_options); ++#ifdef ENABLE_SELINUX + if (moptions != NULL && moptions->mount_label != NULL) { ++ char *tmp = NULL; ++ + tmp = selinux_format_mountlabel(res_str, moptions->mount_label); + if (tmp == NULL) { + goto error_out; +@@ -2854,7 +2862,6 @@ static char *generate_mount_options(const struct driver_mount_opts *moptions, co + res_str = tmp; + tmp = NULL; + } +- + goto out; + + error_out: +@@ -2862,6 +2869,7 @@ error_out: + res_str = NULL; + + out: ++#endif + return res_str; + } + +@@ -2949,17 +2957,10 @@ int unmount_device(const char *hash, const char *mount_path, struct device_set * + goto free_out; + } + +- if (util_detect_mounted(mount_path)) { +- if (umount2(mount_path, MNT_DETACH) < 0 && errno != EINVAL) { +- ERROR("Failed to umount directory %s:%s", mount_path, strerror(errno)); +- ret = -1; +- goto free_out; +- } +- } +- +- if (util_path_remove(mount_path) != 0) { +- DEBUG("devmapper: doing remove on a unmounted device %s failed", mount_path); ++ if (umount2(mount_path, MNT_DETACH) < 0 && errno != EINVAL) { ++ ERROR("Failed to umount directory %s:%s", mount_path, strerror(errno)); + ret = -1; ++ goto free_out; + } + + if (deactivate_device(devset, device_info->info) != 0) { +@@ -3165,7 +3166,6 @@ struct status *device_set_status(struct device_set *devset) + st->sem_msg = util_strdup_s(msg); + } + +- + free_out: + (void)pthread_rwlock_unlock(&devset->devmapper_driver_rwlock); + return st; +@@ -3220,10 +3220,8 @@ static int umount_deactivate_dev_all(struct device_set *devset) + continue; + } + +- if (util_detect_mounted(fname)) { +- if (umount2(fname, MNT_DETACH) < 0 && errno != EINVAL) { +- ERROR("Failed to umount directory %s:%s", fname, strerror(errno)); +- } ++ if (umount2(fname, MNT_DETACH) < 0 && errno != EINVAL) { ++ ERROR("Failed to umount directory %s:%s", fname, strerror(errno)); + } + + device_info = lookup_device(devset, entry->d_name); +@@ -3306,4 +3304,4 @@ void free_device_set(struct device_set *devset) + UTIL_FREE_AND_SET_NULL(devset->base_device_filesystem); + + free(devset); +-} +\ No newline at end of file ++} +diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.c +index 1043c6c..61dbebf 100644 +--- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.c ++++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.c +@@ -82,7 +82,36 @@ out: + static int do_create(const char *id, const char *parent, const struct graphdriver *driver, + const struct driver_create_opts *create_opts) + { +- return add_device(id, parent, driver->devset, create_opts->storage_opt); ++ int ret = 0; ++ char *mnt_parent_dir = NULL; ++ char *mnt_point_dir = NULL; ++ ++ mnt_parent_dir = util_path_join(driver->home, "mnt"); ++ if (mnt_parent_dir == NULL) { ++ ERROR("Failed to join devmapper mnt dir %s", id); ++ ret = -1; ++ goto out; ++ } ++ ++ mnt_point_dir = util_path_join(mnt_parent_dir, id); ++ if (mnt_point_dir == NULL) { ++ ERROR("Failed to join devampper mount point dir %s", id); ++ ret = -1; ++ goto out; ++ } ++ ++ if (util_mkdir_p(mnt_point_dir, DEFAULT_SECURE_DIRECTORY_MODE) != 0) { ++ ERROR("Failed to mkdir path:%s", mnt_point_dir); ++ ret = -1; ++ goto out; ++ } ++ ++ ret = add_device(id, parent, driver->devset, create_opts->storage_opt); ++ ++out: ++ free(mnt_parent_dir); ++ free(mnt_point_dir); ++ return ret; + } + + // devmapper_create_rw creates a layer that is writable for use as a container file system +@@ -186,12 +215,6 @@ char *devmapper_mount_layer(const char *id, const struct graphdriver *driver, + goto out; + } + +- if (util_mkdir_p(mnt_point_dir, DEFAULT_SECURE_DIRECTORY_MODE) != 0) { +- ERROR("Failed to mkdir path:%s", mnt_point_dir); +- ret = -1; +- goto out; +- } +- + if (mount_device(id, mnt_point_dir, mount_opts, driver->devset) != 0) { + ERROR("Mount device:%s to path:%s failed", id, mnt_parent_dir); + ret = -1; +@@ -316,7 +339,7 @@ int devmapper_apply_diff(const char *id, const struct graphdriver *driver, const + goto out; + } + +- options.whiteout_format = OVERLAY_WHITEOUT_FORMATE; ++ options.whiteout_format = REMOVE_WHITEOUT_FORMATE; + if (archive_unpack(content, layer_fs, &options) != 0) { + ERROR("devmapper: failed to unpack to :%s", layer_fs); + ret = -1; +@@ -454,12 +477,15 @@ static void status_append(const char *name, const char *value, uint64_t u_data, + free(human_size); + } else { + // If unsigned long int is bigger than LONG_MAX, just print directly with Byte unit +- nret = snprintf(tmp, MAX_INFO_LENGTH, "%s: %lu B\n", name, u_data); ++ nret = snprintf(tmp, MAX_INFO_LENGTH, "%s: %luB\n", name, u_data); + } + break; + case INT: + nret = snprintf(tmp, MAX_INFO_LENGTH, "%s: %d\n", name, integer_data); + break; ++ case UINT64_NONE: ++ // Print without unit ++ nret = snprintf(tmp, MAX_INFO_LENGTH, "%s: %lu\n", name, u_data); + default: + break; + } +@@ -511,7 +537,7 @@ char *status_to_str(const struct status *st) + status_append("Deferred Deletion Enabled", "false", 0, 0, &str, STRING); + } + +- status_append("Deferred Deleted Device Count", NULL, st->deferred_deleted_device_count, 0, &str, UINT64_T); ++ status_append("Deferred Deleted Device Count", NULL, st->deferred_deleted_device_count, 0, &str, UINT64_NONE); + status_append("Library Version", st->library_version, 0, 0, &str, STRING); + status_append("Semaphore Set Used", NULL, 0, st->semusz, &str, INT); + status_append("Semaphore Set Total", NULL, 0, st->semmni, &str, INT); +diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.h b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.h +index d827d9b..9ee020d 100644 +--- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.h ++++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.h +@@ -41,6 +41,7 @@ typedef enum { + STRING, + UINT64_T, + INT, ++ UINT64_NONE, + } data_type; + + int devmapper_init(struct graphdriver *driver, const char *drvier_home, const char **options, size_t len); +diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/metadata_store.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/metadata_store.c +index 325f963..0185874 100644 +--- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/metadata_store.c ++++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/metadata_store.c +@@ -12,11 +12,10 @@ + * Create: 2020-06-12 + * Description: provide devicemapper metadata store function definition + ******************************************************************************/ +- ++#include "metadata_store.h" + #include + #include + +-#include "metadata_store.h" + #include "utils.h" + #include "isula_libutils/log.h" + #include "util_atomic.h" +diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/wrapper_devmapper.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/wrapper_devmapper.c +index b2f426c..9aa734b 100644 +--- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/wrapper_devmapper.c ++++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/wrapper_devmapper.c +@@ -13,6 +13,7 @@ + * Description: wrap libdevmapper function to manuplite devicemapper + ******************************************************************************/ + #define _GNU_SOURCE ++#include "wrapper_devmapper.h" + #include + #include + #include +@@ -23,7 +24,6 @@ + #include + #include + +-#include "wrapper_devmapper.h" + #include "isula_libutils/log.h" + #include "utils.h" + #include "err_msg.h" +diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.c +index 5fb8b90..f2df4f8 100644 +--- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.c ++++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.c +@@ -8,8 +8,8 @@ + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. +- * Author: tanyifeng +- * Create: 2017-11-22 ++ * Author: lifeng ++ * Create: 2020-04-22 + * Description: provide image functions + ******************************************************************************/ + +diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.h b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.h +index 58eae32..7faf70c 100644 +--- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.h ++++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.h +@@ -8,8 +8,8 @@ + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. +- * Author: tanyifeng +- * Create: 2019-04-02 ++ * Author: lifeng ++ * Create: 2020-04-22 + * Description: provide graphdriver function definition + ******************************************************************************/ + #ifndef DAEMON_MODULES_IMAGE_OCI_STORAGE_LAYER_STORE_GRAPHDRIVER_DRIVER_H +@@ -98,7 +98,8 @@ struct graphdriver { + // options for device mapper + struct device_set *devset; + +- pthread_rwlock_t rwlock; // lock to protect graphdriver between cleanup and other operations ++ // lock to protect graphdriver between cleanup and other operations ++ pthread_rwlock_t rwlock; + }; + + int graphdriver_init(const struct storage_module_init_options *opts); +diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c +index c81c4bc..95909a8 100644 +--- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c ++++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c +@@ -8,8 +8,8 @@ + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. +- * Author: tanyifeng +- * Create: 2019-04-02 ++ * Author: lifeng ++ * Create: 2020-04-02 + * Description: provide overlay2 function definition + ******************************************************************************/ + #include "driver_overlay2.h" +@@ -275,6 +275,7 @@ int overlay2_init(struct graphdriver *driver, const char *drvier_home, const cha + char *root_dir = NULL; + + if (driver == NULL || drvier_home == NULL) { ++ ERROR("Invalid input arguments"); + return -1; + } + +@@ -427,7 +428,7 @@ static int do_diff_symlink(const char *id, char *link_id, const char *driver_hom + goto out; + } + +- if (cleanpath(link_path, clean_path, sizeof(clean_path)) == NULL) { ++ if (util_clean_path(link_path, clean_path, sizeof(clean_path)) == NULL) { + ERROR("failed to get clean path %s", link_path); + ret = -1; + goto out; +@@ -682,7 +683,7 @@ out: + return ret; + } + +-static int mk_sub_directorys(const char *id, const char *parent, const char *layer_dir, const char *driver_home) ++static int mk_sub_directories(const char *id, const char *parent, const char *layer_dir, const char *driver_home) + { + int ret = 0; + char *lowers = NULL; +@@ -802,11 +803,11 @@ static int do_create(const char *id, const char *parent, const struct graphdrive + if (set_layer_quota(layer_dir, create_opts->storage_opt, driver) != 0) { + ERROR("Unable to set layer quota %s", layer_dir); + ret = -1; +- goto out; ++ goto err_out; + } + } + +- if (mk_sub_directorys(id, parent, layer_dir, driver->home) != 0) { ++ if (mk_sub_directories(id, parent, layer_dir, driver->home) != 0) { + ret = -1; + goto err_out; + } +@@ -874,6 +875,7 @@ int overlay2_create_rw(const char *id, const char *parent, const struct graphdri + int ret = 0; + + if (id == NULL || driver == NULL || create_opts == NULL) { ++ ERROR("Invalid input arguments"); + return -1; + } + +@@ -899,22 +901,17 @@ out: + int overlay2_create_ro(const char *id, const char *parent, const struct graphdriver *driver, + const struct driver_create_opts *create_opts) + { +- int ret = 0; +- + if (id == NULL || driver == NULL || create_opts == NULL) { ++ ERROR("Invalid input arguments"); + return -1; + } + + if (create_opts->storage_opt != NULL && create_opts->storage_opt->len != 0) { + ERROR("--storage-opt size is only supported for ReadWrite Layers"); +- ret = -1; +- goto out; ++ return -1; + } + +- ret = do_create(id, parent, driver, create_opts); +- +-out: +- return ret; ++ return do_create(id, parent, driver, create_opts); + } + + static char *read_layer_link_file(const char *layer_dir) +@@ -961,6 +958,7 @@ int overlay2_rm_layer(const char *id, const struct graphdriver *driver) + char clean_path[PATH_MAX] = { 0 }; + + if (id == NULL || driver == NULL) { ++ ERROR("Invalid input arguments"); + return -1; + } + +@@ -979,7 +977,7 @@ int overlay2_rm_layer(const char *id, const struct graphdriver *driver) + ret = -1; + goto out; + } +- if (cleanpath(link_path, clean_path, sizeof(clean_path)) == NULL) { ++ if (util_clean_path(link_path, clean_path, sizeof(clean_path)) == NULL) { + ERROR("failed to get clean path %s", link_path); + ret = -1; + goto out; +@@ -1262,6 +1260,7 @@ static char *get_abs_mount_opt_data(const char *layer_dir, const char *abs_lower + tmp = NULL; + } + ++#ifdef ENABLE_SELINUX + if (mount_opts != NULL && mount_opts->mount_label != NULL) { + tmp = selinux_format_mountlabel(mount_data, mount_opts->mount_label); + if (tmp == NULL) { +@@ -1271,6 +1270,7 @@ static char *get_abs_mount_opt_data(const char *layer_dir, const char *abs_lower + mount_data = tmp; + tmp = NULL; + } ++#endif + + goto out; + +@@ -1344,6 +1344,7 @@ static char *get_rel_mount_opt_data(const char *id, const char *rel_lower_dir, c + tmp = NULL; + } + ++#ifdef ENABLE_SELINUX + if (mount_opts != NULL && mount_opts->mount_label != NULL) { + tmp = selinux_format_mountlabel(mount_data, mount_opts->mount_label); + if (tmp == NULL) { +@@ -1353,6 +1354,7 @@ static char *get_rel_mount_opt_data(const char *id, const char *rel_lower_dir, c + mount_data = tmp; + tmp = NULL; + } ++#endif + + goto out; + +@@ -1494,6 +1496,7 @@ char *overlay2_mount_layer(const char *id, const struct graphdriver *driver, con + char *layer_dir = NULL; + + if (id == NULL || driver == NULL) { ++ ERROR("Invalid input arguments"); + return NULL; + } + +@@ -1526,6 +1529,7 @@ int overlay2_umount_layer(const char *id, const struct graphdriver *driver) + char *layer_dir = NULL; + + if (id == NULL || driver == NULL) { ++ ERROR("Invalid input arguments"); + return -1; + } + +@@ -1815,6 +1819,7 @@ int overlay2_get_driver_status(const struct graphdriver *driver, struct graphdri + char tmp[MAX_INFO_LENGTH] = { 0 }; + + if (driver == NULL || status == NULL) { ++ ERROR("Invalid input arguments"); + return -1; + } + +@@ -1856,6 +1861,7 @@ int overlay2_clean_up(struct graphdriver *driver) + int ret = 0; + + if (driver == NULL) { ++ ERROR("Invalid input arguments"); + ret = -1; + goto out; + } +@@ -1901,6 +1907,7 @@ int overlay2_repair_lowers(const char *id, const char *parent, const struct grap + size_t lowers_size = 0; + + if (id == NULL || driver == NULL) { ++ ERROR("Invalid input arguments"); + return -1; + } + +@@ -1966,7 +1973,7 @@ static int do_cal_layer_fs_info(const char *layer_diff, imagetool_fs_info *fs_in + goto out; + } + +- fs_usage_tmp->timestamp = get_now_time_nanos(); ++ fs_usage_tmp->timestamp = util_get_now_time_nanos(); + + fs_usage_tmp->fs_id = util_common_calloc_s(sizeof(imagetool_fs_info_image_filesystems_fs_id)); + if (fs_usage_tmp->fs_id == NULL) { +@@ -2016,6 +2023,7 @@ int overlay2_get_layer_fs_info(const char *id, const struct graphdriver *driver, + char *layer_diff = NULL; + + if (id == NULL || fs_info == NULL) { ++ ERROR("Invalid input arguments"); + return -1; + } + +diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.h b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.h +index 8e2c30b..5f3228f 100644 +--- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.h ++++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.h +@@ -8,7 +8,7 @@ + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. +- * Author: tanyifeng ++ * Author: lifeng + * Create: 2019-04-02 + * Description: provide overlay2 function definition + ******************************************************************************/ +diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/quota/project_quota.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/quota/project_quota.c +index 8efe709..2bcfb0e 100644 +--- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/quota/project_quota.c ++++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/quota/project_quota.c +@@ -321,7 +321,7 @@ void free_pquota_control(struct pquota_control *ctrl) + ctrl->backing_fs_device = NULL; + + if (pthread_rwlock_destroy(&(ctrl->rwlock)) != 0) { +- SYSERROR("destory pquota_control rwlock failed"); ++ SYSERROR("destroy pquota_control rwlock failed"); + } + free(ctrl); + } +@@ -334,7 +334,7 @@ static int get_quota_stat(const char *backing_fs_blockdev) + + ret = quotactl(QCMD(Q_XGETQSTAT, FS_PROJ_QUOTA), backing_fs_blockdev, 0, (caddr_t)&fs_quota_stat_info); + if (ret != 0) { +- SYSERROR("Failed to get quota stat on %s", backing_fs_blockdev); ++ SYSWARN("Failed to get quota stat on %s", backing_fs_blockdev); + return ret; + } + +diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/quota/project_quota.h b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/quota/project_quota.h +index d88ac30..2aae6bc 100644 +--- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/quota/project_quota.h ++++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/quota/project_quota.h +@@ -44,46 +44,34 @@ + extern "C" { + #endif + +-/* +- * Check whether we have to define FS_IOC_FS[GS]ETXATTR ourselves. These +- * are a copy of the definitions moved to linux/uapi/fs.h in the 4.5 kernel, +- * so this is purely for supporting builds against old kernel headers. +- */ + #if !defined FS_IOC_FSGETXATTR ++// if did not define the fsxattr, define by ourself + struct fsxattr { +- __u32 fsx_xflags; /* xflags field value (get/set) */ +- __u32 fsx_extsize; /* extsize field value (get/set)*/ +- __u32 fsx_nextents; /* nextents field value (get) */ +- __u32 fsx_projid; /* project identifier (get/set) */ +- __u32 fsx_cowextsize; /* cow extsize field value (get/set) */ +- unsigned char fsx_pad[8]; ++ __u32 fsx_xflags, fsx_extsize, fsx_nextents, fsx_projid, fsx_cowextsize; ++ unsigned char fsx_pad[8]; + }; + #endif + + #ifndef FS_IOC_FSGETXATTR +-/* +- * Flags for the fsx_xflags field +- */ +-#define FS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */ +-#define FS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */ +-#define FS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */ +-#define FS_XFLAG_APPEND 0x00000010 /* all writes append */ +-#define FS_XFLAG_SYNC 0x00000020 /* all writes synchronous */ +-#define FS_XFLAG_NOATIME 0x00000040 /* do not update access time */ +-#define FS_XFLAG_NODUMP 0x00000080 /* do not include in backups */ +-#define FS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */ +-#define FS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */ +-#define FS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */ +-#define FS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */ +-#define FS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */ +-#define FS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */ +-#define FS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */ +-#define FS_XFLAG_DAX 0x00008000 /* use DAX for IO */ +-#define FS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ +- +-#define FS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr) +-#define FS_IOC_FSSETXATTR _IOW ('X', 32, struct fsxattr) +- ++// if did not define the FSGETXATTR, define by ourself ++#define FS_XFLAG_REALTIME 0x00000001 ++#define FS_XFLAG_PREALLOC 0x00000002 ++#define FS_XFLAG_IMMUTABLE 0x00000008 ++#define FS_XFLAG_APPEND 0x00000010 ++#define FS_XFLAG_SYNC 0x00000020 ++#define FS_XFLAG_NOATIME 0x00000040 ++#define FS_XFLAG_NODUMP 0x00000080 ++#define FS_XFLAG_RTINHERIT 0x00000100 ++#define FS_XFLAG_PROJINHERIT 0x00000200 ++#define FS_XFLAG_NOSYMLINKS 0x00000400 ++#define FS_XFLAG_EXTSIZE 0x00000800 ++#define FS_XFLAG_EXTSZINHERIT 0x00001000 ++#define FS_XFLAG_NODEFRAG 0x00002000 ++#define FS_XFLAG_FILESTREAM 0x00004000 ++#define FS_XFLAG_DAX 0x00008000 ++#define FS_XFLAG_HASATTR 0x80000000 ++#define FS_IOC_FSGETXATTR _IOR('X', 31, struct fsxattr) ++#define FS_IOC_FSSETXATTR _IOW('X', 32, struct fsxattr) + #endif + + struct pquota_control { +diff --git a/src/daemon/modules/image/oci/storage/layer_store/layer.h b/src/daemon/modules/image/oci/storage/layer_store/layer.h +index d86e02e..f2dad64 100644 +--- a/src/daemon/modules/image/oci/storage/layer_store/layer.h ++++ b/src/daemon/modules/image/oci/storage/layer_store/layer.h +@@ -38,7 +38,7 @@ typedef struct _layer_t_ { + char *mount_point_json_path; + storage_mount_point *smount_point; + +- bool hold; ++ int hold_refs_num; + + uint64_t refcnt; + } layer_t; +diff --git a/src/daemon/modules/image/oci/storage/layer_store/layer_store.c b/src/daemon/modules/image/oci/storage/layer_store/layer_store.c +index 934ec35..704dbd6 100644 +--- a/src/daemon/modules/image/oci/storage/layer_store/layer_store.c ++++ b/src/daemon/modules/image/oci/storage/layer_store/layer_store.c +@@ -556,7 +556,7 @@ static int update_layer_datas(const char *id, const struct layer_opts *opts, lay + if (opts->opts != NULL) { + slayer->mountlabel = util_strdup_s(opts->opts->mount_label); + } +- if (!get_now_local_utc_time_buffer(timebuffer, TIME_STR_SIZE)) { ++ if (!util_get_now_local_utc_time_buffer(timebuffer, TIME_STR_SIZE)) { + ERROR("Get create time failed"); + ret = -1; + goto free_out; +@@ -738,7 +738,7 @@ out: + static int insert_memory_stores(const char *id, const struct layer_opts *opts, layer_t *l) + { + int ret = 0; +- size_t i = 0; ++ int i = 0; + + if (!append_layer_into_list(l)) { + ret = -1; +@@ -863,7 +863,9 @@ static char *caculate_playload(struct archive *ar) + int nret = 0; + const isula_crc_table_t *ctab = NULL; + uint64_t crc = 0; ++ // max crc bits is 8 + unsigned char sum_data[8] = { 0 }; ++ // add \0 at crc bits last, so need a 9 bits array + unsigned char tmp_data[9] = { 0 }; + bool empty = true; + +@@ -893,6 +895,7 @@ static char *caculate_playload(struct archive *ar) + } + + isula_crc_sum(crc, sum_data); ++ // max crc bits is 8 + for (r = 0; r < 8; r++) { + tmp_data[r] = sum_data[r]; + } +@@ -1004,12 +1007,6 @@ out: + + static int make_tar_split_file(const char *lid, const struct io_read_wrapper *diff, int64_t *size) + { +- /* +- * step 1: read header; +- * step 2: build entry json; +- * step 3: write into tar split; +- * step 4: gzip tar split, and save file. +- * */ + int *pfd = (int *)diff->context; + char *save_fname = NULL; + char *save_fname_gz = NULL; +@@ -1024,6 +1021,7 @@ static int make_tar_split_file(const char *lid, const struct io_read_wrapper *di + if (save_fname_gz == NULL) { + goto out; + } ++ // step 1: read header; + tfd = util_open(save_fname, O_WRONLY | O_CREAT, SECURE_CONFIG_FILE_MODE); + if (tfd == -1) { + SYSERROR("touch file failed"); +@@ -1032,6 +1030,8 @@ static int make_tar_split_file(const char *lid, const struct io_read_wrapper *di + close(tfd); + tfd = -1; + ++ // step 2: build entry json; ++ // step 3: write into tar split; + ret = foreach_archive_entry(archive_entry_parse, *pfd, save_fname, size); + if (ret != 0) { + goto out; +@@ -1042,7 +1042,7 @@ static int make_tar_split_file(const char *lid, const struct io_read_wrapper *di + goto out; + } + +- // gzip tar split file ++ // step 4: gzip tar split, and save file. + ret = util_gzip_z(save_fname, save_fname_gz, SECURE_CONFIG_FILE_MODE); + + // always remove tmp tar split file, even though gzip failed. +@@ -1153,28 +1153,32 @@ static int layer_store_remove_layer(const char *id) + return ret; + } + +-int layer_set_hold_flag(const char *layer_id, bool hold) ++int layer_set_hold_refs(const char *layer_id, bool increase) + { + layer_t *l = NULL; + int ret = 0; + + if (layer_id == NULL) { +- ERROR("Invalid NULL layer id when reset hold flag"); ++ ERROR("Invalid NULL layer id when set hold refs"); + return -1; + } + + if (!layer_store_lock(true)) { +- ERROR("Failed to lock layer store, reset hold flag for layer %s failed", layer_id); ++ ERROR("Failed to lock layer store, reset hold refs for layer %s failed", layer_id); + return -1; + } + + l = map_search(g_metadata.by_id, (void *)layer_id); + if (l == NULL) { +- ERROR("layer %s not found when reset hold flag", layer_id); ++ ERROR("layer %s not found when set hold refs", layer_id); + ret = -1; + goto out; + } +- l->hold = hold; ++ if (increase) { ++ l->hold_refs_num++; ++ } else { ++ l->hold_refs_num--; ++ } + + out: + layer_store_unlock(); +@@ -1182,28 +1186,38 @@ out: + return ret; + } + +-int layer_get_hold_flag(const char *layer_id, bool *hold) ++int layer_inc_hold_refs(const char *layer_id) ++{ ++ return layer_set_hold_refs(layer_id, true); ++} ++ ++int layer_dec_hold_refs(const char *layer_id) ++{ ++ return layer_set_hold_refs(layer_id, false); ++} ++ ++int layer_get_hold_refs(const char *layer_id, int *refs_num) + { + int ret = 0; + layer_t *l = NULL; + +- if (layer_id == NULL || hold == NULL) { +- ERROR("Invalid NULL param when get hold flag"); ++ if (layer_id == NULL || refs_num == NULL) { ++ ERROR("Invalid NULL param when get hold refs"); + return -1; + } + + if (!layer_store_lock(true)) { +- ERROR("Failed to lock layer store, get hold flag of layer %s failed", layer_id); ++ ERROR("Failed to lock layer store, get hold refs of layer %s failed", layer_id); + return -1; + } + + l = map_search(g_metadata.by_id, (void *)layer_id); + if (l == NULL) { +- ERROR("layer %s not found when reset hold flag", layer_id); ++ ERROR("layer %s not found when get hold refs", layer_id); + ret = -1; + goto out; + } +- *hold = l->hold; ++ *refs_num = l->hold_refs_num; + + out: + layer_store_unlock(); +@@ -1214,7 +1228,7 @@ out: + int layer_store_create(const char *id, const struct layer_opts *opts, const struct io_read_wrapper *diff, char **new_id) + { + int ret = 0; +- char *lid = util_strdup_s(id); ++ char *lid = NULL; + layer_t *l = NULL; + + if (opts == NULL) { +@@ -1226,10 +1240,12 @@ int layer_store_create(const char *id, const struct layer_opts *opts, const stru + return -1; + } + +- // If the layer already exist, hold the layer is enough ++ lid = util_strdup_s(id); ++ ++ // If the layer already exist, increase refs number to hold the layer is enough + l = lookup(lid); + if (l != NULL) { +- l->hold = true; // mark it as hold, so others can't delete this layer ++ l->hold_refs_num++; // increase refs number, so others can't delete this layer + goto free_out; + } + +@@ -1246,12 +1262,12 @@ int layer_store_create(const char *id, const struct layer_opts *opts, const stru + l = lookup(lid); + if (l == NULL) { + ret = -1; +- goto driver_remove; ++ goto clear_memory; + } + l->slayer->incompelte = true; + if (save_layer(l) != 0) { + ret = -1; +- goto driver_remove; ++ goto clear_memory; + } + + ret = apply_diff(l, diff); +@@ -1272,7 +1288,7 @@ int layer_store_create(const char *id, const struct layer_opts *opts, const stru + *new_id = lid; + lid = NULL; + } +- l->hold = true; // mark it as hold, so others can't delete this layer ++ l->hold_refs_num++; // increase refs number, so others can't delete this layer + goto free_out; + } + ERROR("Save layer failed"); +@@ -1600,8 +1616,8 @@ int layer_store_umount(const char *id, bool force) + } + l = lookup_with_lock(id); + if (l == NULL) { +- ERROR("layer not known"); +- return -1; ++ ERROR("layer not known,skip umount"); ++ return 0; + } + layer_lock(l); + ret = umount_helper(l, force); +@@ -1724,7 +1740,7 @@ out: + return ret; + } + +-static bool load_layer_json_cb(const char *path_name, const struct dirent *sub_dir) ++static bool load_layer_json_cb(const char *path_name, const struct dirent *sub_dir, void *context) + { + #define LAYER_NAME_LEN 64 + bool flag = false; +@@ -1814,7 +1830,7 @@ static int load_layers_from_json_files() + return -1; + } + +- ret = util_scan_subdirs(g_root_dir, load_layer_json_cb); ++ ret = util_scan_subdirs(g_root_dir, load_layer_json_cb, NULL); + if (ret != 0) { + goto unlock_out; + } +@@ -1968,7 +1984,7 @@ static uint64_t payload_to_crc(char *payload) + return crc; + } + +-static int file_crc(char *file, uint64_t *crc, uint64_t policy) ++static int file_crc64(char *file, uint64_t *crc, uint64_t policy) + { + #define BLKSIZE 32768 + int ret = 0; +@@ -2023,7 +2039,7 @@ out: + return ret; + } + +-static int valid_crc(storage_entry *entry, char *rootfs) ++static int valid_crc64(storage_entry *entry, char *rootfs) + { + int ret = 0; + int nret = 0; +@@ -2058,7 +2074,7 @@ static int valid_crc(storage_entry *entry, char *rootfs) + goto out; + } + +- ret = file_crc(file, &crc, ISO_POLY); ++ ret = file_crc64(file, &crc, ISO_POLY); + if (ret != 0) { + ERROR("calc crc of file %s failed", file); + ret = -1; +@@ -2204,7 +2220,7 @@ static int do_integration_check(layer_t *l, char *rootfs) + } + while (entry != NULL) { + if (entry->type == STORAGE_ENTRY_TYPE_CRC) { +- ret = valid_crc(entry, rootfs); ++ ret = valid_crc64(entry, rootfs); + if (ret != 0) { + ERROR("integration check failed, layer %s, file %s", l->slayer->id, entry->name); + goto out; +diff --git a/src/daemon/modules/image/oci/storage/layer_store/layer_store.h b/src/daemon/modules/image/oci/storage/layer_store/layer_store.h +index f025f0f..94d4bf0 100644 +--- a/src/daemon/modules/image/oci/storage/layer_store/layer_store.h ++++ b/src/daemon/modules/image/oci/storage/layer_store/layer_store.h +@@ -57,8 +57,9 @@ void layer_store_cleanup(); + void remove_layer_list_tail(); + int layer_store_create(const char *id, const struct layer_opts *opts, const struct io_read_wrapper *content, + char **new_id); +-int layer_set_hold_flag(const char *layer_id, bool hold); +-int layer_get_hold_flag(const char *layer_id, bool *hold); ++int layer_inc_hold_refs(const char *layer_id); ++int layer_dec_hold_refs(const char *layer_id); ++int layer_get_hold_refs(const char *layer_id, int *ref_num); + int layer_store_delete(const char *id); + bool layer_store_exists(const char *id); + int layer_store_list(struct layer_list *resp); +diff --git a/src/daemon/modules/image/oci/storage/rootfs_store/rootfs_store.c b/src/daemon/modules/image/oci/storage/rootfs_store/rootfs_store.c +index 22a194c..ed4b45c 100644 +--- a/src/daemon/modules/image/oci/storage/rootfs_store/rootfs_store.c ++++ b/src/daemon/modules/image/oci/storage/rootfs_store/rootfs_store.c +@@ -211,15 +211,15 @@ static int get_containers_from_json() + + ret = util_list_all_subdir(g_rootfs_store->dir, &container_dirs); + if (ret != 0) { +- ERROR("Failed to get container directorys"); ++ ERROR("Failed to get container directories"); + goto out; + } + container_dirs_num = util_array_len((const char **)container_dirs); + + for (i = 0; i < container_dirs_num; i++) { + if (util_reg_match(id_patten, container_dirs[i]) != 0) { +- DEBUG("Container's json is placed inside container's data directory, so skip any other file or directory: %s", +- container_dirs[i]); ++ WARN("Container's json is placed inside container's data directory, so skip any other file or directory: %s", ++ container_dirs[i]); + continue; + } + +@@ -227,14 +227,15 @@ static int get_containers_from_json() + nret = snprintf(container_path, sizeof(container_path), "%s/%s", g_rootfs_store->dir, container_dirs[i]); + if (nret < 0 || (size_t)nret >= sizeof(container_path)) { + ERROR("Failed to get container path"); +- ret = -1; +- goto out; ++ continue; + } + + if (append_container_by_directory(container_path) != 0) { +- ERROR("Found container path but load json failed: %s", container_dirs[i]); +- ret = -1; +- goto out; ++ ERROR("Found container path but load json failed: %s, deleting...", container_path); ++ if (util_recursive_rmdir(container_path, 0) != 0) { ++ ERROR("Failed to delete rootfs directory : %s", container_path); ++ } ++ continue; + } + } + +@@ -367,7 +368,7 @@ static int load_container_to_store_field(cntrootfs_t *cntr) + should_save = true; + } + if (!map_replace(g_rootfs_store->byname, (void *)cntr->srootfs->names[i], (void *)cntr)) { +- ERROR("Failed to insert containes to name index"); ++ ERROR("Failed to insert containers to name index"); + ret = -1; + goto out; + } +@@ -662,7 +663,7 @@ static storage_rootfs *new_storage_rootfs(const char *id, const char *image, cha + c->layer = util_strdup_s(layer); + c->metadata = util_strdup_s(metadata); + +- if (!get_now_time_buffer(timebuffer, sizeof(timebuffer))) { ++ if (!util_get_now_time_buffer(timebuffer, sizeof(timebuffer))) { + ERROR("Failed to get now time string"); + ret = -1; + goto out; +@@ -727,90 +728,6 @@ out: + return ret; + } + +-char *rootfs_store_create(const char *id, const char **names, size_t names_len, const char *image, const char *layer, +- const char *metadata, struct storage_rootfs_options *rootfs_opts) +-{ +- int ret = 0; +- char *dst_id = NULL; +- char **unique_names = NULL; +- size_t unique_names_len = 0; +- cntrootfs_t *cntr = NULL; +- storage_rootfs *c = NULL; +- +- if (g_rootfs_store == NULL) { +- ERROR("Container store is not ready"); +- return NULL; +- } +- +- if (!rootfs_store_lock(EXCLUSIVE)) { +- ERROR("Failed to lock container store, not allowed to create new containers"); +- return NULL; +- } +- +- if (id == NULL) { +- dst_id = generate_random_container_id(); +- } else { +- dst_id = util_strdup_s(id); +- } +- +- if (dst_id == NULL) { +- ERROR("Out of memory or generate random container id failed"); +- ret = -1; +- goto out; +- } +- +- if (map_search(g_rootfs_store->byid, (void *)dst_id) != NULL) { +- ERROR("ID is already in use: %s", dst_id); +- ret = -1; +- goto out; +- } +- +- if (util_string_array_unique(names, names_len, &unique_names, &unique_names_len) != 0) { +- ERROR("Failed to unique names"); +- ret = -1; +- goto out; +- } +- +- c = new_storage_rootfs(dst_id, image, unique_names, unique_names_len, layer, metadata, rootfs_opts); +- if (c == NULL) { +- ERROR("Failed to generate new storage container"); +- ret = -1; +- goto out; +- } +- +- cntr = new_rootfs(c); +- if (cntr == NULL) { +- ERROR("Out of memory"); +- ret = -1; +- goto out; +- } +- c = NULL; +- +- if (rootfs_store_append_container_rootfs(dst_id, layer, (const char **)unique_names, unique_names_len, cntr) != 0) { +- ERROR("Failed to append container to container store"); +- ret = -1; +- goto out; +- } +- +- if (save_rootfs(cntr) != 0) { +- ERROR("Failed to save container"); +- ret = -1; +- goto out; +- } +- +-out: +- if (ret != 0) { +- free(dst_id); +- dst_id = NULL; +- free_storage_rootfs(c); +- c = NULL; +- free_rootfs_t(cntr); +- cntr = NULL; +- } +- rootfs_store_unlock(); +- return dst_id; +-} +- + static cntrootfs_t *get_rootfs_for_store_by_prefix(const char *id) + { + bool ret = true; +@@ -882,39 +799,6 @@ found: + return value; + } + +-char *rootfs_store_lookup(const char *id) +-{ +- char *container_id = NULL; +- cntrootfs_t *cntr = NULL; +- +- if (id == NULL) { +- ERROR("Invalid input parameter, id is NULL"); +- return NULL; +- } +- +- if (g_rootfs_store == NULL) { +- ERROR("Container store is not ready"); +- return NULL; +- } +- +- if (!rootfs_store_lock(SHARED)) { +- ERROR("Failed to lock rootfs store, not allowed to lookup rootfs id assginments"); +- return NULL; +- } +- +- cntr = lookup(id); +- if (cntr == NULL) { +- ERROR("Container not known"); +- return NULL; +- } +- +- container_id = util_strdup_s(cntr->srootfs->id); +- rootfs_ref_dec(cntr); +- rootfs_store_unlock(); +- +- return container_id; +-} +- + static int remove_rootfs_from_memory(const char *id) + { + struct linked_list *item = NULL; +@@ -984,13 +868,13 @@ static int remove_rootfs_dir(const char *id) + return 0; + } + +-int rootfs_store_delete(const char *id) ++static int delete_rootfs_from_store_without_lock(const char *id) + { +- cntrootfs_t *cntr = NULL; + int ret = 0; ++ cntrootfs_t *cntr = NULL; + + if (id == NULL) { +- ERROR("Invalid input parameter, id is NULL"); ++ ERROR("Invalid input parameter: empty id"); + return -1; + } + +@@ -999,16 +883,10 @@ int rootfs_store_delete(const char *id) + return -1; + } + +- if (!rootfs_store_lock(EXCLUSIVE)) { +- ERROR("Failed to lock rootfs store"); +- return -1; +- } +- + cntr = lookup(id); + if (cntr == NULL) { +- WARN("rootfs %s not exists already, return success", id); +- ret = 0; +- goto out; ++ ERROR("Rootfs %s not known", id); ++ return -1; + } + + if (remove_rootfs_from_memory(cntr->srootfs->id) != 0) { +@@ -1025,17 +903,138 @@ int rootfs_store_delete(const char *id) + + out: + rootfs_ref_dec(cntr); +- rootfs_store_unlock(); + return ret; + } + +-static int delete_rootfs_from_store_without_lock(const char *id) ++char *rootfs_store_create(const char *id, const char **names, size_t names_len, const char *image, const char *layer, ++ const char *metadata, struct storage_rootfs_options *rootfs_opts) + { + int ret = 0; ++ char *dst_id = NULL; ++ char **unique_names = NULL; ++ size_t unique_names_len = 0; + cntrootfs_t *cntr = NULL; ++ storage_rootfs *c = NULL; ++ ++ if (g_rootfs_store == NULL) { ++ ERROR("Container store is not ready"); ++ return NULL; ++ } ++ ++ if (!rootfs_store_lock(EXCLUSIVE)) { ++ ERROR("Failed to lock container store, not allowed to create new containers"); ++ return NULL; ++ } + + if (id == NULL) { +- ERROR("Invalid input parameter: empty id"); ++ dst_id = generate_random_container_id(); ++ } else { ++ dst_id = util_strdup_s(id); ++ } ++ ++ if (dst_id == NULL) { ++ ERROR("Out of memory or generate random container id failed"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (map_search(g_rootfs_store->byid, (void *)dst_id) != NULL) { ++ ERROR("ID is already in use: %s", dst_id); ++ ret = -1; ++ goto out; ++ } ++ ++ if (util_string_array_unique(names, names_len, &unique_names, &unique_names_len) != 0) { ++ ERROR("Failed to unique names"); ++ ret = -1; ++ goto out; ++ } ++ ++ c = new_storage_rootfs(dst_id, image, unique_names, unique_names_len, layer, metadata, rootfs_opts); ++ if (c == NULL) { ++ ERROR("Failed to generate new storage container"); ++ ret = -1; ++ goto out; ++ } ++ ++ cntr = new_rootfs(c); ++ if (cntr == NULL) { ++ ERROR("Out of memory"); ++ ret = -1; ++ goto out; ++ } ++ c = NULL; ++ ++ if (rootfs_store_append_container_rootfs(dst_id, layer, (const char **)unique_names, unique_names_len, cntr) != 0) { ++ ERROR("Failed to append container to container store"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (save_rootfs(cntr) != 0) { ++ ERROR("Failed to save container"); ++ if (delete_rootfs_from_store_without_lock(dst_id) != 0) { ++ ERROR("Failed to delete rootfs from store"); ++ } ++ c = NULL; ++ cntr = NULL; ++ ret = -1; ++ goto out; ++ } ++ ++out: ++ if (ret != 0) { ++ free(dst_id); ++ dst_id = NULL; ++ free_storage_rootfs(c); ++ c = NULL; ++ free_rootfs_t(cntr); ++ cntr = NULL; ++ } ++ rootfs_store_unlock(); ++ return dst_id; ++} ++ ++char *rootfs_store_lookup(const char *id) ++{ ++ char *container_id = NULL; ++ cntrootfs_t *cntr = NULL; ++ ++ if (id == NULL) { ++ ERROR("Invalid input parameter, id is NULL"); ++ return NULL; ++ } ++ ++ if (g_rootfs_store == NULL) { ++ ERROR("Container store is not ready"); ++ return NULL; ++ } ++ ++ if (!rootfs_store_lock(SHARED)) { ++ ERROR("Failed to lock rootfs store, not allowed to lookup rootfs id assginments"); ++ return NULL; ++ } ++ ++ cntr = lookup(id); ++ if (cntr == NULL) { ++ ERROR("Container not known"); ++ return NULL; ++ } ++ ++ container_id = util_strdup_s(cntr->srootfs->id); ++ rootfs_ref_dec(cntr); ++ rootfs_store_unlock(); ++ ++ return container_id; ++} ++ ++int rootfs_store_delete(const char *id) ++{ ++ cntrootfs_t *cntr = NULL; ++ int ret = 0; ++ ++ if (id == NULL) { ++ ERROR("Invalid input parameter, id is NULL"); + return -1; + } + +@@ -1044,10 +1043,16 @@ static int delete_rootfs_from_store_without_lock(const char *id) + return -1; + } + ++ if (!rootfs_store_lock(EXCLUSIVE)) { ++ ERROR("Failed to lock rootfs store"); ++ return -1; ++ } ++ + cntr = lookup(id); + if (cntr == NULL) { +- ERROR("Rootfs %s not known", id); +- return -1; ++ WARN("rootfs %s not exists already, return success", id); ++ ret = 0; ++ goto out; + } + + if (remove_rootfs_from_memory(cntr->srootfs->id) != 0) { +@@ -1064,6 +1069,7 @@ static int delete_rootfs_from_store_without_lock(const char *id) + + out: + rootfs_ref_dec(cntr); ++ rootfs_store_unlock(); + return ret; + } + +@@ -1262,40 +1268,6 @@ out: + return dup_rootfs; + } + +-char *rootfs_store_metadata(const char *id) +-{ +- cntrootfs_t *img = NULL; +- char *metadata = NULL; +- +- if (id == NULL) { +- ERROR("Invalid parameter, id is NULL"); +- return NULL; +- } +- +- if (g_rootfs_store == NULL) { +- ERROR("Rootfs store is not ready"); +- return NULL; +- } +- +- if (!rootfs_store_lock(SHARED)) { +- ERROR("Failed to lock rootfs store with shared lock, not allowed to get rootfs metadata assignments"); +- return NULL; +- } +- +- img = lookup(id); +- if (img == NULL) { +- ERROR("Rootfs not known"); +- goto out; +- } +- +- metadata = util_strdup_s(img->srootfs->metadata); +- +-out: +- rootfs_ref_dec(img); +- rootfs_store_unlock(); +- return metadata; +-} +- + int rootfs_store_get_all_rootfs(struct rootfs_list *all_rootfs) + { + int ret = 0; +diff --git a/src/daemon/modules/image/oci/storage/rootfs_store/rootfs_store.h b/src/daemon/modules/image/oci/storage/rootfs_store/rootfs_store.h +index 6cab97a..e13f97b 100644 +--- a/src/daemon/modules/image/oci/storage/rootfs_store/rootfs_store.h ++++ b/src/daemon/modules/image/oci/storage/rootfs_store/rootfs_store.h +@@ -62,9 +62,6 @@ bool rootfs_store_exists(const char *id); + // Retrieve information about a container given an ID or name. + storage_rootfs *rootfs_store_get_rootfs(const char *id); + +-// Reads metadata associated with an item with the specified ID. +-char *rootfs_store_metadata(const char *id); +- + // Return a slice enumerating the known containers. + int rootfs_store_get_all_rootfs(struct rootfs_list *all_rootfs); + +diff --git a/src/daemon/modules/image/oci/storage/storage.c b/src/daemon/modules/image/oci/storage/storage.c +index 8ad96d6..f15531b 100644 +--- a/src/daemon/modules/image/oci/storage/storage.c ++++ b/src/daemon/modules/image/oci/storage/storage.c +@@ -103,15 +103,14 @@ static int fill_read_wrapper(const char *layer_data_path, struct io_read_wrapper + reader_tmp = util_common_calloc_s(sizeof(struct io_read_wrapper)); + if (reader_tmp == NULL) { + ERROR("Memory out"); +- ret = -1; +- goto out; ++ return -1; + } + + fd_ptr = util_common_calloc_s(sizeof(int)); + if (fd_ptr == NULL) { + ERROR("Memory out"); + ret = -1; +- goto out; ++ goto err_out; + } + + *fd_ptr = util_open(layer_data_path, O_RDONLY, 0); +@@ -126,12 +125,13 @@ static int fill_read_wrapper(const char *layer_data_path, struct io_read_wrapper + reader_tmp->close = layer_archive_io_close; + *reader = reader_tmp; + +- goto out; ++ fd_ptr = NULL; ++ reader_tmp = NULL; + + err_out: + free(fd_ptr); + free(reader_tmp); +-out: ++ + return ret; + } + +@@ -182,16 +182,32 @@ out: + return opts; + } + +-int storage_set_hold_flag(const char *layer_id, bool hold) ++int storage_inc_hold_refs(const char *layer_id) + { + int ret = 0; + + if (!storage_lock(&g_storage_rwlock, true)) { +- ERROR("Failed to lock image store when reset hold flag for layer %s", layer_id); ++ ERROR("Failed to lock image store when increase hold refs number for layer %s", layer_id); + return -1; + } + +- ret = layer_set_hold_flag(layer_id, hold); ++ ret = layer_inc_hold_refs(layer_id); ++ ++ storage_unlock(&g_storage_rwlock); ++ ++ return ret; ++} ++ ++int storage_dec_hold_refs(const char *layer_id) ++{ ++ int ret = 0; ++ ++ if (!storage_lock(&g_storage_rwlock, true)) { ++ ERROR("Failed to lock image store when decrease hold refs number for layer %s", layer_id); ++ return -1; ++ } ++ ++ ret = layer_dec_hold_refs(layer_id); + + storage_unlock(&g_storage_rwlock); + +@@ -499,7 +515,7 @@ static int do_delete_related_layers(const char *img_id, const char *img_top_laye + char *layer_id = NULL; + char *last_deleted_layer_id = NULL; + struct layer *layer_info = NULL; +- bool hold = false; ++ int refs_num = 0; + + layer_id = util_strdup_s(img_top_layer_id); + if (layer_id == NULL) { +@@ -509,13 +525,13 @@ static int do_delete_related_layers(const char *img_id, const char *img_top_laye + } + + while (layer_id != NULL) { +- ret = layer_get_hold_flag(layer_id, &hold); ++ ret = layer_get_hold_refs(layer_id, &refs_num); + if (ret != 0) { + break; + } +- // if the layer is hold, it means it's pulling/importing/loading or other layer creating actions, +- // so do not delete it +- if (hold) { ++ // if the layer's hold refs number not 0, it means it's pulling/importing/loading or ++ // other layer creating actions, so do not delete it ++ if (refs_num > 0) { + break; + } + +@@ -1197,8 +1213,8 @@ int storage_rootfs_umount(const char *container_id, bool force) + + rootfs_info = rootfs_store_get_rootfs(container_id); + if (rootfs_info == NULL) { +- ERROR("Failed to get rootfs %s info", container_id); +- ret = -1; ++ ERROR("Failed to get rootfs %s info, skip umount", container_id); ++ ret = 0; + goto out; + } + +@@ -1313,7 +1329,7 @@ static int parse_checked_layer_file(const char *path, map_t *checked_layers) + return (errno == ENOENT ? 0 : -1); + } + +- ret = isula_utils_read_line(fp, parse_checked_layer_cb, (void *)checked_layers); ++ ret = util_proc_file_line_by_line(fp, parse_checked_layer_cb, (void *)checked_layers); + + fclose(fp); + return ret; +@@ -1699,10 +1715,18 @@ out: + int storage_module_init(struct storage_module_init_options *opts) + { + int ret = 0; ++ char *oci_load_work_dir = NULL; ++ ++ oci_load_work_dir = storage_oci_load_work_dir(); ++ if (oci_load_work_dir == NULL) { ++ ERROR("Get oci load work dir failed"); ++ ret = -1; ++ goto out; ++ } + +- ret = util_recursive_rmdir(OCI_LOAD_TMP_WORK_DIR, 0); ++ ret = util_recursive_rmdir(oci_load_work_dir, 0); + if (ret != 0) { +- ERROR("failed to remove dir %s", OCI_LOAD_TMP_WORK_DIR); ++ ERROR("failed to remove dir %s", oci_load_work_dir); + goto out; + } + +@@ -1759,5 +1783,25 @@ int storage_module_init(struct storage_module_init_options *opts) + } + + out: ++ free(oci_load_work_dir); + return ret; + } ++ ++ ++char *storage_oci_load_work_dir() ++{ ++ char *isulad_tmp = NULL; ++ char *oci_load_work_dir = NULL; ++ ++ isulad_tmp = oci_get_isulad_tmpdir(); ++ if (isulad_tmp == NULL) { ++ ERROR("Failed to get isulad tmp dir"); ++ goto out; ++ } ++ ++ oci_load_work_dir = util_path_join(isulad_tmp, "isulad-oci-load"); ++ ++out: ++ free(isulad_tmp); ++ return oci_load_work_dir; ++} +\ No newline at end of file +diff --git a/src/daemon/modules/image/oci/storage/storage.h b/src/daemon/modules/image/oci/storage/storage.h +index 4ba6470..b030a3a 100644 +--- a/src/daemon/modules/image/oci/storage/storage.h ++++ b/src/daemon/modules/image/oci/storage/storage.h +@@ -32,7 +32,6 @@ + extern "C" { + #endif + +-#define OCI_LOAD_TMP_WORK_DIR "/var/tmp/isulad-oci-load" + + struct layer { + char *id; +@@ -151,7 +150,9 @@ char *storage_img_get_image_id(const char *img_name); + /* layer operations */ + int storage_layer_create(const char *layer_id, storage_layer_create_opts_t *opts); + +-int storage_set_hold_flag(const char *layer_id, bool hold); ++int storage_inc_hold_refs(const char *layer_id); ++ ++int storage_dec_hold_refs(const char *layer_id); + + struct layer_list *storage_layers_get_by_compress_digest(const char *digest); + +@@ -178,6 +179,8 @@ int storage_rootfs_umount(const char *container_id, bool force); + + container_inspect_graph_driver *storage_get_metadata_by_container_id(const char *id); + ++char *storage_oci_load_work_dir(); ++ + #ifdef __cplusplus + } + #endif +diff --git a/src/daemon/modules/image/oci/utils_images.c b/src/daemon/modules/image/oci/utils_images.c +index 9204d0d..de0eb32 100644 +--- a/src/daemon/modules/image/oci/utils_images.c ++++ b/src/daemon/modules/image/oci/utils_images.c +@@ -14,6 +14,7 @@ + *******************************************************************************/ + + #define _GNU_SOURCE ++#include "utils_images.h" + #include + #include + #include +@@ -29,7 +30,6 @@ + + #include "isula_libutils/log.h" + #include "utils.h" +-#include "utils_images.h" + #include "sha256.h" + #include "utils_array.h" + #include "utils_base64.h" +@@ -39,6 +39,7 @@ + + // nanos of 2038-01-19T03:14:07, the max valid linux time + #define MAX_NANOS 2147483647000000000 ++#define ISULAD_DEFAULT_TMP_DIR "/var/tmp" + + char *get_last_part(char **parts) + { +@@ -63,7 +64,7 @@ char *oci_get_host(const char *name) + } + + parts = util_string_split(name, '/'); +- if ((parts != NULL && *parts != NULL && !strings_contains_any(*parts, ".:") && strcmp(*parts, "localhost")) || ++ if ((parts != NULL && *parts != NULL && !util_strings_contains_any(*parts, ".:") && strcmp(*parts, "localhost")) || + (strstr(name, "/") == NULL)) { + util_free_array(parts); + return NULL; +@@ -382,8 +383,8 @@ static char *convert_created_by(image_manifest_v1_compatibility *config) + return created_by; + } + +-int add_rootfs_and_history(const layer_blob *layers, size_t layers_len, +- const registry_manifest_schema1 *manifest, docker_image_config_v2 *config) ++int add_rootfs_and_history(const layer_blob *layers, size_t layers_len, const registry_manifest_schema1 *manifest, ++ docker_image_config_v2 *config) + { + int i = 0; + int ret = 0; +@@ -464,26 +465,6 @@ out: + return ret; + } + +-types_timestamp_t created_to_timestamp(char *created) +-{ +- int64_t nanos = 0; +- types_timestamp_t timestamp = { 0 }; +- +- if (to_unix_nanos_from_str(created, &nanos) != 0) { +- ERROR("Failed to get created time from image config"); +- goto out; +- } +- +- timestamp.has_seconds = true; +- timestamp.seconds = nanos / Time_Second; +- timestamp.has_nanos = true; +- timestamp.nanos = nanos % Time_Second; +- +-out: +- +- return timestamp; +-} +- + bool oci_valid_time(char *time) + { + int64_t nanos = 0; +@@ -493,7 +474,7 @@ bool oci_valid_time(char *time) + return false; + } + +- if (to_unix_nanos_from_str(time, &nanos) != 0) { ++ if (util_to_unix_nanos_from_str(time, &nanos) != 0) { + ERROR("Failed to translate created time %s to nanos", time); + return false; + } +@@ -506,3 +487,37 @@ bool oci_valid_time(char *time) + + return true; + } ++ ++ ++char *oci_get_isulad_tmpdir() ++{ ++ char *isula_tmp = NULL; ++ ++ isula_tmp = getenv("ISULAD_TMPDIR"); ++ if (util_valid_str(isula_tmp) && !util_dir_exists(isula_tmp)) { ++ if (util_mkdir_p(isula_tmp, TEMP_DIRECTORY_MODE) != 0) { ++ ERROR("make dir:%s failed", isula_tmp); ++ return NULL; ++ } ++ } ++ ++ return util_valid_str(isula_tmp) ? util_strdup_s(isula_tmp) : util_strdup_s(ISULAD_DEFAULT_TMP_DIR); ++} ++ ++char *get_image_tmp_path() ++{ ++ char *isulad_tmp = NULL; ++ char *isula_image = NULL; ++ ++ isulad_tmp = oci_get_isulad_tmpdir(); ++ if (isulad_tmp == NULL) { ++ ERROR("Failed to get isulad tmp dir"); ++ goto out; ++ } ++ ++ isula_image = util_path_join(isulad_tmp, "isula-image"); ++ ++out: ++ free(isulad_tmp); ++ return isula_image; ++} +diff --git a/src/daemon/modules/image/oci/utils_images.h b/src/daemon/modules/image/oci/utils_images.h +index 9f85d1a..5dedd56 100644 +--- a/src/daemon/modules/image/oci/utils_images.h ++++ b/src/daemon/modules/image/oci/utils_images.h +@@ -39,7 +39,6 @@ extern "C" { + #define REPO_PREFIX_TO_STRIP "library/" + #define MAX_ID_BUF_LEN 256 + +-#define IMAGE_TMP_PATH "/var/tmp/isula-image/" + + char *oci_get_host(const char *name); + char *oci_host_from_mirror(const char *mirror); +@@ -53,12 +52,14 @@ char *oci_calc_diffid(const char *file); + void free_items_not_inherit(docker_image_config_v2 *config); + int add_rootfs_and_history(const layer_blob *layers, size_t layers_len, const registry_manifest_schema1 *manifest, + docker_image_config_v2 *config); +-types_timestamp_t created_to_timestamp(char *created); + bool oci_valid_time(char *time); + ++char *oci_get_isulad_tmpdir(); ++ ++char *get_image_tmp_path(); ++ + #ifdef __cplusplus + } + #endif + + #endif // DAEMON_MODULES_IMAGE_OCI_UTILS_IMAGES_H +- +diff --git a/src/daemon/modules/plugin/plugin.c b/src/daemon/modules/plugin/plugin.c +index bead032..2532656 100644 +--- a/src/daemon/modules/plugin/plugin.c ++++ b/src/daemon/modules/plugin/plugin.c +@@ -185,7 +185,7 @@ static char *get_uniq_enable_plugins(const oci_runtime_spec *oci) + UTIL_FREE_AND_SET_NULL(full); + + for (i = 0; i < util_array_len((const char **)raw); i++) { +- if (strings_in_slice((const char **)arr, util_array_len((const char **)arr), raw[i])) { ++ if (util_strings_in_slice((const char **)arr, util_array_len((const char **)arr), raw[i])) { + continue; + } + if (util_array_append(&arr, raw[i]) != 0) { +@@ -274,7 +274,7 @@ static char **get_enable_plugins(const char *plugins) + arr_len = util_array_len((const char **)arr); + + for (i = 0; i < arr_len; i++) { +- if (strings_in_slice((const char **)dst, dst_len, arr[i])) { ++ if (util_strings_in_slice((const char **)dst, dst_len, arr[i])) { + continue; + } + if (util_array_append(&dst, arr[i]) != 0) { +@@ -691,7 +691,7 @@ static void *plugin_manager_routine(void *arg) + // initilize inotify instance + inotify_fd = inotify_init(); + if (inotify_fd < 0) { +- ERROR("Failed to initalize inotify instance"); ++ ERROR("Failed to initialize inotify instance"); + return NULL; + } + // add plugin_dir to watch +@@ -1129,7 +1129,7 @@ static int pm_init_plugin(const plugin_t *plugin) + } + } + /* +- * add elem to reqs, if no containers availabe add no elem. ++ * add elem to reqs, if no containers available add no elem. + */ + for (i = 0; i < container_num; i++) { + ret = pm_prepare_init_reqs(plugin, &reqs, cnames[i]); +diff --git a/src/daemon/modules/plugin/pspec.c b/src/daemon/modules/plugin/pspec.c +index 1193736..8db6c2d 100644 +--- a/src/daemon/modules/plugin/pspec.c ++++ b/src/daemon/modules/plugin/pspec.c +@@ -12,7 +12,7 @@ + * Create: 2018-12-01 + * Description: provide plugin definition + ******************************************************************************/ +- ++#include "pspec.h" + #include + #include + #include +@@ -22,7 +22,6 @@ + #include "isula_libutils/log.h" + #include "isula_libutils/oci_runtime_spec.h" + #include "isula_libutils/oci_runtime_pspec.h" +-#include "pspec.h" + + /* + * update field in old & clear in new. +diff --git a/src/daemon/modules/runtime/engines/engine.h b/src/daemon/modules/runtime/engines/engine.h +index d9482cf..ced3cf2 100644 +--- a/src/daemon/modules/runtime/engines/engine.h ++++ b/src/daemon/modules/runtime/engines/engine.h +@@ -40,6 +40,8 @@ struct engine_cgroup_resources { + uint64_t memory_swap; + uint64_t memory_reservation; + uint64_t kernel_memory_limit; ++ int64_t cpurt_runtime; ++ int64_t cpurt_period; + }; + + typedef struct _engine_start_request_t { +diff --git a/src/daemon/modules/runtime/engines/lcr/lcr_engine.c b/src/daemon/modules/runtime/engines/lcr/lcr_engine.c +index 83a206a..691bfaa 100644 +--- a/src/daemon/modules/runtime/engines/lcr/lcr_engine.c ++++ b/src/daemon/modules/runtime/engines/lcr/lcr_engine.c +@@ -94,6 +94,8 @@ static bool lcr_update_container(const char *name, const char *lcrpath, const st + lcr_cr.memory_swap = cr->memory_swap; + lcr_cr.memory_reservation = cr->memory_reservation; + lcr_cr.kernel_memory_limit = cr->kernel_memory_limit; ++ lcr_cr.cpurt_period = cr->cpurt_period; ++ lcr_cr.cpurt_runtime = cr->cpurt_runtime; + + return g_lcr_update_op(name, lcrpath, &lcr_cr); + } +diff --git a/src/daemon/modules/runtime/engines/lcr/lcr_rt_ops.c b/src/daemon/modules/runtime/engines/lcr/lcr_rt_ops.c +index 77ca9a1..27c6a63 100644 +--- a/src/daemon/modules/runtime/engines/lcr/lcr_rt_ops.c ++++ b/src/daemon/modules/runtime/engines/lcr/lcr_rt_ops.c +@@ -504,6 +504,9 @@ out: + + static void to_engine_resources(const host_config *hostconfig, struct engine_cgroup_resources *cr) + { ++ uint64_t period = 0; ++ int64_t quota = 0; ++ + if (hostconfig == NULL || cr == NULL) { + return; + } +@@ -518,6 +521,15 @@ static void to_engine_resources(const host_config *hostconfig, struct engine_cgr + cr->memory_swap = (uint64_t)hostconfig->memory_swap; + cr->memory_reservation = (uint64_t)hostconfig->memory_reservation; + cr->kernel_memory_limit = (uint64_t)hostconfig->kernel_memory; ++ cr->cpurt_period = hostconfig->cpu_realtime_period; ++ cr->cpurt_runtime = hostconfig->cpu_realtime_runtime; ++ ++ if (hostconfig->nano_cpus > 0) { ++ period = (uint64_t)(100 * Time_Milli / Time_Micro); ++ quota = hostconfig->nano_cpus * (int64_t)period / 1e9; ++ cr->cpu_period = period; ++ cr->cpu_quota = (uint64_t)quota; ++ } + } + + int rt_lcr_update(const char *id, const char *runtime, const rt_update_params_t *params) +diff --git a/src/daemon/modules/runtime/isula/isula_rt_ops.c b/src/daemon/modules/runtime/isula/isula_rt_ops.c +index d056156..540f1f6 100644 +--- a/src/daemon/modules/runtime/isula/isula_rt_ops.c ++++ b/src/daemon/modules/runtime/isula/isula_rt_ops.c +@@ -15,6 +15,7 @@ + + #define _GNU_SOURCE + ++#include "isula_rt_ops.h" + #include + #include + #include +@@ -33,7 +34,6 @@ + #include + #include + +-#include "isula_rt_ops.h" + #include "isula_libutils/log.h" + #include "runtime_api.h" + #include "constants.h" +@@ -155,7 +155,7 @@ static void get_err_message(char *buf, int buf_size, const char *workdir, const + if (pline == NULL) { + break; + } +- if (strings_contains_word(pline, "error")) { ++ if (util_strings_contains_word(pline, "error")) { + if (lines[0] == NULL) { + lines[0] = pline; + pline = NULL; +@@ -714,7 +714,7 @@ realexec: + goto out; + } + +- status = wait_for_pid_status(pid); ++ status = util_wait_for_pid_status(pid); + if (status < 0) { + ERROR("failed wait shim-parent %d exit %s", pid, strerror(errno)); + ret = -1; +@@ -763,7 +763,7 @@ static int get_container_process_pid(const char *workdir) + file_read_int(fname, &pid); + if (!pid) { + if (shim_alive(workdir)) { +- usleep_nointerupt(100000); ++ util_usleep_nointerupt(100000); + continue; + } + ERROR("failed read pid from dead shim %s", workdir); +@@ -851,8 +851,13 @@ out: + int rt_isula_start(const char *id, const char *runtime, const rt_start_params_t *params, pid_ppid_info_t *pid_info) + { + char workdir[PATH_MAX] = { 0 }; ++ char shim_pid_file_name[PATH_MAX] = { 0 }; + pid_t pid = 0; ++ pid_t shim_pid = -1; + int ret = 0; ++ int splice_ret = 0; ++ proc_t *proc = NULL; ++ proc_t *p_proc = NULL; + + if (id == NULL || runtime == NULL || params == NULL || pid_info == NULL) { + ERROR("nullptr arguments not allowed"); +@@ -863,6 +868,12 @@ int rt_isula_start(const char *id, const char *runtime, const rt_start_params_t + return -1; + } + ++ splice_ret = snprintf(shim_pid_file_name, sizeof(shim_pid_file_name), "%s/shim-pid", workdir); ++ if (splice_ret < 0 || splice_ret >= sizeof(shim_pid_file_name)) { ++ ERROR("%s: wrong shim workdir", id); ++ return -1; ++ } ++ + pid = get_container_process_pid(workdir); + if (pid < 0) { + ret = -1; +@@ -870,12 +881,32 @@ int rt_isula_start(const char *id, const char *runtime, const rt_start_params_t + goto out; + } + +- if (util_read_pid_ppid_info(pid, pid_info) != 0) { ++ file_read_int(shim_pid_file_name, &shim_pid); ++ if (shim_pid < 0) { + ret = -1; +- ERROR("%s: failed read pid info", id); ++ ERROR("%s: failed to read isulad shim pid", id); + goto out; + } + ++ proc = util_get_process_proc_info(pid); ++ if (proc == NULL) { ++ ret = -1; ++ ERROR("%s: failed to read pidinfo", id); ++ goto out; ++ } ++ ++ p_proc = util_get_process_proc_info(shim_pid); ++ if (p_proc == NULL) { ++ ret = -1; ++ ERROR("%s: failed to read isulad shim pidinfo", id); ++ goto out; ++ } ++ ++ pid_info->pid = proc->pid; ++ pid_info->start_time = proc->start_time; ++ pid_info->ppid = shim_pid; ++ pid_info->pstart_time = p_proc->start_time; ++ + if (runtime_call_simple(workdir, runtime, "start", NULL, 0, id) != 0) { + ERROR("call runtime start id failed"); + ret = -1; +@@ -888,6 +919,9 @@ out: + shim_kill_force(workdir); + } + ++ free(proc); ++ free(p_proc); ++ + return ret; + } + +diff --git a/src/daemon/modules/service/service_container.c b/src/daemon/modules/service/service_container.c +index 737cfea..529a68d 100644 +--- a/src/daemon/modules/service/service_container.c ++++ b/src/daemon/modules/service/service_container.c +@@ -58,6 +58,7 @@ + #include "utils_fs.h" + #include "utils_string.h" + #include "utils_verify.h" ++#include "volume_api.h" + + int set_container_to_removal(const container_t *cont) + { +@@ -129,6 +130,8 @@ static int create_mtab_link(const oci_runtime_spec *oci_spec) + ret = -1; + goto out; + } ++ // When dir is symbol link, unlink dir to assure creating dir success following ++ (void)unlink(dir); + + if (!util_dir_exists(dir)) { + ret = util_mkdir_p(dir, ETC_FILE_MODE); +@@ -609,6 +612,49 @@ static int umount_dev_tmpfs_for_system_container(const container_t *cont) + return 0; + } + ++static int valid_mount_point(container_config_v2_common_config_mount_points_element *mp) ++{ ++ struct stat st; ++ // ignore checking nonexist mount point ++ if (mp == NULL || mp->type == NULL || mp->source == NULL) { ++ return 0; ++ } ++ ++ // check volumes only currently ++ if (strcmp(mp->type, "volume") != 0) { ++ return 0; ++ } ++ ++ if (lstat(mp->source, &st) != 0) { ++ ERROR("lstat %s: %s", mp->source, strerror(errno)); ++ isulad_set_error_message("lstat %s: %s", mp->source, strerror(errno)); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int verify_mounts(const container_t *cont) ++{ ++ size_t i = 0; ++ container_config_v2_common_config_mount_points *mount_points = NULL; ++ container_config_v2_common_config_mount_points_element *mp = NULL; ++ ++ if (cont->common_config == NULL || cont->common_config->mount_points == NULL) { ++ return 0; ++ } ++ ++ mount_points = cont->common_config->mount_points; ++ for (i = 0; i < mount_points->len; i++) { ++ mp = mount_points->values[i]; ++ if (valid_mount_point(mp) != 0) { ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ + static int do_start_container(container_t *cont, const char *console_fifos[], bool reset_rm, pid_ppid_info_t *pid_info) + { + int ret = 0; +@@ -690,6 +736,11 @@ static int do_start_container(container_t *cont, const char *console_fifos[], bo + goto close_exit_fd; + } + ++ if (verify_mounts(cont)) { ++ ret = -1; ++ goto close_exit_fd; ++ } ++ + if (renew_oci_config(cont, oci_spec) != 0) { + ret = -1; + goto close_exit_fd; +@@ -943,6 +994,43 @@ out: + return ret; + } + ++int release_volumes(container_config_v2_common_config_mount_points *mount_points, ++ char *id, bool rm_anonymous_volumes) ++{ ++ int ret = 0; ++ size_t i = 0; ++ ++ // no mount point is valid ++ if (mount_points == NULL) { ++ return 0; ++ } ++ ++ for (i = 0; i < mount_points->len; i++) { ++ // only volume have name ++ if (mount_points->values[i]->name == NULL) { ++ continue; ++ } ++ ++ // release reference to this volume ++ if (volume_del_ref(mount_points->values[i]->name, id) != 0) { ++ ERROR("delete reference %s to volume %s failed", id, mount_points->values[i]->name); ++ ret = -1; ++ continue; ++ } ++ ++ // --rm delete anonymous volumes only ++ if (!mount_points->values[i]->named && rm_anonymous_volumes) { ++ ret = volume_remove(mount_points->values[i]->name); ++ if (ret != 0 && ret != VOLUME_ERR_NOT_EXIST) { ++ ERROR("remove anonymous volume %s failed", mount_points->values[i]->name); ++ ret = -1; ++ } ++ } ++ } ++ ++ return ret; ++} ++ + static int do_delete_container(container_t *cont) + { + int ret = 0; +@@ -953,6 +1041,7 @@ static int do_delete_container(container_t *cont) + const char *runtime = NULL; + const char *rootpath = NULL; + container_t *cont_tmp = NULL; ++ bool rm_anonymous_volumes = false; + + container_lock(cont); + +@@ -961,6 +1050,7 @@ static int do_delete_container(container_t *cont) + statepath = cont->state_path; + runtime = cont->runtime; + rootpath = cont->root_path; ++ rm_anonymous_volumes = (cont->hostconfig != NULL) && cont->hostconfig->auto_remove; + + /* check if container was deregistered by previous rm already */ + cont_tmp = containers_store_get(id); +@@ -1010,6 +1100,12 @@ static int do_delete_container(container_t *cont) + goto out; + } + ++ ret = release_volumes(cont->common_config->mount_points, id, rm_anonymous_volumes); ++ if (ret != 0) { ++ ERROR("Failed to release volumes of container %s", name); ++ goto out; ++ } ++ + /* broadcast remove condition */ + container_wait_rm_cond_broadcast(cont); + +@@ -1323,7 +1419,7 @@ void umount_share_shm(container_t *cont) + if (cont->hostconfig->system_container) { + return; + } +- if (cont->hostconfig->ipc_mode == NULL || is_shareable(cont->hostconfig->ipc_mode)) { ++ if (cont->hostconfig->ipc_mode == NULL || namespace_is_shareable(cont->hostconfig->ipc_mode)) { + if (cont->common_config == NULL || cont->common_config->shm_path == NULL) { + return; + } +@@ -1375,7 +1471,7 @@ static int do_append_process_exec_env(const char **default_env, defs_process *sp + } + new_size = (spec->env_len + default_env_len) * sizeof(char *); + old_size = spec->env_len * sizeof(char *); +- ret = mem_realloc((void **)&temp, new_size, spec->env, old_size); ++ ret = util_mem_realloc((void **)&temp, new_size, spec->env, old_size); + if (ret != 0) { + ERROR("Failed to realloc memory for envionment variables"); + ret = -1; +@@ -1577,7 +1673,7 @@ static defs_process *make_exec_process_spec(const container_config *container_sp + } + } + +- ret = dup_array_of_strings((const char **)request->argv, request->argv_len, &(spec->args), &(spec->args_len)); ++ ret = util_dup_array_of_strings((const char **)request->argv, request->argv_len, &(spec->args), &(spec->args_len)); + if (ret != 0) { + ERROR("Failed to dup envs for exec process spec"); + goto err_out; +diff --git a/src/daemon/modules/spec/parse_volume.c b/src/daemon/modules/spec/parse_volume.c +new file mode 100644 +index 0000000..ba5278b +--- /dev/null ++++ b/src/daemon/modules/spec/parse_volume.c +@@ -0,0 +1,413 @@ ++/****************************************************************************** ++ * 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-11-04 ++ * Description: provide parse volume functions ++ ******************************************************************************/ ++#include "parse_volume.h" ++#include ++#include ++#include ++#include ++#include ++ ++#include "isula_libutils/log.h" ++#include "utils.h" ++#include "path.h" ++#include "err_msg.h" ++ ++#define DefaultPropagationMode "rprivate" ++#define DefaultROMode "rw" ++#define DefaultRBind "rbind" ++#define DefaultSelinuxOpt "z" ++ ++static int check_mode(char **valid_modes, size_t valid_modes_len, char *mode) ++{ ++ size_t i = 0; ++ ++ for (i = 0; i < valid_modes_len; i++) { ++ if (strcmp(valid_modes[i], mode) == 0) { ++ return 0; ++ } ++ } ++ ++ return -1; ++} ++ ++static int check_modes(const defs_mount *m, const char *volume_str, char **valid_modes, size_t valid_modes_len) ++{ ++ size_t i = 0; ++ ++ for (i = 0; i < m->options_len; i++) { ++ if (check_mode(valid_modes, valid_modes_len, m->options[i]) != 0) { ++ isulad_set_error_message("Invalid volume specification '%s',Invalid mode %s for type %s", ++ volume_str, m->options[i], m->type); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++static int check_volume_opts(const char *volume_str, const defs_mount *m) ++{ ++ char *valid_bind_modes[] = {"ro", "rw", "z", "Z", "private", "rprivate", "slave", "rslave", "shared", "rshared"}; ++ char *valid_volume_modes[] = {"ro", "rw", "z", "Z", "nocopy"}; ++ int ret = 0; ++ ++ if (strcmp(m->type, "bind") == 0) { ++ ret = check_modes(m, volume_str, valid_bind_modes, sizeof(valid_bind_modes) / sizeof(char*)); ++ } ++ if (strcmp(m->type, "volume") == 0) { ++ ret = check_modes(m, volume_str, valid_volume_modes, sizeof(valid_volume_modes) / sizeof(char*)); ++ } ++ ++ return ret; ++} ++ ++static int check_mount_dst(const defs_mount *m) ++{ ++ if (m->destination == NULL) { ++ ERROR("destination is requested"); ++ isulad_set_error_message("destination is requested"); ++ return -1; ++ } ++ ++ if (m->destination[0] != '/') { ++ ERROR("destination should be absolute path"); ++ isulad_set_error_message("destination should be absolute path"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int check_mount_source(const defs_mount *m) ++{ ++ if (strcmp(m->type, "volume") && ++ (m->source == NULL || m->source[0] != '/')) { ++ ERROR("Invalid source %s, type %s", m->source, m->type); ++ isulad_set_error_message("Invalid source %s, type %s", m->source, m->type); ++ return EINVALIDARGS; ++ } ++ ++ if (m->source != NULL && m->source[0] != '/' && ++ !util_valid_volume_name(m->source)) { ++ ERROR("Invalid volume name %s, only \"%s\" are allowed", m->source, VALID_VOLUME_NAME); ++ isulad_set_error_message("Invalid volume name %s, only \"%s\" are allowed. If you intended to pass " ++ "a host directory, use absolute path.", m->source, VALID_VOLUME_NAME); ++ return EINVALIDARGS; ++ } ++ ++ return 0; ++} ++ ++int append_default_mount_options(defs_mount *m, bool has_ro, bool has_pro, bool has_sel) ++{ ++ int ret = 0; ++ ++ if (m == NULL) { ++ ret = -1; ++ goto out; ++ } ++ ++ if (strcmp(m->type, "bind") == 0) { ++ if (!has_ro) { ++ ret = util_array_append(&m->options, DefaultROMode); ++ if (ret != 0) { ++ ERROR("append default ro mode to array failed"); ++ ret = -1; ++ goto out; ++ } ++ m->options_len++; ++ } ++ ++ if (!has_pro) { ++ ret = util_array_append(&m->options, DefaultPropagationMode); ++ if (ret != 0) { ++ ERROR("append default propagation mode to array failed"); ++ ret = -1; ++ goto out; ++ } ++ m->options_len++; ++ } ++ } ++ ++ if (!has_sel && strcmp(m->type, "volume") == 0) { ++ ret = util_array_append(&m->options, DefaultSelinuxOpt); ++ if (ret != 0) { ++ ERROR("append default rbind to array failed"); ++ ret = -1; ++ goto out; ++ } ++ m->options_len++; ++ } ++ ++ if (strcmp(m->type, "bind") == 0 || strcmp(m->type, "volume") == 0) { ++ ret = util_array_append(&m->options, DefaultRBind); ++ if (ret != 0) { ++ ERROR("append default rbind to array failed"); ++ ret = -1; ++ goto out; ++ } ++ m->options_len++; ++ } ++ ++out: ++ return ret; ++} ++ ++static int check_mount_element(const char *volume_str, const defs_mount *m) ++{ ++ int ret = 0; ++ ++ if (m == NULL) { ++ ret = EINVALIDARGS; ++ goto out; ++ } ++ ++ if (m->type == NULL) { ++ ERROR("type is requested"); ++ ret = EINVALIDARGS; ++ goto out; ++ } ++ ++ if (strcmp(m->type, "bind") && strcmp(m->type, "volume")) { ++ ERROR("invalid type %s, only support bind/volume", m->type); ++ isulad_set_error_message("invalid type %s, only support bind/volume", m->type); ++ ret = EINVALIDARGS; ++ goto out; ++ } ++ ++ if (check_mount_source(m) != 0) { ++ ret = EINVALIDARGS; ++ goto out; ++ } ++ ++ if (check_mount_dst(m) != 0) { ++ ret = EINVALIDARGS; ++ goto out; ++ } ++ ++ if (check_volume_opts(volume_str, m) != 0) { ++ ret = EINVALIDARGS; ++ goto out; ++ } ++ ++out: ++ return ret; ++} ++ ++static int get_src_dst_mode_by_volume(const char *volume, defs_mount *mount_element, char ***modes) ++{ ++ int ret = 0; ++ size_t alen = 0; ++ char **array = NULL; ++ ++ // split volume to src:dest:mode ++ array = util_string_split(volume, ':'); ++ if (array == NULL) { ++ ERROR("Out of memory"); ++ ret = -1; ++ goto free_out; ++ } ++ ++ alen = util_array_len((const char **)array); ++ switch (alen) { ++ case 1: ++ // anonymous volume ++ mount_element->destination = util_strdup_s(array[0]); ++ goto free_out; ++ case 2: ++ if (util_valid_mount_mode(array[1])) { ++ // Destination + Mode is not a valid volume - volumes ++ // cannot include a mode. eg /foo:rw ++ ERROR("Invalid volume specification '%s'", volume); ++ isulad_set_error_message("Invalid volume specification '%s',Invalid mode:%s", volume, array[1]); ++ ret = -1; ++ break; ++ } ++ mount_element->source = util_strdup_s(array[0]); ++ mount_element->destination = util_strdup_s(array[1]); ++ break; ++ case 3: ++ mount_element->source = util_strdup_s(array[0]); ++ mount_element->destination = util_strdup_s(array[1]); ++ if (!util_valid_mount_mode(array[2])) { ++ ERROR("Invalid volume specification '%s'", volume); ++ isulad_set_error_message("Invalid volume specification '%s'.Invalid mode:%s", volume, array[2]); ++ ret = -1; ++ break; ++ } ++ *modes = util_string_split(array[2], ','); ++ if (*modes == NULL) { ++ ERROR("Out of memory"); ++ ret = -1; ++ break; ++ } ++ ++ break; ++ default: ++ ERROR("Invalid volume specification '%s'", volume); ++ isulad_set_error_message("Invalid volume specification '%s'", volume); ++ ret = -1; ++ break; ++ } ++ if (ret != 0) { ++ goto free_out; ++ } ++ ++ if (mount_element->source[0] != '/' && !util_valid_volume_name(mount_element->source)) { ++ ERROR("Invalid volume name %s, only \"%s\" are allowed", mount_element->source, VALID_VOLUME_NAME); ++ isulad_set_error_message("Invalid volume name %s, only \"%s\" are allowed. If you intended to pass " ++ "a host directory, use absolute path.", mount_element->source, VALID_VOLUME_NAME); ++ ret = -1; ++ goto free_out; ++ } ++ ++ if (mount_element->destination[0] != '/' || strcmp(mount_element->destination, "/") == 0) { ++ ERROR("Invalid volume: path must be absolute, and destination can't be '/'"); ++ isulad_set_error_message("Invalid volume: path must be absolute, and destination can't be '/'"); ++ ret = -1; ++ goto free_out; ++ } ++ ++free_out: ++ util_free_array(array); ++ return ret; ++} ++ ++static int check_volume_element(const char *volume) ++{ ++ int ret = 0; ++ ++ if (volume == NULL || !strcmp(volume, "")) { ++ ERROR("Volume can't be empty"); ++ ret = -1; ++ return ret; ++ } ++ ++ if (volume[0] == ':' || volume[strlen(volume) - 1] == ':') { ++ ERROR("Delimiter ':' can't be the first or the last character"); ++ ret = -1; ++ return ret; ++ } ++ ++ return ret; ++} ++ ++defs_mount *parse_volume(const char *volume) ++{ ++ int ret = 0; ++ size_t i = 0, mlen = 0; ++ defs_mount *mount_element = NULL; ++ char **modes = NULL; ++ char path[PATH_MAX] = { 0x00 }; ++ char *rw = NULL; ++ char *pro = NULL; ++ char *label = NULL; ++ size_t max_options_len = 4; ++ char *nocopy = NULL; ++ ++ ret = check_volume_element(volume); ++ if (ret != 0) { ++ goto free_out; ++ } ++ ++ mount_element = util_common_calloc_s(sizeof(defs_mount)); ++ if (mount_element == NULL) { ++ ERROR("Out of memory"); ++ return NULL; ++ } ++ ++ ret = get_src_dst_mode_by_volume(volume, mount_element, &modes); ++ if (ret != 0) { ++ goto free_out; ++ } ++ ++ mlen = util_array_len((const char **)modes); ++ for (i = 0; i < mlen; i++) { ++ if (util_valid_rw_mode(modes[i])) { ++ rw = modes[i]; ++ } else if (util_valid_propagation_mode(modes[i])) { ++ pro = modes[i]; ++ } else if (util_valid_label_mode(modes[i])) { ++ label = modes[i]; ++ } else if (util_valid_copy_mode(modes[i])) { ++ nocopy = modes[i]; ++ } ++ } ++ ++ if (!util_clean_path(mount_element->destination, path, sizeof(path))) { ++ ERROR("Failed to get clean path"); ++ ret = -1; ++ goto free_out; ++ } ++ free(mount_element->destination); ++ mount_element->destination = util_strdup_s(path); ++ ++ if (mount_element->source != NULL && mount_element->source[0] == '/') { ++ if (!util_clean_path(mount_element->source, path, sizeof(path))) { ++ ERROR("Failed to get clean path"); ++ ret = -1; ++ goto free_out; ++ } ++ free(mount_element->source); ++ mount_element->source = util_strdup_s(path); ++ } ++ ++ mount_element->options = util_common_calloc_s(max_options_len * sizeof(char *)); ++ if (mount_element->options == NULL) { ++ ERROR("Out of memory"); ++ mount_element->options_len = 0; ++ ret = -1; ++ goto free_out; ++ } ++ if (rw != NULL) { ++ mount_element->options[mount_element->options_len++] = util_strdup_s(rw); ++ } ++ if (pro != NULL) { ++ mount_element->options[mount_element->options_len++] = util_strdup_s(pro); ++ } ++ if (label != NULL) { ++ mount_element->options[mount_element->options_len++] = util_strdup_s(label); ++ } ++ if (nocopy != NULL) { ++ mount_element->options[mount_element->options_len++] = util_strdup_s(nocopy); ++ } ++ if (mount_element->source != NULL && mount_element->source[0] == '/') { ++ mount_element->type = util_strdup_s("bind"); ++ } else { ++ mount_element->type = util_strdup_s("volume"); ++ if (mount_element->source != NULL) { ++ mount_element->named = true; ++ } ++ } ++ ++ ret = check_mount_element(volume, mount_element); ++ if (ret != 0) { ++ goto free_out; ++ } ++ ++ ret = append_default_mount_options(mount_element, rw != NULL, pro != NULL, label != NULL); ++ if (ret != 0) { ++ goto free_out; ++ } ++ ++free_out: ++ util_free_array(modes); ++ if (ret != 0) { ++ free_defs_mount(mount_element); ++ mount_element = NULL; ++ } ++ return mount_element; ++} ++ +diff --git a/src/daemon/modules/spec/parse_volume.h b/src/daemon/modules/spec/parse_volume.h +new file mode 100644 +index 0000000..dc64390 +--- /dev/null ++++ b/src/daemon/modules/spec/parse_volume.h +@@ -0,0 +1,33 @@ ++/****************************************************************************** ++ * 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-11-04 ++ * Description: provide parse volume definition ++ ******************************************************************************/ ++#ifndef DAEMON_MODULES_SPEC_PARSE_VOLUME_H ++#define DAEMON_MODULES_SPEC_PARSE_VOLUME_H ++ ++#include "isula_libutils/defs.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#define DefaultMountType "volume" ++ ++defs_mount *parse_volume(const char *volume); ++int append_default_mount_options(defs_mount *m, bool has_ro, bool has_pro, bool has_sel); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +diff --git a/src/daemon/modules/spec/specs.c b/src/daemon/modules/spec/specs.c +index 030a1ba..5c52d63 100644 +--- a/src/daemon/modules/spec/specs.c ++++ b/src/daemon/modules/spec/specs.c +@@ -39,7 +39,9 @@ + #include "specs_namespace.h" + #include "path.h" + #include "constants.h" ++#ifdef ENABLE_SELINUX + #include "selinux_label.h" ++#endif + #include "err_msg.h" + #include "utils_array.h" + #include "utils_file.h" +@@ -179,7 +181,7 @@ static int make_annotations_cgroup_dir(const container_config *container_spec, c + if (path == NULL) { + path = "/isulad"; + } +- if (cleanpath(path, cleaned, sizeof(cleaned)) == NULL) { ++ if (util_clean_path(path, cleaned, sizeof(cleaned)) == NULL) { + ERROR("Failed to clean path: %s", path); + ret = -1; + goto out; +@@ -676,7 +678,8 @@ static int merge_hugetlbs(oci_runtime_spec *oci_spec, host_config_hugetlbs_eleme + old_size = oci_spec->linux->resources->hugepage_limits_len * sizeof(defs_resources_hugepage_limits_element *); + new_size = (oci_spec->linux->resources->hugepage_limits_len + hugetlbs_len) * + sizeof(defs_resources_hugepage_limits_element *); +- ret = mem_realloc((void **)&hugepage_limits_temp, new_size, oci_spec->linux->resources->hugepage_limits, old_size); ++ ret = util_mem_realloc((void **)&hugepage_limits_temp, new_size, oci_spec->linux->resources->hugepage_limits, ++ old_size); + if (ret != 0) { + ERROR("Failed to realloc memory for hugepage limits"); + ret = -1; +@@ -901,10 +904,39 @@ static int merge_hostname(oci_runtime_spec *oci_spec, const host_config *host_sp + return 0; + } + ++static int merge_nanocpus(oci_runtime_spec *oci_spec, int64_t nanocpus) ++{ ++ int ret = 0; ++ uint64_t period = 0; ++ int64_t quota = 0; ++ ++ ret = make_sure_oci_spec_linux_resources_cpu(oci_spec); ++ if (ret < 0) { ++ goto out; ++ } ++ ++ period = (uint64_t)(100 * Time_Milli / Time_Micro); ++ quota = nanocpus * (int64_t)period / 1e9; ++ ++ oci_spec->linux->resources->cpu->quota = quota; ++ oci_spec->linux->resources->cpu->period = period; ++ ++out: ++ return ret; ++} ++ + static int merge_conf_cgroup_cpu_int64(oci_runtime_spec *oci_spec, const host_config *host_spec) + { + int ret = 0; + ++ if (host_spec->nano_cpus > 0) { ++ ret = merge_nanocpus(oci_spec, host_spec->nano_cpus); ++ if (ret != 0) { ++ ERROR("Failed to merge cgroup nano cpus"); ++ goto out; ++ } ++ } ++ + /* cpu shares */ + if (host_spec->cpu_shares != 0) { + ret = merge_cpu_shares(oci_spec, host_spec->cpu_shares); +@@ -1291,8 +1323,8 @@ static int replace_entrypoint_cmds_from_spec(const oci_runtime_spec *oci_spec, c + isulad_set_error_message("No command specified"); + return -1; + } +- return dup_array_of_strings((const char **)(oci_spec->process->args), oci_spec->process->args_len, +- &(container_spec->cmd), &(container_spec->cmd_len)); ++ return util_dup_array_of_strings((const char **)(oci_spec->process->args), oci_spec->process->args_len, ++ &(container_spec->cmd), &(container_spec->cmd_len)); + } + + static int merge_conf_args(oci_runtime_spec *oci_spec, container_config *container_spec) +@@ -1381,8 +1413,8 @@ static int merge_share_namespace_helper(const oci_runtime_spec *oci_spec, const + goto out; + } + +- ret = mem_realloc((void **)&work_ns, (len + 1) * sizeof(defs_namespace_reference *), (void *)work_ns, +- len * sizeof(defs_namespace_reference *)); ++ ret = util_mem_realloc((void **)&work_ns, (len + 1) * sizeof(defs_namespace_reference *), (void *)work_ns, ++ len * sizeof(defs_namespace_reference *)); + if (ret != 0) { + ERROR("Out of memory"); + goto out; +@@ -1658,7 +1690,7 @@ static int split_security_opt(const char *security_opt, char ***items, size_t *i + { + int ret = 0; + +- if (strings_contains_any(security_opt, "=")) { ++ if (util_strings_contains_any(security_opt, "=")) { + *items = util_string_split_n(security_opt, '=', 2); + if (*items == NULL) { + ERROR("Out of memory"); +@@ -1666,7 +1698,7 @@ static int split_security_opt(const char *security_opt, char ***items, size_t *i + goto out; + } + *items_size = util_array_len((const char **)*items); +- } else if (strings_contains_any(security_opt, ":")) { ++ } else if (util_strings_contains_any(security_opt, ":")) { + *items = util_string_split_n(security_opt, ':', 2); + if (*items == NULL) { + ERROR("Out of memory"); +@@ -1751,6 +1783,7 @@ out: + return ret; + } + ++#ifdef ENABLE_SELINUX + static int to_host_config_selinux_labels(const char **labels, size_t len, char ***dst, size_t *dst_len) + { + int ret = 0; +@@ -1837,8 +1870,8 @@ static int handle_connected_container_mode(host_config *hc) + char **pid_label = NULL; + size_t pid_label_len = 0; + +- char *ipc_container = connected_container(hc->ipc_mode); +- char *pid_container = connected_container(hc->pid_mode); ++ char *ipc_container = namespace_get_connected_container(hc->ipc_mode); ++ char *pid_container = namespace_get_connected_container(hc->pid_mode); + if (ipc_container != NULL) { + char *ipc_process_label = get_container_process_label(ipc_container); + if (dup_security_opt(ipc_process_label, &ipc_label, &ipc_label_len) != 0) { +@@ -1908,23 +1941,26 @@ static int generate_security_opt(host_config *hc) + util_free_array(items); + } + +- if (is_host(hc->ipc_mode) || is_host(hc->pid_mode) || hc->privileged) { ++ if (namespace_is_host(hc->ipc_mode) || namespace_is_host(hc->pid_mode) || hc->privileged) { + return handle_host_or_privileged_mode(hc); + } + + return handle_connected_container_mode(hc); + } ++#endif + + static int merge_security_conf(oci_runtime_spec *oci_spec, host_config *host_spec, + container_config_v2_common_config *v2_spec) + { + int ret = 0; + ++#ifdef ENABLE_SELINUX + ret = generate_security_opt(host_spec); + if (ret != 0) { + ERROR("Failed to generate security opt"); + goto out; + } ++#endif + + ret = merge_caps(oci_spec, (const char **)host_spec->cap_add, host_spec->cap_add_len, + (const char **)host_spec->cap_drop, host_spec->cap_drop_len); +@@ -1952,13 +1988,53 @@ static int merge_security_conf(oci_runtime_spec *oci_spec, host_config *host_spe + goto out; + } + ++#ifdef ENABLE_SELINUX + ret = merge_selinux(oci_spec, v2_spec); + if (ret != 0) { + ERROR("Failed to merge selinux config"); + goto out; + } ++#endif ++ ++out: ++ return ret; ++} ++ ++int merge_oci_cgroups_path(const char *id, oci_runtime_spec *oci_spec, const host_config *host_spec) ++{ ++ int ret = 0; ++ char *default_cgroup_parent = NULL; ++ char *path = NULL; ++ ++ if (id == NULL || oci_spec == NULL || host_spec == NULL) { ++ ERROR("Invalid arguments"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (make_sure_oci_spec_linux(oci_spec) != 0) { ++ ERROR("Failed to make oci spec linux"); ++ ret = -1; ++ goto out; ++ } ++ ++ default_cgroup_parent = conf_get_isulad_cgroup_parent(); ++ path = default_cgroup_parent; ++ if (host_spec->cgroup_parent != NULL) { ++ path = host_spec->cgroup_parent; ++ } ++ ++ if (path == NULL) { ++ free(oci_spec->linux->cgroups_path); ++ oci_spec->linux->cgroups_path = util_path_join("/isulad", id); ++ return 0; ++ } ++ ++ free(oci_spec->linux->cgroups_path); ++ oci_spec->linux->cgroups_path = util_path_join(path, id); + + out: ++ free(default_cgroup_parent); + return ret; + } + +@@ -2029,45 +2105,13 @@ int merge_all_specs(host_config *host_spec, const char *real_rootfs, container_c + goto out; + } + +-out: +- return ret; +-} +- +-int merge_oci_cgroups_path(const char *id, oci_runtime_spec *oci_spec, const host_config *host_spec) +-{ +- int ret = 0; +- char *default_cgroup_parent = NULL; +- char *path = NULL; +- +- if (id == NULL || oci_spec == NULL || host_spec == NULL) { +- ERROR("Invalid arguments"); +- ret = -1; +- goto out; +- } +- +- if (make_sure_oci_spec_linux(oci_spec) != 0) { +- ERROR("Failed to make oci spec linux"); +- ret = -1; ++ ret = merge_oci_cgroups_path(v2_spec->id, oci_spec, host_spec); ++ if (ret != 0) { ++ ERROR("Failed to make cgroup parent"); + goto out; + } + +- default_cgroup_parent = conf_get_isulad_cgroup_parent(); +- path = default_cgroup_parent; +- if (host_spec->cgroup_parent != NULL) { +- path = host_spec->cgroup_parent; +- } +- +- if (path == NULL) { +- free(oci_spec->linux->cgroups_path); +- oci_spec->linux->cgroups_path = util_path_join("/isulad", id); +- return 0; +- } +- +- free(oci_spec->linux->cgroups_path); +- oci_spec->linux->cgroups_path = util_path_join(path, id); +- + out: +- UTIL_FREE_AND_SET_NULL(default_cgroup_parent); + return ret; + } + +diff --git a/src/daemon/modules/spec/specs_extend.c b/src/daemon/modules/spec/specs_extend.c +index 13b597e..7f43ae5 100644 +--- a/src/daemon/modules/spec/specs_extend.c ++++ b/src/daemon/modules/spec/specs_extend.c +@@ -12,6 +12,7 @@ + * Create: 2017-11-22 + * Description: provide container specs functions + ******************************************************************************/ ++#include "specs_extend.h" + #include + #include + #include +@@ -27,7 +28,6 @@ + #include "utils.h" + #include "path.h" + #include "isulad_config.h" +-#include "specs_extend.h" + #include "daemon_arguments.h" + #include "err_msg.h" + #include "utils_array.h" +@@ -50,7 +50,7 @@ + } \ + old_size = dest->item##_len * sizeof(defs_hook *); \ + new_size = (dest->item##_len + src->item##_len + 1) * sizeof(defs_hook *); \ +- ret = mem_realloc((void **)&(item), new_size, dest->item, old_size); \ ++ ret = util_mem_realloc((void **)&(item), new_size, dest->item, old_size); \ + if (ret != 0) { \ + ERROR("Failed to realloc memory for hooks_" #item " variables"); \ + ret = -1; \ +@@ -360,7 +360,7 @@ static char *get_env_abs_file_path(const oci_runtime_spec *oci_spec, const char + if (oci_spec->root == NULL || oci_spec->root->path == NULL) { + return NULL; + } +- if (realpath_in_scope(oci_spec->root->path, env_target_file, &env_path) < 0) { ++ if (util_realpath_in_scope(oci_spec->root->path, env_target_file, &env_path) < 0) { + ERROR("env target file '%s' real path must be under rootfs '%s'", env_target_file, oci_spec->root->path); + goto out; + } +@@ -437,7 +437,7 @@ int merge_env(oci_runtime_spec *oci_spec, const char **env, size_t env_len) + } + new_size = (oci_spec->process->env_len + env_len) * sizeof(char *); + old_size = oci_spec->process->env_len * sizeof(char *); +- ret = mem_realloc((void **)&temp, new_size, oci_spec->process->env, old_size); ++ ret = util_mem_realloc((void **)&temp, new_size, oci_spec->process->env, old_size); + if (ret != 0) { + ERROR("Failed to realloc memory for envionment variables"); + ret = -1; +@@ -547,7 +547,7 @@ int merge_ulimits_pre(oci_runtime_spec *oci_spec, size_t host_ulimits_len) + } + old_size = oci_spec->process->rlimits_len * sizeof(defs_process_rlimits_element *); + new_size = (oci_spec->process->rlimits_len + host_ulimits_len) * sizeof(defs_process_rlimits_element *); +- ret = mem_realloc((void **)&rlimits_temp, new_size, oci_spec->process->rlimits, old_size); ++ ret = util_mem_realloc((void **)&rlimits_temp, new_size, oci_spec->process->rlimits, old_size); + if (ret != 0) { + ERROR("Failed to realloc memory for rlimits"); + ret = -1; +@@ -603,47 +603,49 @@ out: + return ret; + } + +-static int do_merge_one_ulimit(const oci_runtime_spec *oci_spec, defs_process_rlimits_element *rlimit) ++static bool rlimit_already_exists(const oci_runtime_spec *oci_spec, defs_process_rlimits_element *rlimit) + { + size_t j; + bool exists = false; + + for (j = 0; j < oci_spec->process->rlimits_len; j++) { + if (oci_spec->process->rlimits[j]->type == NULL) { +- ERROR("rlimit type is empty"); +- UTIL_FREE_AND_SET_NULL(rlimit->type); +- free(rlimit); +- return -1; ++ continue; + } + if (strcmp(oci_spec->process->rlimits[j]->type, rlimit->type) == 0) { + exists = true; + break; + } + } +- if (exists) { +- /* ulimit exist, discard default ulimit */ +- UTIL_FREE_AND_SET_NULL(rlimit->type); +- free(rlimit); +- } else { +- oci_spec->process->rlimits[oci_spec->process->rlimits_len] = rlimit; +- oci_spec->process->rlimits_len++; +- } + +- return 0; ++ return exists; + } + +-static int merge_one_ulimit(const oci_runtime_spec *oci_spec, const host_config_ulimits_element *ulimit) ++static int append_one_ulimit(const oci_runtime_spec *oci_spec, const host_config_ulimits_element *ulimit) + { ++ int ret = 0; + defs_process_rlimits_element *rlimit = NULL; + + if (trans_ulimit_to_rlimit(&rlimit, ulimit) != 0) { +- return -1; ++ ret = -1; ++ goto out; ++ } ++ ++ if (rlimit_already_exists(oci_spec, rlimit)) { ++ ret = 0; ++ goto out; + } + +- return do_merge_one_ulimit(oci_spec, rlimit); ++ oci_spec->process->rlimits[oci_spec->process->rlimits_len] = rlimit; ++ oci_spec->process->rlimits_len++; ++ rlimit = NULL; ++ ++out: ++ free_defs_process_rlimits_element(rlimit); ++ return ret; + } + +-static int merge_ulimits(oci_runtime_spec *oci_spec, host_config_ulimits_element **ulimits, size_t ulimits_len) ++static int append_global_ulimits(oci_runtime_spec *oci_spec, host_config_ulimits_element **ulimits, size_t ulimits_len) + { + int ret = 0; + size_t i = 0; +@@ -658,7 +660,7 @@ static int merge_ulimits(oci_runtime_spec *oci_spec, host_config_ulimits_element + } + + for (i = 0; i < ulimits_len; i++) { +- ret = merge_one_ulimit(oci_spec, ulimits[i]); ++ ret = append_one_ulimit(oci_spec, ulimits[i]); + if (ret != 0) { + ret = -1; + goto out; +@@ -682,7 +684,7 @@ int merge_global_ulimit(oci_runtime_spec *oci_spec) + + if (ulimits != NULL) { + ulimits_len = ulimit_array_len(ulimits); +- if (merge_ulimits(oci_spec, ulimits, ulimits_len)) { ++ if (append_global_ulimits(oci_spec, ulimits, ulimits_len)) { + ret = -1; + goto out; + } +diff --git a/src/daemon/modules/spec/specs_mount.c b/src/daemon/modules/spec/specs_mount.c +index 9c4b109..db7e4fd 100644 +--- a/src/daemon/modules/spec/specs_mount.c ++++ b/src/daemon/modules/spec/specs_mount.c +@@ -12,6 +12,7 @@ + * Create: 2017-11-22 + * Description: provide container specs functions + ******************************************************************************/ ++#include "specs_mount.h" + #include + #include + #include +@@ -33,19 +34,30 @@ + #include "isula_libutils/log.h" + #include "isula_libutils/oci_runtime_spec.h" + #include "isula_libutils/host_config.h" ++#include "isula_libutils/container_inspect.h" + #include "utils.h" + #include "path.h" + #include "isulad_config.h" + #include "namespace.h" +-#include "specs_mount.h" + #include "specs_extend.h" + #include "container_api.h" ++#ifdef ENABLE_SELINUX + #include "selinux_label.h" ++#endif + #include "err_msg.h" + #include "utils_array.h" + #include "utils_file.h" + #include "utils_string.h" + #include "utils_verify.h" ++#include "image_api.h" ++#include "volume_api.h" ++#include "parse_volume.h" ++ ++enum update_rw { ++ update_rw_untouch, ++ update_rw_readonly, ++ update_rw_readwrite, ++}; + + static int get_devices(const char *dir, char ***devices, size_t *device_len, int recursive_depth); + +@@ -88,7 +100,7 @@ static int append_additional_mounts(oci_runtime_spec *oci_spec, const char *type + new_size = (oci_spec->mounts_len + files_len) * sizeof(defs_mount *); + old_size = oci_spec->mounts_len * sizeof(defs_mount *); + +- ret = mem_realloc((void **)&spec_mounts, new_size, oci_spec->mounts, old_size); ++ ret = util_mem_realloc((void **)&spec_mounts, new_size, oci_spec->mounts, old_size); + if (ret != 0) { + ERROR("Out of memory"); + ret = -1; +@@ -176,7 +188,7 @@ static bool valid_dirent_info(const char *dir, const struct dirent *info_archivo + return false; + } + +- // do not map device which name containes ":" ++ // do not map device which name contains ":" + pdot = strstr(info_archivo->d_name, ":"); + if (pdot != NULL) { + INFO("Skipping device %s include \":\"", info_archivo->d_name); +@@ -216,7 +228,7 @@ static int pack_devices(const char *fullpath, char ***devices, size_t *device_le + tmp_length += 1; + new_size = sizeof(char *) * tmp_length; + +- ret = mem_realloc((void **)&tmp_device, new_size, *devices, old_size); ++ ret = util_mem_realloc((void **)&tmp_device, new_size, *devices, old_size); + if (ret != 0) { + ERROR("get_devices: Failed to realloc memory"); + ret = -1; +@@ -316,387 +328,340 @@ static int get_devices(const char *dir, char ***devices, size_t *device_len, int + return 0; + } + +-#define DefaultPropagationMode "rprivate" +-#define DefaultROMode "rw" +-#define DefaultRBind "rbind" +- +-static int fill_mounts_readonly_item(const char *value, defs_mount *mount_element) ++int split_volume_from(char *volume_from, char **id, char **mode) + { +- char *romode = DefaultROMode; +- +- if (mount_element == NULL) { +- return 2; +- } ++ char **parts = NULL; ++ size_t size = 0; ++ int ret = 0; + +- if (value != NULL) { +- if (util_valid_value_true(value)) { +- romode = "ro"; +- } else if (util_valid_value_false(value)) { +- /* use default value rw */ +- } else { +- ERROR("invalid value for readonly: %s", value); +- return 2; +- } ++ parts = util_string_split(volume_from, ':'); ++ size = util_array_len((const char **)parts); ++ if (size == 0 || size > 2) { ++ ret = -1; ++ goto out; + } + +- if (util_array_append(&mount_element->options, romode)) { +- ERROR("append ro mode to array failed"); +- return 2; ++ *id = util_strdup_s(parts[0]); ++ if (size == 2) { ++ *mode = util_strdup_s(parts[1]); + } +- mount_element->options_len++; +- +- return 0; +-} +- +-/* +- * 0: success +- * 1: ignore this item, continue +- * 2: failed +- */ +-static int fill_mounts_item(const char *key, const char *value, defs_mount *mount_element, bool *has_ro, bool *has_pro) +-{ +- if (value == NULL && !util_valid_key_ro(key)) { +- ERROR("unsupported item %s", key); +- return 1; +- } +- +- if (util_valid_key_type(key)) { +- free(mount_element->type); +- mount_element->type = util_strdup_s(value); +- } else if (util_valid_key_src(key)) { +- free(mount_element->source); +- mount_element->source = util_strdup_s(value); +- } else if (util_valid_key_dst(key)) { +- free(mount_element->destination); +- mount_element->destination = util_strdup_s(value); +- } else if (util_valid_key_ro(key)) { +- int ret = fill_mounts_readonly_item(value, mount_element); +- if (ret != 0) { +- return ret; +- } +- +- *has_ro = true; +- } else if (util_valid_key_propagation(key)) { +- if (!util_valid_propagation_mode(value)) { +- ERROR("invalid propagation mode %s", value); +- return 2; +- } +- +- if (util_array_append(&mount_element->options, value)) { +- ERROR("append bind propagation to array failed"); +- return 2; +- } +- mount_element->options_len++; +- *has_pro = true; +- } else if (util_valid_key_selinux(key)) { +- if (!util_valid_label_mode(value)) { +- ERROR("invalid bind selinux opts %s", value); +- return 2; +- } + +- /* This option is not supported currently. Hasen does't want to modify +- * code if it's supported in future, so we support it in interface but +- * not implement it currently. +- */ +- WARN("Valid bind selinux opts %s found but not configured for now", value); +- } else { +- ERROR("unsupported item %s", key); +- return 2; +- } ++out: ++ util_free_array(parts); + +- return 0; ++ return ret; + } + +-static int check_mount_element(const defs_mount *mount_element) ++static defs_mount *mount_point_to_defs_mnt(container_config_v2_common_config_mount_points_element *mp, ++ enum update_rw update_rw_mode) + { ++ defs_mount *mnt = NULL; ++ char **parts = NULL; ++ size_t options_len = 0; + int ret = 0; ++ size_t i = 0; ++ bool has_ro = false; ++ bool has_pro = false; ++ bool has_sel = false; + +- if (mount_element == NULL) { +- ret = EINVALIDARGS; ++ parts = util_string_split(mp->relabel, ','); ++ options_len = util_array_len((const char **)parts); ++ ++ mnt = util_common_calloc_s(sizeof(defs_mount)); ++ if (mnt == NULL) { ++ ERROR("Out of memory"); ++ return NULL; ++ } ++ mnt->options = util_common_calloc_s(sizeof(char *) * (options_len + 3)); // +2 for readonly/propagation/selinux_relabel ++ if (mnt->options == NULL) { ++ ERROR("Out of memory"); ++ ret = -1; + goto out; + } + +- if (mount_element->type == NULL) { +- ERROR("type is requested"); +- ret = EINVALIDARGS; +- goto out; ++ mnt->type = util_strdup_s(mp->type); ++ if (strcmp(mnt->type, "volume") == 0) { ++ mnt->source = util_strdup_s(mp->name); ++ mnt->named = mp->named; ++ } else { ++ mnt->source = util_strdup_s(mp->source); ++ } ++ mnt->destination = util_strdup_s(mp->destination); ++ if (update_rw_mode == update_rw_readonly || (update_rw_mode == update_rw_untouch && !mp->rw)) { ++ has_ro = true; ++ } ++ if (mp->propagation != NULL) { ++ mnt->options[mnt->options_len++] = util_strdup_s(mp->propagation); ++ has_pro = true; + } + +- if (strcmp(mount_element->type, "squashfs") && strcmp(mount_element->type, "bind")) { +- ERROR("invalid type %s, only support squashfs and bind", mount_element->type); +- ret = EINVALIDARGS; +- goto out; ++ for (i = 0; i < options_len; i++) { ++ if (strcmp(parts[i], "ro") == 0 || strcmp(parts[i], "rw") == 0) { ++ continue; ++ } ++ mnt->options[mnt->options_len++] = util_strdup_s(parts[i]); ++ if (util_valid_label_mode(parts[i])) { ++ has_sel = true; ++ } + } + +- if (mount_element->source == NULL) { +- ERROR("source is requested"); +- ret = EINVALIDARGS; +- goto out; ++ if (has_ro) { ++ mnt->options[mnt->options_len++] = util_strdup_s("ro"); + } + +- if (mount_element->source[0] != '/') { +- ERROR("source should be absolute path"); +- ret = EINVALIDARGS; ++ ret = append_default_mount_options(mnt, has_ro, has_pro, has_sel); ++ if (ret != 0) { + goto out; + } + +- if (mount_element->destination == NULL) { +- ERROR("destination is requested"); +- ret = EINVALIDARGS; +- goto out; ++out: ++ util_free_array(parts); ++ if (ret != 0) { ++ free_defs_mount(mnt); ++ mnt = NULL; + } + +- if (mount_element->destination[0] != '/') { +- ERROR("destination should be absolute path"); +- ret = EINVALIDARGS; +- goto out; ++ return mnt; ++} ++ ++void free_defs_mounts(defs_mount **mnts, size_t mnts_len) ++{ ++ size_t i = 0; ++ ++ for (i = 0; i < mnts_len; i++) { ++ free_defs_mount(mnts[i]); ++ mnts[i] = NULL; + } +-out: +- return ret; ++ free(mnts); ++ ++ return; + } + +-static int append_default_mount_options(defs_mount *mount_element, bool has_ro, bool has_pro) ++static int mount_points_to_defs_mnts(container_config_v2_common_config_mount_points *mount_points, ++ enum update_rw update_rw_mode, defs_mount ***mnts_out, size_t *mnts_len_out) + { ++ defs_mount **mnts = NULL; ++ size_t mnts_len = 0; + int ret = 0; ++ size_t i = 0; + +- if (mount_element == NULL) { +- ret = -1; +- goto out; ++ mnts = util_common_calloc_s(sizeof(defs_mount *) * mount_points->len); ++ if (mnts == NULL) { ++ ERROR("Out of memory"); ++ return -1; + } + +- if (strcmp(mount_element->type, "bind") == 0) { +- if (!has_ro) { +- ret = util_array_append(&mount_element->options, DefaultROMode); +- if (ret != 0) { +- ERROR("append default ro mode to array failed"); +- ret = -1; +- goto out; +- } +- mount_element->options_len++; +- } +- +- if (!has_pro) { +- ret = util_array_append(&mount_element->options, DefaultPropagationMode); +- if (ret != 0) { +- ERROR("append default propagation mode to array failed"); +- ret = -1; +- goto out; +- } +- mount_element->options_len++; ++ for (i = 0; i < mount_points->len; i++) { ++ if (strcmp(mount_points->values[i]->type, "volume") != 0 && ++ strcmp(mount_points->values[i]->type, "bind") != 0) { ++ continue; + } + +- ret = util_array_append(&mount_element->options, DefaultRBind); +- if (ret != 0) { +- ERROR("append default rbind to array failed"); ++ mnts[mnts_len] = mount_point_to_defs_mnt(mount_points->values[i], update_rw_mode); ++ if (mnts[i] == NULL) { + ret = -1; + goto out; + } +- mount_element->options_len++; ++ mnts_len++; + } + ++ *mnts_out = mnts; ++ *mnts_len_out = mnts_len; + out: ++ if (ret != 0) { ++ free_defs_mounts(mnts, mnts_len); ++ } ++ + return ret; + } + +-defs_mount *parse_mount(const char *mount) ++static int parser_volume_from_mode(char *mode, enum update_rw *rw) + { +- char **items = NULL; +- defs_mount *mount_element = NULL; ++ char **parts = NULL; + int ret = 0; +- size_t items_len = 0; + size_t i = 0; +- char **kv = NULL; +- bool has_ro = false; +- bool has_pro = false; +- char dstpath[PATH_MAX] = { 0 }; ++ *rw = update_rw_untouch; // default to use the same readonly mode + +- if (mount == NULL) { +- ERROR("invalid NULL param"); +- ret = EINVALIDARGS; +- goto out; +- } +- if (!mount[0]) { +- ERROR("mount can't be empty"); +- ret = EINVALIDARGS; +- goto out; ++ if (mode == NULL) { ++ return 0; + } + +- mount_element = util_common_calloc_s(sizeof(defs_mount)); +- if (mount_element == NULL) { +- ERROR("Out of memory"); +- return NULL; ++ if (!util_valid_mount_mode(mode)) { ++ ERROR("invalid mode %s found", mode); ++ return -1; + } + +- items = util_string_split(mount, ','); +- if (items == NULL) { +- ERROR("split mount %s failed", mount); ++ parts = util_string_split(mode, ','); ++ if (parts == NULL) { + ret = -1; + goto out; + } + +- items_len = util_array_len((const char **)items); +- +- for (i = 0; i < items_len; i++) { +- kv = util_string_split(items[i], '='); +- if (kv == NULL) { +- continue; ++ for (i = 0; i < util_array_len((const char **)parts); i++) { ++ if (util_valid_propagation_mode(parts[i]) || util_valid_copy_mode(parts[i])) { ++ ret = -1; ++ goto out; + } + +- ret = fill_mounts_item(kv[0], kv[1], mount_element, &has_ro, &has_pro); +- if (ret == 1) { /* ignore this item */ +- ret = 0; +- util_free_array(kv); +- kv = NULL; +- continue; +- } else if (ret == 2) { /* invalid args */ +- ret = EINVALIDARGS; +- goto out; ++ if (util_valid_rw_mode(parts[i])) { ++ if (strcmp(mode, "rw") == 0) { ++ *rw = update_rw_readwrite; ++ } else if (strcmp(mode, "ro") == 0) { ++ *rw = update_rw_readonly; ++ } + } +- util_free_array(kv); +- kv = NULL; + } + +- ret = check_mount_element(mount_element); ++out: ++ util_free_array(parts); ++ ++ return ret; ++} ++ ++static int parse_volumes_from(char *volume_from, defs_mount ***mnts_out, size_t *mnts_len_out) ++{ ++ char *id = NULL; ++ char *mode = NULL; ++ container_t *cont = NULL; ++ defs_mount **mnts = NULL; ++ size_t mnts_len = 0; ++ int ret = 0; ++ enum update_rw update_rw_mode = update_rw_untouch; ++ ++ ret = split_volume_from(volume_from, &id, &mode); + if (ret != 0) { +- goto out; ++ ERROR("failed to split volume-from: %s", volume_from); ++ isulad_set_error_message("failed to split volume-from: %s", volume_from); ++ return -1; + } + +- if (!cleanpath(mount_element->destination, dstpath, sizeof(dstpath))) { +- ERROR("failed to get clean path"); +- ret = EINVALIDARGS; ++ ret = parser_volume_from_mode(mode, &update_rw_mode); ++ if (ret != 0) { ++ ERROR("failed to parser mode %s, volume-from %s", mode, volume_from); ++ isulad_set_error_message("failed to parser mode %s, volume-from %s", mode, volume_from); + goto out; + } + +- free(mount_element->destination); +- mount_element->destination = util_strdup_s(dstpath); +- if (mount_element->destination == NULL) { +- ERROR("out of memory"); ++ cont = containers_store_get(id); ++ if (cont == NULL) { ++ ERROR("container %s not found when parse volumes-from:%s", id, volume_from); ++ isulad_set_error_message("container %s not found when parse volumes-from:%s", id, volume_from); + ret = -1; + goto out; + } + +- /* append default options if it's bind mount */ +- ret = append_default_mount_options(mount_element, has_ro, has_pro); +- if (ret != 0) { ++ // no mount point ++ if (cont->common_config == NULL || cont->common_config->mount_points == NULL) { + goto out; + } + +-out: ++ ret = mount_points_to_defs_mnts(cont->common_config->mount_points, update_rw_mode, &mnts, &mnts_len); + if (ret != 0) { +- free_defs_mount(mount_element); +- mount_element = NULL; ++ goto out; + } + +- util_free_array(kv); +- util_free_array(items); +- +- return mount_element; +-} +- +-static int check_volume_element(const char *volume) +-{ +- int ret = 0; +- +- if (volume == NULL || !strcmp(volume, "")) { +- ERROR("Volume can't be empty"); +- ret = -1; +- return ret; +- } ++ *mnts_out = mnts; ++ *mnts_len_out = mnts_len; + +- if (volume[0] == ':' || volume[strlen(volume) - 1] == ':') { +- ERROR("Delimiter ':' can't be the first or the last character"); +- ret = -1; +- return ret; ++out: ++ container_unref(cont); ++ free(id); ++ free(mode); ++ if (ret != 0) { ++ free_defs_mounts(mnts, mnts_len); + } + + return ret; + } + +-static int get_src_dst_mode_by_volume(const char *volume, defs_mount *mount_element, char ***modes) ++static defs_mount *parse_mount(mount_spec *spec) + { + int ret = 0; +- size_t alen = 0; +- char **array = NULL; ++ defs_mount *m = NULL; ++ bool has_pro = false; ++ bool has_sel = false; + +- // split volume to src:dest:mode +- array = util_string_split(volume, ':'); +- if (array == NULL) { ++ m = util_common_calloc_s(sizeof(defs_mount)); ++ if (m == NULL) { + ERROR("Out of memory"); +- ret = -1; +- goto free_out; ++ return NULL; + } + +- alen = util_array_len((const char **)array); +- switch (alen) { +- case 1: +- ERROR("Not supported volume format '%s'", volume); ++ m->type = util_strdup_s(spec->type); ++ m->source = util_strdup_s(spec->source); ++ m->destination = util_strdup_s(spec->target); ++ if (strcmp(m->type, "volume") == 0 && m->source != NULL) { ++ m->named = true; ++ } ++ ++ if (spec->readonly) { ++ if (util_array_append(&m->options, "ro")) { ++ ERROR("append ro mode to array failed"); + ret = -1; +- break; +- case 2: +- if (util_valid_mount_mode(array[1])) { +- // Destination + Mode is not a valid volume - volumes +- // cannot include a mode. eg /foo:rw +- ERROR("Invalid volume specification '%s'", volume); +- isulad_set_error_message("Invalid volume specification '%s',Invalid mode:%s", volume, array[1]); +- ret = -1; +- break; +- } +- mount_element->source = util_strdup_s(array[0]); +- mount_element->destination = util_strdup_s(array[1]); +- break; +- case 3: +- mount_element->source = util_strdup_s(array[0]); +- mount_element->destination = util_strdup_s(array[1]); +- if (!util_valid_mount_mode(array[2])) { +- ERROR("Invalid volume specification '%s'", volume); +- isulad_set_error_message("Invalid volume specification '%s'.Invalid mode:%s", volume, array[2]); ++ goto out; ++ } ++ m->options_len++; ++ } ++ ++ if (spec->bind_options != NULL) { ++ if (spec->bind_options->propagation != NULL) { ++ if (util_array_append(&m->options, spec->bind_options->propagation)) { ++ ERROR("append propagation to array failed"); + ret = -1; +- break; ++ goto out; + } +- *modes = util_string_split(array[2], ','); +- if (*modes == NULL) { +- ERROR("Out of memory"); ++ m->options_len++; ++ has_pro = true; ++ } ++ if (spec->bind_options->selinux_opts != NULL) { ++ if (util_array_append(&m->options, spec->bind_options->selinux_opts)) { ++ ERROR("append selinux opts to array failed"); + ret = -1; +- break; ++ goto out; + } ++ m->options_len++; ++ has_sel = true; ++ } ++ } + +- break; +- default: +- ERROR("Invalid volume specification '%s'", volume); ++ if (spec->volume_options != NULL && spec->volume_options->no_copy) { ++ if (util_array_append(&m->options, "nocopy")) { ++ ERROR("append nocopy to array failed"); + ret = -1; +- break; ++ goto out; ++ } ++ m->options_len++; + } ++ ++ ret = append_default_mount_options(m, true, has_pro, has_sel); + if (ret != 0) { +- goto free_out; ++ goto out; + } + +- if (mount_element->source[0] != '/' || mount_element->destination[0] != '/' || +- strcmp(mount_element->destination, "/") == 0) { +- ERROR("Invalid volume: path must be absolute, and destination can't be '/'"); +- ret = -1; +- goto free_out; ++out: ++ if (ret != 0) { ++ free_defs_mount(m); ++ m = NULL; + } + +-free_out: +- util_free_array(array); +- return ret; ++ return m; + } + +-defs_mount *parse_volume(const char *volume) ++static defs_mount * parse_anonymous_volume(char *volume) + { + int ret = 0; +- size_t i = 0, mlen = 0; ++ char path[PATH_MAX] = {0}; + defs_mount *mount_element = NULL; +- char **modes = NULL; +- char dstpath[PATH_MAX] = { 0x00 }; +- char *rw = "rw"; +- char *pro = DefaultPropagationMode; +- char *label = NULL; +- size_t options_len = 3; + +- ret = check_volume_element(volume); +- if (ret != 0) { +- goto free_out; ++ if (!util_clean_path(volume, path, sizeof(path))) { ++ ERROR("Failed to get clean path %s", volume); ++ return NULL; ++ } ++ ++ if (volume == NULL || path[0] != '/' || strcmp(path, "/") == 0) { ++ ERROR("invalid anonymous volume %s", volume); ++ isulad_set_error_message("invalid anonymous volume %s", volume); ++ return NULL; + } + + mount_element = util_common_calloc_s(sizeof(defs_mount)); +@@ -705,52 +670,16 @@ defs_mount *parse_volume(const char *volume) + return NULL; + } + +- ret = get_src_dst_mode_by_volume(volume, mount_element, &modes); ++ mount_element->type = util_strdup_s("volume"); ++ mount_element->source = NULL; ++ mount_element->destination = util_strdup_s(path); ++ mount_element->named = false; ++ ret = append_default_mount_options(mount_element, false, false, false); + if (ret != 0) { +- goto free_out; +- } +- +- mlen = util_array_len((const char **)modes); +- for (i = 0; i < mlen; i++) { +- if (util_valid_rw_mode(modes[i])) { +- rw = modes[i]; +- } else if (util_valid_propagation_mode(modes[i])) { +- pro = modes[i]; +- } else if (util_valid_label_mode(modes[i])) { +- label = modes[i]; +- } else if (util_valid_copy_mode(modes[i])) { +- WARN("Valid mode '%s' found but not configured for now", modes[i]); +- } +- } +- +- if (!cleanpath(mount_element->destination, dstpath, sizeof(dstpath))) { +- ERROR("Failed to get clean path"); +- ret = -1; +- goto free_out; +- } +- free(mount_element->destination); +- mount_element->destination = util_strdup_s(dstpath); +- if (label != NULL) { +- options_len++; +- } +- mount_element->options = util_common_calloc_s(options_len * sizeof(char *)); +- if (mount_element->options == NULL) { +- ERROR("Out of memory"); +- mount_element->options_len = 0; +- ret = -1; +- goto free_out; +- } +- mount_element->options[0] = util_strdup_s(rw); +- mount_element->options[1] = util_strdup_s(pro); +- mount_element->options[2] = util_strdup_s("rbind"); +- if (options_len >= 4) { +- mount_element->options[3] = util_strdup_s(label); ++ goto out; + } +- mount_element->options_len = options_len; +- mount_element->type = util_strdup_s("bind"); + +-free_out: +- util_free_array(modes); ++out: + if (ret != 0) { + free_defs_mount(mount_element); + mount_element = NULL; +@@ -899,7 +828,7 @@ out: + return ret; + } + +-static int get_weight_devices_from_path(const host_config_blkio_weight_device_element *weight_dev, ++static int get_weight_devices_from_path(const defs_blkio_weight_device *weight_dev, + defs_block_io_device_weight *spec_weight_dev) + { + int ret = 0; +@@ -929,7 +858,7 @@ static int get_weight_devices_from_path(const host_config_blkio_weight_device_el + } + + static int merge_host_config_blk_weight_device(defs_block_io_device_weight **out_spec_weight_dev, +- const host_config_blkio_weight_device_element *weight_dev) ++ const defs_blkio_weight_device *weight_dev) + { + int ret = 0; + defs_block_io_device_weight *spec_weight_dev = NULL; +@@ -958,112 +887,56 @@ out: + return ret; + } + +-static int get_read_bps_devices_from_path(const host_config_blkio_device_read_bps_element *read_bps_dev, +- defs_block_io_device_throttle *spec_read_bps_dev) ++static int get_blkio_device_throttle_info(const defs_blkio_device *blkio_dev_info, ++ defs_block_io_device_throttle *blkio_dev_throttle) + { + int ret = 0; + struct stat st; + +- if (read_bps_dev == NULL || spec_read_bps_dev == NULL) { ++ if (blkio_dev_info == NULL || blkio_dev_throttle == NULL) { + return -1; + } + +- ret = stat(read_bps_dev->path, &st); ++ ret = stat(blkio_dev_info->path, &st); + if (ret < 0) { +- ERROR("Failed to get state of device:%s", read_bps_dev->path); +- isulad_set_error_message("no such file or directory: %s", read_bps_dev->path); +- return -1; +- } +- +- /* fill spec throttle read bps dev */ +- spec_read_bps_dev->rate = read_bps_dev->rate; +- spec_read_bps_dev->major = (int64_t)major(st.st_rdev); +- spec_read_bps_dev->minor = (int64_t)minor(st.st_rdev); +- +- return 0; +-} +- +-static int merge_host_config_blk_read_bps_device(defs_block_io_device_throttle **out_spec_read_bps_dev, +- const host_config_blkio_device_read_bps_element *blkio_device_read_bps) +-{ +- int ret = 0; +- defs_block_io_device_throttle *spec_read_bps_dev = NULL; +- +- spec_read_bps_dev = util_common_calloc_s(sizeof(defs_block_io_device_throttle)); +- if (spec_read_bps_dev == NULL) { +- ERROR("Memory out"); +- ret = -1; +- goto erro_out; +- } +- +- ret = get_read_bps_devices_from_path(blkio_device_read_bps, spec_read_bps_dev); +- if (ret != 0) { +- ERROR("Failed to get throttle read bps devices info"); +- ret = -1; +- goto erro_out; +- } +- +- *out_spec_read_bps_dev = spec_read_bps_dev; +- goto out; +- +-erro_out: +- free_defs_block_io_device_throttle(spec_read_bps_dev); +- +-out: +- return ret; +-} +- +-static int get_write_bps_devices_from_path(const host_config_blkio_device_write_bps_element *write_bps_dev, +- defs_block_io_device_throttle *spec_write_bps_dev) +-{ +- int ret = 0; +- struct stat st; +- +- if (write_bps_dev == NULL || spec_write_bps_dev == NULL) { +- return -1; +- } +- +- ret = stat(write_bps_dev->path, &st); +- if (ret < 0) { +- ERROR("no such file or directory :%s", write_bps_dev->path); +- isulad_set_error_message("no such file or directory: %s", write_bps_dev->path); ++ ERROR("no such file or directory :%s", blkio_dev_info->path); ++ isulad_set_error_message("no such file or directory: %s", blkio_dev_info->path); + return -1; + } + + /* fill spec throttle write bps dev */ +- spec_write_bps_dev->rate = write_bps_dev->rate; +- spec_write_bps_dev->major = (int64_t)major(st.st_rdev); +- spec_write_bps_dev->minor = (int64_t)minor(st.st_rdev); ++ blkio_dev_throttle->rate = blkio_dev_info->rate; ++ blkio_dev_throttle->major = (int64_t)major(st.st_rdev); ++ blkio_dev_throttle->minor = (int64_t)minor(st.st_rdev); + + return 0; + } + +-static int +-merge_host_config_blk_write_bps_device(defs_block_io_device_throttle **out_spec_write_bps_dev, +- const host_config_blkio_device_write_bps_element *blkio_device_write_bps) ++static int merge_host_config_blk_device(defs_block_io_device_throttle **blkio_dev_throttle, ++ const defs_blkio_device *blkio_dev) + { + int ret = 0; +- defs_block_io_device_throttle *spec_write_bps_dev = NULL; ++ defs_block_io_device_throttle *tmp_throttle = NULL; + +- spec_write_bps_dev = util_common_calloc_s(sizeof(defs_block_io_device_throttle)); +- if (spec_write_bps_dev == NULL) { ++ tmp_throttle = util_common_calloc_s(sizeof(defs_block_io_device_throttle)); ++ if (tmp_throttle == NULL) { + ERROR("Memory out"); + ret = -1; + goto erro_out; + } + +- ret = get_write_bps_devices_from_path(blkio_device_write_bps, spec_write_bps_dev); ++ ret = get_blkio_device_throttle_info(blkio_dev, tmp_throttle); + if (ret != 0) { +- ERROR("Failed to get throttle write bps devices info"); ++ ERROR("Failed to get throttle read bps devices info"); + ret = -1; + goto erro_out; + } + +- *out_spec_write_bps_dev = spec_write_bps_dev; ++ *blkio_dev_throttle = tmp_throttle; + goto out; + + erro_out: +- free_defs_block_io_device_throttle(spec_write_bps_dev); ++ free_defs_block_io_device_throttle(tmp_throttle); + + out: + return ret; +@@ -1091,7 +964,7 @@ static int merge_all_devices(oci_runtime_spec *oci_spec, host_config_devices_ele + } + new_size = (oci_spec->linux->devices_len + devices_len) * sizeof(defs_device *); + old_size = oci_spec->linux->devices_len * sizeof(defs_device *); +- ret = mem_realloc((void **)&spec_dev, new_size, oci_spec->linux->devices, old_size); ++ ret = util_mem_realloc((void **)&spec_dev, new_size, oci_spec->linux->devices, old_size); + if (ret != 0) { + ERROR("Out of memory"); + ret = -1; +@@ -1108,7 +981,7 @@ static int merge_all_devices(oci_runtime_spec *oci_spec, host_config_devices_ele + } + new_size = (oci_spec->linux->resources->devices_len + devices_len) * sizeof(defs_device_cgroup *); + old_size = oci_spec->linux->resources->devices_len * sizeof(defs_device_cgroup *); +- ret = mem_realloc((void **)&spec_cgroup_dev, new_size, oci_spec->linux->resources->devices, old_size); ++ ret = util_mem_realloc((void **)&spec_cgroup_dev, new_size, oci_spec->linux->resources->devices, old_size); + if (ret != 0) { + ERROR("Out of memory"); + ret = -1; +@@ -1352,6 +1225,7 @@ static container_config_v2_common_config_mount_points_element *defs_mnt_to_mount + ERROR("Out of memory"); + return NULL; + } ++ mp->type = util_strdup_s(mnt->type); + mp->source = util_strdup_s(mnt->source); + mp->destination = util_strdup_s(mnt->destination); + mp->rw = true; +@@ -1362,6 +1236,7 @@ static container_config_v2_common_config_mount_points_element *defs_mnt_to_mount + if (util_valid_propagation_mode(mnt->options[i])) { + free(mp->propagation); + mp->propagation = util_strdup_s(mnt->options[i]); ++ continue; + } + if (strstr(mnt->options[i], "bind") != NULL) { + continue; +@@ -1394,31 +1269,146 @@ cleanup: + return NULL; + } + +-int merge_volumes(oci_runtime_spec *oci_spec, char **volumes, size_t volumes_len, +- container_config_v2_common_config *common_config, parse_mount_cb parse_mount) ++static char *container_path_in_host(char *base_fs, char *container_path) ++{ ++ return util_path_join(base_fs, container_path + 1); // +1 means strip prefix "/" ++} ++ ++static bool have_nocopy(defs_mount *mnt) + { +- int ret = 0; +- size_t new_size = 0, old_size = 0; +- size_t new_mp_key_size, new_mp_val_size, old_mp_key_size, old_mp_val_size; + size_t i = 0; +- char **mp_key = NULL; +- container_config_v2_common_config_mount_points_element **mp_val = NULL; +- defs_mount **mounts_temp = NULL; +- if (oci_spec == NULL) { ++ for (i = 0; i < mnt->options_len; i++) { ++ if (strcmp(mnt->options[i], "nocopy") == 0) { ++ return true; ++ } ++ } ++ return false; ++} ++ ++static int copy_data_to_volume(char *base_fs, defs_mount *mnt) ++{ ++ int ret = 0; ++ char *copy_src = NULL; ++ char *copy_dst = NULL; ++ struct stat st; ++ char **entries = NULL; ++ size_t entry_num = 0; ++ ++ if (base_fs == NULL || mnt == NULL) { ++ ERROR("Invalid NULL param"); ++ return -1; ++ } ++ ++ // copy data from container volume mount point to host volume directory ++ copy_src = container_path_in_host(base_fs, mnt->destination); ++ copy_dst = mnt->source; ++ ++ if (stat(copy_src, &st) != 0) { ++ if (errno == ENOENT) { ++ goto out; ++ } ++ ERROR("stat for copy data to volume failed: %s", strerror(errno)); + ret = -1; + goto out; + } +- if (volumes_len > LIST_SIZE_MAX - oci_spec->mounts_len) { +- ERROR("Too many volumes to merge, the limit is %lld", LIST_SIZE_MAX); +- isulad_set_error_message("Too many volumes to merge, the limit is %d", LIST_SIZE_MAX); ++ if (!S_ISDIR(st.st_mode)) { ++ ERROR("mount point %s in container is not direcotry", mnt->destination); + ret = -1; + goto out; + } +- new_size = (oci_spec->mounts_len + volumes_len) * sizeof(defs_mount *); ++ ++ ret = util_list_all_entries(copy_dst, &entries); ++ if (ret != 0) { ++ ERROR("list entries of %s failed", copy_src); ++ goto out; ++ } ++ entry_num = util_array_len((const char **)entries); ++ if (entry_num != 0) { ++ // ignore copy nonempty directory ++ goto out; ++ } ++ ++ ret = util_copy_dir_recursive(copy_dst, copy_src); ++ ++out: ++ util_free_array(entries); ++ free(copy_src); ++ ++ return ret; ++} ++ ++#ifdef ENABLE_SELINUX ++static int relabel_volume(struct volume *vol, defs_mount *mnt, char *mount_label) ++{ ++ int ret = 0; ++ bool need_relabel = false; ++ bool is_shared = false; ++ size_t i = 0; ++ ++ if (vol == NULL || mnt == NULL) { ++ ERROR("Invalid NULL param"); ++ return -1; ++ } ++ ++ for (i = 0; i < mnt->options_len; i++) { ++ if (strcmp(mnt->options[i], "Z") == 0) { ++ need_relabel = true; ++ is_shared = false; ++ } else if (strcmp(mnt->options[i], "z") == 0) { ++ need_relabel = true; ++ is_shared = true; ++ } ++ } ++ ++ ret = volume_mount(vol->name); ++ if (ret != 0) { ++ goto out; ++ } ++ ++ if (need_relabel && relabel(vol->mount_point, mount_label, is_shared) != 0) { ++ ERROR("Error setting label on mount source '%s'", mnt->source); ++ ret = -1; ++ goto out; ++ } ++ ++out: ++ (void)volume_umount(vol->name); ++ ++ return ret; ++} ++#endif ++ ++static int merge_fs_mounts_to_oci_and_spec(oci_runtime_spec *oci_spec, defs_mount **mounts, size_t mounts_len, ++ container_config_v2_common_config *common_config) ++{ ++ int ret = 0; ++ size_t new_size = 0, old_size = 0; ++ size_t new_mp_key_size, new_mp_val_size, old_mp_key_size, old_mp_val_size; ++ size_t i = 0; ++ char **mp_key = NULL; ++ container_config_v2_common_config_mount_points_element **mp_val = NULL; ++ defs_mount **mounts_temp = NULL; ++ struct volume *vol = NULL; ++ ++ if (mounts_len == 0) { ++ return 0; ++ } ++ ++ if (oci_spec == NULL) { ++ ret = -1; ++ goto out; ++ } ++ if (mounts_len > LIST_SIZE_MAX - oci_spec->mounts_len) { ++ ERROR("Too many mounts to merge, the limit is %lld", LIST_SIZE_MAX); ++ isulad_set_error_message("Too many mounts to merge, the limit is %d", LIST_SIZE_MAX); ++ ret = -1; ++ goto out; ++ } ++ new_size = (oci_spec->mounts_len + mounts_len) * sizeof(defs_mount *); + old_size = oci_spec->mounts_len * sizeof(defs_mount *); +- ret = mem_realloc((void **)&mounts_temp, new_size, oci_spec->mounts, old_size); ++ ret = util_mem_realloc((void **)&mounts_temp, new_size, oci_spec->mounts, old_size); + if (ret != 0) { +- ERROR("Failed to realloc memory volumes"); ++ ERROR("Failed to realloc memory mounts"); + ret = -1; + goto out; + } +@@ -1433,21 +1423,21 @@ int merge_volumes(oci_runtime_spec *oci_spec, char **volumes, size_t volumes_len + goto out; + } + } +- new_mp_key_size = (common_config->mount_points->len + volumes_len) * sizeof(char *); ++ new_mp_key_size = (common_config->mount_points->len + mounts_len) * sizeof(char *); + old_mp_key_size = common_config->mount_points->len * sizeof(char *); +- new_mp_val_size = (common_config->mount_points->len + volumes_len) * ++ new_mp_val_size = (common_config->mount_points->len + mounts_len) * + sizeof(container_config_v2_common_config_mount_points_element *); + old_mp_val_size = + common_config->mount_points->len * sizeof(container_config_v2_common_config_mount_points_element *); + +- ret = mem_realloc((void **)&mp_key, new_mp_key_size, common_config->mount_points->keys, old_mp_key_size); ++ ret = util_mem_realloc((void **)&mp_key, new_mp_key_size, common_config->mount_points->keys, old_mp_key_size); + if (ret != 0) { + ERROR("Failed to realloc memory mount point"); + ret = -1; + goto out; + } + common_config->mount_points->keys = mp_key; +- ret = mem_realloc((void **)&mp_val, new_mp_val_size, common_config->mount_points->values, old_mp_val_size); ++ ret = util_mem_realloc((void **)&mp_val, new_mp_val_size, common_config->mount_points->values, old_mp_val_size); + if (ret != 0) { + ERROR("Failed to realloc memory mount point"); + ret = -1; +@@ -1456,15 +1446,31 @@ int merge_volumes(oci_runtime_spec *oci_spec, char **volumes, size_t volumes_len + common_config->mount_points->values = mp_val; + } + +- for (i = 0; i < volumes_len; i++) { +- defs_mount *mnt = parse_mount(volumes[i]); +- if (mnt == NULL) { +- ERROR("Failed to parse volume: %s", volumes[i]); +- ret = -1; +- goto out; ++ for (i = 0; i < mounts_len; i++) { ++ defs_mount *mnt = mounts[i]; ++ if (strcmp(mnt->type, "volume") == 0) { ++ struct volume_options opts = {.ref = common_config->id}; ++ // support local volume only currently. ++ vol = volume_create(VOLUME_DEFAULT_DRIVER_NAME, mnt->source, &opts); ++ if (vol == NULL) { ++ ERROR("Failed to create volume"); ++ ret = -1; ++ goto out; ++ } ++ free(mnt->source); ++ mnt->source = util_strdup_s(vol->path); ++ ++#ifdef ENABLE_SELINUX ++ if (oci_spec->linux != NULL) { ++ ret = relabel_volume(vol, mnt, oci_spec->linux->mount_label); ++ if (ret != 0) { ++ ERROR("Failed to relabel volume"); ++ ret = -1; ++ goto out; ++ } ++ } ++#endif + } +- oci_spec->mounts[oci_spec->mounts_len] = mnt; +- oci_spec->mounts_len++; + + if (common_config != NULL) { + common_config->mount_points->values[common_config->mount_points->len] = defs_mnt_to_mount_point(mnt); +@@ -1473,12 +1479,41 @@ int merge_volumes(oci_runtime_spec *oci_spec, char **volumes, size_t volumes_len + ret = -1; + goto out; + } ++ if (vol != NULL) { ++ common_config->mount_points->values[common_config->mount_points->len]->name = util_strdup_s(vol->name); ++ common_config->mount_points->values[common_config->mount_points->len]->driver = util_strdup_s(vol->driver); ++ } ++ common_config->mount_points->values[common_config->mount_points->len]->named = mnt->named; + common_config->mount_points->keys[common_config->mount_points->len] = util_strdup_s(mnt->destination); + common_config->mount_points->len++; + } ++ ++ if (vol != NULL && !have_nocopy(mnt)) { ++ /* if mount point have data and it's mounted from volume, ++ * we need to copy data from destination mount point to volume */ ++ ret = copy_data_to_volume(common_config->base_fs, mnt); ++ if (ret != 0) { ++ ERROR("Failed to copy data to volume"); ++ goto out; ++ } ++ } ++ ++ // mount -t have no type volume, use bind in oci spec ++ if (strcmp(mnt->type, "volume") == 0) { ++ free(mnt->type); ++ mnt->type = util_strdup_s("bind"); ++ } ++ oci_spec->mounts[oci_spec->mounts_len] = mnt; ++ oci_spec->mounts_len++; ++ mounts[i] = NULL; ++ ++ free_volume(vol); ++ vol = NULL; + } + + out: ++ free_volume(vol); ++ + return ret; + } + +@@ -1502,7 +1537,7 @@ static int merge_custom_one_device(oci_runtime_spec *oci_spec, const host_config + } + new_size = (oci_spec->linux->devices_len + 1) * sizeof(defs_device *); + old_size = new_size - sizeof(defs_device *); +- ret = mem_realloc((void **)&spec_dev, new_size, oci_spec->linux->devices, old_size); ++ ret = util_mem_realloc((void **)&spec_dev, new_size, oci_spec->linux->devices, old_size); + if (ret != 0) { + ERROR("Failed to realloc memory for devices"); + ret = -1; +@@ -1520,7 +1555,7 @@ static int merge_custom_one_device(oci_runtime_spec *oci_spec, const host_config + } + new_size = (oci_spec->linux->resources->devices_len + 1) * sizeof(defs_device_cgroup *); + old_size = new_size - sizeof(defs_device_cgroup *); +- ret = mem_realloc((void **)&spec_cgroup_dev, new_size, oci_spec->linux->resources->devices, old_size); ++ ret = util_mem_realloc((void **)&spec_cgroup_dev, new_size, oci_spec->linux->resources->devices, old_size); + if (ret != 0) { + ERROR("Failed to realloc memory for cgroup devices"); + ret = -1; +@@ -1583,8 +1618,7 @@ out: + return ret; + } + +-static int merge_blkio_weight_device(oci_runtime_spec *oci_spec, +- host_config_blkio_weight_device_element **blkio_weight_device, ++static int merge_blkio_weight_device(oci_runtime_spec *oci_spec, defs_blkio_weight_device **blkio_weight_device, + size_t blkio_weight_device_len) + { + int ret = 0; +@@ -1608,7 +1642,8 @@ static int merge_blkio_weight_device(oci_runtime_spec *oci_spec, + new_size = (oci_spec->linux->resources->block_io->weight_device_len + blkio_weight_device_len) * + sizeof(defs_block_io_device_weight *); + old_size = oci_spec->linux->resources->block_io->weight_device_len * sizeof(defs_block_io_device_weight *); +- ret = mem_realloc((void **)&weight_device, new_size, oci_spec->linux->resources->block_io->weight_device, old_size); ++ ret = util_mem_realloc((void **)&weight_device, new_size, oci_spec->linux->resources->block_io->weight_device, ++ old_size); + if (ret != 0) { + ERROR("Failed to realloc memory for weight devices"); + ret = -1; +@@ -1633,8 +1668,7 @@ out: + return ret; + } + +-static int merge_blkio_read_bps_device(oci_runtime_spec *oci_spec, +- host_config_blkio_device_read_bps_element **blkio_read_bps_device, ++static int merge_blkio_read_bps_device(oci_runtime_spec *oci_spec, defs_blkio_device **blkio_read_bps_device, + size_t throttle_read_bps_device_len) + { + int ret = 0; +@@ -1661,8 +1695,8 @@ static int merge_blkio_read_bps_device(oci_runtime_spec *oci_spec, + sizeof(defs_block_io_device_throttle *); + old_size = oci_spec->linux->resources->block_io->throttle_read_bps_device_len * + sizeof(defs_block_io_device_throttle *); +- ret = mem_realloc((void **)&throttle_read_bps_device, new_size, +- oci_spec->linux->resources->block_io->throttle_read_bps_device, old_size); ++ ret = util_mem_realloc((void **)&throttle_read_bps_device, new_size, ++ oci_spec->linux->resources->block_io->throttle_read_bps_device, old_size); + if (ret != 0) { + ERROR("Failed to realloc memory for blkio throttle read bps devices"); + ret = -1; +@@ -1671,7 +1705,7 @@ static int merge_blkio_read_bps_device(oci_runtime_spec *oci_spec, + oci_spec->linux->resources->block_io->throttle_read_bps_device = throttle_read_bps_device; + + for (i = 0; i < throttle_read_bps_device_len; i++) { +- ret = merge_host_config_blk_read_bps_device( ++ ret = merge_host_config_blk_device( + &oci_spec->linux->resources->block_io + ->throttle_read_bps_device[oci_spec->linux->resources->block_io->throttle_read_bps_device_len], + blkio_read_bps_device[i]); +@@ -1687,8 +1721,7 @@ out: + return ret; + } + +-static int merge_blkio_write_bps_device(oci_runtime_spec *oci_spec, +- host_config_blkio_device_write_bps_element **blkio_write_bps_device, ++static int merge_blkio_write_bps_device(oci_runtime_spec *oci_spec, defs_blkio_device **blkio_write_bps_device, + size_t throttle_write_bps_device_len) + { + int ret = 0; +@@ -1715,8 +1748,8 @@ static int merge_blkio_write_bps_device(oci_runtime_spec *oci_spec, + sizeof(defs_block_io_device_throttle *); + old_size = oci_spec->linux->resources->block_io->throttle_write_bps_device_len * + sizeof(defs_block_io_device_throttle *); +- ret = mem_realloc((void **)&throttle_write_bps_device, new_size, +- oci_spec->linux->resources->block_io->throttle_write_bps_device, old_size); ++ ret = util_mem_realloc((void **)&throttle_write_bps_device, new_size, ++ oci_spec->linux->resources->block_io->throttle_write_bps_device, old_size); + if (ret != 0) { + ERROR("Failed to realloc memory for throttle write bps devices"); + ret = -1; +@@ -1725,7 +1758,7 @@ static int merge_blkio_write_bps_device(oci_runtime_spec *oci_spec, + oci_spec->linux->resources->block_io->throttle_write_bps_device = throttle_write_bps_device; + + for (i = 0; i < throttle_write_bps_device_len; i++) { +- ret = merge_host_config_blk_write_bps_device( ++ ret = merge_host_config_blk_device( + &oci_spec->linux->resources->block_io + ->throttle_write_bps_device[oci_spec->linux->resources->block_io->throttle_write_bps_device_len], + blkio_write_bps_device[i]); +@@ -1741,6 +1774,300 @@ out: + return ret; + } + ++static int merge_blkio_read_iops_device(oci_runtime_spec *oci_spec, defs_blkio_device **blkio_read_iops_device, ++ size_t throttle_read_iops_device_len) ++{ ++ int ret = 0; ++ size_t new_size = 0; ++ size_t old_size = 0; ++ size_t i = 0; ++ defs_block_io_device_throttle **throttle_read_iops_device = NULL; ++ ++ ret = make_sure_oci_spec_linux_resources_blkio(oci_spec); ++ if (ret < 0) { ++ goto out; ++ } ++ ++ if (oci_spec->linux->resources->block_io->throttle_read_iops_device_len > ++ LIST_DEVICE_SIZE_MAX - throttle_read_iops_device_len) { ++ ERROR("Too many throttle read iops devices to merge, the limit is %lld", LIST_DEVICE_SIZE_MAX); ++ isulad_set_error_message("Too many throttle read iops devices devices to merge, the limit is %d", ++ LIST_DEVICE_SIZE_MAX); ++ ret = -1; ++ goto out; ++ } ++ ++ new_size = (oci_spec->linux->resources->block_io->throttle_read_iops_device_len + throttle_read_iops_device_len) * ++ sizeof(defs_block_io_device_throttle *); ++ old_size = oci_spec->linux->resources->block_io->throttle_read_iops_device_len * ++ sizeof(defs_block_io_device_throttle *); ++ ret = util_mem_realloc((void **)&throttle_read_iops_device, new_size, ++ oci_spec->linux->resources->block_io->throttle_read_iops_device, old_size); ++ if (ret != 0) { ++ ERROR("Failed to realloc memory for blkio throttle read iops devices"); ++ ret = -1; ++ goto out; ++ } ++ oci_spec->linux->resources->block_io->throttle_read_iops_device = throttle_read_iops_device; ++ ++ for (i = 0; i < throttle_read_iops_device_len; i++) { ++ ret = merge_host_config_blk_device( ++ &oci_spec->linux->resources->block_io ++ ->throttle_read_iops_device[oci_spec->linux->resources->block_io->throttle_read_iops_device_len], ++ blkio_read_iops_device[i]); ++ if (ret != 0) { ++ ERROR("Failed to merge blkio throttle read iops device"); ++ ret = -1; ++ goto out; ++ } ++ oci_spec->linux->resources->block_io->throttle_read_iops_device_len++; ++ } ++ ++out: ++ return ret; ++} ++ ++static int merge_blkio_write_iops_device(oci_runtime_spec *oci_spec, defs_blkio_device **blkio_write_iops_device, ++ size_t throttle_write_iops_device_len) ++{ ++ int ret = 0; ++ size_t new_size = 0; ++ size_t old_size = 0; ++ size_t i = 0; ++ defs_block_io_device_throttle **throttle_write_iops_device = NULL; ++ ++ ret = make_sure_oci_spec_linux_resources_blkio(oci_spec); ++ if (ret < 0) { ++ goto out; ++ } ++ ++ if (oci_spec->linux->resources->block_io->throttle_write_iops_device_len > ++ LIST_DEVICE_SIZE_MAX - throttle_write_iops_device_len) { ++ ERROR("Too many throttle write iops devices to merge, the limit is %lld", LIST_DEVICE_SIZE_MAX); ++ isulad_set_error_message("Too many throttle write iops devices devices to merge, the limit is %d", ++ LIST_DEVICE_SIZE_MAX); ++ ret = -1; ++ goto out; ++ } ++ ++ new_size = (oci_spec->linux->resources->block_io->throttle_write_iops_device_len + throttle_write_iops_device_len) * ++ sizeof(defs_block_io_device_throttle *); ++ old_size = oci_spec->linux->resources->block_io->throttle_write_iops_device_len * ++ sizeof(defs_block_io_device_throttle *); ++ ret = util_mem_realloc((void **)&throttle_write_iops_device, new_size, ++ oci_spec->linux->resources->block_io->throttle_write_iops_device, old_size); ++ if (ret != 0) { ++ ERROR("Failed to realloc memory for throttle write iops devices"); ++ ret = -1; ++ goto out; ++ } ++ oci_spec->linux->resources->block_io->throttle_write_iops_device = throttle_write_iops_device; ++ ++ for (i = 0; i < throttle_write_iops_device_len; i++) { ++ ret = merge_host_config_blk_device( ++ &oci_spec->linux->resources->block_io->throttle_write_iops_device ++ [oci_spec->linux->resources->block_io->throttle_write_iops_device_len], ++ blkio_write_iops_device[i]); ++ if (ret != 0) { ++ ERROR("Failed to merge blkio throttle write iops device"); ++ ret = -1; ++ goto out; ++ } ++ oci_spec->linux->resources->block_io->throttle_write_iops_device_len++; ++ } ++ ++out: ++ return ret; ++} ++ ++static int merge_conf_populate_device(oci_runtime_spec *oci_spec, host_config *host_spec) ++{ ++ int ret = 0; ++ ++ if (host_spec->privileged) { ++ INFO("Skipped \"--device\" due to conflict with \"--privileged\""); ++ return 0; ++ } ++ ++ if (host_spec->devices != NULL && host_spec->devices_len != 0) { ++ /* privileged containers will populate all devices in host */ ++ ret = merge_custom_devices(oci_spec, host_spec->devices, host_spec->devices_len); ++ if (ret != 0) { ++ ERROR("Failed to merge custom devices"); ++ goto out; ++ } ++ } ++out: ++ return ret; ++} ++ ++/* format example: b 7:* rmw */ ++static int parse_device_cgroup_rule(defs_device_cgroup *spec_dev_cgroup, const char *rule) ++{ ++ int ret = 0; ++ char **parts = NULL; ++ size_t parts_len = 0; ++ char **file_mode = NULL; ++ size_t file_mode_len = 0; ++ ++ if (rule == NULL || spec_dev_cgroup == NULL) { ++ return -1; ++ } ++ ++ parts = util_string_split(rule, ' '); ++ if (parts == NULL) { ++ ERROR("Failed to split rule %s", rule); ++ ret = -1; ++ goto free_out; ++ } ++ ++ parts_len = util_array_len((const char **)parts); ++ if (parts_len != 3) { ++ ERROR("Invalid rule %s", rule); ++ ret = -1; ++ goto free_out; ++ } ++ ++ /* fill spec cgroup dev */ ++ spec_dev_cgroup->allow = true; ++ spec_dev_cgroup->access = util_strdup_s(parts[2]); ++ spec_dev_cgroup->type = util_strdup_s(parts[0]); ++ ++ file_mode = util_string_split(parts[1], ':'); ++ if (file_mode == NULL) { ++ ERROR("Invalid rule mode %s", parts[1]); ++ ret = -1; ++ goto free_out; ++ } ++ ++ file_mode_len = util_array_len((const char **)file_mode); ++ if (file_mode_len != 2) { ++ ERROR("Invalid rule mode %s", parts[1]); ++ ret = -1; ++ goto free_out; ++ } ++ ++ if (strcmp(file_mode[0], "*") == 0) { ++ spec_dev_cgroup->major = -1; ++ } else { ++ if (util_safe_llong(file_mode[0], (long long *)&spec_dev_cgroup->major) != 0) { ++ ERROR("Invalid rule mode %s", file_mode[0]); ++ ret = -1; ++ goto free_out; ++ } ++ } ++ ++ if (strcmp(file_mode[1], "*") == 0) { ++ spec_dev_cgroup->minor = -1; ++ } else { ++ if (util_safe_llong(file_mode[1], (long long *)&spec_dev_cgroup->minor) != 0) { ++ ERROR("Invalid rule mode %s", file_mode[1]); ++ ret = -1; ++ goto free_out; ++ } ++ } ++ ++free_out: ++ util_free_array(parts); ++ util_free_array(file_mode); ++ ++ return ret; ++} ++ ++static int make_device_cgroup_rule(defs_device_cgroup **out_spec_dev_cgroup, const char *dev_cgroup_rule) ++{ ++ int ret = 0; ++ defs_device_cgroup *spec_dev_cgroup = NULL; ++ ++ spec_dev_cgroup = util_common_calloc_s(sizeof(defs_device_cgroup)); ++ if (spec_dev_cgroup == NULL) { ++ ERROR("Memory out"); ++ ret = -1; ++ goto erro_out; ++ } ++ ++ ret = parse_device_cgroup_rule(spec_dev_cgroup, dev_cgroup_rule); ++ if (ret != 0) { ++ ERROR("Failed to parse device cgroup rule %s", dev_cgroup_rule); ++ ret = -1; ++ goto erro_out; ++ } ++ ++ *out_spec_dev_cgroup = spec_dev_cgroup; ++ goto out; ++ ++erro_out: ++ free_defs_device_cgroup(spec_dev_cgroup); ++out: ++ return ret; ++} ++ ++static int do_merge_device_cgroup_rules(oci_runtime_spec *oci_spec, const char **dev_cgroup_rules, ++ size_t dev_cgroup_rules_len) ++{ ++ int ret = 0; ++ size_t new_size = 0, old_size = 0; ++ size_t i = 0; ++ ++ ret = make_sure_oci_spec_linux_resources(oci_spec); ++ if (ret < 0) { ++ goto out; ++ } ++ ++ /* malloc for cgroup->device */ ++ defs_device_cgroup **spec_cgroup_dev = NULL; ++ if (dev_cgroup_rules_len > SIZE_MAX / sizeof(defs_device_cgroup *) - oci_spec->linux->resources->devices_len) { ++ ERROR("Too many cgroup devices to merge!"); ++ ret = -1; ++ goto out; ++ } ++ new_size = (oci_spec->linux->resources->devices_len + dev_cgroup_rules_len) * sizeof(defs_device_cgroup *); ++ old_size = oci_spec->linux->resources->devices_len * sizeof(defs_device_cgroup *); ++ ret = util_mem_realloc((void **)&spec_cgroup_dev, new_size, oci_spec->linux->resources->devices, old_size); ++ if (ret != 0) { ++ ERROR("Out of memory"); ++ ret = -1; ++ goto out; ++ } ++ oci_spec->linux->resources->devices = spec_cgroup_dev; ++ ++ for (i = 0; i < dev_cgroup_rules_len; i++) { ++ ret = make_device_cgroup_rule(&oci_spec->linux->resources->devices[oci_spec->linux->resources->devices_len], ++ dev_cgroup_rules[i]); ++ if (ret != 0) { ++ ERROR("Failed to merge custom device"); ++ ret = -1; ++ goto out; ++ } ++ oci_spec->linux->resources->devices_len++; ++ } ++out: ++ return ret; ++} ++ ++static int merge_conf_device_cgroup_rule(oci_runtime_spec *oci_spec, host_config *host_spec) ++{ ++ int ret = 0; ++ ++ if (host_spec->privileged) { ++ INFO("Skipped \"--device-cgroup-rule\" due to conflict with \"--privileged\""); ++ return 0; ++ } ++ ++ if (host_spec->device_cgroup_rules == NULL || host_spec->device_cgroup_rules_len == 0) { ++ return 0; ++ } ++ ++ ret = do_merge_device_cgroup_rules(oci_spec, (const char **)host_spec->device_cgroup_rules, ++ host_spec->device_cgroup_rules_len); ++ if (ret != 0) { ++ ERROR("Failed to merge custom devices cgroup rules"); ++ goto out; ++ } ++out: ++ return ret; ++} ++ + int merge_conf_device(oci_runtime_spec *oci_spec, host_config *host_spec) + { + int ret = 0; +@@ -1774,20 +2101,38 @@ int merge_conf_device(oci_runtime_spec *oci_spec, host_config *host_spec) + } + } + +- /* devices which will be populated into container */ +- if (host_spec->devices != NULL && host_spec->devices_len != 0) { +- /* privileged containers will populate all devices in host */ +- if (!host_spec->privileged) { +- ret = merge_custom_devices(oci_spec, host_spec->devices, host_spec->devices_len); +- if (ret != 0) { +- ERROR("Failed to merge custom devices"); +- goto out; +- } +- } else { +- INFO("Skipped \"--device\" due to conflict with \"--privileged\""); ++ /* blkio throttle read iops devices */ ++ if (host_spec->blkio_device_read_iops != NULL && host_spec->blkio_device_read_iops_len != 0) { ++ ret = merge_blkio_read_iops_device(oci_spec, host_spec->blkio_device_read_iops, ++ host_spec->blkio_device_read_iops_len); ++ if (ret != 0) { ++ ERROR("Failed to merge blkio read iops devices"); ++ goto out; ++ } ++ } ++ ++ /* blkio throttle write iops devices */ ++ if (host_spec->blkio_device_write_iops != NULL && host_spec->blkio_device_write_iops_len != 0) { ++ ret = merge_blkio_write_iops_device(oci_spec, host_spec->blkio_device_write_iops, ++ host_spec->blkio_device_write_iops_len); ++ if (ret != 0) { ++ ERROR("Failed to merge blkio write iops devices"); ++ goto out; + } + } + ++ /* devices which will be populated into container */ ++ if (merge_conf_populate_device(oci_spec, host_spec)) { ++ ret = -1; ++ goto out; ++ } ++ ++ /* device cgroup rules which will be added into container */ ++ if (merge_conf_device_cgroup_rule(oci_spec, host_spec)) { ++ ret = -1; ++ goto out; ++ } ++ + out: + return ret; + } +@@ -1801,8 +2146,8 @@ static bool mounts_expand(oci_runtime_spec *container, size_t add_len) + ERROR("Too many mount elements!"); + return false; + } +- ret = mem_realloc((void **)&tmp_mount, (old_len + add_len) * sizeof(defs_mount *), container->mounts, +- old_len * sizeof(defs_mount *)); ++ ret = util_mem_realloc((void **)&tmp_mount, (old_len + add_len) * sizeof(defs_mount *), container->mounts, ++ old_len * sizeof(defs_mount *)); + if (ret < 0) { + ERROR("memory realloc failed for mount array expand"); + return false; +@@ -1920,7 +2265,7 @@ static int change_dev_shm_size(oci_runtime_spec *oci_spec, host_config *host_spe + char size_opt[MOUNT_PROPERTIES_SIZE] = { 0 }; + char *tmp = NULL; + +- if (is_none(host_spec->ipc_mode)) { ++ if (namespace_is_none(host_spec->ipc_mode)) { + return 0; + } + +@@ -1982,7 +2327,9 @@ static int append_network_files_mounts(oci_runtime_spec *oci_spec, host_config * + bool has_hosts_mount = false; + bool has_resolv_mount = false; + bool has_hostname_mount = false; +- bool share = is_container(host_spec->network_mode); ++#ifdef ENABLE_SELINUX ++ bool share = namespace_is_container(host_spec->network_mode); ++#endif + + for (i = 0; i < oci_spec->mounts_len; i++) { + if (is_mount_destination_hosts(oci_spec->mounts[i]->destination)) { +@@ -2007,11 +2354,13 @@ static int append_network_files_mounts(oci_runtime_spec *oci_spec, host_config * + } else { + /* add network config files */ + if (!has_hosts_mount) { ++#ifdef ENABLE_SELINUX + if (relabel(v2_spec->hosts_path, v2_spec->mount_label, share) != 0) { + ERROR("Error to relabel hosts path: %s", v2_spec->hosts_path); + ret = -1; + goto out; + } ++#endif + if (!mount_file(oci_spec, v2_spec->hosts_path, ETC_HOSTS)) { + ERROR("Merge hosts mount failed"); + ret = -1; +@@ -2023,11 +2372,13 @@ static int append_network_files_mounts(oci_runtime_spec *oci_spec, host_config * + WARN("ResolvConfPath set to %s, but can't stat this filename skipping", v2_spec->resolv_conf_path); + } else { + if (!has_resolv_mount) { ++#ifdef ENABLE_SELINUX + if (relabel(v2_spec->resolv_conf_path, v2_spec->mount_label, share) != 0) { + ERROR("Error to relabel resolv.conf path: %s", v2_spec->resolv_conf_path); + ret = -1; + goto out; + } ++#endif + if (!mount_file(oci_spec, v2_spec->resolv_conf_path, RESOLV_CONF_PATH)) { + ERROR("Merge resolv.conf mount failed"); + ret = -1; +@@ -2040,10 +2391,12 @@ static int append_network_files_mounts(oci_runtime_spec *oci_spec, host_config * + WARN("HostnamePath set to %s, but can't stat this filename; skipping", v2_spec->resolv_conf_path); + } else { + if (!has_hostname_mount) { ++#ifdef ENABLE_SELINUX + if (relabel(v2_spec->hostname_path, v2_spec->mount_label, share) != 0) { + ERROR("Error to relabel hostname path: %s", v2_spec->hostname_path); + return -1; + } ++#endif + if (!mount_file(oci_spec, v2_spec->hostname_path, ETC_HOSTNAME)) { + ERROR("Merge hostname mount failed"); + ret = -1; +@@ -2263,12 +2616,12 @@ static int setup_ipc_dirs(oci_runtime_spec *oci_spec, host_config *host_spec, + return 0; + } + // setup shareable dirs +- if (host_spec->ipc_mode == NULL || is_shareable(host_spec->ipc_mode)) { ++ if (host_spec->ipc_mode == NULL || namespace_is_shareable(host_spec->ipc_mode)) { + return prepare_share_shm(oci_spec, host_spec, v2_spec); + } + +- if (is_container(host_spec->ipc_mode)) { +- tmp_cid = connected_container(host_spec->ipc_mode); ++ if (namespace_is_container(host_spec->ipc_mode)) { ++ tmp_cid = namespace_get_connected_container(host_spec->ipc_mode); + cont = containers_store_get(tmp_cid); + if (cont == NULL) { + ERROR("Invalid share path: %s", host_spec->ipc_mode); +@@ -2277,7 +2630,7 @@ static int setup_ipc_dirs(oci_runtime_spec *oci_spec, host_config *host_spec, + } + right_path = util_strdup_s(cont->common_config->shm_path); + container_unref(cont); +- } else if (is_host(host_spec->ipc_mode)) { ++ } else if (namespace_is_host(host_spec->ipc_mode)) { + if (!util_file_exists(SHM_MOUNT_POINT)) { + ERROR("/dev/shm is not mounted, but must be for --ipc=host"); + ret = -1; +@@ -2301,29 +2654,304 @@ int destination_compare(const void *p1, const void *p2) + return strcmp(mount_1->destination, mount_2->destination); + } + +-int merge_conf_mounts(oci_runtime_spec *oci_spec, host_config *host_spec, container_config_v2_common_config *v2_spec) ++static defs_mount * get_conflict_mount_point(defs_mount **mounts, size_t mounts_len, defs_mount *mnt) + { ++ size_t i = 0; ++ ++ for (i = 0; i < mounts_len; i++) { ++ if (mounts[i] == NULL) { ++ continue; ++ } ++ if (strcmp(mounts[i]->destination, mnt->destination) == 0) { ++ return mounts[i]; ++ } ++ } ++ ++ return NULL; ++} ++ ++static int calc_volumes_from_len(host_config *host_spec, size_t *len) ++{ ++ char *id = NULL; ++ char *mode = NULL; ++ container_t *cont = NULL; + int ret = 0; +- container_config *container_spec = v2_spec->config; ++ int i = 0; + +- /* mounts to mount filesystem */ +- if (container_spec->mounts && container_spec->mounts_len) { +- ret = merge_volumes(oci_spec, container_spec->mounts, container_spec->mounts_len, v2_spec, parse_mount); +- if (ret) { +- ERROR("Failed to merge mounts"); ++ *len = 0; ++ for (i = 0; i < host_spec->volumes_from_len; i++) { ++ ret = split_volume_from(host_spec->volumes_from[i], &id, &mode); ++ if (ret != 0) { ++ ERROR("failed to split volume-from: %s", host_spec->volumes_from[i]); + goto out; + } ++ ++ cont = containers_store_get(id); ++ if (cont == NULL) { ++ ERROR("container %s not found when calc volumes from len, volumes-from:%s", id, host_spec->volumes_from[i]); ++ ret = -1; ++ goto out; ++ } ++ ++ if (cont->common_config != NULL && cont->common_config->mount_points != NULL) { ++ *len += cont->common_config->mount_points->len; ++ } + } + +- /* volumes to mount */ +- if (host_spec->binds != NULL && host_spec->binds_len) { +- ret = merge_volumes(oci_spec, host_spec->binds, host_spec->binds_len, v2_spec, parse_volume); +- if (ret) { +- ERROR("Failed to merge volumes"); ++out: ++ free(id); ++ free(mode); ++ container_unref(cont); ++ ++ return ret; ++} ++ ++static int calc_mounts_len(host_config *host_spec, container_config *container_spec, size_t *len) ++{ ++ size_t volumes_from_len = 0; ++ ++ if (calc_volumes_from_len(host_spec, &volumes_from_len) != 0) { ++ return -1; ++ } ++ ++ *len = host_spec->mounts_len + host_spec->binds_len + volumes_from_len; ++ if (container_spec->volumes != NULL && container_spec->volumes->len != 0) { ++ (*len) += container_spec->volumes->len; ++ } ++ ++ return 0; ++} ++ ++static void add_mount(defs_mount **merged_mounts, size_t *merged_mounts_len, defs_mount *mnt) ++{ ++ merged_mounts[*merged_mounts_len] = mnt; ++ *merged_mounts_len += 1; ++} ++ ++static int add_mounts(host_config *host_spec, defs_mount **merged_mounts, size_t *merged_mounts_len) ++{ ++ int ret = 0; ++ size_t i = 0; ++ defs_mount *mnt = NULL; ++ ++ for (i = 0; i < host_spec->mounts_len; i++) { ++ mnt = parse_mount(host_spec->mounts[i]); ++ if (mnt == NULL) { ++ ERROR("parse mount failed"); ++ ret = -1; + goto out; + } ++ ++ add_mount(merged_mounts, merged_mounts_len, mnt); + } + ++out: ++ ++ return ret; ++} ++ ++static int add_volumes(host_config *host_spec, defs_mount **merged_mounts, size_t *merged_mounts_len) ++{ ++ int ret = 0; ++ size_t i = 0; ++ defs_mount *mnt = NULL; ++ defs_mount *conflict = NULL; ++ ++ for (i = 0; i < host_spec->binds_len; i++) { ++ mnt = parse_volume(host_spec->binds[i]); ++ if (mnt == NULL) { ++ ERROR("parse binds %s failed", host_spec->binds[i]); ++ ret = -1; ++ goto out; ++ } ++ ++ conflict = get_conflict_mount_point(merged_mounts, *merged_mounts_len, mnt); ++ if (conflict != NULL) { ++ ERROR("Duplicate mount point: %s", conflict->destination); ++ isulad_set_error_message("Duplicate mount point: %s", conflict->destination); ++ ret = -1; ++ goto out; ++ } ++ ++ add_mount(merged_mounts, merged_mounts_len, mnt); ++ mnt = NULL; ++ } ++ ++out: ++ if (ret != 0) { ++ free_defs_mount(mnt); ++ } ++ ++ return ret; ++} ++ ++static int add_volumes_from(host_config *host_spec, defs_mount **merged_mounts, size_t *merged_mounts_len) ++{ ++ int ret = 0; ++ size_t i = 0; ++ size_t j = 0; ++ defs_mount **mnts = NULL; ++ size_t mnts_len = 0; ++ defs_mount *conflict = NULL; ++ ++ for (i = 0; i < host_spec->volumes_from_len; i++) { ++ ret = parse_volumes_from(host_spec->volumes_from[i], &mnts, &mnts_len); ++ if (ret != 0) { ++ ERROR("parse mount failed"); ++ goto out; ++ } ++ ++ for (j = 0; j < mnts_len; j++) { ++ // use user specified config and drop the mount config from other containers if conflict ++ conflict = get_conflict_mount_point(merged_mounts, *merged_mounts_len, mnts[j]); ++ if (conflict != NULL) { ++ free_defs_mount(mnts[j]); ++ mnts[j] = NULL; ++ continue; ++ } ++ ++ add_mount(merged_mounts, merged_mounts_len, mnts[j]); ++ mnts[j] = NULL; ++ } ++ free_defs_mounts(mnts, mnts_len); ++ mnts = NULL; ++ mnts_len = 0; ++ } ++out: ++ ++ free_defs_mounts(mnts, mnts_len); ++ ++ return ret; ++} ++ ++static int add_image_config_volumes(container_config *container_spec, defs_mount **merged_mounts, ++ size_t *merged_mounts_len) ++{ ++ int ret = 0; ++ size_t i = 0; ++ defs_mount *mnt = NULL; ++ defs_mount *conflict = NULL; ++ ++ for (i = 0; container_spec->volumes != 0 && i < container_spec->volumes->len; i++) { ++ mnt = parse_anonymous_volume(container_spec->volumes->keys[i]); ++ if (mnt == NULL) { ++ ERROR("parse binds %s failed", container_spec->volumes->keys[i]); ++ ret = -1; ++ goto out; ++ } ++ ++ // use user specified config and drop the volume config in image config if conflict ++ conflict = get_conflict_mount_point(merged_mounts, *merged_mounts_len, mnt); ++ if (conflict != NULL) { ++ free_defs_mount(mnt); ++ mnt = NULL; ++ continue; ++ } ++ ++ add_mount(merged_mounts, merged_mounts_len, mnt); ++ mnt = NULL; ++ } ++ ++out: ++ free_defs_mount(mnt); ++ ++ return ret; ++} ++ ++// merge rules: ++// 1. if -v conflict with --mount, fail ++// 2. if --volumes-from conflict with -v/--mount, drop the mount of --volumes-from ++// 3. if anonymous volumes in image config conflict with -v/--mount/--volumes-from, ++// drop the anonymous volumes in image config ++static int merge_all_fs_mounts(host_config *host_spec, container_config *container_spec, ++ defs_mount ***all_mounts, size_t *all_mounts_len) ++{ ++ int ret = 0; ++ defs_mount **merged_mounts = NULL; ++ size_t merged_mounts_len = 0; ++ size_t len = 0; ++ ++ ret = calc_mounts_len(host_spec, container_spec, &len); ++ if (ret != 0) { ++ return -1; ++ } ++ if (len == 0) { ++ return 0; ++ } ++ ++ merged_mounts = util_common_calloc_s(sizeof(defs_mount *) * len); ++ if (merged_mounts == NULL) { ++ ERROR("out of memory"); ++ ret = -1; ++ goto out; ++ } ++ ++ // add --mounts ++ ret = add_mounts(host_spec, merged_mounts, &merged_mounts_len); ++ if (ret != 0) { ++ goto out; ++ } ++ ++ // add --volume ++ ret = add_volumes(host_spec, merged_mounts, &merged_mounts_len); ++ if (ret != 0) { ++ goto out; ++ } ++ ++ // add --volumes-from ++ ret = add_volumes_from(host_spec, merged_mounts, &merged_mounts_len); ++ if (ret != 0) { ++ goto out; ++ } ++ ++ // add anonymous volumes in image config ++ ret = add_image_config_volumes(container_spec, merged_mounts, &merged_mounts_len); ++ if (ret != 0) { ++ goto out; ++ } ++ ++ *all_mounts = merged_mounts; ++ *all_mounts_len = merged_mounts_len; ++ ++out: ++ if (ret != 0) { ++ free_defs_mounts(merged_mounts, merged_mounts_len); ++ } ++ ++ return ret; ++} ++ ++int merge_conf_mounts(oci_runtime_spec *oci_spec, host_config *host_spec, container_config_v2_common_config *v2_spec) ++{ ++ int ret = 0; ++ container_config *container_spec = v2_spec->config; ++ defs_mount **all_fs_mounts = NULL; ++ size_t all_fs_mounts_len = 0; ++ bool mounted = false; ++ ++ ret = im_mount_container_rootfs(v2_spec->image_type, v2_spec->image, v2_spec->id); ++ if (ret != 0) { ++ ERROR("Mount container %s failed when merge mounts", v2_spec->id); ++ goto out; ++ } ++ mounted = true; ++ ++ ret = merge_all_fs_mounts(host_spec, container_spec, &all_fs_mounts, &all_fs_mounts_len); ++ if (ret != 0) { ++ ERROR("Failed to merge all mounts"); ++ goto out; ++ } ++ ++ /* mounts to mount filesystem */ ++ ret = merge_fs_mounts_to_oci_and_spec(oci_spec, all_fs_mounts, all_fs_mounts_len, v2_spec); ++ if (ret) { ++ ERROR("Failed to merge mounts"); ++ goto out; ++ } ++ ++ (void)im_umount_container_rootfs(v2_spec->image_type, v2_spec->image, v2_spec->id); ++ mounted = false; ++ + /* host channel to mount */ + if (host_spec->host_channel != NULL) { + if (!add_host_channel_mount(oci_spec, host_spec->host_channel)) { +@@ -2367,6 +2995,12 @@ int merge_conf_mounts(oci_runtime_spec *oci_spec, host_config *host_spec, contai + qsort(oci_spec->mounts, oci_spec->mounts_len, sizeof(oci_spec->mounts[0]), destination_compare); + + out: ++ if (mounted) { ++ (void)im_umount_container_rootfs(v2_spec->image_type, v2_spec->image, v2_spec->id); ++ } ++ ++ free_defs_mounts(all_fs_mounts, all_fs_mounts_len); ++ + return ret; + } + +diff --git a/src/daemon/modules/spec/specs_mount.h b/src/daemon/modules/spec/specs_mount.h +index 3ab65de..b1e987e 100644 +--- a/src/daemon/modules/spec/specs_mount.h ++++ b/src/daemon/modules/spec/specs_mount.h +@@ -28,15 +28,6 @@ + + int adapt_settings_for_mounts(oci_runtime_spec *oci_spec, container_config *container_spec); + +-typedef defs_mount *(*parse_mount_cb)(const char *mount); +- +-int merge_volumes(oci_runtime_spec *oci_spec, char **volumes, size_t volumes_len, +- container_config_v2_common_config *common_config, parse_mount_cb parse_mount); +- +-defs_mount *parse_mount(const char *mount); +- +-defs_mount *parse_volume(const char *volume); +- + int merge_conf_mounts(oci_runtime_spec *oci_spec, host_config *host_spec, + container_config_v2_common_config *common_config); + +diff --git a/src/daemon/modules/spec/specs_namespace.c b/src/daemon/modules/spec/specs_namespace.c +index 7364617..e291f09 100644 +--- a/src/daemon/modules/spec/specs_namespace.c ++++ b/src/daemon/modules/spec/specs_namespace.c +@@ -37,7 +37,7 @@ static char *parse_share_namespace_with_prefix(const char *type, const char *pat + char ns_path[PATH_MAX] = { 0 }; + char *ns_type = NULL; + +- tmp_cid = connected_container(path); ++ tmp_cid = namespace_get_connected_container(path); + if (tmp_cid == NULL) { + goto out; + } +@@ -96,14 +96,14 @@ int get_share_namespace_path(const char *type, const char *src_path, char **dest + return -1; + } + +- if (is_none(src_path)) { ++ if (namespace_is_none(src_path)) { + *dest_path = NULL; +- } else if (is_host(src_path)) { +- *dest_path = get_host_namespace_path(type); ++ } else if (namespace_is_host(src_path)) { ++ *dest_path = namespace_get_host_namespace_path(type); + if (*dest_path == NULL) { + ret = -1; + } +- } else if (is_container(src_path)) { ++ } else if (namespace_is_container(src_path)) { + *dest_path = parse_share_namespace_with_prefix(type, src_path); + if (*dest_path == NULL) { + ret = -1; +diff --git a/src/daemon/modules/spec/specs_security.c b/src/daemon/modules/spec/specs_security.c +index 3273b31..c90d193 100644 +--- a/src/daemon/modules/spec/specs_security.c ++++ b/src/daemon/modules/spec/specs_security.c +@@ -58,7 +58,8 @@ static int append_capability(char ***dstcaps, size_t *dstcaps_len, const char *c + ret = -1; + goto out; + } +- ret = mem_realloc((void **)&tmp, sizeof(char *) * (*dstcaps_len + 1), *dstcaps, sizeof(char *) * (*dstcaps_len)); ++ ret = util_mem_realloc((void **)&tmp, sizeof(char *) * (*dstcaps_len + 1), *dstcaps, ++ sizeof(char *) * (*dstcaps_len)); + if (ret != 0) { + ERROR("Out of memory"); + ret = -1; +@@ -108,7 +109,7 @@ static int tweak_drops_capabilities(char ***new_caps, size_t *new_caps_len, char + size_t i = 0; + int ret = 0; + +- if (strings_in_slice((const char **)drops, drops_len, "all")) { ++ if (util_strings_in_slice((const char **)drops, drops_len, "all")) { + goto out; + } + +@@ -119,7 +120,7 @@ static int tweak_drops_capabilities(char ***new_caps, size_t *new_caps_len, char + } + + // if we don't drop `all`, add back all the non-dropped caps +- if (!strings_in_slice((const char **)drops, drops_len, basic_caps[i] + strlen("CAP_"))) { ++ if (!util_strings_in_slice((const char **)drops, drops_len, basic_caps[i] + strlen("CAP_"))) { + ret = append_capability(new_caps, new_caps_len, basic_caps[i]); + if (ret != 0) { + ERROR("Failed to append capabilities"); +@@ -155,14 +156,14 @@ static int tweak_adds_capabilities(char ***new_caps, size_t *new_caps_len, const + ret = -1; + goto out; + } +- if (!strings_in_slice(g_all_caps, all_caps_len, tmpcap)) { ++ if (!util_strings_in_slice(g_all_caps, all_caps_len, tmpcap)) { + ERROR("Unknown capability to add: '%s'", tmpcap); + ret = -1; + goto out; + } + + // add cap if not already in the list +- if (!strings_in_slice((const char **)*new_caps, *new_caps_len, tmpcap)) { ++ if (!util_strings_in_slice((const char **)*new_caps, *new_caps_len, tmpcap)) { + ret = append_capability(new_caps, new_caps_len, tmpcap); + if (ret != 0) { + ERROR("Failed to append capabilities"); +@@ -195,7 +196,7 @@ static bool valid_drops_cap(const char **drops, size_t drops_len) + ERROR("Failed to print string"); + return false; + } +- if (!strings_in_slice(g_all_caps, all_caps_len, tmpcap)) { ++ if (!util_strings_in_slice(g_all_caps, all_caps_len, tmpcap)) { + ERROR("Unknown capability to drop: '%s'", drops[i]); + return false; + } +@@ -222,7 +223,7 @@ static int tweak_capabilities(char ***caps, size_t *caps_len, const char **adds, + return -1; + } + +- if (strings_in_slice((const char **)adds, adds_len, "all")) { ++ if (util_strings_in_slice((const char **)adds, adds_len, "all")) { + ret = copy_capabilities(&basic_caps, &basic_caps_len, g_all_caps, all_caps_len); + } else { + ret = copy_capabilities(&basic_caps, &basic_caps_len, (const char **)*caps, *caps_len); +@@ -361,16 +362,16 @@ static bool is_arch_in_seccomp(const docker_seccomp *seccomp, const char *arch) + return false; + } + +-static bool is_cap_in_seccomp(const defs_process_capabilities *capabilites, const char *cap) ++static bool is_cap_in_seccomp(const defs_process_capabilities *capabilities, const char *cap) + { + size_t i = 0; + +- if (capabilites == NULL) { ++ if (capabilities == NULL) { + return false; + } + +- for (i = 0; i < capabilites->bounding_len; i++) { +- if (strcasecmp(capabilites->bounding[i], cap) == 0) { ++ for (i = 0; i < capabilities->bounding_len; i++) { ++ if (strcasecmp(capabilities->bounding[i], cap) == 0) { + return true; + } + } +@@ -378,7 +379,7 @@ static bool is_cap_in_seccomp(const defs_process_capabilities *capabilites, cons + } + + static void meet_include(const docker_seccomp *seccomp, const docker_seccomp_syscalls_element *syscall, +- const defs_process_capabilities *capabilites, bool *meet_include_arch, bool *meet_include_cap) ++ const defs_process_capabilities *capabilities, bool *meet_include_arch, bool *meet_include_cap) + { + size_t i; + +@@ -401,7 +402,7 @@ static void meet_include(const docker_seccomp *seccomp, const docker_seccomp_sys + *meet_include_cap = true; + } else { + for (i = 0; i < syscall->includes->caps_len; i++) { +- if (is_cap_in_seccomp(capabilites, syscall->includes->caps[i])) { ++ if (is_cap_in_seccomp(capabilities, syscall->includes->caps[i])) { + *meet_include_cap = true; + break; + } +@@ -410,7 +411,7 @@ static void meet_include(const docker_seccomp *seccomp, const docker_seccomp_sys + } + + static void meet_exclude(const docker_seccomp *seccomp, const docker_seccomp_syscalls_element *syscall, +- const defs_process_capabilities *capabilites, bool *meet_exclude_arch, bool *meet_exclude_cap) ++ const defs_process_capabilities *capabilities, bool *meet_exclude_arch, bool *meet_exclude_cap) + { + size_t i; + +@@ -434,7 +435,7 @@ static void meet_exclude(const docker_seccomp *seccomp, const docker_seccomp_sys + *meet_exclude_cap = true; + } else { + for (i = 0; i < syscall->excludes->caps_len; i++) { +- if (is_cap_in_seccomp(capabilites, syscall->excludes->caps[i])) { ++ if (is_cap_in_seccomp(capabilities, syscall->excludes->caps[i])) { + *meet_exclude_cap = false; + break; + } +@@ -443,15 +444,15 @@ static void meet_exclude(const docker_seccomp *seccomp, const docker_seccomp_sys + } + + static bool meet_filtering_rules(const docker_seccomp *seccomp, const docker_seccomp_syscalls_element *syscall, +- const defs_process_capabilities *capabilites) ++ const defs_process_capabilities *capabilities) + { + bool meet_include_arch = false; + bool meet_include_cap = false; + bool meet_exclude_arch = true; + bool meet_exclude_cap = true; + +- meet_include(seccomp, syscall, capabilites, &meet_include_arch, &meet_include_cap); +- meet_exclude(seccomp, syscall, capabilites, &meet_exclude_arch, &meet_exclude_cap); ++ meet_include(seccomp, syscall, capabilities, &meet_include_arch, &meet_include_cap); ++ meet_exclude(seccomp, syscall, capabilities, &meet_exclude_arch, &meet_exclude_cap); + + return meet_include_arch && meet_include_cap && meet_exclude_arch && meet_exclude_cap; + } +@@ -530,7 +531,7 @@ static int dup_syscall_args_to_oci_spec(const docker_seccomp_syscalls_element *d + + static int dup_syscall_to_oci_spec(const docker_seccomp *docker_seccomp_spec, + oci_runtime_config_linux_seccomp *oci_seccomp_spec, +- const defs_process_capabilities *capabilites) ++ const defs_process_capabilities *capabilities) + { + int ret = 0; + size_t i, j, k; +@@ -550,7 +551,7 @@ static int dup_syscall_to_oci_spec(const docker_seccomp *docker_seccomp_spec, + return -1; + } + for (i = 0; i < docker_seccomp_spec->syscalls_len; i++) { +- if (!meet_filtering_rules(docker_seccomp_spec, docker_seccomp_spec->syscalls[i], capabilites)) { ++ if (!meet_filtering_rules(docker_seccomp_spec, docker_seccomp_spec->syscalls[i], capabilities)) { + continue; + } + k = oci_seccomp_spec->syscalls_len; +@@ -581,7 +582,7 @@ static int dup_syscall_to_oci_spec(const docker_seccomp *docker_seccomp_spec, + + new_size = sizeof(defs_syscall *) * oci_seccomp_spec->syscalls_len; + old_size = sizeof(defs_syscall *) * docker_seccomp_spec->syscalls_len; +- ret = mem_realloc((void **)&tmp_syscalls, new_size, oci_seccomp_spec->syscalls, old_size); ++ ret = util_mem_realloc((void **)&tmp_syscalls, new_size, oci_seccomp_spec->syscalls, old_size); + if (ret < 0) { + ERROR("Out of memory"); + return -1; +@@ -593,7 +594,7 @@ static int dup_syscall_to_oci_spec(const docker_seccomp *docker_seccomp_spec, + + static oci_runtime_config_linux_seccomp * + trans_docker_seccomp_to_oci_format(const docker_seccomp *docker_seccomp_spec, +- const defs_process_capabilities *capabilites) ++ const defs_process_capabilities *capabilities) + { + oci_runtime_config_linux_seccomp *oci_seccomp_spec = NULL; + +@@ -611,7 +612,7 @@ trans_docker_seccomp_to_oci_format(const docker_seccomp *docker_seccomp_spec, + } + + // syscalls +- if (dup_syscall_to_oci_spec(docker_seccomp_spec, oci_seccomp_spec, capabilites)) { ++ if (dup_syscall_to_oci_spec(docker_seccomp_spec, oci_seccomp_spec, capabilities)) { + goto out; + } + +@@ -626,7 +627,7 @@ done: + return oci_seccomp_spec; + } + +-int merge_default_seccomp_spec(oci_runtime_spec *oci_spec, const defs_process_capabilities *capabilites) ++int merge_default_seccomp_spec(oci_runtime_spec *oci_spec, const defs_process_capabilities *capabilities) + { + oci_runtime_config_linux_seccomp *oci_seccomp_spec = NULL; + docker_seccomp *docker_seccomp_spec = NULL; +@@ -641,7 +642,7 @@ int merge_default_seccomp_spec(oci_runtime_spec *oci_spec, const defs_process_ca + isulad_set_error_message("failed to parse seccomp file: %s", SECCOMP_DEFAULT_PATH); + return -1; + } +- oci_seccomp_spec = trans_docker_seccomp_to_oci_format(docker_seccomp_spec, capabilites); ++ oci_seccomp_spec = trans_docker_seccomp_to_oci_format(docker_seccomp_spec, capabilities); + free_docker_seccomp(docker_seccomp_spec); + if (oci_seccomp_spec == NULL) { + ERROR("Failed to trans docker format seccomp profile to oci standard"); +@@ -669,7 +670,7 @@ static int append_systemcall_to_seccomp(oci_runtime_config_linux_seccomp *seccom + } + new_size = (seccomp->syscalls_len + 1) * sizeof(defs_syscall *); + old_size = new_size - sizeof(defs_syscall *); +- nret = mem_realloc((void **)&tmp_syscalls, new_size, seccomp->syscalls, old_size); ++ nret = util_mem_realloc((void **)&tmp_syscalls, new_size, seccomp->syscalls, old_size); + if (nret < 0) { + CRIT("Memory allocation error."); + return -1; +@@ -849,6 +850,7 @@ out: + return ret; + } + ++#ifdef ENABLE_SELINUX + int merge_selinux(oci_runtime_spec *oci_spec, container_config_v2_common_config *v2_spec) + { + if (make_sure_oci_spec_process(oci_spec) < 0) { +@@ -860,6 +862,7 @@ int merge_selinux(oci_runtime_spec *oci_spec, container_config_v2_common_config + + return 0; + } ++#endif + + static int get_adds_cap_for_system_container(const host_config *host_spec, char ***adds, size_t *adds_len) + { +@@ -880,7 +883,7 @@ static int get_adds_cap_for_system_container(const host_config *host_spec, char + + // if cap_drop in g_system_caps, move it from g_system_caps + for (i = 0; i < system_caps_len; i++) { +- if (!strings_in_slice((const char **)drops, drops_len, g_system_caps[i])) { ++ if (!util_strings_in_slice((const char **)drops, drops_len, g_system_caps[i])) { + ret = append_capability(adds, adds_len, g_system_caps[i]); + if (ret != 0) { + ERROR("Failed to append capabilities"); +diff --git a/src/daemon/modules/spec/specs_security.h b/src/daemon/modules/spec/specs_security.h +index 5131d7f..f33814d 100644 +--- a/src/daemon/modules/spec/specs_security.h ++++ b/src/daemon/modules/spec/specs_security.h +@@ -25,13 +25,15 @@ + #include "isula_libutils/container_config_v2.h" + #include "isula_libutils/oci_runtime_spec.h" + +-int merge_default_seccomp_spec(oci_runtime_spec *oci_spec, const defs_process_capabilities *capabilites); ++int merge_default_seccomp_spec(oci_runtime_spec *oci_spec, const defs_process_capabilities *capabilities); + int merge_caps(oci_runtime_spec *oci_spec, const char **adds, size_t adds_len, const char **drops, size_t drops_len); + int refill_oci_process_capabilities(defs_process_capabilities **caps, const char **src_caps, size_t src_caps_len); + int merge_sysctls(oci_runtime_spec *oci_spec, const json_map_string_string *sysctls); + int merge_no_new_privileges(oci_runtime_spec *oci_spec, bool value); + int adapt_settings_for_system_container(oci_runtime_spec *oci_spec, const host_config *host_spec); + int merge_seccomp(oci_runtime_spec *oci_spec, const char *seccomp_profile); ++#ifdef ENABLE_SELINUX + int merge_selinux(oci_runtime_spec *oci_spec, container_config_v2_common_config *v2_spec); ++#endif + + #endif +diff --git a/src/daemon/modules/spec/verify.c b/src/daemon/modules/spec/verify.c +index b257def..68f816d 100644 +--- a/src/daemon/modules/spec/verify.c ++++ b/src/daemon/modules/spec/verify.c +@@ -16,6 +16,7 @@ + #define _GNU_SOURCE + #endif + ++#include "verify.h" + #include + #include + #include +@@ -38,7 +39,6 @@ + #include "err_msg.h" + #include "isula_libutils/log.h" + #include "sysinfo.h" +-#include "verify.h" + #include "selinux_label.h" + #include "image_api.h" + #include "utils.h" +@@ -765,37 +765,12 @@ out: + return ret; + } + +-static inline bool is_hostconfig_blkio_weight_invalid(uint16_t weight) +-{ +- return weight > 0 && (weight < 10 || weight > 1000); +-} +- +-/* verify hostconfig blkio weight */ +-static int verify_hostconfig_blkio_weight(const sysinfo_t *sysinfo, uint16_t weight) +-{ +- int ret = 0; +- +- if (weight > 0 && !(sysinfo->blkioinfo.blkio_weight)) { +- ERROR("Your kernel does not support Block I/O weight. Weight in host config discarded."); +- isulad_set_error_message("Your kernel does not support Block I/O weight. Weight in host config discarded."); +- ret = -1; +- goto out; +- } +- if (is_hostconfig_blkio_weight_invalid(weight)) { +- ERROR("Range of blkio weight is from 10 to 1000."); +- isulad_set_error_message("Range of blkio weight is from 10 to 1000."); +- ret = -1; +- goto out; +- } +- +-out: +- return ret; +-} +- + /* verify blkio device */ +-static int verify_blkio_device(const sysinfo_t *sysinfo, size_t weight_device_len) ++static int verify_blkio_device(const sysinfo_t *sysinfo, const defs_block_io_device_weight **weight_device, ++ size_t weight_device_len) + { + int ret = 0; ++ size_t i = 0; + + if (weight_device_len > 0 && !(sysinfo->blkioinfo.blkio_weight_device)) { + ERROR("Your kernel does not support Block I/O weight_device."); +@@ -803,6 +778,16 @@ static int verify_blkio_device(const sysinfo_t *sysinfo, size_t weight_device_le + ret = -1; + } + ++ for (i = 0; i < weight_device_len; i++) { ++ if (is_blkio_weight_invalid(weight_device[i]->weight)) { ++ ERROR("Range of blkio weight is from 10 to 1000."); ++ isulad_set_error_message("Range of blkio weight is from 10 to 1000."); ++ ret = -1; ++ goto out; ++ } ++ } ++ ++out: + return ret; + } + +@@ -929,7 +914,8 @@ static int verify_resources_blkio(const sysinfo_t *sysinfo, const defs_resources + goto out; + } + +- ret = verify_blkio_device(sysinfo, blkio->weight_device_len); ++ ret = verify_blkio_device(sysinfo, (const defs_block_io_device_weight **)blkio->weight_device, ++ blkio->weight_device_len); + if (ret != 0) { + goto out; + } +@@ -1028,7 +1014,7 @@ static int verify_resources_hugetlbs(const sysinfo_t *sysinfo, defs_resources_hu + } + newsize = sizeof(defs_resources_hugepage_limits_element *) * (newlen + 1); + oldsize = newsize - sizeof(defs_resources_hugepage_limits_element *); +- ret = mem_realloc((void **)&tmphugetlb, newsize, newhugetlb, oldsize); ++ ret = util_mem_realloc((void **)&tmphugetlb, newsize, newhugetlb, oldsize); + if (ret < 0) { + free(pagesize); + ERROR("Out of memory"); +@@ -1147,7 +1133,7 @@ static bool verify_oci_linux_sysctl(const oci_runtime_config_linux *l) + } + for (i = 0; i < l->sysctl->len; i++) { + if (strcmp("kernel.pid_max", l->sysctl->keys[i]) == 0) { +- if (!pid_max_kernel_namespaced()) { ++ if (!util_check_pid_max_kernel_namespaced()) { + isulad_set_error_message("Sysctl '%s' is not kernel namespaced, it cannot be changed", + l->sysctl->keys[i]); + return false; +@@ -1155,7 +1141,7 @@ static bool verify_oci_linux_sysctl(const oci_runtime_config_linux *l) + return true; + } + } +- if (!check_sysctl_valid(l->sysctl->keys[i])) { ++ if (!util_valid_sysctl(l->sysctl->keys[i])) { + isulad_set_error_message("Sysctl %s=%s is not whitelist", l->sysctl->keys[i], l->sysctl->values[i]); + return false; + } +@@ -1484,7 +1470,7 @@ static int verify_process_env(const defs_process *process) + char *new_env = NULL; + + for (i = 0; i < process->env_len; i++) { +- if (util_validate_env(process->env[i], &new_env) != 0) { ++ if (util_valid_env(process->env[i], &new_env) != 0) { + ERROR("Invalid environment %s", process->env[i]); + isulad_set_error_message("Invalid environment %s", process->env[i]); + ret = -1; +@@ -1619,7 +1605,7 @@ static int append_hugetlb_array(host_config_hugetlbs_element ***hugetlb, size_t + + newsize = sizeof(host_config_hugetlbs_element *) * (len + 1); + oldsize = newsize - sizeof(host_config_hugetlbs_element *); +- ret = mem_realloc((void **)&tmphugetlb, newsize, *hugetlb, oldsize); ++ ret = util_mem_realloc((void **)&tmphugetlb, newsize, *hugetlb, oldsize); + if (ret < 0) { + return -1; + } +@@ -1738,10 +1724,58 @@ out: + return ret; + } + ++static int verify_nano_cpus(const sysinfo_t *sysinfo, const host_config *hostconfig) ++{ ++ int ret = 0; ++ ++ if (hostconfig->nano_cpus == 0) { ++ return 0; ++ } ++ ++ if (hostconfig->nano_cpus > 0 && hostconfig->cpu_period > 0) { ++ ERROR("Conflicting options: Nano CPUs and CPU Period cannot both be set."); ++ isulad_set_error_message("Conflicting options: Nano CPUs and CPU Period cannot both be set."); ++ ret = -1; ++ goto out; ++ } ++ ++ if (hostconfig->nano_cpus > 0 && hostconfig->cpu_quota > 0) { ++ ERROR("Conflicting options: Nano CPUs and CPU Quota cannot both be set."); ++ isulad_set_error_message("Conflicting options: Nano CPUs and CPU Quota cannot both be set."); ++ ret = -1; ++ goto out; ++ } ++ ++ if (hostconfig->nano_cpus > 0 && (!(sysinfo->cgcpuinfo.cpu_cfs_quota) || !(sysinfo->cgcpuinfo.cpu_cfs_period))) { ++ ERROR("NanoCPUs can not be set, as your kernel does not support CPU cfs period/quota or the cgroup is not mounted."); ++ isulad_set_error_message( ++ "NanoCPUs can not be set, as your kernel does not support CPU cfs period/quota or the cgroup is not mounted."); ++ ret = -1; ++ goto out; ++ } ++ ++ if (hostconfig->nano_cpus < 0 || (hostconfig->nano_cpus > (sysinfo->ncpus * 1e9))) { ++ ERROR("Range of CPUs is from 0.01 to %d.00, as there are only %d CPUs available", sysinfo->ncpus, ++ sysinfo->ncpus); ++ isulad_set_error_message("Range of CPUs is from 0.01 to %d.00, as there are only %d CPUs available", ++ sysinfo->ncpus, sysinfo->ncpus); ++ ret = -1; ++ goto out; ++ } ++ ++out: ++ return ret; ++} ++ + static int host_config_settings_cpu(const sysinfo_t *sysinfo, const host_config *hostconfig) + { + int ret = 0; + ++ ret = verify_nano_cpus(sysinfo, hostconfig); ++ if (ret != 0) { ++ goto out; ++ } ++ + ret = verify_cpu_realtime(sysinfo, hostconfig->cpu_realtime_period, hostconfig->cpu_realtime_runtime); + if (ret != 0) { + goto out; +@@ -1771,12 +1805,25 @@ static int host_config_settings_blkio(const sysinfo_t *sysinfo, const host_confi + { + int ret = 0; + +- ret = verify_hostconfig_blkio_weight(sysinfo, hostconfig->blkio_weight); ++ ret = verify_blkio_weight(sysinfo, hostconfig->blkio_weight); ++ if (ret != 0) { ++ goto out; ++ } ++ ++ ret = verify_blkio_device(sysinfo, (const defs_block_io_device_weight **)hostconfig->blkio_weight_device, ++ hostconfig->blkio_weight_device_len); ++ if (ret != 0) { ++ goto out; ++ } ++ ++ ret = verify_blkio_rw_bps_device(sysinfo, hostconfig->blkio_device_read_bps_len, ++ hostconfig->blkio_device_write_bps_len); + if (ret != 0) { + goto out; + } + +- ret = verify_blkio_device(sysinfo, hostconfig->blkio_weight_device_len); ++ ret = verify_blkio_rw_iops_device(sysinfo, hostconfig->blkio_device_read_iops_len, ++ hostconfig->blkio_device_write_iops_len); + if (ret != 0) { + goto out; + } +@@ -1904,6 +1951,25 @@ out: + return ret; + } + ++/* verify device cgroup rule */ ++static int verify_host_config_device_cgroup_rules(const host_config *hostconfig) ++{ ++ int ret = 0; ++ size_t i = 0; ++ ++ for (i = 0; i < hostconfig->device_cgroup_rules_len; i++) { ++ if (!util_valid_device_cgroup_rule(hostconfig->device_cgroup_rules[i])) { ++ ERROR("Invalid device cgroup rule %s", hostconfig->device_cgroup_rules[i]); ++ isulad_set_error_message("Invalid device cgroup rule %s", hostconfig->device_cgroup_rules[i]); ++ ret = -1; ++ goto out; ++ } ++ } ++ ++out: ++ return ret; ++} ++ + /* verify host config settings */ + int verify_host_config_settings(host_config *hostconfig, bool update) + { +@@ -1930,6 +1996,11 @@ int verify_host_config_settings(host_config *hostconfig, bool update) + goto out; + } + ++ ret = verify_host_config_device_cgroup_rules(hostconfig); ++ if (ret != 0) { ++ goto out; ++ } ++ + #ifdef ENABLE_OCI_IMAGE + // storage options + ret = verify_storage_opts(hostconfig); +@@ -1942,6 +2013,7 @@ out: + return ret; + } + ++#ifdef ENABLE_SELINUX + static int relabel_mounts_if_needed(defs_mount **mounts, size_t len, const char *mount_label) + { + int ret = 0; +@@ -1976,6 +2048,7 @@ static int relabel_mounts_if_needed(defs_mount **mounts, size_t len, const char + out: + return ret; + } ++#endif + + /* verify container settings start */ + int verify_container_settings_start(const oci_runtime_spec *oci_spec) +@@ -1989,11 +2062,13 @@ int verify_container_settings_start(const oci_runtime_spec *oci_spec) + ret = -1; + goto out; + } ++#ifdef ENABLE_SELINUX + if (relabel_mounts_if_needed(oci_spec->mounts, oci_spec->mounts_len, oci_spec->linux->mount_label) != 0) { + ERROR("Failed to relabel mount"); + ret = -1; + goto out; + } ++#endif + } + + out: +diff --git a/src/daemon/modules/volume/CMakeLists.txt b/src/daemon/modules/volume/CMakeLists.txt +new file mode 100644 +index 0000000..7a00dbf +--- /dev/null ++++ b/src/daemon/modules/volume/CMakeLists.txt +@@ -0,0 +1,12 @@ ++# get current directory sources files ++aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} local_volume_srcs) ++ ++set(VOLUME_SRCS ++ ${local_volume_srcs} ++ PARENT_SCOPE ++ ) ++ ++set(VOLUME_INCS ++ ${CMAKE_CURRENT_SOURCE_DIR} ++ PARENT_SCOPE ++ ) +diff --git a/src/daemon/modules/volume/local.c b/src/daemon/modules/volume/local.c +new file mode 100644 +index 0000000..a80a5ec +--- /dev/null ++++ b/src/daemon/modules/volume/local.c +@@ -0,0 +1,633 @@ ++/****************************************************************************** ++ * 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-09-07 ++ * Description: provide isula local volume functions ++ ******************************************************************************/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "isula_libutils/log.h" ++#include "volume_api.h" ++#include "utils.h" ++#include "map.h" ++#include "path.h" ++#include "err_msg.h" ++#include "utils_file.h" ++#include "utils_string.h" ++#include "utils_verify.h" ++ ++#define LOCAL_VOLUME_DRIVER_NAME "local" ++#define LOCAL_VOLUME_ROOT_DIR_NAME "volumes" ++#define LOCAL_VOLUME_ROOT_DIR_MODE 0700 ++#define LOCAL_VOLUME_DATA_DIR_NAME "_data" ++#define LOCAL_VOLUME_DIR_MODE 0755 ++ ++struct volumes_info { ++ char *root_dir; ++ ++ // map locker ++ pthread_mutex_t mutex; ++ bool mutex_inited; ++ map_t *vols_by_name; ++}; ++ ++static struct volumes_info *g_volumes; ++ ++static void mutex_lock(pthread_mutex_t *mutex) ++{ ++ if (pthread_mutex_lock(mutex)) { ++ ERROR("Failed to lock"); ++ } ++} ++ ++static void mutex_unlock(pthread_mutex_t *mutex) ++{ ++ if (pthread_mutex_unlock(mutex)) { ++ ERROR("Failed to unlock"); ++ } ++} ++ ++static void volume_kvfree(void *key, void *value) ++{ ++ free(key); ++ free_volume((struct volume *)value); ++ return; ++} ++ ++void free_volumes_info(struct volumes_info *vols) ++{ ++ if (vols == NULL) { ++ return; ++ } ++ if (vols->mutex_inited) { ++ pthread_mutex_destroy(&vols->mutex); ++ } ++ free(vols->root_dir); ++ map_free(vols->vols_by_name); ++ free(vols); ++ return; ++} ++ ++static struct volume * dup_volume(char *name, char *path) ++{ ++ struct volume *vol = NULL; ++ ++ vol = util_common_calloc_s(sizeof(struct volume)); ++ if (vol == NULL) { ++ ERROR("out of memory"); ++ return NULL; ++ } ++ ++ vol->driver = util_strdup_s(LOCAL_VOLUME_DRIVER_NAME); ++ vol->name = util_strdup_s(name); ++ vol->path = util_strdup_s(path); ++ vol->mount_point = util_strdup_s(path); ++ ++ return vol; ++} ++ ++struct volume * local_volume_get(char *name) ++{ ++ struct volume *v = NULL; ++ ++ if (!util_valid_volume_name(name)) { ++ ERROR("failed to get volume, invalid volume name %s", name); ++ isulad_try_set_error_message("failed to get volume, invalid volume name %s", name); ++ return NULL; ++ } ++ ++ mutex_lock(&g_volumes->mutex); ++ v = map_search(g_volumes->vols_by_name, name); ++ if (v == NULL) { ++ goto out; ++ } ++ v = dup_volume(v->name, v->path); ++ ++out: ++ mutex_unlock(&g_volumes->mutex); ++ ++ return v; ++} ++ ++static struct volumes_info *new_empty_volumes_info() ++{ ++ int ret = 0; ++ struct volumes_info *vols_info = NULL; ++ ++ vols_info = util_common_calloc_s(sizeof(struct volumes_info)); ++ if (vols_info == NULL) { ++ ERROR("out of memory"); ++ ret = -1; ++ goto out; ++ } ++ ++ vols_info->vols_by_name = map_new(MAP_STR_PTR, MAP_DEFAULT_CMP_FUNC, volume_kvfree); ++ if (vols_info->vols_by_name == NULL) { ++ ERROR("out of memory"); ++ ret = -1; ++ goto out; ++ } ++ ++out: ++ if (ret != 0) { ++ free_volumes_info(vols_info); ++ vols_info = NULL; ++ } ++ ++ return vols_info; ++} ++ ++static int init_volume_root_dir(struct volumes_info *vols_info, char *root_dir) ++{ ++ int ret = 0; ++ ++ ret = util_mkdir_p(root_dir, LOCAL_VOLUME_ROOT_DIR_MODE); ++ if (ret != 0) { ++ ERROR("create volume directory %s failed: %s", root_dir, strerror(errno)); ++ goto out; ++ } ++ ++ vols_info->root_dir = util_strdup_s(root_dir); ++ ++out: ++ ++ return ret; ++} ++ ++static char *build_and_valid_data_dir(const char *root_dir, const char *name) ++{ ++ int ret = 0; ++ char *data_dir = NULL; ++ char *vol_dir = NULL; ++ char *tmp_dir = NULL; ++ struct stat st; ++ ++ if (!util_valid_volume_name(name)) { ++ ERROR("Invalid volume dir %s, ignore", name); ++ return NULL; ++ } ++ ++ vol_dir = util_path_join(root_dir, name); ++ if (vol_dir == NULL) { ++ ERROR("out of memory"); ++ ret = -1; ++ goto out; ++ } ++ ++ tmp_dir = util_follow_symlink_in_scope(vol_dir, root_dir); ++ if (tmp_dir == NULL) { ++ ERROR("%s not inside %s", vol_dir, root_dir); ++ ret = -1; ++ goto out; ++ } ++ ++ data_dir = util_path_join(vol_dir, LOCAL_VOLUME_DATA_DIR_NAME); ++ if (data_dir == NULL) { ++ ERROR("out of memory"); ++ ret = -1; ++ goto out; ++ } ++ ++ free(tmp_dir); ++ tmp_dir = util_follow_symlink_in_scope(data_dir, vol_dir); ++ if (tmp_dir == NULL) { ++ ERROR("%s not inside %s", data_dir, root_dir); ++ ret = -1; ++ goto out; ++ } ++ ++ if (lstat(tmp_dir, &st) != 0) { ++ ERROR("lstat %s: %s", tmp_dir, strerror(errno)); ++ ret = -1; ++ goto out; ++ } ++ ++out: ++ free(tmp_dir); ++ free(vol_dir); ++ if (ret != 0) { ++ free(data_dir); ++ data_dir = NULL; ++ } ++ ++ return data_dir; ++} ++ ++static bool load_volume(const char *root_dir, const struct dirent *dir, void *userdata) ++{ ++ int ret = 0; ++ char *data_dir = NULL; ++ struct volumes_info *vols = (struct volumes_info *)userdata; ++ struct volume *vol = NULL; ++ ++ data_dir = build_and_valid_data_dir(root_dir, dir->d_name); ++ if (data_dir == NULL) { ++ ERROR("failed to load volume %s", dir->d_name); ++ // always return true so we can walk next subdir but not failed to start isulad ++ return true; ++ } ++ ++ mutex_lock(&g_volumes->mutex); ++ vol = dup_volume((char *)dir->d_name, data_dir); ++ if (vol == NULL) { ++ ERROR("out of memory"); ++ ret = -1; ++ goto out; ++ } ++ ++ // No need to check conflict because the key is folder name in disk ++ // and they are definitely unique. ++ if (!map_insert(vols->vols_by_name, (char *)dir->d_name, vol)) { ++ ERROR("failed to insert volume %s", dir->d_name); ++ ret = -1; ++ goto out; ++ } ++ ++out: ++ mutex_unlock(&g_volumes->mutex); ++ ++ free(data_dir); ++ if (ret != 0) { ++ free_volume(vol); ++ } ++ ++ // always return true so we can walk next subdir but not failed to start isulad ++ return true; ++} ++ ++static int load_volumes(struct volumes_info *vols) ++{ ++ return util_scan_subdirs((const char*)vols->root_dir, load_volume, vols); ++} ++ ++static int local_volume_init(char *scope) ++{ ++ int ret = 0; ++ ++ if (scope == NULL) { ++ ERROR("invalid NULL param"); ++ return -1; ++ } ++ ++ g_volumes = new_empty_volumes_info(); ++ if (g_volumes == NULL) { ++ ret = -1; ++ goto out; ++ } ++ ++ ret = pthread_mutex_init(&g_volumes->mutex, NULL); ++ if (ret != 0) { ++ ERROR("init mutex failed"); ++ ret = -1; ++ goto out; ++ } ++ g_volumes->mutex_inited = true; ++ ++ ret = init_volume_root_dir(g_volumes, scope); ++ if (ret != 0) { ++ goto out; ++ } ++ ++ ret = load_volumes(g_volumes); ++ if (ret != 0) { ++ goto out; ++ } ++ ++out: ++ if (ret != 0) { ++ free_volumes_info(g_volumes); ++ g_volumes = NULL; ++ } ++ ++ return ret; ++} ++ ++static int create_volume_meminfo(char *name, struct volume **vol) ++{ ++ struct volume *v = NULL; ++ int ret = 0; ++ int sret = 0; ++ char path[PATH_MAX] = {0}; ++ ++ v = util_common_calloc_s(sizeof(struct volume)); ++ if (v == NULL) { ++ ERROR("out of memory"); ++ return -1; ++ } ++ ++ v->name = util_strdup_s(name); ++ ++ sret = snprintf(path, sizeof(path), "%s/%s/%s", g_volumes->root_dir, v->name, LOCAL_VOLUME_DATA_DIR_NAME); ++ if (sret < 0 || (size_t)sret >= sizeof(path)) { ++ ERROR("failed to sprintf to create volume"); ++ ret = -1; ++ goto out; ++ } ++ ++ v->path = util_strdup_s(path); ++ ++ *vol = v; ++ v = NULL; ++ ++out: ++ free_volume(v); ++ ++ return ret; ++} ++ ++static struct volume * volume_create_nolock(char *name) ++{ ++ struct volume *v = NULL; ++ int ret = 0; ++ ++ v = map_search(g_volumes->vols_by_name, name); ++ if (v != NULL) { ++ // volume already exist, consider it as success ++ return v; ++ } ++ ++ ret = create_volume_meminfo(name, &v); ++ if (ret != 0) { ++ return NULL; ++ } ++ ++ ret = util_mkdir_p(v->path, LOCAL_VOLUME_DIR_MODE); ++ if (ret != 0) { ++ ERROR("failed to create %s for volume %s: %s", v->path, v->name, strerror(errno)); ++ goto out; ++ } ++ ++ if (!map_insert(g_volumes->vols_by_name, v->name, v)) { ++ ERROR("failed to insert volume %s", v->name); ++ goto out; ++ } ++ ++out: ++ if (ret != 0) { ++ (void)util_recursive_rmdir(v->path, 0); ++ free_volume(v); ++ v = NULL; ++ } ++ ++ return v; ++} ++ ++struct volume * local_volume_create(char *name) ++{ ++ struct volume *v_out = NULL; ++ struct volume *v = NULL; ++ ++ if (name == NULL) { ++ ERROR("invalid null volume name when create volume"); ++ return NULL; ++ } ++ ++ if (!util_valid_volume_name(name)) { ++ ERROR("failed to create volume, invalid volume name %s", name); ++ isulad_try_set_error_message("failed to create volume, invalid volume name %s", name); ++ return NULL; ++ } ++ ++ mutex_lock(&g_volumes->mutex); ++ v = volume_create_nolock(name); ++ if (v == NULL) { ++ goto out; ++ } ++ v_out = dup_volume(v->name, v->path); ++out: ++ mutex_unlock(&g_volumes->mutex); ++ ++ return v_out; ++} ++ ++int local_volume_mount(char *name) ++{ ++ // local volume do not need mount ++ return 0; ++} ++ ++int local_volume_umount(char *name) ++{ ++ // local volume do not need umount ++ return 0; ++} ++ ++static struct volumes *new_empty_volumes(size_t size) ++{ ++ struct volumes *vols = NULL; ++ ++ vols = util_common_calloc_s(sizeof(struct volumes)); ++ if (vols == NULL) { ++ ERROR("out of memory"); ++ return NULL; ++ } ++ ++ if (size == 0) { ++ return vols; ++ } ++ ++ vols->vols = util_common_calloc_s(sizeof(struct volume*) * size); ++ if (vols->vols == NULL) { ++ ERROR("out of memory"); ++ free_volumes(vols); ++ return NULL; ++ } ++ ++ return vols; ++} ++ ++struct volumes * local_volume_list(void) ++{ ++ int ret = 0; ++ map_itor *itor = NULL; ++ struct volume *vol = NULL; ++ struct volume *v = NULL; ++ struct volumes *vols = NULL; ++ size_t size = 0; ++ ++ mutex_lock(&g_volumes->mutex); ++ ++ size = map_size(g_volumes->vols_by_name); ++ ++ vols = new_empty_volumes(size); ++ if (vols == NULL) { ++ ERROR("out of memory"); ++ return NULL; ++ } ++ ++ itor = map_itor_new(g_volumes->vols_by_name); ++ if (itor == NULL) { ++ ERROR("failed to get volumes's iterator to get all volumes"); ++ ret = -1; ++ goto out; ++ } ++ ++ for (; map_itor_valid(itor); map_itor_next(itor)) { ++ v = map_itor_value(itor); ++ vol = dup_volume(v->name, v->path); ++ if (vol == NULL) { ++ ERROR("out of memory"); ++ ret = -1; ++ goto out; ++ } ++ vols->vols[vols->vols_len] = vol; ++ vols->vols_len++; ++ } ++ ++out: ++ map_itor_free(itor); ++ mutex_unlock(&g_volumes->mutex); ++ ++ if (ret != 0) { ++ free_volumes(vols); ++ vols = NULL; ++ } ++ ++ return vols; ++} ++ ++static int remove_volume_dir(char *path) ++{ ++ int ret = 0; ++ char *vol_dir = NULL; ++ ++ if (path == NULL) { ++ ERROR("Invalid NULL param"); ++ return -1; ++ } ++ ++ vol_dir = util_path_dir(path); ++ if (!util_has_prefix(vol_dir, g_volumes->root_dir) || ++ strlen(vol_dir) <= (strlen(g_volumes->root_dir) + strlen("/"))) { ++ ERROR("remove volume dir %s failed, path invalid. volume root is %s", vol_dir, g_volumes->root_dir); ++ ret = -1; ++ goto out; ++ } ++ ++ // First we remove data directory of volume to keep structure of volume directory ++ // remain untouched if we remove the data directory failed. ++ ret = util_recursive_rmdir(path, 0); ++ if (ret != 0) { ++ ERROR("failed to remove volume data dir %s: %s", path, strerror(errno)); ++ isulad_try_set_error_message("failed to remove volume data dir %s: %s", path, strerror(errno)); ++ goto out; ++ } ++ ++ ret = util_recursive_rmdir(vol_dir, 0); ++ if (ret != 0) { ++ ERROR("failed to remove volume dir %s: %s", vol_dir, strerror(errno)); ++ isulad_try_set_error_message("failed to remove volume dir %s: %s", vol_dir, strerror(errno)); ++ goto out; ++ } ++ ++out: ++ free(vol_dir); ++ ++ return ret; ++} ++ ++static int volume_remove_nolock(char *name) ++{ ++ struct volume *v = NULL; ++ ++ v = map_search(g_volumes->vols_by_name, name); ++ if (v == NULL) { ++ ERROR("No such volume: %s", name); ++ isulad_try_set_error_message("No such volume: %s", name); ++ return VOLUME_ERR_NOT_EXIST; ++ } ++ ++ if (remove_volume_dir(v->path) != 0) { ++ ERROR("failed to remove volume dir %s: %s", v->path, strerror(errno)); ++ return -1; ++ } ++ ++ if (!map_remove(g_volumes->vols_by_name, name)) { ++ ERROR("remove volume %s in memory failed", name); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int local_volume_remove(char *name) ++{ ++ int ret = 0; ++ ++ if (name == NULL) { ++ ERROR("invalid param"); ++ return -1; ++ } ++ ++ if (!util_valid_volume_name(name)) { ++ ERROR("failed to remove volume, invalid volume name %s", name); ++ isulad_try_set_error_message("failed to remove volume, invalid volume name %s", name); ++ return -1; ++ } ++ ++ mutex_lock(&g_volumes->mutex); ++ ret = volume_remove_nolock(name); ++ mutex_unlock(&g_volumes->mutex); ++ ++ return ret; ++} ++ ++int register_local_volume(char *root_dir) ++{ ++ int ret = 0; ++ char *local_volume_root_dir = NULL; ++ ++ if (root_dir == NULL) { ++ ERROR("Invalid NULL param"); ++ return -1; ++ } ++ ++ local_volume_root_dir = util_path_join(root_dir, LOCAL_VOLUME_ROOT_DIR_NAME); ++ if (root_dir == NULL) { ++ ERROR("out of memory"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (local_volume_init(local_volume_root_dir) != 0) { ++ ret = -1; ++ goto out; ++ } ++ ++ // support local driver only right now ++ volume_driver driver = { ++ .create = local_volume_create, ++ .get = local_volume_get, ++ .mount = local_volume_mount, ++ .umount = local_volume_umount, ++ .list = local_volume_list, ++ .remove = local_volume_remove, ++ }; ++ ++ ret = register_driver(LOCAL_VOLUME_DRIVER_NAME, &driver); ++ if (ret != 0) { ++ goto out; ++ } ++ ++out: ++ free(local_volume_root_dir); ++ ++ return ret; ++} ++ +diff --git a/src/daemon/modules/volume/local.h b/src/daemon/modules/volume/local.h +new file mode 100644 +index 0000000..8d72b54 +--- /dev/null ++++ b/src/daemon/modules/volume/local.h +@@ -0,0 +1,44 @@ ++/****************************************************************************** ++* 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-09-07 ++* Description: provide isula local volume definition ++*******************************************************************************/ ++#ifndef DAEMON_MODULES_VOLUME_LOCAL_H ++#define DAEMON_MODULES_VOLUME_LOCAL_H ++ ++#include "volume_api.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++int register_local_volume(char *root_dir); ++ ++struct volume * local_volume_create(char *name); ++ ++struct volume * local_volume_get(char *name); ++ ++int local_volume_mount(char *name); ++ ++int local_volume_umount(char *name); ++ ++struct volumes * local_volume_list(void); ++ ++int local_volume_remove(char *name); ++ ++char *local_volume_driver_name(); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif // DAEMON_MODULES_VOLUME_LOCAL_H +diff --git a/src/daemon/modules/volume/volume.c b/src/daemon/modules/volume/volume.c +new file mode 100644 +index 0000000..9d49659 +--- /dev/null ++++ b/src/daemon/modules/volume/volume.c +@@ -0,0 +1,655 @@ ++/****************************************************************************** ++ * 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-09-07 ++ * Description: provide isula volume functions ++ ******************************************************************************/ ++#include ++#include ++#include ++#include ++#include ++ ++#include "isula_libutils/log.h" ++#include "volume_api.h" ++#include "utils.h" ++#include "map.h" ++#include "local.h" ++#include "err_msg.h" ++#include "utils_file.h" ++ ++typedef struct { ++ pthread_mutex_t mutex; ++ map_t *drivers; ++ map_t *name_refs; ++} volume_store; ++ ++// volume store object ++static volume_store g_vs; ++ ++static void mutex_lock(pthread_mutex_t *mutex) ++{ ++ if (pthread_mutex_lock(mutex)) { ++ ERROR("Failed to lock"); ++ } ++} ++ ++static void mutex_unlock(pthread_mutex_t *mutex) ++{ ++ if (pthread_mutex_unlock(mutex)) { ++ ERROR("Failed to unlock"); ++ } ++} ++ ++static int valid_driver(volume_driver *driver) ++{ ++ if (driver->create == NULL || driver->get == NULL || driver->mount == NULL || ++ driver->umount == NULL || driver->list == NULL || driver->remove == NULL) { ++ ERROR("Invalid volume driver, NULL function found"); ++ return -1; ++ } ++ return 0; ++} ++ ++static volume_driver * lookup_driver(char *name) ++{ ++ if (name == NULL) { ++ ERROR("invalid NULL volume driver name"); ++ return NULL; ++ } ++ return map_search(g_vs.drivers, name); ++} ++ ++static volume_driver * lookup_driver_by_volume_name(char *name) ++{ ++ struct volume *vol = NULL; ++ static volume_driver *driver = NULL; ++ map_itor *itor = NULL; ++ ++ if (name == NULL) { ++ ERROR("invalid NULL volume name"); ++ return NULL; ++ } ++ ++ itor = map_itor_new(g_vs.drivers); ++ if (itor == NULL) { ++ ERROR("failed to get volumes's iterator to query volume driver by volume name"); ++ goto out; ++ } ++ ++ for (; map_itor_valid(itor); map_itor_next(itor)) { ++ driver = map_itor_value(itor); ++ vol = driver->get(name); ++ if (vol != NULL) { ++ free_volume(vol); ++ break; ++ } ++ } ++ ++out: ++ map_itor_free(itor); ++ ++ return driver; ++} ++ ++static volume_driver * dup_driver(volume_driver *driver) ++{ ++ volume_driver *d = NULL; ++ ++ d = util_common_calloc_s(sizeof(volume_driver)); ++ if (d == NULL) { ++ ERROR("out of memory"); ++ return NULL; ++ } ++ ++ *d = *driver; ++ ++ return d; ++} ++ ++static int insert_driver(char *name, volume_driver *driver) ++{ ++ int ret = 0; ++ volume_driver *d = NULL; ++ ++ if (valid_driver(driver) != 0) { ++ return -1; ++ } ++ ++ d = dup_driver(driver); ++ if (d == NULL) { ++ return -1; ++ } ++ ++ if (!map_insert(g_vs.drivers, name, d)) { ++ ERROR("out of memory"); ++ ret = -1; ++ goto out; ++ } ++ ++out: ++ if (ret != 0) { ++ free(d); ++ d = NULL; ++ } ++ ++ return ret; ++} ++ ++int register_driver(char *name, volume_driver *driver) ++{ ++ int ret = 0; ++ ++ if (name == NULL || driver == NULL) { ++ ERROR("Invalid NULL param"); ++ return -1; ++ } ++ ++ mutex_lock(&g_vs.mutex); ++ ++ if (lookup_driver(name) != NULL) { ++ ERROR("driver %s already exist", name); ++ ret = -1; ++ goto out; ++ } ++ ++ ret = insert_driver(name, driver); ++ ++out: ++ mutex_unlock(&g_vs.mutex); ++ ++ return ret; ++} ++ ++// key: name of volume ++// value: ids map of contianer ++static void refs_kvfree(void *key, void *value) ++{ ++ free(key); ++ map_free((map_t*)value); ++ return; ++} ++ ++static int add_name_ref(map_t *name_refs, char *name, char *ref) ++{ ++ map_t *refs = NULL; ++ ++ refs = map_search(name_refs, name); ++ if (refs == NULL) { ++ refs = map_new(MAP_STR_BOOL, MAP_DEFAULT_CMP_FUNC, MAP_DEFAULT_FREE_FUNC); ++ if (refs == NULL) { ++ ERROR("out of memory"); ++ return -1; ++ } ++ if (!map_insert(name_refs, name, refs)) { ++ ERROR("insert refs to %s failed, ref is %s", name, ref); ++ map_free(refs); ++ return -1; ++ } ++ } ++ ++ if (map_search(refs, ref) == NULL) { ++ bool b = true; ++ if (!map_insert(refs, ref, &b)) { ++ ERROR("insert name %s ref %s failed", name, ref); ++ if (map_size(refs) == 0) { ++ (void)map_remove(name_refs, refs); ++ } ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++static struct volume_names * empty_volume_names(size_t size) ++{ ++ int ret = 0; ++ struct volume_names *vns = NULL; ++ ++ vns = util_common_calloc_s(sizeof(struct volume_names)); ++ if (vns == NULL) { ++ ERROR("out of memory"); ++ return NULL; ++ } ++ ++ vns->names = util_common_calloc_s(sizeof(char *) * size); ++ if (vns->names == NULL) { ++ ERROR("out of memory"); ++ ret = -1; ++ goto out; ++ } ++out: ++ if (ret != 0) { ++ free_volume_names(vns); ++ vns = NULL; ++ } ++ ++ return vns; ++} ++ ++static struct volume_names * get_name_refs(map_t *name_refs, char *name) ++{ ++ int ret = 0; ++ map_itor *itor = NULL; ++ struct volume_names *vns = NULL; ++ map_t *refs = NULL; ++ ++ refs = map_search(name_refs, name); ++ if (refs == NULL) { ++ return NULL; ++ } ++ ++ vns = empty_volume_names(map_size(refs)); ++ if (vns == NULL) { ++ ERROR("out of memory"); ++ return NULL; ++ } ++ ++ itor = map_itor_new(refs); ++ if (itor == NULL) { ++ ERROR("failed to get volumes's iterator to get all volumes"); ++ ret = -1; ++ goto out; ++ } ++ ++ for (; map_itor_valid(itor); map_itor_next(itor)) { ++ vns->names[vns->names_len] = util_strdup_s(map_itor_key(itor)); ++ vns->names_len++; ++ } ++ ++out: ++ map_itor_free(itor); ++ ++ if (ret != 0) { ++ free_volume_names(vns); ++ vns = NULL; ++ } ++ ++ return vns; ++} ++ ++static int del_name_ref(map_t *name_refs, char *name, char *ref) ++{ ++ map_t *refs = NULL; ++ ++ refs = map_search(name_refs, name); ++ if (refs == NULL) { ++ return 0; ++ } ++ ++ if (map_size(refs) != 0) { ++ if (!map_remove(refs, ref)) { ++ ERROR("failed to delete ref %s for volume %s", ref, name); ++ return -1; ++ } ++ } ++ ++ if (map_size(refs) == 0) { ++ if (!map_remove(name_refs, name)) { ++ ERROR("delete volume %s ref %s failed", name, ref); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++static int register_drivers(char *root_dir) ++{ ++ // support local volume driver only right now ++ return register_local_volume(root_dir); ++} ++ ++int volume_init(char *root_dir) ++{ ++ int ret = 0; ++ ++ g_vs.drivers = map_new(MAP_STR_PTR, MAP_DEFAULT_CMP_FUNC, MAP_DEFAULT_FREE_FUNC); ++ if (g_vs.drivers == NULL) { ++ ERROR("out of memory"); ++ ret = -1; ++ goto out; ++ } ++ ++ g_vs.name_refs = map_new(MAP_STR_PTR, MAP_DEFAULT_CMP_FUNC, refs_kvfree); ++ if (g_vs.name_refs == NULL) { ++ ERROR("out of memory"); ++ ret = -1; ++ goto out; ++ } ++ ++ ret = register_drivers(root_dir); ++ ++out: ++ if (ret != 0) { ++ map_free((map_t*)g_vs.drivers); ++ g_vs.drivers = NULL; ++ map_free((map_t*)g_vs.name_refs); ++ g_vs.name_refs = NULL; ++ } ++ ++ return ret; ++} ++ ++struct volume * volume_create(char *driver_name, char *name, struct volume_options *opts) ++{ ++ int ret = 0; ++ struct volume * vol = NULL; ++ volume_driver *driver = NULL; ++ char volume_name[VOLUME_DEFAULT_NAME_LEN + 1] = {0}; ++ ++ if (driver_name == NULL || opts == NULL || opts->ref == NULL) { ++ ERROR("invalid null param for volume create"); ++ return NULL; ++ } ++ ++ mutex_lock(&g_vs.mutex); ++ driver = lookup_driver(driver_name); ++ if (driver == NULL) { ++ ret = -1; ++ ERROR("volume driver %s not found", driver_name); ++ goto out; ++ } ++ ++ if (name == NULL) { ++ if (util_generate_random_str(volume_name, VOLUME_DEFAULT_NAME_LEN) != 0) { ++ ERROR("generate random string for volume name failed"); ++ ret = -1; ++ goto out; ++ } ++ name = (char*)volume_name; ++ } ++ ++ vol = driver->create(name); ++ if (vol == NULL) { ++ ret = -1; ++ goto out; ++ } ++ ++ ret = add_name_ref(g_vs.name_refs, name, opts->ref); ++ if (ret != 0) { ++ goto out; ++ } ++ ++out: ++ mutex_unlock(&g_vs.mutex); ++ ++ if (ret != 0) { ++ free_volume(vol); ++ vol = NULL; ++ } ++ ++ return vol; ++} ++ ++int volume_mount(char *name) ++{ ++ int ret = 0; ++ volume_driver *driver = NULL; ++ ++ if (name == NULL) { ++ ERROR("invalid null param for volume mount"); ++ return -1; ++ } ++ ++ mutex_lock(&g_vs.mutex); ++ driver = lookup_driver_by_volume_name(name); ++ if (driver == NULL) { ++ ret = -1; ++ goto out; ++ } ++ ret = driver->mount(name); ++ ++out: ++ mutex_unlock(&g_vs.mutex); ++ ++ return ret; ++} ++ ++int volume_umount(char *name) ++{ ++ int ret = 0; ++ volume_driver *driver = NULL; ++ ++ if (name == NULL) { ++ ERROR("invalid null param for volume umount"); ++ return -1; ++ } ++ ++ mutex_lock(&g_vs.mutex); ++ driver = lookup_driver_by_volume_name(name); ++ if (driver == NULL) { ++ ret = -1; ++ goto out; ++ } ++ ret = driver->umount(name); ++ ++out: ++ mutex_unlock(&g_vs.mutex); ++ ++ return ret; ++} ++ ++static struct volumes * list_all_driver_volumes() ++{ ++ int ret = 0; ++ volume_driver *driver = NULL; ++ map_itor *itor = NULL; ++ struct volumes *vols = NULL; ++ ++ itor = map_itor_new(g_vs.drivers); ++ if (itor == NULL) { ++ ERROR("failed to get volumes's iterator to list all volumes"); ++ ret = -1; ++ goto out; ++ } ++ ++ for (; map_itor_valid(itor); map_itor_next(itor)) { ++ driver = map_itor_value(itor); ++ vols = driver->list(); ++ // only one driver currently ++ break; ++ } ++ ++out: ++ map_itor_free(itor); ++ if (ret != 0) { ++ free_volumes(vols); ++ vols = NULL; ++ } ++ ++ return vols; ++} ++ ++struct volumes * volume_list(void) ++{ ++ struct volumes *vols = NULL; ++ ++ mutex_lock(&g_vs.mutex); ++ vols = list_all_driver_volumes(); ++ mutex_unlock(&g_vs.mutex); ++ ++ return vols; ++} ++ ++int volume_add_ref(char *name, char *ref) ++{ ++ int ret = 0; ++ ++ if (name == NULL || ref == NULL) { ++ ERROR("invalid null param for volume release"); ++ return -1; ++ } ++ ++ mutex_lock(&g_vs.mutex); ++ ret = add_name_ref(g_vs.name_refs, name, ref); ++ mutex_unlock(&g_vs.mutex); ++ ++ return ret; ++} ++ ++int volume_del_ref(char *name, char *ref) ++{ ++ int ret = 0; ++ ++ if (name == NULL || ref == NULL) { ++ ERROR("invalid null param for volume release"); ++ return -1; ++ } ++ ++ mutex_lock(&g_vs.mutex); ++ ret = del_name_ref(g_vs.name_refs, name, ref); ++ mutex_unlock(&g_vs.mutex); ++ ++ return ret; ++} ++ ++int volume_remove(char *name) ++{ ++ int ret = 0; ++ volume_driver *driver = NULL; ++ struct volume_names *vns = NULL; ++ ++ if (name == NULL) { ++ ERROR("invalid null param for volume remove"); ++ return -1; ++ } ++ ++ mutex_lock(&g_vs.mutex); ++ driver = lookup_driver_by_volume_name(name); ++ if (driver == NULL) { ++ ret = -1; ++ goto out; ++ } ++ ++ vns = get_name_refs(g_vs.name_refs, name); ++ if (vns != NULL && vns->names_len > 0) { ++ ERROR("remove volume %s failed: volume is used by container %s", name, vns->names[0]); ++ isulad_try_set_error_message("remove volume %s failed: volume is used by container %s", name, vns->names[0]); ++ ret = -1; ++ goto out; ++ } ++ ++ ret = driver->remove(name); ++ if (ret != 0) { ++ goto out; ++ } ++ ++out: ++ mutex_unlock(&g_vs.mutex); ++ free_volume_names(vns); ++ ++ return ret; ++} ++ ++int volume_prune(struct volume_names **pruned) ++{ ++ size_t i = 0; ++ int ret = 0; ++ struct volumes *list = NULL; ++ ++ if (pruned == NULL) { ++ ERROR("invalid NULL param"); ++ return -1; ++ } ++ ++ *pruned = util_common_calloc_s(sizeof(struct volume_names)); ++ if (*pruned == NULL) { ++ ERROR("out of memory"); ++ return -1; ++ } ++ ++ list = volume_list(); ++ if (list == NULL) { ++ ret = -1; ++ goto out; ++ } ++ ++ if (list->vols_len != 0) { ++ (*pruned)->names = util_common_calloc_s(sizeof(char*) * list->vols_len); ++ if ((*pruned)->names == NULL) { ++ ret = -1; ++ goto out; ++ } ++ ++ for (i = 0; i < list->vols_len; i++) { ++ if (volume_remove(list->vols[i]->name)) { ++ continue; ++ } ++ (*pruned)->names[(*pruned)->names_len] = util_strdup_s(list->vols[i]->name); ++ (*pruned)->names_len++; ++ } ++ } ++ ++out: ++ if (ret != 0) { ++ free_volume_names(*pruned); ++ *pruned = NULL; ++ } ++ free_volumes(list); ++ ++ return ret; ++} ++ ++void free_volume_names(struct volume_names *vns) ++{ ++ size_t i = 0; ++ ++ if (vns == NULL) { ++ return; ++ } ++ ++ for (i = 0; i < vns->names_len; i++) { ++ free(vns->names[i]); ++ vns->names[i] = NULL; ++ } ++ vns->names_len = 0; ++ free(vns->names); ++ vns->names = NULL; ++ free(vns); ++ ++ return; ++} ++ ++void free_volume(struct volume *vol) ++{ ++ if (vol == NULL) { ++ return; ++ } ++ free(vol->driver); ++ vol->driver = NULL; ++ free(vol->name); ++ vol->name = NULL; ++ free(vol->path); ++ vol->path = NULL; ++ free(vol->mount_point); ++ vol->mount_point = NULL; ++ free(vol); ++ return; ++} ++ ++void free_volumes(struct volumes *vols) ++{ ++ size_t i = 0; ++ if (vols == NULL) { ++ return; ++ } ++ for (i = 0; i < vols->vols_len; i++) { ++ free_volume(vols->vols[i]); ++ vols->vols[i] = NULL; ++ } ++ vols->vols_len = 0; ++ free(vols->vols); ++ vols->vols = NULL; ++ free(vols); ++ return; ++} +diff --git a/src/utils/console/console.c b/src/utils/console/console.c +index 70cea1f..d14eaab 100644 +--- a/src/utils/console/console.c ++++ b/src/utils/console/console.c +@@ -12,6 +12,7 @@ + * Create: 2018-11-08 + * Description: provide console definition + ******************************************************************************/ ++#include "console.h" + #include + #include + #include +@@ -23,7 +24,6 @@ + #include + #include + +-#include "console.h" + #include "mainloop.h" + #include "isula_libutils/log.h" + #include "utils.h" +diff --git a/src/utils/cutils/mainloop.c b/src/utils/cutils/mainloop.c +index f8333bd..07c54f4 100644 +--- a/src/utils/cutils/mainloop.c ++++ b/src/utils/cutils/mainloop.c +@@ -12,13 +12,13 @@ + * Create: 2018-11-08 + * Description: provide container mainloop functions + ******************************************************************************/ ++#include "mainloop.h" + #include + #include + #include + #include + #include + +-#include "mainloop.h" + #include "utils.h" + + struct epoll_loop_handler { +diff --git a/src/utils/cutils/map/map.c b/src/utils/cutils/map/map.c +index b810e5a..2fe96a5 100644 +--- a/src/utils/cutils/map/map.c ++++ b/src/utils/cutils/map/map.c +@@ -12,9 +12,9 @@ + * Create: 2018-11-08 + * Description: provide container map functions + ******************************************************************************/ ++#include "map.h" + #include + +-#include "map.h" + #include "isula_libutils/log.h" + #include "utils.h" + +diff --git a/src/utils/cutils/map/rb_tree.c b/src/utils/cutils/map/rb_tree.c +index 30f5330..ddae064 100644 +--- a/src/utils/cutils/map/rb_tree.c ++++ b/src/utils/cutils/map/rb_tree.c +@@ -106,16 +106,16 @@ rb_tree_t *rbtree_new(key_comparator comparator, key_value_freer kvfreer) + return tree; + } + +-static void rbtree_destory_all(rb_tree_t *tree, rb_node_t *node) ++static void rbtree_destroy_all(rb_tree_t *tree, rb_node_t *node) + { + if (node == tree->nil) { + return; + } + if (node->left != tree->nil) { +- rbtree_destory_all(tree, node->left); ++ rbtree_destroy_all(tree, node->left); + } + if (node->right != tree->nil) { +- rbtree_destory_all(tree, node->right); ++ rbtree_destroy_all(tree, node->right); + } + if (tree->kvfreer != NULL) { + tree->kvfreer(node->key, node->value); +@@ -128,7 +128,7 @@ void rbtree_clear(rb_tree_t *tree) + if (tree == NULL) { + return; + } +- rbtree_destory_all(tree, tree->root); ++ rbtree_destroy_all(tree, tree->root); + } + + void rbtree_free(rb_tree_t *tree) +diff --git a/src/utils/cutils/namespace.c b/src/utils/cutils/namespace.c +index 202dc55..2916c8b 100644 +--- a/src/utils/cutils/namespace.c ++++ b/src/utils/cutils/namespace.c +@@ -18,18 +18,18 @@ + + #include "utils.h" + +-char *connected_container(const char *mode) ++char *namespace_get_connected_container(const char *mode) + { + const char *p = mode != NULL ? (mode + strlen(SHARE_NAMESPACE_PREFIX)) : NULL; + +- if (is_container(mode)) { ++ if (namespace_is_container(mode)) { + return util_strdup_s(p); + } + + return NULL; + } + +-char *get_host_namespace_path(const char *type) ++char *namespace_get_host_namespace_path(const char *type) + { + if (type == NULL) { + return NULL; +diff --git a/src/utils/cutils/namespace.h b/src/utils/cutils/namespace.h +index 8d7e41a..cf76805 100644 +--- a/src/utils/cutils/namespace.h ++++ b/src/utils/cutils/namespace.h +@@ -58,7 +58,7 @@ typedef enum { + #define ETC_HOSTNAME "/etc/hostname" + #define RESOLV_CONF_PATH "/etc/resolv.conf" + +-static inline bool is_host(const char *mode) ++static inline bool namespace_is_host(const char *mode) + { + if (mode != NULL && strcmp(mode, SHARE_NAMESPACE_HOST) == 0) { + return true; +@@ -66,7 +66,7 @@ static inline bool is_host(const char *mode) + return false; + } + +-static inline bool is_none(const char *mode) ++static inline bool namespace_is_none(const char *mode) + { + if (mode != NULL && strcmp(mode, SHARE_NAMESPACE_NONE) == 0) { + return true; +@@ -74,7 +74,7 @@ static inline bool is_none(const char *mode) + return false; + } + +-static inline bool is_container(const char *mode) ++static inline bool namespace_is_container(const char *mode) + { + if (mode != NULL && strncmp(mode, SHARE_NAMESPACE_PREFIX, strlen(SHARE_NAMESPACE_PREFIX)) == 0) { + return true; +@@ -82,7 +82,7 @@ static inline bool is_container(const char *mode) + return false; + } + +-static inline bool is_shareable(const char *mode) ++static inline bool namespace_is_shareable(const char *mode) + { + if (mode != NULL && strcmp(mode, SHARE_NAMESPACE_SHAREABLE) == 0) { + return true; +@@ -90,8 +90,8 @@ static inline bool is_shareable(const char *mode) + return false; + } + +-char *connected_container(const char *mode); +-char *get_host_namespace_path(const char *type); ++char *namespace_get_connected_container(const char *mode); ++char *namespace_get_host_namespace_path(const char *type); + + #ifdef __cplusplus + } +diff --git a/src/utils/cutils/path.c b/src/utils/cutils/path.c +index 8bf9b67..f195257 100644 +--- a/src/utils/cutils/path.c ++++ b/src/utils/cutils/path.c +@@ -12,6 +12,7 @@ + * Create: 2018-11-08 + * Description: provide container path functions + ******************************************************************************/ ++#include "path.h" + #include + #include + #include +@@ -24,7 +25,6 @@ + #include + + #include "isula_libutils/log.h" +-#include "path.h" + #include "utils.h" + #include "utils_file.h" + +@@ -90,7 +90,7 @@ static int do_clean_path(const char *respath, const char *limit_respath, const c + return 0; + } + +-char *cleanpath(const char *path, char *realpath, size_t realpath_len) ++char *util_clean_path(const char *path, char *realpath, size_t realpath_len) + { + char *respath = NULL; + char *dest = NULL; +@@ -168,7 +168,7 @@ static int do_path_realloc(const char *start, const char *end, char **rpath, cha + } else { + new_size += PATH_MAX; + } +- nret = mem_realloc((void **)(&new_rpath), new_size, *rpath, PATH_MAX); ++ nret = util_mem_realloc((void **)(&new_rpath), new_size, *rpath, PATH_MAX); + if (nret) { + ERROR("Failed to realloc memory for files limit variables"); + return -1; +@@ -363,7 +363,7 @@ static char *eval_symlinks_in_scope(const char *fullpath, const char *rootpath) + return NULL; + } + +- root = cleanpath(rootpath, resroot, sizeof(resroot)); ++ root = util_clean_path(rootpath, resroot, sizeof(resroot)); + if (root == NULL) { + ERROR("Failed to get cleaned path"); + return NULL; +@@ -418,20 +418,20 @@ out: + return NULL; + } + +-char *follow_symlink_in_scope(const char *fullpath, const char *rootpath) ++char *util_follow_symlink_in_scope(const char *fullpath, const char *rootpath) + { + char resfull[PATH_MAX] = { 0 }; + char *full = NULL; + char resroot[PATH_MAX] = { 0 }; + char *root = NULL; + +- full = cleanpath(fullpath, resfull, sizeof(resfull)); ++ full = util_clean_path(fullpath, resfull, sizeof(resfull)); + if (full == NULL) { + ERROR("Failed to get cleaned path"); + return NULL; + } + +- root = cleanpath(rootpath, resroot, sizeof(resroot)); ++ root = util_clean_path(rootpath, resroot, sizeof(resroot)); + if (root == NULL) { + ERROR("Failed to get cleaned path"); + return NULL; +@@ -440,7 +440,7 @@ char *follow_symlink_in_scope(const char *fullpath, const char *rootpath) + return eval_symlinks_in_scope(full, root); + } + +-bool specify_current_dir(const char *path) ++bool util_specify_current_dir(const char *path) + { + char *dup = NULL; + char *base = NULL; +@@ -461,7 +461,7 @@ bool specify_current_dir(const char *path) + return res; + } + +-bool has_trailing_path_separator(const char *path) ++bool util_has_trailing_path_separator(const char *path) + { + return path != NULL && strlen(path) > 0 && (path[strlen(path) - 1] == '/'); + } +@@ -471,7 +471,7 @@ static void set_char_to_separator(char *p) + *p = '/'; + } + +-char *preserve_trailing_dot_or_separator(const char *cleanedpath, const char *originalpath) ++char *util_preserve_trailing_dot_or_separator(const char *cleanedpath, const char *originalpath) + { + int nret; + char respath[PATH_MAX + 3] = { 0 }; +@@ -490,21 +490,21 @@ char *preserve_trailing_dot_or_separator(const char *cleanedpath, const char *or + return NULL; + } + +- if (!specify_current_dir(cleanedpath) && specify_current_dir(originalpath)) { +- if (!has_trailing_path_separator(respath)) { ++ if (!util_specify_current_dir(cleanedpath) && util_specify_current_dir(originalpath)) { ++ if (!util_has_trailing_path_separator(respath)) { + set_char_to_separator(&respath[strlen(respath)]); + } + respath[strlen(respath)] = '.'; + } + +- if (!has_trailing_path_separator(respath) && has_trailing_path_separator(originalpath)) { ++ if (!util_has_trailing_path_separator(respath) && util_has_trailing_path_separator(originalpath)) { + set_char_to_separator(&respath[strlen(respath)]); + } + + return util_strdup_s(respath); + } + +-int filepath_split(const char *path, char **dir, char **base) ++int util_filepath_split(const char *path, char **dir, char **base) + { + ssize_t i; + char *dup = NULL; +@@ -539,7 +539,7 @@ int filepath_split(const char *path, char **dir, char **base) + return 0; + } + +-int split_dir_and_base_name(const char *path, char **dir, char **base) ++int util_split_dir_and_base_name(const char *path, char **dir, char **base) + { + char *dupdir = NULL; + char *dupbase = NULL; +@@ -561,7 +561,7 @@ int split_dir_and_base_name(const char *path, char **dir, char **base) + return 0; + } + +-char *get_resource_path(const char *rootpath, const char *path) ++char *util_get_resource_path(const char *rootpath, const char *path) + { + int nret; + char tmppath[PATH_MAX] = { 0 }; +@@ -572,14 +572,14 @@ char *get_resource_path(const char *rootpath, const char *path) + return NULL; + } + +- if (cleanpath(tmppath, fullpath, sizeof(fullpath)) == NULL) { ++ if (util_clean_path(tmppath, fullpath, sizeof(fullpath)) == NULL) { + return NULL; + } + +- return follow_symlink_in_scope(fullpath, rootpath); ++ return util_follow_symlink_in_scope(fullpath, rootpath); + } + +-int resolve_path(const char *rootpath, const char *path, char **resolvedpath, char **abspath) ++int util_resolve_path(const char *rootpath, const char *path, char **resolvedpath, char **abspath) + { + int ret = -1; + int nret; +@@ -599,24 +599,24 @@ int resolve_path(const char *rootpath, const char *path, char **resolvedpath, ch + return -1; + } + +- if (cleanpath(tmppath, cleanedpath, sizeof(cleanedpath)) == NULL) { ++ if (util_clean_path(tmppath, cleanedpath, sizeof(cleanedpath)) == NULL) { + ERROR("Failed to get cleaned path: %s", tmppath); + return -1; + } + +- *abspath = preserve_trailing_dot_or_separator(cleanedpath, tmppath); ++ *abspath = util_preserve_trailing_dot_or_separator(cleanedpath, tmppath); + if (*abspath == NULL) { + ERROR("Failed to preserve path"); + goto cleanup; + } + +- nret = filepath_split(*abspath, &dirpath, &basepath); ++ nret = util_filepath_split(*abspath, &dirpath, &basepath); + if (nret < 0) { + ERROR("Failed to split path"); + goto cleanup; + } + +- resolved_dir_path = get_resource_path(rootpath, dirpath); ++ resolved_dir_path = util_get_resource_path(rootpath, dirpath); + if (resolved_dir_path == NULL) { + ERROR("Failed to get resource path"); + goto cleanup; +@@ -648,17 +648,17 @@ cleanup: + return ret; + } + +-int split_path_dir_entry(const char *path, char **dir, char **base) ++int util_split_path_dir_entry(const char *path, char **dir, char **base) + { + #define EXTRA_LEN 3 + char cleaned[PATH_MAX + EXTRA_LEN] = { 0 }; + char *dup = NULL; + +- if (cleanpath(path, cleaned, PATH_MAX) == NULL) { ++ if (util_clean_path(path, cleaned, PATH_MAX) == NULL) { + ERROR("Failed to clean path"); + return -1; + } +- if (specify_current_dir(path)) { ++ if (util_specify_current_dir(path)) { + set_char_to_separator(&cleaned[strlen(cleaned)]); + cleaned[strlen(cleaned)] = '.'; + } +@@ -694,7 +694,7 @@ static char *find_realpath(const char *path) + } + // is not absolutely path + if (target[0] != '\0' && target[0] != '/') { +- if (split_path_dir_entry(iter_path, &parent, NULL) < 0) { ++ if (util_split_path_dir_entry(iter_path, &parent, NULL) < 0) { + goto out; + } + free(iter_path); +@@ -721,7 +721,7 @@ out: + return NULL; + } + +-int realpath_in_scope(const char *rootfs, const char *path, char **real_path) ++int util_realpath_in_scope(const char *rootfs, const char *path, char **real_path) + { + int ret = 0; + char full_path[PATH_MAX] = { 0 }; +@@ -734,7 +734,7 @@ int realpath_in_scope(const char *rootfs, const char *path, char **real_path) + ret = -1; + goto out; + } +- if (cleanpath(full_path, cleaned, PATH_MAX) == NULL) { ++ if (util_clean_path(full_path, cleaned, PATH_MAX) == NULL) { + ERROR("Failed to clean path: %s", full_path); + ret = -1; + goto out; +diff --git a/src/utils/cutils/path.h b/src/utils/cutils/path.h +index 21986ec..7f926b2 100644 +--- a/src/utils/cutils/path.h ++++ b/src/utils/cutils/path.h +@@ -22,34 +22,33 @@ extern "C" { + #endif + + /* +- * cleanpath is similar to realpath of glibc, but not expands symbolic links, ++ * util_clean_path is similar to realpath of glibc, but not expands symbolic links, + * and not check the existence of components of the path. + */ +-char *cleanpath(const char *path, char *realpath, size_t realpath_len); ++char *util_clean_path(const char *path, char *realpath, size_t realpath_len); + +-bool specify_current_dir(const char *path); ++bool util_specify_current_dir(const char *path); + +-char *follow_symlink_in_scope(const char *fullpath, const char *rootpath); ++char *util_follow_symlink_in_scope(const char *fullpath, const char *rootpath); + +-int split_dir_and_base_name(const char *path, char **dir, char **base); ++int util_split_dir_and_base_name(const char *path, char **dir, char **base); + +-int filepath_split(const char *path, char **dir, char **base); ++int util_filepath_split(const char *path, char **dir, char **base); + +-char *get_resource_path(const char *rootpath, const char *path); ++char *util_get_resource_path(const char *rootpath, const char *path); + +-int resolve_path(const char *rootpath, const char *path, char **resolvedpath, char **abspath); ++int util_resolve_path(const char *rootpath, const char *path, char **resolvedpath, char **abspath); + +-bool has_trailing_path_separator(const char *path); ++bool util_has_trailing_path_separator(const char *path); + +-char *preserve_trailing_dot_or_separator(const char *cleanedpath, const char *originalpath); ++char *util_preserve_trailing_dot_or_separator(const char *cleanedpath, const char *originalpath); + +-int split_path_dir_entry(const char *path, char **dir, char **base); ++int util_split_path_dir_entry(const char *path, char **dir, char **base); + +-int realpath_in_scope(const char *rootfs, const char *path, char **real_path); ++int util_realpath_in_scope(const char *rootfs, const char *path, char **real_path); + + #ifdef __cplusplus + } + #endif + + #endif +- +diff --git a/src/utils/cutils/utils.c b/src/utils/cutils/utils.c +index e9ef33b..6ce161e 100644 +--- a/src/utils/cutils/utils.c ++++ b/src/utils/cutils/utils.c +@@ -14,6 +14,7 @@ + *******************************************************************************/ + + #define _GNU_SOURCE ++#include "utils.h" + #include + #include + #include +@@ -35,7 +36,6 @@ + #include + #include + +-#include "utils.h" + #include "isula_libutils/log.h" + #include "isula_libutils/json_common.h" + #include "utils_array.h" +@@ -45,9 +45,7 @@ + #include "utils_string.h" + #include "utils_verify.h" + +-#define MAX_NUM_STR_LEN 21 +- +-int mem_realloc(void **newptr, size_t newsize, void *oldptr, size_t oldsize) ++int util_mem_realloc(void **newptr, size_t newsize, void *oldptr, size_t oldsize) + { + void *tmp = NULL; + +@@ -105,7 +103,7 @@ static int util_read_pipe(int pipe_fd, char **out_buf, size_t *out_buf_size, siz + } + + new_size = old_size + PIPE_BUF + 1; +- ret = mem_realloc((void *)(&tmp), new_size, (void *)buffer, old_size); ++ ret = util_mem_realloc((void *)(&tmp), new_size, (void *)buffer, old_size); + if (ret != 0) { + ERROR("Memory out"); + ret = -1; +@@ -244,20 +242,6 @@ int util_sig_parse(const char *sig_name) + return -1; + } + +-bool util_check_signal_valid(int sig) +-{ +- size_t i; +- const struct signame signames[] = SIGNAL_MAP_DEFAULT; +- +- for (i = 0; i < sizeof(signames) / sizeof(signames[0]); i++) { +- if (signames[i].num == sig) { +- return true; +- } +- } +- +- return false; +-} +- + void *util_smart_calloc_s(size_t unit_size, size_t count) + { + if (unit_size == 0) { +@@ -296,7 +280,7 @@ char *util_strdup_s(const char *src) + return dst; + } + +-int wait_for_pid(pid_t pid) ++int util_wait_for_pid(pid_t pid) + { + int st; + int nret = 0; +@@ -318,7 +302,7 @@ rep: + return 0; + } + +-int wait_for_pid_status(pid_t pid) ++int util_wait_for_pid_status(pid_t pid) + { + int st; + int nret = 0; +@@ -706,12 +690,12 @@ bool util_exec_top_cmd(exec_top_func_t cb_func, char **args, const char *pid_arg + if (stdout_close_flag != 0 && stderr_close_flag != 0) { + break; + } +- usleep_nointerupt(1000); ++ util_usleep_nointerupt(1000); + } + + marshal_stderr_msg(&stderr_buffer, &stderr_real_size); + +- status = wait_for_pid_status(pid); ++ status = util_wait_for_pid_status(pid); + + ret = deal_with_result_of_waitpid(status, &stderr_buffer, stderr_real_size); + +@@ -840,12 +824,12 @@ bool util_exec_cmd(exec_func_t cb_func, void *args, const char *stdin_msg, char + if (stdout_close_flag != 0 && stderr_close_flag != 0) { + break; + } +- usleep_nointerupt(1000); ++ util_usleep_nointerupt(1000); + } + + marshal_stderr_msg(&stderr_buffer, &stderr_real_size); + +- status = wait_for_pid_status(pid); ++ status = util_wait_for_pid_status(pid); + + ret = deal_with_result_of_waitpid(status, &stderr_buffer, stderr_real_size); + +@@ -857,7 +841,7 @@ out: + return ret; + } + +-char **get_backtrace(void) ++char **util_get_backtrace(void) + { + #define BACKTRACE_SIZE 16 + int addr_cnts; +@@ -877,78 +861,6 @@ char **get_backtrace(void) + return syms; + } + +-static long long get_time_unit(int unit) +-{ +- long long u[255] = { 0 }; +- +- u['M'] = Time_Milli; +- u['s'] = Time_Second; +- u['m'] = Time_Minute; +- u['h'] = Time_Hour; +- +- return u[unit]; +-} +- +-static int get_time_ns(long long *pns, long long unit) +-{ +- if (unit == 0) { +- return -1; +- } +- +- if (INT64_MAX / *pns >= unit) { +- *pns *= unit; +- return 0; +- } +- +- return -1; +-} +- +-int util_parse_time_str_to_nanoseconds(const char *value, int64_t *nanoseconds) +-{ +- int ret = 0; +- long long tmp = 0; +- char unit = 0; +- size_t len = 0; +- char *num_str = NULL; +- +- if (value == NULL || nanoseconds == NULL) { +- return -1; +- } +- +- if (util_reg_match("^([0-9]+)+(ms|s|m|h)$", value) != 0) { +- return -1; +- } +- num_str = util_strdup_s(value); +- len = strlen(value); +- +- if (strstr(value, "ms") == NULL) { +- unit = *(value + len - 1); +- *(num_str + len - 1) = '\0'; +- } else { +- unit = 'M'; +- *(num_str + len - 2) = '\0'; +- } +- ret = util_safe_llong(num_str, &tmp); +- if (ret < 0) { +- ERROR("Illegal unsigned integer: %s", num_str); +- ret = -1; +- goto out; +- } +- if (tmp == 0) { +- goto out; +- } +- +- ret = get_time_ns(&tmp, get_time_unit(unit)); +- if (ret != 0) { +- ERROR("failed get nano seconds for %s", num_str); +- } +- *nanoseconds = (int64_t)tmp; +- +-out: +- free(num_str); +- return ret; +-} +- + /* isulad: get starttime of process pid */ + proc_t *util_get_process_proc_info(pid_t pid) + { +@@ -1031,7 +943,7 @@ int util_env_insert(char ***penv, size_t *penv_len, const char *key, size_t key_ + return -1; + } + +- ret = mem_realloc((void **)(&temp), (env_len + 1) * sizeof(char *), env, env_len * sizeof(char *)); ++ ret = util_mem_realloc((void **)(&temp), (env_len + 1) * sizeof(char *), env, env_len * sizeof(char *)); + if (ret != 0) { + ERROR("Failed to realloc memory for envionment variables"); + return -1; +@@ -1117,38 +1029,7 @@ out: + return ret; + } + +-char *util_str_token(char **input, const char *delimiter) +-{ +- char *str = NULL; +- char *delimiter_found = NULL; +- char *tok = NULL; +- size_t tok_length = 0; +- +- if (input == NULL || delimiter == NULL) { +- return NULL; +- } +- +- str = *input; +- +- if (str == NULL) { +- return NULL; +- } +- delimiter_found = strstr(str, delimiter); +- if (delimiter_found != NULL) { +- tok_length = delimiter_found - str; +- } else { +- tok_length = strlen(str); +- } +- tok = strndup(str, tok_length); +- if (tok == NULL) { +- ERROR("strndup failed"); +- return NULL; +- } +- *input = delimiter_found != NULL ? delimiter_found + strlen(delimiter) : NULL; +- return tok; +-} +- +-bool pid_max_kernel_namespaced() ++bool util_check_pid_max_kernel_namespaced() + { + bool ret = false; + FILE *fp = NULL; +@@ -1172,37 +1053,7 @@ out: + return ret; + } + +-bool check_sysctl_valid(const char *sysctl_key) +-{ +- size_t i = 0; +- size_t full_keys_len = 0; +- size_t key_prefixes_len = 0; +- const char *sysctl_full_keys[] = { "kernel.msgmax", "kernel.msgmnb", "kernel.msgmni", "kernel.sem", +- "kernel.shmall", "kernel.shmmax", "kernel.shmmni", "kernel.shm_rmid_forced" +- }; +- const char *sysctl_key_prefixes[] = { "net.", "fs.mqueue." }; +- +- if (sysctl_key == NULL) { +- return false; +- } +- +- full_keys_len = sizeof(sysctl_full_keys) / sizeof(char *); +- key_prefixes_len = sizeof(sysctl_key_prefixes) / sizeof(char *); +- +- for (i = 0; i < full_keys_len; i++) { +- if (strcmp(sysctl_full_keys[i], sysctl_key) == 0) { +- return true; +- } +- } +- for (i = 0; i < key_prefixes_len; i++) { +- if (strncmp(sysctl_key_prefixes[i], sysctl_key, strlen(sysctl_key_prefixes[i])) == 0) { +- return true; +- } +- } +- return false; +-} +- +-void free_sensitive_string(char *str) ++void util_free_sensitive_string(char *str) + { + if (!util_valid_str(str)) { + goto out; +@@ -1214,7 +1065,7 @@ out: + free(str); + } + +-void memset_sensitive_string(char *str) ++void util_memset_sensitive_string(char *str) + { + if (!util_valid_str(str)) { + return; +@@ -1223,113 +1074,6 @@ void memset_sensitive_string(char *str) + (void)memset(str, 0, strlen(str)); + } + +-static char *get_mtpoint(const char *line) +-{ +- int i; +- const char *tmp = NULL; +- char *pend = NULL; +- char *sret = NULL; +- size_t len; +- +- if (line == NULL) { +- goto err_out; +- } +- +- tmp = line; +- +- for (i = 0; i < 4; i++) { +- tmp = strchr(tmp, ' '); +- if (tmp == NULL) { +- goto err_out; +- } +- tmp++; +- } +- pend = strchr(tmp, ' '); +- if ((pend == NULL) || pend == tmp) { +- goto err_out; +- } +- +- /* stuck a \0 after the mountpoint */ +- len = (size_t)(pend - tmp); +- sret = util_common_calloc_s(len + 1); +- if (sret == NULL) { +- goto err_out; +- } +- (void)memcpy(sret, tmp, len); +- sret[len] = '\0'; +- +-err_out: +- return sret; +-} +- +-bool detect_mount(const char *path) +-{ +- FILE *fp = NULL; +- char *line = NULL; +- char *mountpoint = NULL; +- size_t length = 0; +- bool bret = false; +- +- fp = util_fopen("/proc/self/mountinfo", "r"); +- if (fp == NULL) { +- ERROR("Failed opening /proc/self/mountinfo"); +- return false; +- } +- +- while (getline(&line, &length, fp) != -1) { +- mountpoint = get_mtpoint(line); +- if (mountpoint == NULL) { +- INFO("Error reading mountinfo: bad line '%s'", line); +- continue; +- } +- if (strcmp(mountpoint, path) == 0) { +- free(mountpoint); +- bret = true; +- goto out; +- } +- free(mountpoint); +- } +-out: +- fclose(fp); +- free(line); +- return bret; +-} +- +-bool util_deal_with_mount_info(mount_info_call_back_t cb, const char *pattern) +-{ +- FILE *fp = NULL; +- char *line = NULL; +- char *mountpoint = NULL; +- size_t length = 0; +- bool bret = true; +- int nret = 0; +- +- fp = util_fopen("/proc/self/mountinfo", "r"); +- if (fp == NULL) { +- ERROR("Failed opening /proc/self/mountinfo"); +- return false; +- } +- +- while (getline(&line, &length, fp) != -1) { +- mountpoint = get_mtpoint(line); +- if (mountpoint == NULL) { +- INFO("Error reading mountinfo: bad line '%s'", line); +- continue; +- } +- nret = cb(mountpoint, pattern); +- free(mountpoint); +- if (nret != 0) { +- bret = false; +- goto out; +- } +- } +- +-out: +- fclose(fp); +- free(line); +- return bret; +-} +- + static int set_echo_back(bool echo_back) + { + struct termios old, new; +@@ -1429,7 +1173,7 @@ static int util_input(char *buf, size_t maxlen, bool echo_back) + return ret; + } + +-// Get input from stdin, echo back if get any charactor. ++// Get input from stdin, echo back if get any character. + int util_input_echo(char *buf, size_t maxlen) + { + return util_input(buf, maxlen, true); +@@ -1441,7 +1185,7 @@ int util_input_noecho(char *buf, size_t maxlen) + return util_input(buf, maxlen, false); + } + +-void usleep_nointerupt(unsigned long usec) ++void util_usleep_nointerupt(unsigned long usec) + { + #define SECOND_TO_USECOND_MUTIPLE 1000000 + int ret = 0; +@@ -1492,71 +1236,6 @@ int util_generate_random_str(char *id, size_t len) + return 0; + } + +-void add_array_elem(char **array, size_t total, size_t *pos, const char *elem) +-{ +- if (*pos + 1 >= total - 1) { +- return; +- } +- array[*pos] = util_strdup_s(elem); +- *pos += 1; +-} +- +-void add_array_kv(char **array, size_t total, size_t *pos, const char *k, const char *v) +-{ +- if (k == NULL || v == NULL) { +- return; +- } +- add_array_elem(array, total, pos, k); +- add_array_elem(array, total, pos, v); +-} +- +-int util_validate_env(const char *env, char **dst) +-{ +- int ret = 0; +- char *value = NULL; +- +- char **arr = util_string_split_multi(env, '='); +- if (arr == NULL) { +- ERROR("Failed to split env string"); +- return -1; +- } +- if (strlen(arr[0]) == 0) { +- ERROR("Invalid environment variable: %s", env); +- ret = -1; +- goto out; +- } +- +- if (util_array_len((const char **)arr) > 1) { +- *dst = util_strdup_s(env); +- goto out; +- } +- +- value = getenv(env); +- if (value == NULL) { +- *dst = NULL; +- goto out; +- } else { +- int sret; +- size_t len = strlen(env) + 1 + strlen(value) + 1; +- *dst = (char *)util_common_calloc_s(len); +- if (*dst == NULL) { +- ERROR("Out of memory"); +- ret = -1; +- goto out; +- } +- sret = snprintf(*dst, len, "%s=%s", env, value); +- if (sret < 0 || (size_t)sret >= len) { +- ERROR("Failed to compose env string"); +- ret = -1; +- goto out; +- } +- } +- +-out: +- util_free_array(arr); +- return ret; +-} +- + int util_check_inherited_exclude_fds(bool closeall, int *fds_to_ignore, size_t len_fds) + { + struct dirent *pdirent = NULL; +@@ -1613,42 +1292,6 @@ restart: + return 0; + } + +-int get_cpu_num_cores(void) +-{ +- int ncpus = (int)sysconf(_SC_NPROCESSORS_ONLN); +- if (ncpus < 1) { +- ERROR("Cannot determine number of CPUs: assuming 1\n"); +- ncpus = 1; +- } +- return ncpus; +-} +- +-char *util_uint_to_string(long long unsigned int data) +-{ +- char numstr[MAX_NUM_STR_LEN] = { 0 }; +- int ret; +- +- ret = snprintf(numstr, sizeof(numstr), "%llu", data); +- if (ret < 0 || (size_t)ret >= sizeof(numstr)) { +- return NULL; +- } +- +- return util_strdup_s(numstr); +-} +- +-char *util_int_to_string(long long int data) +-{ +- char numstr[MAX_NUM_STR_LEN] = { 0 }; +- int ret; +- +- ret = snprintf(numstr, sizeof(numstr), "%lld", data); +- if (ret < 0 || (size_t)ret >= sizeof(numstr)) { +- return NULL; +- } +- +- return util_strdup_s(numstr); +-} +- + static char *get_cpu_variant() + { + char *variant = NULL; +@@ -1679,7 +1322,7 @@ static char *get_cpu_variant() + util_trim_newline(start_pos); + start_pos = util_trim_space(start_pos); + +- variant = strings_to_lower(start_pos); ++ variant = util_strings_to_lower(start_pos); + + out: + free(cpuinfo); +@@ -1688,7 +1331,7 @@ out: + return variant; + } + +-int normalized_host_os_arch(char **host_os, char **host_arch, char **host_variant) ++int util_normalized_host_os_arch(char **host_os, char **host_arch, char **host_variant) + { + int ret = 0; + struct utsname uts; +@@ -1705,7 +1348,7 @@ int normalized_host_os_arch(char **host_os, char **host_arch, char **host_varian + goto out; + } + +- *host_os = strings_to_lower(uts.sysname); ++ *host_os = util_strings_to_lower(uts.sysname); + + if (strcasecmp("i386", uts.machine) == 0) { + *host_arch = util_strdup_s("386"); +@@ -1792,4 +1435,81 @@ out: + free(proc); + free(p_proc); + return ret; +-} +\ No newline at end of file ++} ++ ++void util_parse_user_group(const char *username, char **user, char **group, char **tmp_dup) ++{ ++ char *tmp = NULL; ++ char *pdot = NULL; ++ ++ if (user == NULL || group == NULL || tmp_dup == NULL) { ++ return; ++ } ++ ++ if (username != NULL) { ++ tmp = util_strdup_s(username); ++ ++ // for free tmp in caller ++ *tmp_dup = tmp; ++ ++ pdot = strstr(tmp, ":"); ++ if (pdot != NULL) { ++ *pdot = '\0'; ++ if (pdot != tmp) { ++ // User found ++ *user = tmp; ++ } ++ if (*(pdot + 1) != '\0') { ++ // group found ++ *group = pdot + 1; ++ } ++ } else { ++ // No : found ++ if (*tmp != '\0') { ++ *user = tmp; ++ } ++ } ++ } ++ ++ return; ++} ++ ++defs_map_string_object * dup_map_string_empty_object(defs_map_string_object *src) ++{ ++ int ret = 0; ++ size_t i = 0; ++ defs_map_string_object *dst = NULL; ++ ++ if (src == NULL) { ++ ERROR("invalid null param"); ++ return NULL; ++ } ++ ++ dst = util_common_calloc_s(sizeof(defs_map_string_object)); ++ if (dst == NULL) { ++ ERROR("out of memory"); ++ return NULL; ++ } ++ ++ dst->keys = util_common_calloc_s(src->len * sizeof(char*)); ++ dst->values = util_common_calloc_s(src->len * sizeof(defs_map_string_object_element*)); ++ if (dst->keys == NULL || dst->values == NULL) { ++ ERROR("Out of memory"); ++ ret = -1; ++ goto out; ++ } ++ ++ for (i = 0; i < src->len; i++) { ++ dst->keys[i] = util_strdup_s(src->keys[i]); ++ dst->values[i] = NULL; ++ } ++ dst->len = src->len; ++ ++out: ++ if (ret != 0) { ++ free_defs_map_string_object(dst); ++ dst = NULL; ++ } ++ ++ return dst; ++} +diff --git a/src/utils/cutils/utils.h b/src/utils/cutils/utils.h +index ca3afb1..f638d50 100644 +--- a/src/utils/cutils/utils.h ++++ b/src/utils/cutils/utils.h +@@ -40,6 +40,7 @@ + #include "utils_fs.h" + #include "utils_regex.h" + #include "utils_verify.h" ++#include "isula_libutils/defs.h" + + #ifdef __cplusplus + extern "C" { +@@ -106,31 +107,11 @@ extern "C" { + #define SIZE_TB (1024LL * SIZE_GB) + #define SIZE_PB (1024LL * SIZE_TB) + +-#define Time_Nano 1LL +-#define Time_Micro (1000LL * Time_Nano) +-#define Time_Milli (1000LL * Time_Micro) +-#define Time_Second (1000LL * Time_Milli) +-#define Time_Minute (60LL * Time_Second) +-#define Time_Hour (60LL * Time_Minute) +- + /* Max regular file size for isula\isulad to open as same as docker */ + #define REGULAR_FILE_SIZE (10 * SIZE_MB) + +-#define rFC339Local "2006-01-02T15:04:05" +-#define rFC339NanoLocal "2006-01-02T15:04:05.999999999" +-#define dateLocal "2006-01-02" +-#define defaultContainerTime "0001-01-01T00:00:00Z" + #define TIME_STR_SIZE 512 + +-#define HOST_NAME_REGEXP \ +- "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*" \ +- "([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])$" +-#define __TagPattern "^:([A-Za-z_0-9][A-Za-z_0-9.-]{0,127})$" +-#define __NamePattern \ +- "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])" \ +- "((\\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+)?(:[0-9]+)?/)?[a-z0-9]" \ +- "+((([._]|__|[-]*)[a-z0-9]+)+)?((/[a-z0-9]+((([._]|__|[-]*)[a-z0-9]+)+)?)+)?$" +- + // native umask value + #define ANNOTATION_UMAKE_KEY "native.umask" + #define UMASK_NORMAL "normal" +@@ -319,7 +300,7 @@ struct signame { + } \ + } while (0) + +-int mem_realloc(void **newptr, size_t newsize, void *oldptr, size_t oldsize); ++int util_mem_realloc(void **newptr, size_t newsize, void *oldptr, size_t oldsize); + + int util_check_inherited(bool closeall, int fd_to_ignore); + +@@ -331,7 +312,7 @@ void *util_common_calloc_s(size_t size); + + char *util_strdup_s(const char *src); + +-int wait_for_pid(pid_t pid); ++int util_wait_for_pid(pid_t pid); + + void util_contain_errmsg(const char *errmsg, int *exit_code); + +@@ -343,7 +324,7 @@ proc_t *util_stat2proc(const char *s, size_t len); + + bool util_process_alive(pid_t pid, unsigned long long start_time); + +-int wait_for_pid_status(pid_t pid); ++int util_wait_for_pid_status(pid_t pid); + + typedef void (*exec_func_t)(void *args); + bool util_exec_cmd(exec_func_t cb_func, void *args, const char *stdin_msg, char **stdout_msg, char **stderr_msg); +@@ -352,9 +333,7 @@ typedef void (*exec_top_func_t)(char **args, const char *pid_args, size_t args_l + bool util_exec_top_cmd(exec_top_func_t cb_func, char **args, const char *pid_args, size_t args_len, char **stdout_msg, + char **stderr_msg); + +-char **get_backtrace(void); +- +-int util_parse_time_str_to_nanoseconds(const char *value, int64_t *nanoseconds); ++char **util_get_backtrace(void); + + proc_t *util_get_process_proc_info(pid_t pid); + +@@ -364,46 +343,30 @@ int util_env_insert(char ***penv, size_t *penv_len, const char *key, size_t key_ + int util_env_set_val(char ***penv, const size_t *penv_len, const char *key, size_t key_len, const char *newkv); + char *util_env_get_val(char **env, size_t env_len, const char *key, size_t key_len); + +-char *util_str_token(char **input, const char *delimiter); +-bool check_sysctl_valid(const char *sysctl_key); +-bool pid_max_kernel_namespaced(); +-void free_sensitive_string(char *str); +-void memset_sensitive_string(char *str); ++bool util_check_pid_max_kernel_namespaced(); ++ ++void util_free_sensitive_string(char *str); ++void util_memset_sensitive_string(char *str); + + int util_input_readall(char *buf, size_t maxlen); + int util_input_echo(char *buf, size_t maxlen); + int util_input_noecho(char *buf, size_t maxlen); + +-bool util_check_signal_valid(int sig); +- +-void usleep_nointerupt(unsigned long usec); ++void util_usleep_nointerupt(unsigned long usec); + + int util_generate_random_str(char *id, size_t len); + +-void add_array_elem(char **array, size_t total, size_t *pos, const char *elem); +- +-void add_array_kv(char **array, size_t total, size_t *pos, const char *k, const char *v); +- +-typedef int (*mount_info_call_back_t)(const char *, const char *); +-bool util_deal_with_mount_info(mount_info_call_back_t cb, const char *); +- +-int util_validate_env(const char *env, char **dst); +- + int util_check_inherited_exclude_fds(bool closeall, int *fds_to_ignore, size_t len_fds); + +-int get_cpu_num_cores(void); +- +-char *util_uint_to_string(long long unsigned int data); ++char *util_without_sha256_prefix(char *digest); + +-char *util_int_to_string(long long int data); ++int util_normalized_host_os_arch(char **host_os, char **host_arch, char **host_variant); + +-char *without_sha256_prefix(char *digest); +- +-int normalized_host_os_arch(char **host_os, char **host_arch, char **host_variant); ++int util_read_pid_ppid_info(uint32_t pid, pid_ppid_info_t *pid_info); + +-char *util_full_digest_str(char *str); ++void util_parse_user_group(const char *username, char **user, char **group, char **tmp_dup); + +-int util_read_pid_ppid_info(uint32_t pid, pid_ppid_info_t *pid_info); ++defs_map_string_object * dup_map_string_empty_object(defs_map_string_object *src); + + #ifdef __cplusplus + } +diff --git a/src/utils/cutils/utils_aes.c b/src/utils/cutils/utils_aes.c +index 1674b47..67ab32c 100644 +--- a/src/utils/cutils/utils_aes.c ++++ b/src/utils/cutils/utils_aes.c +@@ -14,6 +14,7 @@ + *******************************************************************************/ + + #define _GNU_SOURCE ++#include "utils_aes.h" + #include + #include + #include +@@ -23,7 +24,6 @@ + + #include "isula_libutils/log.h" + #include "utils.h" +-#include "utils_aes.h" + #include "openssl/aes.h" + #include "openssl/evp.h" + #include "utils_file.h" +diff --git a/src/utils/cutils/utils_base64.c b/src/utils/cutils/utils_base64.c +index f82da2b..2eb6b6b 100644 +--- a/src/utils/cutils/utils_base64.c ++++ b/src/utils/cutils/utils_base64.c +@@ -14,6 +14,7 @@ + *******************************************************************************/ + + #define _GNU_SOURCE ++#include "utils_base64.h" + #include + #include + #include +@@ -21,7 +22,6 @@ + #include + + #include "isula_libutils/log.h" +-#include "utils_base64.h" + #include "openssl/bio.h" + #include "utils.h" + +diff --git a/src/utils/cutils/utils_convert.c b/src/utils/cutils/utils_convert.c +index c14e147..077b062 100644 +--- a/src/utils/cutils/utils_convert.c ++++ b/src/utils/cutils/utils_convert.c +@@ -20,6 +20,10 @@ + #include + #include + #include ++#include ++#include "utils.h" ++ ++#define MAX_NUM_STR_LEN 21 + + static inline bool is_invalid_error_str(const char *err_str, const char *numstr) + { +@@ -107,6 +111,29 @@ int util_safe_uint(const char *numstr, unsigned int *converted) + return 0; + } + ++int util_safe_uint64(const char *numstr, uint64_t *converted) ++{ ++ char *err_str = NULL; ++ uint64_t ull; ++ ++ if (numstr == NULL || converted == NULL) { ++ return -EINVAL; ++ } ++ ++ errno = 0; ++ ull = strtoull(numstr, &err_str, 0); ++ if (errno > 0) { ++ return -errno; ++ } ++ ++ if (is_invalid_error_str(err_str, numstr)) { ++ return -EINVAL; ++ } ++ ++ *converted = (uint64_t)ull; ++ return 0; ++} ++ + int util_safe_llong(const char *numstr, long long *converted) + { + char *err_str = NULL; +@@ -180,3 +207,28 @@ int util_str_to_bool(const char *boolstr, bool *converted) + return 0; + } + ++char *util_uint_to_string(long long unsigned int data) ++{ ++ char numstr[MAX_NUM_STR_LEN] = { 0 }; ++ int ret; ++ ++ ret = snprintf(numstr, sizeof(numstr), "%llu", data); ++ if (ret < 0 || (size_t)ret >= sizeof(numstr)) { ++ return NULL; ++ } ++ ++ return util_strdup_s(numstr); ++} ++ ++char *util_int_to_string(long long int data) ++{ ++ char numstr[MAX_NUM_STR_LEN] = { 0 }; ++ int ret; ++ ++ ret = snprintf(numstr, sizeof(numstr), "%lld", data); ++ if (ret < 0 || (size_t)ret >= sizeof(numstr)) { ++ return NULL; ++ } ++ ++ return util_strdup_s(numstr); ++} +\ No newline at end of file +diff --git a/src/utils/cutils/utils_convert.h b/src/utils/cutils/utils_convert.h +index 5b4ae3d..e1c70ba 100644 +--- a/src/utils/cutils/utils_convert.h ++++ b/src/utils/cutils/utils_convert.h +@@ -28,10 +28,12 @@ int util_safe_uint(const char *numstr, unsigned int *converted); + int util_safe_llong(const char *numstr, long long *converted); + int util_safe_strtod(const char *numstr, double *converted); + int util_str_to_bool(const char *boolstr, bool *converted); ++int util_safe_uint64(const char *numstr, uint64_t *converted); ++char *util_uint_to_string(long long unsigned int data); ++char *util_int_to_string(long long int data); + + #ifdef __cplusplus + } + #endif + + #endif // UTILS_CUTILS_UTILS_CONVERT_H +- +diff --git a/src/utils/cutils/utils_file.c b/src/utils/cutils/utils_file.c +index 266afea..aa0980f 100644 +--- a/src/utils/cutils/utils_file.c ++++ b/src/utils/cutils/utils_file.c +@@ -29,6 +29,9 @@ + #include + #include + #include ++#include ++#include ++#include + + #include "constants.h" + #include "isula_libutils/log.h" +@@ -38,6 +41,7 @@ + #include "utils_array.h" + #include "utils_string.h" + ++int copy_dir_recursive(char *copy_dst, char *copy_src, map_t *inodes); + static void do_calculate_dir_size_without_hardlink(const char *dirpath, int recursive_depth, int64_t *total_size, + int64_t *total_inode, map_t *map); + +@@ -280,7 +284,7 @@ static int recursive_rmdir_helper(const char *dirpath, int recursive_depth, int + struct dirent *pdirent = NULL; + DIR *directory = NULL; + int failure = 0; +- char fname[MAXPATHLEN]; ++ char fname[PATH_MAX]; + + directory = opendir(dirpath); + if (directory == NULL) { +@@ -298,8 +302,8 @@ static int recursive_rmdir_helper(const char *dirpath, int recursive_depth, int + + (void)memset(fname, 0, sizeof(fname)); + +- pathname_len = snprintf(fname, MAXPATHLEN, "%s/%s", dirpath, pdirent->d_name); +- if (pathname_len < 0 || pathname_len >= MAXPATHLEN) { ++ pathname_len = snprintf(fname, PATH_MAX, "%s/%s", dirpath, pdirent->d_name); ++ if (pathname_len < 0 || pathname_len >= PATH_MAX) { + ERROR("Pathname too long"); + failure = 1; + continue; +@@ -413,7 +417,7 @@ char *util_path_join(const char *dir, const char *file) + return NULL; + } + +- if (cleanpath(path, cleaned, sizeof(cleaned)) == NULL) { ++ if (util_clean_path(path, cleaned, sizeof(cleaned)) == NULL) { + ERROR("Failed to clean path: %s", path); + return NULL; + } +@@ -547,13 +551,13 @@ char *util_human_size_decimal(int64_t val) + char out[16] = { 0 }; /* 16 is enough, format like: 123.456 MB */ + + if (val >= gb) { +- nret = snprintf(out, sizeof(out), "%.3lf GB", ((double)val / gb)); ++ nret = snprintf(out, sizeof(out), "%.3lfGB", ((double)val / gb)); + } else if (val >= mb) { +- nret = snprintf(out, sizeof(out), "%.3lf MB", ((double)val / mb)); ++ nret = snprintf(out, sizeof(out), "%.3lfMB", ((double)val / mb)); + } else if (val >= kb) { +- nret = snprintf(out, sizeof(out), "%.3lf KB", ((double)val / kb)); ++ nret = snprintf(out, sizeof(out), "%.3lfKB", ((double)val / kb)); + } else { +- nret = snprintf(out, sizeof(out), "%lld B", (long long int)val); ++ nret = snprintf(out, sizeof(out), "%lldB", (long long int)val); + } + if (nret < 0 || nret >= sizeof(out)) { + ERROR("Failed to print string"); +@@ -567,7 +571,7 @@ int util_open(const char *filename, int flags, mode_t mode) + { + char rpath[PATH_MAX] = { 0x00 }; + +- if (cleanpath(filename, rpath, sizeof(rpath)) == NULL) { ++ if (util_clean_path(filename, rpath, sizeof(rpath)) == NULL) { + return -1; + } + if (mode) { +@@ -589,8 +593,8 @@ FILE *util_fopen(const char *filename, const char *mode) + return NULL; + } + +- if (cleanpath(filename, rpath, sizeof(rpath)) == NULL) { +- ERROR("cleanpath failed"); ++ if (util_clean_path(filename, rpath, sizeof(rpath)) == NULL) { ++ ERROR("util_clean_path failed"); + return NULL; + } + if (strncmp(mode, "a+", 2) == 0) { +@@ -840,7 +844,7 @@ int64_t util_file_size(const char *filename) + return (int64_t)st.st_size; + } + +-int util_scan_subdirs(const char *directory, subdir_callback_t cb) ++int util_scan_subdirs(const char *directory, subdir_callback_t cb, void *context) + { + DIR *dir = NULL; + struct dirent *direntp = NULL; +@@ -858,11 +862,11 @@ int util_scan_subdirs(const char *directory, subdir_callback_t cb) + + direntp = readdir(dir); + for (; direntp != NULL; direntp = readdir(dir)) { +- if (strncmp(direntp->d_name, ".", 1) == 0) { ++ if (strncmp(direntp->d_name, ".", PATH_MAX) == 0 || strncmp(direntp->d_name, "..", PATH_MAX) == 0) { + continue; + } + +- if (!cb(directory, direntp)) { ++ if (!cb(directory, direntp, context)) { + ERROR("Dealwith subdir: %s failed", direntp->d_name); + ret = -1; + break; +@@ -892,7 +896,7 @@ int util_list_all_subdir(const char *directory, char ***out) + } + direntp = readdir(dir); + for (; direntp != NULL; direntp = readdir(dir)) { +- if (strncmp(direntp->d_name, ".", 1) == 0) { ++ if (strncmp(direntp->d_name, ".", PATH_MAX) == 0 || strncmp(direntp->d_name, "..", PATH_MAX) == 0) { + continue; + } + +@@ -976,7 +980,7 @@ char *look_path(const char *file, char **err) + } + + /* if slash in file, directly use file and do not try PATH. */ +- if (strings_contains_any(file, "/")) { ++ if (util_strings_contains_any(file, "/")) { + int en = find_executable(file); + if (en == 0) { + return util_strdup_s(file); +@@ -1140,7 +1144,7 @@ static void recursive_cal_dir_size_helper(const char *dirpath, int recursive_dep + struct dirent *pdirent = NULL; + DIR *directory = NULL; + struct stat fstat; +- char fname[MAXPATHLEN]; ++ char fname[PATH_MAX]; + + // cal dir self node and size + nret = lstat(dirpath, &fstat); +@@ -1167,8 +1171,8 @@ static void recursive_cal_dir_size_helper(const char *dirpath, int recursive_dep + + (void)memset(fname, 0, sizeof(fname)); + +- pathname_len = snprintf(fname, MAXPATHLEN, "%s/%s", dirpath, pdirent->d_name); +- if (pathname_len < 0 || pathname_len >= MAXPATHLEN) { ++ pathname_len = snprintf(fname, PATH_MAX, "%s/%s", dirpath, pdirent->d_name); ++ if (pathname_len < 0 || pathname_len >= PATH_MAX) { + ERROR("Pathname too long"); + continue; + } +@@ -1237,7 +1241,7 @@ static void recursive_cal_dir_size__without_hardlink_helper(const char *dirpath, + int nret = 0; + struct dirent *pdirent = NULL; + DIR *directory = NULL; +- char fname[MAXPATHLEN]; ++ char fname[PATH_MAX]; + + directory = opendir(dirpath); + if (directory == NULL) { +@@ -1255,8 +1259,8 @@ static void recursive_cal_dir_size__without_hardlink_helper(const char *dirpath, + + (void)memset(fname, 0, sizeof(fname)); + +- pathname_len = snprintf(fname, MAXPATHLEN, "%s/%s", dirpath, pdirent->d_name); +- if (pathname_len < 0 || pathname_len >= MAXPATHLEN) { ++ pathname_len = snprintf(fname, PATH_MAX, "%s/%s", dirpath, pdirent->d_name); ++ if (pathname_len < 0 || pathname_len >= PATH_MAX) { + ERROR("Pathname too long"); + continue; + } +@@ -1401,6 +1405,39 @@ out: + return result; + } + ++static int do_atomic_write_file(const char *fname, const char *content, size_t content_len, mode_t mode) ++{ ++ int ret = 0; ++ int dst_fd = -1; ++ ssize_t len = 0; ++ ++ dst_fd = util_open(fname, O_WRONLY | O_CREAT | O_TRUNC, mode); ++ if (dst_fd < 0) { ++ ERROR("Creat file: %s, failed: %s", fname, strerror(errno)); ++ ret = -1; ++ goto free_out; ++ } ++ ++ len = util_write_nointr(dst_fd, content, content_len); ++ if (len < 0 || ((size_t)len) != content_len) { ++ ret = -1; ++ ERROR("Write file failed: %s", strerror(errno)); ++ goto free_out; ++ } ++ ++ if (fdatasync(dst_fd) != 0) { ++ ret = -1; ++ SYSERROR("Failed to sync data of file:%s", fname); ++ goto free_out; ++ } ++ ++free_out: ++ if (dst_fd >= 0) { ++ close(dst_fd); ++ } ++ return ret; ++} ++ + int util_atomic_write_file(const char *fname, const char *content, size_t content_len, mode_t mode) + { + int ret = 0; +@@ -1414,7 +1451,7 @@ int util_atomic_write_file(const char *fname, const char *content, size_t conten + return 0; + } + +- if (cleanpath(fname, rpath, sizeof(rpath)) == NULL) { ++ if (util_clean_path(fname, rpath, sizeof(rpath)) == NULL) { + return -1; + } + +@@ -1425,7 +1462,7 @@ int util_atomic_write_file(const char *fname, const char *content, size_t conten + goto free_out; + } + +- ret = util_write_file(tmp_file, content, content_len, mode); ++ ret = do_atomic_write_file(tmp_file, content, content_len, mode); + if (ret != 0) { + ERROR("Failed to write content to tmp file for %s", tmp_file); + ret = -1; +@@ -1444,7 +1481,7 @@ free_out: + return ret; + } + +-static char *isula_utils_fisula_utils_read_file(FILE *stream, size_t *length) ++static char *do_read_file(FILE *stream, size_t *length) + { + #define JSON_MAX_SIZE (10LL * 1024LL * 1024LL) + char *buf = NULL; +@@ -1504,7 +1541,7 @@ static int do_check_args(const char *path) + return 0; + } + +-char *isula_utils_read_file(const char *path) ++char *util_read_content_from_file(const char *path) + { + #define FILE_MODE 0640 + char *buf = NULL; +@@ -1535,12 +1572,12 @@ char *isula_utils_read_file(const char *path) + return NULL; + } + +- buf = isula_utils_fisula_utils_read_file(fp, &length); ++ buf = do_read_file(fp, &length); + (void)fclose(fp); + return buf; + } + +-int isula_utils_read_line(FILE *fp, read_line_callback_t cb, void *context) ++int util_proc_file_line_by_line(FILE *fp, read_line_callback_t cb, void *context) + { + size_t len = 0; + char *line = NULL; +@@ -1574,3 +1611,436 @@ out: + free(line); + return ret; + } ++ ++int util_set_file_group(const char *fname, const char *group) ++{ ++ int ret = 0; ++ struct group *grp = NULL; ++ gid_t gid; ++ ++ if (fname == NULL || group == NULL) { ++ ERROR("Invalid NULL params"); ++ return -1; ++ } ++ ++ grp = getgrnam(group); ++ if (grp != NULL) { ++ gid = grp->gr_gid; ++ DEBUG("Group %s found, gid: %d", group, gid); ++ if (chown(fname, -1, gid) != 0) { ++ ERROR("Failed to chown %s to gid: %d", fname, gid); ++ ret = -1; ++ goto out; ++ } ++ } else { ++ if (strcmp(group, "docker") == 0 || strcmp(group, "isula") == 0) { ++ DEBUG("Warning: could not change group %s to %s", fname, group); ++ } else { ++ ERROR("Group %s not found", group); ++ ret = -1; ++ goto out; ++ } ++ } ++ ++out: ++ return ret; ++} ++ ++int util_recursive_remove_path(const char *path) ++{ ++ int ret = 0; ++ ++ if (unlink(path) != 0 && errno != ENOENT) { ++ ret = util_recursive_rmdir(path, 0); ++ } ++ ++ return ret; ++} ++ ++static bool list_entries(const char *path, const struct dirent *entry, void *context) ++{ ++ char ***names = (char ***)context; ++ ++ if (util_array_append(names, entry->d_name) != 0) { ++ ERROR("out of memory"); ++ return false; ++ } ++ return true; ++} ++ ++int util_list_all_entries(const char *directory, char ***out) ++{ ++ return util_scan_subdirs(directory, list_entries, out); ++} ++ ++static int copy_own(char *copy_dst, struct stat *src_stat) ++{ ++ int ret = 0; ++ struct stat dst_stat = {0}; ++ ++ if (lstat(copy_dst, &dst_stat) != 0) { ++ ERROR("lstat %s failed: %s", copy_dst, strerror(errno)); ++ return -1; ++ } ++ ++ ret = lchown(copy_dst, src_stat->st_uid, src_stat->st_gid); ++ if (ret == 0 || (ret == EPERM && src_stat->st_uid == dst_stat.st_uid && src_stat->st_gid == dst_stat.st_gid)) { ++ return 0; ++ } ++ ++ ERROR("lchown %s failed: %s", copy_dst, strerror(errno)); ++ ++ return ret; ++} ++ ++static int copy_mode(char *copy_dst, struct stat *src_stat) ++{ ++ if (S_ISLNK(src_stat->st_mode)) { ++ return 0; ++ } ++ ++ if (chmod(copy_dst, src_stat->st_mode) != 0) { ++ ERROR("chmod %s failed: %s", copy_dst, strerror(errno)); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int copy_time(char *copy_dst, struct stat *src_stat) ++{ ++ const struct timespec tm[] = {{src_stat->st_atime}, {src_stat->st_mtime}}; ++ ++ // copy_dst is absolute path, so first argment is ignored. ++ if (utimensat(0, copy_dst, tm, AT_SYMLINK_NOFOLLOW) != 0) { ++ ERROR("failed to set time of %s: %s", copy_dst, strerror(errno)); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int set_one_xattr(char *copy_dst, char *key, char *value, ssize_t size) ++{ ++ if (lsetxattr(copy_dst, key, value, size, 0) != 0) { ++ if (errno == ENOTSUP) { ++ DEBUG("ignore copy xattr %s of %s: %s", key, copy_dst, strerror(errno)); ++ return 0; ++ } ++ ERROR("failed to set xattr %s of %s: %s", key, copy_dst, strerror(errno)); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int do_copy_xattrs(char *copy_dst, char *copy_src, char *xattrs, ssize_t xattrs_len) ++{ ++ char *key = NULL; ++ ssize_t size = 0; ++ char *value = NULL; ++ int ret = 0; ++ ++ for (key = xattrs; key < xattrs + xattrs_len; key += strlen(key) + 1) { ++ if (*key == '\0') { ++ break; ++ } ++ ++ size = lgetxattr(copy_src, key, NULL, 0); ++ if (size < 0) { ++ if (errno == ENOTSUP) { ++ DEBUG("ignore copy xattr %s of %s: %s", key, copy_src, strerror(errno)); ++ continue; ++ } ++ ERROR("failed to get xattr %s of %s: %s", key, copy_src, strerror(errno)); ++ ret = -1; ++ goto out; ++ } ++ ++ // no value ++ if (size == 0) { ++ DEBUG("no value for key %s", key); ++ continue; ++ } ++ ++ free(value); ++ value = util_common_calloc_s(size); ++ if (value == NULL) { ++ ERROR("out of memory"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (lgetxattr(copy_src, key, value, size) < 0) { ++ if (errno == ENOTSUP) { ++ DEBUG("ignore copy xattr %s of %s: %s", key, copy_src, strerror(errno)); ++ continue; ++ } ++ ERROR("failed to get xattr %s of %s: %s", key, copy_src, strerror(errno)); ++ ret = -1; ++ goto out; ++ } ++ ++ ret = set_one_xattr(copy_dst, key, value, size); ++ if (ret != 0) { ++ goto out; ++ } ++ } ++ ++out: ++ free(value); ++ ++ return ret; ++} ++ ++static int copy_xattrs(char *copy_dst, char *copy_src) ++{ ++ ssize_t xattrs_len = 0; ++ char *xattrs = NULL; ++ int ret = 0; ++ ++ xattrs_len = llistxattr(copy_src, NULL, 0); ++ if (xattrs_len < 0) { ++ if (errno == ENOTSUP) { ++ DEBUG("ignore copy xattrs of %s: %s", copy_src, strerror(errno)); ++ return 0; ++ } ++ ERROR("failed to get xattrs length of %s: %s", copy_src, strerror(errno)); ++ return -1; ++ } ++ ++ // no xattrs ++ if (xattrs_len == 0) { ++ return 0; ++ } ++ ++ xattrs = util_common_calloc_s(xattrs_len); ++ if (xattrs == NULL) { ++ ERROR("out of memory"); ++ return -1; ++ } ++ ++ if (llistxattr(copy_src, xattrs, xattrs_len) < 0) { ++ if (errno == ENOTSUP) { ++ DEBUG("ignore copy xattrs of %s: %s", copy_src, strerror(errno)); ++ goto out; ++ } ++ ERROR("failed to list xattrs of %s: %s", copy_src, strerror(errno)); ++ ret = -1; ++ goto out; ++ } ++ ++ ret = do_copy_xattrs(copy_dst, copy_src, xattrs, xattrs_len); ++ ++out: ++ free(xattrs); ++ ++ return ret; ++} ++ ++static int copy_infos(char *copy_dst, char *copy_src, struct stat *src_stat) ++{ ++ int ret = 0; ++ ++ ret = copy_own(copy_dst, src_stat); ++ if (ret != 0) { ++ return -1; ++ } ++ ++ ret = copy_mode(copy_dst, src_stat); ++ if (ret != 0) { ++ return -1; ++ } ++ ++ ret = copy_time(copy_dst, src_stat); ++ if (ret != 0) { ++ return -1; ++ } ++ ++ ret = copy_xattrs(copy_dst, copy_src); ++ if (ret != 0) { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int copy_folder(char *copy_dst, char *copy_src) ++{ ++ struct stat src_stat = {0}; ++ struct stat dst_stat = {0}; ++ ++ if (lstat(copy_src, &src_stat) != 0) { ++ ERROR("stat %s failed: %s", copy_src, strerror(errno)); ++ return -1; ++ } ++ if (!S_ISDIR(src_stat.st_mode)) { ++ ERROR("copy source %s is not directory", copy_src); ++ return -1; ++ } ++ ++ if (lstat(copy_dst, &dst_stat) != 0) { ++ if (mkdir(copy_dst, src_stat.st_mode) != 0) { ++ ERROR("failed to mkdir %s: %s", copy_dst, strerror(errno)); ++ return -1; ++ } ++ } else if (!S_ISDIR(dst_stat.st_mode)) { ++ ERROR("copy destination %s is not directory", copy_dst); ++ return -1; ++ } else { ++ if (chmod(copy_dst, src_stat.st_mode) != 0) { ++ ERROR("failed to chmod %s: %s", copy_dst, strerror(errno)); ++ return -1; ++ } ++ } ++ ++ return copy_infos(copy_dst, copy_src, &src_stat); ++} ++ ++static int copy_regular(char *copy_dst, char *copy_src, struct stat *src_stat, map_t *inodes) ++{ ++ char *target = NULL; ++ ++ if (src_stat->st_nlink > 1) { ++ // target hard link file exist, try link it ++ target = map_search(inodes, (void *)(&(src_stat->st_ino))); ++ if (target != NULL) { ++ if (link(target, copy_dst) != 0) { ++ ERROR("failed to link %s to %s: %s", target, copy_dst, strerror(errno)); ++ return -1; ++ } ++ return 0; ++ } ++ if (!map_insert(inodes, (void*)(&src_stat->st_ino), (void*)copy_dst)) { ++ ERROR("out of memory"); ++ return -1; ++ } ++ } ++ ++ // no same file exist, try copy it ++ return util_copy_file(copy_src, copy_dst, src_stat->st_mode); ++} ++ ++static int copy_symbolic(char *copy_dst, char *copy_src) ++{ ++ char link[PATH_MAX] = {0}; ++ ++ if (readlink(copy_src, link, sizeof(link)) < 0) { ++ ERROR("readlink of %s failed: %s", copy_src, strerror(errno)); ++ return -1; ++ } ++ ++ if (symlink(link, copy_dst) != 0) { ++ ERROR("create symbolic %s failed: %s", copy_dst, strerror(errno)); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int copy_device(char *copy_dst, char *copy_src, struct stat *src_stat) ++{ ++ if (mknod(copy_dst, src_stat->st_mode, src_stat->st_dev) != 0) { ++ ERROR("mknod %s failed: %s", copy_dst, strerror(errno)); ++ return -1; ++ } ++ return 0; ++} ++ ++static int copy_file(char *copy_dst, char *copy_src, struct stat *src_stat, map_t *inodes) ++{ ++ int ret = 0; ++ ++ if (S_ISREG(src_stat->st_mode)) { ++ ret = copy_regular(copy_dst, copy_src, src_stat, inodes); ++ } else if (S_ISLNK(src_stat->st_mode)) { ++ ret = copy_symbolic(copy_dst, copy_src); ++ } else if (S_ISCHR(src_stat->st_mode) || S_ISBLK(src_stat->st_mode)) { ++ ret = copy_device(copy_dst, copy_src, src_stat); ++ } else { // fifo and socket ++ ERROR("copy %s failed, unsupported type %d", copy_src, src_stat->st_mode); ++ return -1; ++ } ++ if (ret != 0) { ++ return -1; ++ } ++ ++ return copy_infos(copy_dst, copy_src, src_stat); ++} ++ ++int util_copy_dir_recursive(char *copy_dst, char *copy_src) ++{ ++ int ret = 0; ++ map_t *inodes = NULL; ++ ++ // key: source inode, value: target file path ++ inodes = map_new(MAP_INT_STR, MAP_DEFAULT_CMP_FUNC, MAP_DEFAULT_FREE_FUNC); ++ if (inodes == NULL) { ++ ERROR("out of memory"); ++ return -1; ++ } ++ ++ ret = copy_dir_recursive(copy_dst, copy_src, inodes); ++ ++ map_free(inodes); ++ ++ return ret; ++} ++ ++int copy_dir_recursive(char *copy_dst, char *copy_src, map_t *inodes) ++{ ++ char **entries = NULL; ++ size_t entry_num = 0; ++ int ret = 0; ++ struct stat st = {0}; ++ size_t i = 0; ++ char *src = NULL; ++ char *dst = NULL; ++ ++ ret = copy_folder(copy_dst, copy_src); ++ if (ret != 0) { ++ return -1; ++ } ++ ++ ret = util_list_all_entries(copy_src, &entries); ++ if (ret != 0) { ++ ERROR("list entries of %s failed", copy_src); ++ return -1; ++ } ++ entry_num = util_array_len((const char **)entries); ++ ++ for (i = 0; i < entry_num; i++) { ++ src = util_path_join(copy_src, entries[i]); ++ dst = util_path_join(copy_dst, entries[i]); ++ if (src == NULL || dst == NULL) { ++ ERROR("join path failed"); ++ ret = -1; ++ goto out; ++ } ++ ++ ret = lstat(src, &st); ++ if (ret != 0) { ++ goto out; ++ } ++ ++ if (S_ISDIR(st.st_mode)) { ++ ret = copy_dir_recursive(dst, src, inodes); ++ } else { ++ ret = copy_file(dst, src, &st, inodes); ++ } ++ if (ret != 0) { ++ goto out; ++ } ++ free(src); ++ src = NULL; ++ free(dst); ++ dst = NULL; ++ } ++ ++out: ++ util_free_array(entries); ++ free(src); ++ free(dst); ++ ++ return ret; ++} +diff --git a/src/utils/cutils/utils_file.h b/src/utils/cutils/utils_file.h +index 2b37fee..13aaecd 100644 +--- a/src/utils/cutils/utils_file.h ++++ b/src/utils/cutils/utils_file.h +@@ -82,21 +82,34 @@ int util_copy_file(const char *src_file, const char *dst_file, mode_t mode); + + char *util_path_base(const char *path); + +-char *isula_utils_read_file(const char *path); ++char *util_read_content_from_file(const char *path); + + void util_calculate_dir_size(const char *dirpath, int recursive_depth, int64_t *total_size, int64_t *total_inode); + + void utils_calculate_dir_size_without_hardlink(const char *dirpath, int64_t *total_size, int64_t *total_inode); + +-typedef bool (*subdir_callback_t)(const char *, const struct dirent *); ++typedef bool (*subdir_callback_t)(const char *, const struct dirent *, void *context); + +-int util_scan_subdirs(const char *directory, subdir_callback_t cb); ++int util_scan_subdirs(const char *directory, subdir_callback_t cb, void *context); + + int util_atomic_write_file(const char *fname, const char *content, size_t content_len, mode_t mode); + + typedef bool (*read_line_callback_t)(const char *, void *context); + +-int isula_utils_read_line(FILE *fp, read_line_callback_t cb, void *context); ++int util_proc_file_line_by_line(FILE *fp, read_line_callback_t cb, void *context); ++ ++int util_set_file_group(const char *fname, const char *group); ++ ++// try to remove the path, path is file or dir ++int util_recursive_remove_path(const char *path); ++ ++// list only current directory's entries, not list recursive subdirs ++int util_list_all_entries(const char *directory, char ***out); ++ ++// note: 1. If xattrs not support in src or dst filesystem, this function will ignore copying xattrs ++// and will NOT error out. ++// 2. If fifo or socket exist in source, this function will return failure. ++int util_copy_dir_recursive(char *copy_dst, char *copy_src); + + #ifdef __cplusplus + } +diff --git a/src/utils/cutils/utils_fs.c b/src/utils/cutils/utils_fs.c +index e018744..788557f 100644 +--- a/src/utils/cutils/utils_fs.c ++++ b/src/utils/cutils/utils_fs.c +@@ -42,8 +42,8 @@ + #define VXFS_SUPER_MAGIC 0xa501fcf5 + #endif + +-#ifndef OVERLAY_SUPER_MAGIC +-#define OVERLAY_SUPER_MAGIC 0x794c7630 ++#ifndef OVERLAYFS_SUPER_MAGIC ++#define OVERLAYFS_SUPER_MAGIC 0x794c7630 + #endif + + #ifndef NSFS_MAGIC +@@ -386,6 +386,41 @@ out: + return bret; + } + ++bool util_deal_with_mount_info(mount_info_call_back_t cb, const char *pattern) ++{ ++ FILE *fp = NULL; ++ char *line = NULL; ++ char *mountpoint = NULL; ++ size_t length = 0; ++ bool bret = true; ++ int nret = 0; ++ ++ fp = util_fopen("/proc/self/mountinfo", "r"); ++ if (fp == NULL) { ++ ERROR("Failed opening /proc/self/mountinfo"); ++ return false; ++ } ++ ++ while (getline(&line, &length, fp) != -1) { ++ mountpoint = get_mtpoint(line); ++ if (mountpoint == NULL) { ++ INFO("Error reading mountinfo: bad line '%s'", line); ++ continue; ++ } ++ nret = cb(mountpoint, pattern); ++ free(mountpoint); ++ if (nret != 0) { ++ bret = false; ++ goto out; ++ } ++ } ++ ++out: ++ fclose(fp); ++ free(line); ++ return bret; ++} ++ + // is_remount returns true if either device name or flags identify a remount request, false otherwise. + static bool is_remount(const char *src, unsigned long mntflags) + { +@@ -577,7 +612,7 @@ child_out: + } + } + +- ret = wait_for_pid(pid); ++ ret = util_wait_for_pid(pid); + if (ret != 0) { + ERROR("Wait util_mount_from failed"); + } +diff --git a/src/utils/cutils/utils_fs.h b/src/utils/cutils/utils_fs.h +index 198e4d4..6ab6b78 100644 +--- a/src/utils/cutils/utils_fs.h ++++ b/src/utils/cutils/utils_fs.h +@@ -36,9 +36,10 @@ int util_force_mount(const char *src, const char *dst, const char *mtype, const + bool util_detect_mounted(const char *path); + int util_ensure_mounted_as(const char *dst, const char *mntopts); + int util_mount_from(const char *base, const char *src, const char *dst, const char *mtype, const char *mntopts); ++typedef int (*mount_info_call_back_t)(const char *, const char *); ++bool util_deal_with_mount_info(mount_info_call_back_t cb, const char *); + #ifdef __cplusplus + } + #endif + + #endif // UTILS_CUTILS_UTILS_FS_H +- +diff --git a/src/utils/cutils/utils_mount_spec.c b/src/utils/cutils/utils_mount_spec.c +new file mode 100644 +index 0000000..5eadd77 +--- /dev/null ++++ b/src/utils/cutils/utils_mount_spec.c +@@ -0,0 +1,456 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. 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-10-19 ++ * Description: provide mount spec utils functions ++ *******************************************************************************/ ++ ++#define _GNU_SOURCE ++#include "utils_mount_spec.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "utils.h" ++#include "utils_array.h" ++#include "utils_string.h" ++#include "path.h" ++ ++#define CACHE_ERRMSG_LEN 512 ++#define CACHE_ERRMSG(errmsg, fmt, args...) \ ++ do { \ ++ (void)snprintf(errmsg, CACHE_ERRMSG_LEN, fmt, ##args); \ ++ } while (0) ++ ++static int parse_mount_item_type(const char *value, char *mount_str, mount_spec *m, char *errmsg) ++{ ++ if (m->type != NULL) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.More than one type found", mount_str); ++ return EINVALIDARGS; ++ } ++ ++ if (value == NULL || value[0] == 0) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.Type is required", mount_str); ++ return EINVALIDARGS; ++ } ++ ++#ifdef ENABLE_OCI_IMAGE ++ if (strcmp(value, "squashfs") && strcmp(value, "bind") && strcmp(value, "volume")) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.Type must be one of squashfs/bind/volume", mount_str); ++#else ++ if (strcmp(value, "squashfs") && strcmp(value, "bind")) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.Type must be squashfs or bind", mount_str); ++#endif ++ return EINVALIDARGS; ++ } ++ ++ m->type = util_strdup_s(value); ++ ++ return 0; ++} ++ ++static int parse_mount_item_src(const char *value, char *mount_str, mount_spec *m, char *errmsg) ++{ ++ char srcpath[PATH_MAX] = {0}; ++ ++ /* If value of source is NULL, ignore it */ ++ if (value == NULL) { ++ return 0; ++ } ++ ++ if (m->source) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.More than one source found", mount_str); ++ return EINVALIDARGS; ++ } ++ ++#ifndef ENABLE_OCI_IMAGE ++ if (value[0] != '/') { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.Source must be absolute path", mount_str); ++ return EINVALIDARGS; ++ } ++#endif ++ ++ if (value[0] == '/') { ++ if (!util_clean_path(value, srcpath, sizeof(srcpath))) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.Can't translate source path to clean path", mount_str); ++ return EINVALIDARGS; ++ } ++ m->source = util_strdup_s(srcpath); ++ } else { ++ m->source = util_strdup_s(value); ++ } ++ ++ return 0; ++} ++ ++static int parse_mount_item_dst(const char *value, char *mount_str, mount_spec *m, char *errmsg) ++{ ++ char dstpath[PATH_MAX] = { 0 }; ++ ++ /* If value of destination is NULL, ignore it */ ++ if (value == NULL) { ++ return 0; ++ } ++ ++ if (m->target) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.More than one destination found", mount_str); ++ return EINVALIDARGS; ++ } ++ ++ if (value[0] != '/') { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.Destination must be absolute path", mount_str); ++ return EINVALIDARGS; ++ } ++ ++ if (!util_clean_path(value, dstpath, sizeof(dstpath))) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.Can't translate destination path to clean path", mount_str); ++ return EINVALIDARGS; ++ } ++ ++ if (strcmp(dstpath, "/") == 0) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.Destination can't be '/'", mount_str); ++ return EINVALIDARGS; ++ } ++ ++ m->target = util_strdup_s(dstpath); ++ ++ return 0; ++} ++ ++static int parse_mount_item_ro(const char *value, char *mount_str, mount_spec *m, char *errmsg) ++{ ++ if (value == NULL || util_valid_value_true(value)) { ++ m->readonly = true; ++ } else if (util_valid_value_false(value)) { ++ m->readonly = false; ++ } else { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.Invalid readonly mode:%s", mount_str, value); ++ return EINVALIDARGS; ++ } ++ return 0; ++} ++ ++static int parse_mount_item_propagation(const char *value, char *mount_str, mount_spec *m, char *errmsg) ++{ ++ /* If value of destination is NULL, ignore it */ ++ if (value == NULL) { ++ return 0; ++ } ++ ++ if (m->bind_options != NULL && m->bind_options->propagation != NULL) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.More than one bind-propagation found", mount_str); ++ return EINVALIDARGS; ++ } ++ ++ if (!util_valid_propagation_mode(value)) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.Invalid propagation mode:%s", mount_str, value); ++ return EINVALIDARGS; ++ } ++ ++ if (m->bind_options == NULL) { ++ m->bind_options = util_common_calloc_s(sizeof(bind_options)); ++ if (m->bind_options == NULL) { ++ CACHE_ERRMSG(errmsg, "Out of memory"); ++ return EINVALIDARGS; ++ } ++ } ++ m->bind_options->propagation = util_strdup_s(value); ++ ++ return 0; ++} ++ ++static int parse_mount_item_selinux(const char *value, char *mount_str, mount_spec *m, char *errmsg) ++{ ++ /* If value of destination is NULL, ignore it */ ++ if (value == NULL) { ++ return 0; ++ } ++ ++ if (m->bind_options != NULL && m->bind_options->selinux_opts != NULL) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.More than one bind-selinux-opts found", mount_str); ++ return EINVALIDARGS; ++ } ++ ++ if (!util_valid_label_mode(value)) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.Invalid bind selinux opts:%s", mount_str, value); ++ return EINVALIDARGS; ++ } ++ ++ if (m->bind_options == NULL) { ++ m->bind_options = util_common_calloc_s(sizeof(bind_options)); ++ if (m->bind_options == NULL) { ++ CACHE_ERRMSG(errmsg, "Out of memory"); ++ return EINVALIDARGS; ++ } ++ } ++ m->bind_options->selinux_opts = util_strdup_s(value); ++ ++ return 0; ++} ++ ++#ifdef ENABLE_OCI_IMAGE ++static int parse_mount_item_nocopy(const char *value, char *mount_str, mount_spec *m, char *errmsg) ++{ ++ /* If value of destination is NULL, ignore it */ ++ if (value == NULL) { ++ return 0; ++ } ++ ++ if (m->volume_options != NULL) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.More than one volume-nocopy found", mount_str); ++ return EINVALIDARGS; ++ } ++ ++ if (!util_valid_value_true(value) && !util_valid_value_false(value)) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.Invalid volume nocopy:%s", mount_str, value); ++ return EINVALIDARGS; ++ } ++ ++ if (m->volume_options == NULL) { ++ m->volume_options = util_common_calloc_s(sizeof(volume_options)); ++ if (m->volume_options == NULL) { ++ CACHE_ERRMSG(errmsg, "Out of memory"); ++ return EINVALIDARGS; ++ } ++ } ++ ++ if (util_valid_value_true(value)) { ++ m->volume_options->no_copy = true; ++ } else { ++ m->volume_options->no_copy = false; ++ } ++ ++ return 0; ++} ++#endif ++ ++static bool exist_readonly_mode(char *mount_str) ++{ ++ char tmp_mount_str[PATH_MAX] = {0}; ++ int sret = 0; ++ ++ // add "," at start and end of mount string to simplize check ++ sret = snprintf(tmp_mount_str, sizeof(tmp_mount_str), ",%s,", mount_str); ++ if (sret < 0 || (size_t)sret >= sizeof(tmp_mount_str)) { ++ return false; ++ } ++ ++ if (strstr(tmp_mount_str, ",ro,") != NULL || strstr(tmp_mount_str, ",readonly,") != NULL || ++ strstr(tmp_mount_str, ",ro=") != NULL || strstr(tmp_mount_str, ",readonly=") != NULL) { ++ return true; ++ } ++ ++ return false; ++} ++ ++static bool valid_mount_spec_mode(char *mount_str, mount_spec *m, char *errmsg) ++{ ++ if (strcmp(m->type, "volume") == 0) { ++ if (m->bind_options != NULL && m->bind_options->propagation != NULL) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.Propagation must not be specified for type %s", ++ mount_str, m->type); ++ return false; ++ } ++ if (exist_readonly_mode(mount_str) && m->source == NULL) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.Readonly mode must not be specified " ++ "for anonymous volume", mount_str); ++ return false; ++ } ++ } ++ if (strcmp(m->type, "bind") == 0 && m->volume_options != NULL) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.nocopy must not be specified for type %s", ++ mount_str, m->type); ++ return false; ++ } ++ ++ return true; ++} ++ ++// check mount spec valid ++static int check_mount_spec(char *mount_str, mount_spec *m, char *errmsg) ++{ ++ // check source ++ if (strcmp(m->type, "volume") != 0 && m->source == NULL) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.Missing source", mount_str); ++ return EINVALIDARGS; ++ } ++ ++ if (strcmp(m->type, "volume") != 0) { ++ if (m->source == NULL || m->source[0] != '/') { ++ CACHE_ERRMSG(errmsg, "source %s should be absolute path for type %s", m->source, m->type); ++ return -1; ++ } ++ } ++ ++ if (strcmp(m->type, "volume") == 0 && m->source != NULL && !util_valid_volume_name(m->source)) { ++ CACHE_ERRMSG(errmsg, "Invalid volume name %s, only \"%s\" are allowed", m->source, VALID_VOLUME_NAME); ++ return -1; ++ } ++ ++ // check destination ++ if (m->target == NULL) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.Missing destination", mount_str); ++ return EINVALIDARGS; ++ } ++ ++ if (m->target[0] != '/') { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.destination should be absolute path", mount_str); ++ return -1; ++ } ++ ++ if (strcmp(m->type, "squashfs") == 0) { ++ char real_path[PATH_MAX] = { 0 }; ++ if (strlen(m->source) > PATH_MAX || realpath(m->source, real_path) == NULL) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.Source %s not exist", mount_str, m->source); ++ return EINVALIDARGS; ++ } ++ ++ /* Make sure it's a regular file */ ++ if (!util_valid_file(real_path, S_IFREG)) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.Source %s is not a squashfs file", mount_str, ++ m->source); ++ return EINVALIDARGS; ++ } ++ } ++ ++ if (!valid_mount_spec_mode(mount_str, m, errmsg)) { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++static int parse_mounts_item(const char *mntkey, const char *value, char *mount_str, mount_spec *m, char *errmsg) ++{ ++ if (util_valid_key_type(mntkey)) { ++ return parse_mount_item_type(value, mount_str, m, errmsg); ++ } else if (util_valid_key_src(mntkey)) { ++ return parse_mount_item_src(value, mount_str, m, errmsg); ++ } else if (util_valid_key_dst(mntkey)) { ++ return parse_mount_item_dst(value, mount_str, m, errmsg); ++ } else if (util_valid_key_ro(mntkey)) { ++ return parse_mount_item_ro(value, mount_str, m, errmsg); ++ } else if (util_valid_key_propagation(mntkey)) { ++ return parse_mount_item_propagation(value, mount_str, m, errmsg); ++ } else if (util_valid_key_selinux(mntkey)) { ++ return parse_mount_item_selinux(value, mount_str, m, errmsg); ++#ifdef ENABLE_OCI_IMAGE ++ } else if (util_valid_key_nocopy(mntkey)) { ++ return parse_mount_item_nocopy(value, mount_str, m, errmsg); ++#endif ++ } else { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.Unsupported item:%s", mount_str, mntkey); ++ return EINVALIDARGS; ++ } ++} ++ ++int util_parse_mount_spec(char *mount_str, mount_spec **spec, char **errmsg_out) ++{ ++ mount_spec *m = NULL; ++ int ret = 0; ++ size_t i = 0; ++ size_t items_len = 0; ++ char **items = NULL; ++ char **key_val = NULL; ++ char errmsg[CACHE_ERRMSG_LEN] = {0}; ++ ++ if (mount_str == NULL) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification: can't be empty"); ++ ret = -1; ++ goto out; ++ } ++ if (!mount_str[0]) { ++ CACHE_ERRMSG(errmsg, "Invalid mount specification: can't be empty"); ++ ret = -1; ++ goto out; ++ } ++ ++ m = util_common_calloc_s(sizeof(mount_spec)); ++ if (m == NULL) { ++ CACHE_ERRMSG(errmsg, "out of memory"); ++ ret = -1; ++ goto out; ++ } ++ ++ items = util_string_split(mount_str, ','); ++ if (items == NULL) { ++ ret = EINVALIDARGS; ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'. unsupported format", mount_str); ++ goto out; ++ } ++ ++ items_len = util_array_len((const char **)items); ++ ++ for (i = 0; i < items_len; i++) { ++ key_val = util_string_split(items[i], '='); ++ if (key_val == NULL) { ++ continue; ++ } ++ ret = parse_mounts_item(key_val[0], key_val[1], mount_str, m, errmsg); ++ if (ret != 0) { ++ goto out; ++ } ++ util_free_array(key_val); ++ key_val = NULL; ++ } ++ ++ if (m->type == NULL) { ++#ifdef ENABLE_OCI_IMAGE ++ m->type = util_strdup_s(DEFAULT_MOUNT_TYPE); ++#else ++ CACHE_ERRMSG(errmsg, "Invalid mount specification '%s'.Missing type", mount_str); ++ ret = EINVALIDARGS; ++ goto out; ++#endif ++ } ++ ++ if (check_mount_spec(mount_str, m, errmsg) != 0) { ++ ret = EINVALIDARGS; ++ goto out; ++ } ++ ++ *spec = m; ++ m = NULL; ++ ++out: ++ if (ret != 0 && strlen(errmsg) != 0 && errmsg_out != NULL) { ++ *errmsg_out = util_strdup_s(errmsg); ++ } ++ free_mount_spec(m); ++ util_free_array(key_val); ++ util_free_array(items); ++ return ret; ++} ++ ++bool util_valid_mount_spec(const char *mount_str, char **errmsg) ++{ ++ int ret = 0; ++ mount_spec *m = NULL; ++ ++ // if parse success, it's valid ++ ret = util_parse_mount_spec((char*)mount_str, &m, errmsg); ++ if (ret != 0) { ++ goto out; ++ } ++ ++out: ++ free_mount_spec(m); ++ ++ return ret ? false : true; ++} ++ +diff --git a/src/cmd/isula/information/health.h b/src/utils/cutils/utils_mount_spec.h +similarity index 51% +rename from src/cmd/isula/information/health.h +rename to src/utils/cutils/utils_mount_spec.h +index 704d7d9..509e307 100644 +--- a/src/cmd/isula/information/health.h ++++ b/src/utils/cutils/utils_mount_spec.h +@@ -8,35 +8,33 @@ + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. +- * Author: lifeng +- * Create: 2018-11-08 +- * Description: provide container health definition +- ******************************************************************************/ +-#ifndef CMD_ISULA_INFORMATION_HEALTH_H +-#define CMD_ISULA_INFORMATION_HEALTH_H ++ * Author: wangfengtu ++ * Create: 2020-10-19 ++ * Description: provide mount spec utils functions ++ ********************************************************************************/ ++ ++#ifndef UTILS_CUTILS_UTILS_MOUNT_SPEC_H ++#define UTILS_CUTILS_UTILS_MOUNT_SPEC_H + + #include + #include ++#include ++#include + +-#include "client_arguments.h" +-#include "command_parser.h" ++#include "isula_libutils/mount_spec.h" + + #ifdef __cplusplus + extern "C" { + #endif + +-#define HEALTH_OPTIONS(cmdargs) \ +- { \ +- CMD_OPT_TYPE_STRING, false, "service", 'S', &(cmdargs).service, "GRPC service name", NULL \ +- } ++#define DEFAULT_MOUNT_TYPE "volume" ++ ++bool util_valid_mount_spec(const char *mount_str, char **errmsg); + +-extern const char g_cmd_health_check_desc[]; +-extern const char g_cmd_health_check_usage[]; +-extern struct client_arguments g_cmd_health_check_args; +-int cmd_health_check_main(int argc, const char **argv); ++int util_parse_mount_spec(char *mount_str, mount_spec **spec, char **errmsg_out); + + #ifdef __cplusplus + } + #endif + +-#endif ++#endif // UTILS_CUTILS_UTILS_MOUNT_SPEC_H +diff --git a/src/utils/cutils/utils_regex.c b/src/utils/cutils/utils_regex.c +index ca82227..71edcc6 100644 +--- a/src/utils/cutils/utils_regex.c ++++ b/src/utils/cutils/utils_regex.c +@@ -14,6 +14,7 @@ + ********************************************************************************/ + + #define _GNU_SOURCE ++#include "utils_regex.h" + #include + #include + #include +@@ -22,7 +23,6 @@ + + #include "isula_libutils/log.h" + #include "utils.h" +-#include "utils_regex.h" + #include "utils_string.h" + + /* +@@ -72,7 +72,7 @@ static int get_regex_size_from_wildcard(const char *wildcard, const char *escape + size_t i, tmp; + + for (i = 0; i < escapes_size; i++) { +- tmp = strings_count(wildcard, escapes[i]); ++ tmp = util_strings_count(wildcard, escapes[i]); + if (tmp > SIZE_MAX - size) { + ERROR("Invalid wildcard"); + return -1; +@@ -80,7 +80,7 @@ static int get_regex_size_from_wildcard(const char *wildcard, const char *escape + size += tmp; + } + +- tmp = strings_count(wildcard, '*'); ++ tmp = util_strings_count(wildcard, '*'); + if (tmp > SIZE_MAX - size - strlen(wildcard) - 3) { + ERROR("Invalid wildcard"); + return -1; +@@ -138,4 +138,3 @@ int util_wildcard_to_regex(const char *wildcard, char **regex) + + return 0; + } +- +diff --git a/src/utils/cutils/utils_string.c b/src/utils/cutils/utils_string.c +index 6543021..d303114 100644 +--- a/src/utils/cutils/utils_string.c ++++ b/src/utils/cutils/utils_string.c +@@ -47,7 +47,7 @@ static struct unit_map_def const g_unit_map[] = { + + static size_t const g_unit_map_len = sizeof(g_unit_map) / sizeof(g_unit_map[0]); + +-bool strings_contains_any(const char *str, const char *substr) ++bool util_strings_contains_any(const char *str, const char *substr) + { + size_t i = 0; + size_t j; +@@ -71,7 +71,7 @@ bool strings_contains_any(const char *str, const char *substr) + return false; + } + +-bool strings_contains_word(const char *str, const char *substr) ++bool util_strings_contains_word(const char *str, const char *substr) + { + if (str == NULL || substr == NULL) { + return false; +@@ -83,7 +83,7 @@ bool strings_contains_word(const char *str, const char *substr) + return false; + } + +-int strings_count(const char *str, unsigned char c) ++int util_strings_count(const char *str, unsigned char c) + { + size_t i = 0; + int res = 0; +@@ -102,9 +102,9 @@ int strings_count(const char *str, unsigned char c) + return res; + } + +-// strings_in_slice tests whether a string is contained in array of strings or not. ++// util_strings_in_slice tests whether a string is contained in array of strings or not. + // Comparison is case insensitive +-bool strings_in_slice(const char **strarray, size_t alen, const char *str) ++bool util_strings_in_slice(const char **strarray, size_t alen, const char *str) + { + size_t i; + +@@ -123,7 +123,7 @@ bool strings_in_slice(const char **strarray, size_t alen, const char *str) + + // Returns a string that is generated after converting + // all uppercase characters in the str to lowercase. +-char *strings_to_lower(const char *str) ++char *util_strings_to_lower(const char *str) + { + char *newstr = NULL; + char *pos = NULL; +@@ -145,7 +145,7 @@ char *strings_to_lower(const char *str) + + // Returns a string that is generated after converting + // all lowercase characters in the str to uppercase. +-char *strings_to_upper(const char *str) ++char *util_strings_to_upper(const char *str) + { + char *newstr = NULL; + char *pos = NULL; +@@ -182,7 +182,7 @@ static int parse_unit_multiple(const char *unit, int64_t *mltpl) + return -EINVAL; + } + +-static int util_parse_size_int_and_float(const char *numstr, int64_t mlt, int64_t *converted) ++int util_parse_size_int_and_float(const char *numstr, int64_t mlt, int64_t *converted) + { + long long int_size = 0; + double float_size = 0; +@@ -461,7 +461,7 @@ err_out: + return NULL; + } + +-const char *str_skip_str(const char *str, const char *skip) ++const char *util_str_skip_str(const char *str, const char *skip) + { + if (str == NULL || skip == NULL) { + return NULL; +@@ -613,7 +613,7 @@ char *util_trim_quotation(char *str) + return str; + } + +-char **str_array_dup(const char **src, size_t len) ++char **util_str_array_dup(const char **src, size_t len) + { + size_t i; + char **dest = NULL; +@@ -710,7 +710,7 @@ char *util_string_append(const char *post, const char *pre) + return res_string; + } + +-int dup_array_of_strings(const char **src, size_t src_len, char ***dst, size_t *dst_len) ++int util_dup_array_of_strings(const char **src, size_t src_len, char ***dst, size_t *dst_len) + { + size_t i; + +@@ -824,8 +824,7 @@ bool util_has_suffix(const char *str, const char *suffix) + return true; + } + +-int util_string_array_unique(const char **elements, size_t length, char ***unique_elements, +- size_t *unique_elements_len) ++int util_string_array_unique(const char **elements, size_t length, char ***unique_elements, size_t *unique_elements_len) + { + int ret = 0; + size_t i; +@@ -885,21 +884,33 @@ out: + return ret; + } + +-int util_parse_bool_string(const char *str, bool *converted) ++char *util_str_token(char **input, const char *delimiter) + { +- int ret = 0; ++ char *str = NULL; ++ char *delimiter_found = NULL; ++ char *tok = NULL; ++ size_t tok_length = 0; + +- if (str == NULL || converted == NULL) { +- return -EINVAL; ++ if (input == NULL || delimiter == NULL) { ++ return NULL; + } + +- if (strcasecmp(str, "true") == 0) { +- *converted = true; +- } else if (strcasecmp(str, "false") == 0) { +- *converted = false; ++ str = *input; ++ ++ if (str == NULL) { ++ return NULL; ++ } ++ delimiter_found = strstr(str, delimiter); ++ if (delimiter_found != NULL) { ++ tok_length = delimiter_found - str; + } else { +- ret = -EINVAL; ++ tok_length = strlen(str); + } +- +- return ret; +-} ++ tok = strndup(str, tok_length); ++ if (tok == NULL) { ++ ERROR("strndup failed"); ++ return NULL; ++ } ++ *input = delimiter_found != NULL ? delimiter_found + strlen(delimiter) : NULL; ++ return tok; ++} +\ No newline at end of file +diff --git a/src/utils/cutils/utils_string.h b/src/utils/cutils/utils_string.h +index 4d48f72..48733f3 100644 +--- a/src/utils/cutils/utils_string.h ++++ b/src/utils/cutils/utils_string.h +@@ -24,17 +24,17 @@ + extern "C" { + #endif + +-bool strings_contains_any(const char *str, const char *substr); ++bool util_strings_contains_any(const char *str, const char *substr); + +-bool strings_contains_word(const char *str, const char *substr); ++bool util_strings_contains_word(const char *str, const char *substr); + +-int strings_count(const char *str, unsigned char c); ++int util_strings_count(const char *str, unsigned char c); + +-bool strings_in_slice(const char **strarray, size_t alen, const char *str); ++bool util_strings_in_slice(const char **strarray, size_t alen, const char *str); + +-char *strings_to_lower(const char *str); ++char *util_strings_to_lower(const char *str); + +-char *strings_to_upper(const char *str); ++char *util_strings_to_upper(const char *str); + + int util_parse_byte_size_string(const char *s, int64_t *converted); + +@@ -50,7 +50,7 @@ char **util_string_split_multi(const char *src_str, char delim); + + char **util_string_split_n(const char *src_str, char delim, size_t n); + +-const char *str_skip_str(const char *str, const char *skip); ++const char *util_str_skip_str(const char *str, const char *skip); + + char *util_string_delchar(const char *ss, unsigned char c); + +@@ -60,13 +60,13 @@ char *util_trim_space(char *str); + + char *util_trim_quotation(char *str); + +-char **str_array_dup(const char **src, size_t len); ++char **util_str_array_dup(const char **src, size_t len); + + char *util_string_join(const char *sep, const char **parts, size_t len); + + char *util_string_append(const char *post, const char *pre); + +-int dup_array_of_strings(const char **src, size_t src_len, char ***dst, size_t *dst_len); ++int util_dup_array_of_strings(const char **src, size_t src_len, char ***dst, size_t *dst_len); + + char *util_sub_string(const char *source, size_t offset, size_t length); + +@@ -79,11 +79,11 @@ bool util_has_suffix(const char *str, const char *suffix); + int util_string_array_unique(const char **elements, size_t length, char ***unique_elements, + size_t *unique_elements_len); + +-int util_parse_bool_string(const char *str, bool *converted); ++int util_parse_size_int_and_float(const char *numstr, int64_t mlt, int64_t *converted); + ++char *util_str_token(char **input, const char *delimiter); + #ifdef __cplusplus + } + #endif + + #endif // UTILS_CUTILS_UTILS_STRING_H +- +diff --git a/src/utils/cutils/utils_timestamp.c b/src/utils/cutils/utils_timestamp.c +index 41a0e1c..d03eb52 100644 +--- a/src/utils/cutils/utils_timestamp.c ++++ b/src/utils/cutils/utils_timestamp.c +@@ -77,7 +77,7 @@ int types_timestamp_cmp_nanos(const types_timestamp_t *t1, const types_timestamp + } + + /* types timestamp cmp */ +-int types_timestamp_cmp(const types_timestamp_t *t1, const types_timestamp_t *t2) ++int util_types_timestamp_cmp(const types_timestamp_t *t1, const types_timestamp_t *t2) + { + int ret = 0; + +@@ -106,7 +106,7 @@ int types_timestamp_cmp(const types_timestamp_t *t1, const types_timestamp_t *t2 + } + + /* get timestamp */ +-bool get_timestamp(const char *str_time, types_timestamp_t *timestamp) ++bool util_get_timestamp(const char *str_time, types_timestamp_t *timestamp) + { + int64_t seconds = 0; + int32_t nanos = 0; +@@ -118,7 +118,7 @@ bool get_timestamp(const char *str_time, types_timestamp_t *timestamp) + return false; + } + +- if (!get_tm_from_str(str_time, &tm_day, &nanos)) { ++ if (!util_get_tm_from_str(str_time, &tm_day, &nanos)) { + return false; + } + +@@ -144,6 +144,7 @@ bool get_time_buffer_help(const types_timestamp_t *timestamp, char *timebuffer, + int32_t nanos; + int nret = 0; + time_t seconds; ++ size_t tmp_size = 0; + + if (timebuffer == NULL || maxsize == 0 || !timestamp->has_seconds) { + return false; +@@ -159,8 +160,10 @@ bool get_time_buffer_help(const types_timestamp_t *timestamp, char *timebuffer, + nanos = 0; + } + ++ tmp_size = maxsize - strlen(timebuffer); ++ + if (local_utc) { +- nret = snprintf(timebuffer + strlen(timebuffer), maxsize - strlen(timebuffer), ".%09dZ", nanos); ++ nret = snprintf(timebuffer + strlen(timebuffer), tmp_size, ".%09dZ", nanos); + goto out; + } + +@@ -173,14 +176,14 @@ bool get_time_buffer_help(const types_timestamp_t *timestamp, char *timebuffer, + } + + if (tm_zone >= 0) { +- nret = snprintf(timebuffer + strlen(timebuffer), maxsize - strlen(timebuffer), ".%09d+%02d:00", nanos, tm_zone); ++ nret = snprintf(timebuffer + strlen(timebuffer), tmp_size, ".%09d+%02d:00", nanos, tm_zone); + } else { +- nret = snprintf(timebuffer + strlen(timebuffer), maxsize - strlen(timebuffer), ".%09d-%02d:00", nanos, ++ nret = snprintf(timebuffer + strlen(timebuffer), tmp_size, ".%09d-%02d:00", nanos, + -tm_zone); + } + + out: +- if (nret < 0 || nret >= maxsize - strlen(timebuffer)) { ++ if (nret < 0 || (size_t)nret >= tmp_size) { + ERROR("sprintf timebuffer failed"); + return false; + } +@@ -189,12 +192,12 @@ out: + } + + /* get time buffer */ +-bool get_time_buffer(const types_timestamp_t *timestamp, char *timebuffer, size_t maxsize) ++bool util_get_time_buffer(const types_timestamp_t *timestamp, char *timebuffer, size_t maxsize) + { + return get_time_buffer_help(timestamp, timebuffer, maxsize, false); + } + +-bool get_now_time_stamp(types_timestamp_t *timestamp) ++bool util_get_now_time_stamp(types_timestamp_t *timestamp) + { + int err = 0; + struct timespec ts; +@@ -211,7 +214,7 @@ bool get_now_time_stamp(types_timestamp_t *timestamp) + return true; + } + +-int64_t get_now_time_nanos() ++int64_t util_get_now_time_nanos() + { + int err = 0; + struct timespec ts; +@@ -226,30 +229,30 @@ int64_t get_now_time_nanos() + } + + /* get now time buffer */ +-bool get_now_time_buffer(char *timebuffer, size_t maxsize) ++bool util_get_now_time_buffer(char *timebuffer, size_t maxsize) + { + types_timestamp_t timestamp; + +- if (get_now_time_stamp(×tamp) == false) { ++ if (util_get_now_time_stamp(×tamp) == false) { + return false; + } + +- return get_time_buffer(×tamp, timebuffer, maxsize); ++ return util_get_time_buffer(×tamp, timebuffer, maxsize); + } + + /* get now local utc time buffer */ +-bool get_now_local_utc_time_buffer(char *timebuffer, size_t maxsize) ++bool util_get_now_local_utc_time_buffer(char *timebuffer, size_t maxsize) + { + types_timestamp_t timestamp; + +- if (get_now_time_stamp(×tamp) == false) { ++ if (util_get_now_time_stamp(×tamp) == false) { + return false; + } + + return get_time_buffer_help(×tamp, timebuffer, maxsize, true); + } + +-int get_time_interval(types_timestamp_t first, types_timestamp_t last, int64_t *result) ++int util_get_time_interval(types_timestamp_t first, types_timestamp_t last, int64_t *result) + { + int64_t seconds_diff = 0; + int64_t nanos_diff = 0; +@@ -348,7 +351,7 @@ static void parsing_time_data(const char *time, struct tm *tm) + parsing_time_data_sec(tm, time, &i); + } + +-bool parsing_time(const char *format, const char *time, struct tm *tm, int32_t *nanos) ++bool util_parsing_time(const char *format, const char *time, struct tm *tm, int32_t *nanos) + { + size_t len_format = 0; + size_t len_time = 0; +@@ -429,7 +432,7 @@ int get_valid_days(int mon, int year) + return valid_days; + } + +-bool fix_date(struct tm *tm) ++bool util_fix_date(struct tm *tm) + { + if (tm == NULL) { + return false; +@@ -456,7 +459,7 @@ bool fix_date(struct tm *tm) + return true; + } + +-bool get_tm_from_str(const char *str, struct tm *tm, int32_t *nanos) ++bool util_get_tm_from_str(const char *str, struct tm *tm, int32_t *nanos) + { + char *format = NULL; + +@@ -464,10 +467,10 @@ bool get_tm_from_str(const char *str, struct tm *tm, int32_t *nanos) + return false; + } + +- if (strings_contains_any(str, ".")) { ++ if (util_strings_contains_any(str, ".")) { + format = rFC339NanoLocal; +- } else if (strings_contains_any(str, "T")) { +- int tcolons = strings_count(str, ':'); ++ } else if (util_strings_contains_any(str, "T")) { ++ int tcolons = util_strings_count(str, ':'); + switch (tcolons) { + case 0: + format = "2016-01-02T15"; +@@ -486,12 +489,12 @@ bool get_tm_from_str(const char *str, struct tm *tm, int32_t *nanos) + format = dateLocal; + } + +- if (!parsing_time(format, str, tm, nanos)) { ++ if (!util_parsing_time(format, str, tm, nanos)) { + ERROR("Failed to parse time \"%s\" with format \"%s\"", str, format); + return false; + } + +- if (!fix_date(tm)) { ++ if (!util_fix_date(tm)) { + ERROR("\"%s\" is invalid", str); + return false; + } +@@ -578,7 +581,7 @@ static bool get_tm_zone_from_str(const char *str, struct tm *tm, int32_t *nanos, + zonestr = util_strdup_s(zp); + *zp = '\0'; + +- if (!get_tm_from_str(tmstr, tm, nanos)) { ++ if (!util_get_tm_from_str(tmstr, tm, nanos)) { + ERROR("Get tm from str failed"); + goto err_out; + } +@@ -616,7 +619,7 @@ static int64_t get_minmus_time(struct tm *tm1, struct tm *tm2) + return result; + } + +-int64_t time_seconds_since(const char *in) ++int64_t util_time_seconds_since(const char *in) + { + int32_t nanos = 0; + int64_t result = 0; +@@ -835,7 +838,7 @@ static int time_format_duration_bad(char *out, size_t len) + return 1; /* format ok with bad data, return 1 */ + } + +-int time_format_duration(const char *in, char *out, size_t len) ++int util_time_format_duration(const char *in, char *out, size_t len) + { + int32_t nanos = 0; + int64_t result = 0; +@@ -873,9 +876,9 @@ int time_format_duration(const char *in, char *out, size_t len) + return 0; + } + +-int time_format_duration_ago(const char *in, char *out, size_t len) ++int util_time_format_duration_ago(const char *in, char *out, size_t len) + { +- if (time_format_duration(in, out, len) != 0) { ++ if (util_time_format_duration(in, out, len) != 0) { + ERROR("Get format duration"); + return -1; + } +@@ -908,7 +911,7 @@ static int time_tz_to_seconds_nanos(const char *time_tz, int64_t *seconds, int32 + time_str = util_strdup_s(time_tz); + time_str[strlen(time_str) - 1] = '\0'; /* strip last 'Z' */ + +- if (!get_tm_from_str(time_str, &t, &nano)) { ++ if (!util_get_tm_from_str(time_str, &t, &nano)) { + ERROR("get tm from string %s failed", time_str); + nret = -1; + goto err_out; +@@ -927,7 +930,7 @@ err_out: + return nret; + } + +-int to_unix_nanos_from_str(const char *str, int64_t *nanos) ++int util_to_unix_nanos_from_str(const char *str, int64_t *nanos) + { + struct tm tm = { 0 }; + struct types_timezone tz; +@@ -969,3 +972,94 @@ int to_unix_nanos_from_str(const char *str, int64_t *nanos) + *nanos = mktime(&tm) * Time_Second + nano; + return 0; + } ++ ++types_timestamp_t util_to_timestamp_from_str(const char *str) ++{ ++ int64_t nanos = 0; ++ types_timestamp_t timestamp = { 0 }; ++ ++ if (util_to_unix_nanos_from_str(str, &nanos) != 0) { ++ ERROR("Failed to get created time from image config"); ++ goto out; ++ } ++ ++ timestamp.has_seconds = true; ++ timestamp.seconds = nanos / Time_Second; ++ timestamp.has_nanos = true; ++ timestamp.nanos = nanos % Time_Second; ++ ++out: ++ return timestamp; ++} ++ ++static int get_time_ns(long long *pns, long long unit) ++{ ++ if (unit == 0) { ++ return -1; ++ } ++ ++ if (INT64_MAX / *pns >= unit) { ++ *pns *= unit; ++ return 0; ++ } ++ ++ return -1; ++} ++ ++static long long get_time_unit(int unit) ++{ ++ long long u[255] = { 0 }; ++ ++ u['M'] = Time_Milli; ++ u['s'] = Time_Second; ++ u['m'] = Time_Minute; ++ u['h'] = Time_Hour; ++ ++ return u[unit]; ++} ++ ++int util_time_str_to_nanoseconds(const char *value, int64_t *nanoseconds) ++{ ++ int ret = 0; ++ long long tmp = 0; ++ char unit = 0; ++ size_t len = 0; ++ char *num_str = NULL; ++ ++ if (value == NULL || nanoseconds == NULL) { ++ return -1; ++ } ++ ++ if (util_reg_match("^([0-9]+)+(ms|s|m|h)$", value) != 0) { ++ return -1; ++ } ++ num_str = util_strdup_s(value); ++ len = strlen(value); ++ ++ if (strstr(value, "ms") == NULL) { ++ unit = *(value + len - 1); ++ *(num_str + len - 1) = '\0'; ++ } else { ++ unit = 'M'; ++ *(num_str + len - 2) = '\0'; ++ } ++ ret = util_safe_llong(num_str, &tmp); ++ if (ret < 0) { ++ ERROR("Illegal unsigned integer: %s", num_str); ++ ret = -1; ++ goto out; ++ } ++ if (tmp == 0) { ++ goto out; ++ } ++ ++ ret = get_time_ns(&tmp, get_time_unit(unit)); ++ if (ret != 0) { ++ ERROR("failed get nano seconds for %s", num_str); ++ } ++ *nanoseconds = (int64_t)tmp; ++ ++out: ++ free(num_str); ++ return ret; ++} +\ No newline at end of file +diff --git a/src/utils/cutils/utils_timestamp.h b/src/utils/cutils/utils_timestamp.h +index 603fa73..2e93a21 100644 +--- a/src/utils/cutils/utils_timestamp.h ++++ b/src/utils/cutils/utils_timestamp.h +@@ -26,6 +26,18 @@ struct tm; + extern "C" { + #endif + ++#define Time_Nano 1LL ++#define Time_Micro (1000LL * Time_Nano) ++#define Time_Milli (1000LL * Time_Micro) ++#define Time_Second (1000LL * Time_Milli) ++#define Time_Minute (60LL * Time_Second) ++#define Time_Hour (60LL * Time_Minute) ++ ++#define rFC339Local "2006-01-02T15:04:05" ++#define rFC339NanoLocal "2006-01-02T15:04:05.999999999" ++#define dateLocal "2006-01-02" ++#define defaultContainerTime "0001-01-01T00:00:00Z" ++ + typedef struct types_timestamp { + bool has_seconds; + int64_t seconds; +@@ -40,38 +52,41 @@ struct types_timezone { + + bool unix_nanos_to_timestamp(int64_t nanos, types_timestamp_t *timestamp); + +-int64_t time_seconds_since(const char *in); ++int64_t util_time_seconds_since(const char *in); ++ ++int util_types_timestamp_cmp(const types_timestamp_t *t1, const types_timestamp_t *t2); + +-int types_timestamp_cmp(const types_timestamp_t *t1, const types_timestamp_t *t2); ++bool util_get_timestamp(const char *str_time, types_timestamp_t *timestamp); + +-bool get_timestamp(const char *str_time, types_timestamp_t *timestamp); ++bool util_get_time_buffer(const types_timestamp_t *timestamp, char *timebuffer, size_t maxsize); + +-bool get_time_buffer(const types_timestamp_t *timestamp, char *timebuffer, size_t maxsize); ++bool util_get_now_time_stamp(types_timestamp_t *timestamp); + +-bool get_now_time_stamp(types_timestamp_t *timestamp); ++bool util_get_now_local_utc_time_buffer(char *timebuffer, size_t maxsize); + +-bool get_now_local_utc_time_buffer(char *timebuffer, size_t maxsize); ++bool util_get_now_time_buffer(char *timebuffer, size_t maxsize); + +-bool get_now_time_buffer(char *timebuffer, size_t maxsize); ++int util_get_time_interval(types_timestamp_t first, types_timestamp_t last, int64_t *result); + +-int get_time_interval(types_timestamp_t first, types_timestamp_t last, int64_t *result); ++int util_to_unix_nanos_from_str(const char *str, int64_t *nanos); + +-int to_unix_nanos_from_str(const char *str, int64_t *nanos); ++bool util_parsing_time(const char *format, const char *time, struct tm *tm, int32_t *nanos); + +-bool parsing_time(const char *format, const char *time, struct tm *tm, int32_t *nanos); ++bool util_fix_date(struct tm *tm); + +-bool fix_date(struct tm *tm); ++bool util_get_tm_from_str(const char *str, struct tm *tm, int32_t *nanos); + +-bool get_tm_from_str(const char *str, struct tm *tm, int32_t *nanos); ++int util_time_format_duration(const char *in, char *out, size_t len); + +-int time_format_duration(const char *in, char *out, size_t len); ++int util_time_format_duration_ago(const char *in, char *out, size_t len); + +-int time_format_duration_ago(const char *in, char *out, size_t len); ++types_timestamp_t util_to_timestamp_from_str(const char *str); + +-int64_t get_now_time_nanos(); ++int util_time_str_to_nanoseconds(const char *value, int64_t *nanoseconds); ++ ++int64_t util_get_now_time_nanos(); + #ifdef __cplusplus + } + #endif + + #endif +- +diff --git a/src/utils/cutils/utils_verify.c b/src/utils/cutils/utils_verify.c +index 530e26b..bd1603e 100644 +--- a/src/utils/cutils/utils_verify.c ++++ b/src/utils/cutils/utils_verify.c +@@ -225,7 +225,7 @@ bool util_valid_cap(const char *cap) + cret = false; + goto err_out; + } +- if (!strings_in_slice(g_all_caps, all_caps_len, tmpcap)) { ++ if (!util_strings_in_slice(g_all_caps, all_caps_len, tmpcap)) { + cret = false; + goto err_out; + } +@@ -484,7 +484,7 @@ bool util_valid_key_dst(const char *key) + return false; + } + +- return !strcmp(key, "dst") || !strcmp(key, "destination"); ++ return !strcmp(key, "dst") || !strcmp(key, "destination") || !strcmp(key, "target"); + } + + bool util_valid_key_ro(const char *key) +@@ -511,7 +511,16 @@ bool util_valid_key_selinux(const char *key) + return false; + } + +- return !strcmp(key, "bind-selinux-opts"); ++ return !strcmp(key, "bind-selinux-opts") || !strcmp(key, "selinux-opts"); ++} ++ ++bool util_valid_key_nocopy(const char *key) ++{ ++ if (key == NULL) { ++ return false; ++ } ++ ++ return !strcmp(key, "volume-nocopy"); + } + + bool util_valid_value_true(const char *value) +@@ -640,3 +649,114 @@ bool util_valid_exec_suffix(const char *suffix) + + return util_reg_match(patten, suffix) == 0; + } ++ ++bool util_valid_positive_interger(const char *value) ++{ ++ const char *patten = "^[0-9]*$"; ++ ++ if (value == NULL) { ++ return false; ++ } ++ ++ return util_reg_match(patten, value) == 0; ++} ++ ++bool util_valid_device_cgroup_rule(const char *value) ++{ ++ const char *patten = "^([acb]) ([0-9]+|\\*):([0-9]+|\\*) ([rwm]{1,3})$"; ++ ++ if (value == NULL) { ++ return false; ++ } ++ ++ return util_reg_match(patten, value) == 0; ++} ++ ++int util_valid_env(const char *env, char **dst) ++{ ++ int ret = 0; ++ char *value = NULL; ++ ++ char **arr = util_string_split_multi(env, '='); ++ if (arr == NULL) { ++ ERROR("Failed to split env string"); ++ return -1; ++ } ++ if (strlen(arr[0]) == 0) { ++ ERROR("Invalid environment variable: %s", env); ++ ret = -1; ++ goto out; ++ } ++ ++ if (util_array_len((const char **)arr) > 1) { ++ *dst = util_strdup_s(env); ++ goto out; ++ } ++ ++ value = getenv(env); ++ if (value == NULL) { ++ *dst = NULL; ++ goto out; ++ } else { ++ int sret; ++ size_t len = strlen(env) + 1 + strlen(value) + 1; ++ *dst = (char *)util_common_calloc_s(len); ++ if (*dst == NULL) { ++ ERROR("Out of memory"); ++ ret = -1; ++ goto out; ++ } ++ sret = snprintf(*dst, len, "%s=%s", env, value); ++ if (sret < 0 || (size_t)sret >= len) { ++ ERROR("Failed to compose env string"); ++ ret = -1; ++ goto out; ++ } ++ } ++ ++out: ++ util_free_array(arr); ++ return ret; ++} ++ ++bool util_valid_sysctl(const char *sysctl_key) ++{ ++ size_t i = 0; ++ size_t full_keys_len = 0; ++ size_t key_prefixes_len = 0; ++ const char *sysctl_full_keys[] = { "kernel.msgmax", "kernel.msgmnb", "kernel.msgmni", "kernel.sem", ++ "kernel.shmall", "kernel.shmmax", "kernel.shmmni", "kernel.shm_rmid_forced" ++ }; ++ const char *sysctl_key_prefixes[] = { "net.", "fs.mqueue." }; ++ ++ if (sysctl_key == NULL) { ++ return false; ++ } ++ ++ full_keys_len = sizeof(sysctl_full_keys) / sizeof(char *); ++ key_prefixes_len = sizeof(sysctl_key_prefixes) / sizeof(char *); ++ ++ for (i = 0; i < full_keys_len; i++) { ++ if (strcmp(sysctl_full_keys[i], sysctl_key) == 0) { ++ return true; ++ } ++ } ++ for (i = 0; i < key_prefixes_len; i++) { ++ if (strncmp(sysctl_key_prefixes[i], sysctl_key, strlen(sysctl_key_prefixes[i])) == 0) { ++ return true; ++ } ++ } ++ return false; ++} ++ ++bool util_valid_volume_name(const char *name) ++{ ++ char *patten = "^[a-zA-Z0-9][a-zA-Z0-9_.-]{1,63}$"; ++ ++ if (name == NULL) { ++ ERROR("invalid NULL param"); ++ return false; ++ } ++ ++ return util_reg_match(patten, name) == 0; ++} +diff --git a/src/utils/cutils/utils_verify.h b/src/utils/cutils/utils_verify.h +index 7d431b1..9e32f00 100644 +--- a/src/utils/cutils/utils_verify.h ++++ b/src/utils/cutils/utils_verify.h +@@ -25,6 +25,16 @@ + extern "C" { + #endif + ++#define HOST_NAME_REGEXP \ ++ "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*" \ ++ "([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])$" ++#define __TagPattern "^:([A-Za-z_0-9][A-Za-z_0-9.-]{0,127})$" ++#define __NamePattern \ ++ "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])" \ ++ "((\\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+)?(:[0-9]+)?/)?[a-z0-9]" \ ++ "+((([._]|__|[-]*)[a-z0-9]+)+)?((/[a-z0-9]+((([._]|__|[-]*)[a-z0-9]+)+)?)+)?$" ++#define VALID_VOLUME_NAME "[a-zA-Z0-9][a-zA-Z0-9_.-]{1,63}" ++ + extern const char *g_all_caps[]; + + bool util_valid_cmd_arg(const char *arg); +@@ -71,6 +81,8 @@ bool util_valid_key_propagation(const char *key); + + bool util_valid_key_selinux(const char *key); + ++bool util_valid_key_nocopy(const char *key); ++ + bool util_valid_value_true(const char *value); + + bool util_valid_value_false(const char *value); +@@ -99,6 +111,16 @@ bool util_valid_short_sha256_id(const char *id); + + bool util_valid_exec_suffix(const char *suffix); + ++bool util_valid_positive_interger(const char *value); ++ ++bool util_valid_device_cgroup_rule(const char *value); ++ ++int util_valid_env(const char *env, char **dst); ++ ++bool util_valid_sysctl(const char *sysctl_key); ++ ++bool util_valid_volume_name(const char *name); ++ + #ifdef __cplusplus + } + #endif +diff --git a/src/utils/http/http.c b/src/utils/http/http.c +index 259f087..bf9b8ab 100644 +--- a/src/utils/http/http.c ++++ b/src/utils/http/http.c +@@ -12,6 +12,7 @@ + * Create: 2018-11-08 + * Description: provide container http function + ******************************************************************************/ ++#include "http.h" + #include + #include + #include +@@ -20,7 +21,6 @@ + #include + #include + +-#include "http.h" + #include "buffer.h" + #include "isula_libutils/log.h" + #include "utils.h" +diff --git a/src/utils/http/parser.c b/src/utils/http/parser.c +index ec4ae43..eb62648 100644 +--- a/src/utils/http/parser.c ++++ b/src/utils/http/parser.c +@@ -37,13 +37,13 @@ + * IN THE SOFTWARE. + */ + ++#include "parser.h" + #include + #include + #include + #include + #include + +-#include "parser.h" + #include "utils.h" + #include "isula_libutils/log.h" + +@@ -303,7 +303,7 @@ int parse_http(const char *buf, size_t len, struct parsed_http_message *m, + + nparsed = parse(buf, len, parser); + if (nparsed != len) { +- ERROR("Failed to parse it, parsed :%ld, intput:%ld \n", nparsed, len); ++ ERROR("Failed to parse it, parsed :%zu, intput:%zu \n", nparsed, len); + ret = -1; + goto free_out; + } +diff --git a/src/utils/http/rest_common.c b/src/utils/http/rest_common.c +index 7d1f1e3..1916959 100644 +--- a/src/utils/http/rest_common.c ++++ b/src/utils/http/rest_common.c +@@ -224,9 +224,9 @@ static int set_http_get_options(const char *socket, char *request_body, size_t b + + options->input_len = body_len; + raw_socket = socket; +- unix_raw_socket = str_skip_str(raw_socket, "unix://"); ++ unix_raw_socket = util_str_skip_str(raw_socket, "unix://"); + if (unix_raw_socket == NULL) { +- ERROR("Failed to str_skip_str raw_socket"); ++ ERROR("Failed to util_str_skip_str raw_socket"); + return -1; + } + options->unix_socket_path = util_strdup_s(unix_raw_socket); +@@ -291,4 +291,3 @@ void put_body(char *body) + { + free(body); + } +- +diff --git a/src/utils/sha256/sha256.c b/src/utils/sha256/sha256.c +index 31dcc9b..7bd6046 100644 +--- a/src/utils/sha256/sha256.c ++++ b/src/utils/sha256/sha256.c +@@ -14,6 +14,7 @@ + *******************************************************************************/ + + #define _GNU_SOURCE /* See feature_test_macros(7) */ ++#include "sha256.h" + #include /* Obtain O_* constant definitions */ + #include + #include +@@ -21,7 +22,6 @@ + #include + #include + +-#include "sha256.h" + #include "isula_libutils/log.h" + #include "utils.h" + #include "utils_file.h" +@@ -308,7 +308,7 @@ char *sha256_full_digest_str(char *str) + return full_digest; + } + +-char *without_sha256_prefix(char *digest) ++char *util_without_sha256_prefix(char *digest) + { + if (digest == NULL || !util_has_prefix(digest, SHA256_PREFIX)) { + ERROR("Invalid digest when strip sha256 prefix"); +diff --git a/src/utils/sha256/sha256.h b/src/utils/sha256/sha256.h +index 8a40a4f..1c0750f 100644 +--- a/src/utils/sha256/sha256.h ++++ b/src/utils/sha256/sha256.h +@@ -36,7 +36,7 @@ bool sha256_valid_digest_file(const char *path, const char *digest); + + char *sha256_full_digest_str(char *str); + +-char *without_sha256_prefix(char *digest); ++char *util_without_sha256_prefix(char *digest); + + #ifdef __cplusplus + } +diff --git a/src/utils/tar/isulad_tar.c b/src/utils/tar/isulad_tar.c +index 7d0088e..9e98f11 100644 +--- a/src/utils/tar/isulad_tar.c ++++ b/src/utils/tar/isulad_tar.c +@@ -13,6 +13,7 @@ + * Description: provide tar functions + ********************************************************************************/ + #define _GNU_SOURCE /* See feature_test_macros(7) */ ++#include "isulad_tar.h" + #include /* Obtain O_* constant definitions */ + #include + #include +@@ -25,7 +26,6 @@ + #include + + #include "stdbool.h" +-#include "isulad_tar.h" + #include "utils.h" + #include "path.h" + #include "isula_libutils/log.h" +@@ -247,21 +247,21 @@ static int get_rebase_name(const char *path, const char *real_path, + return -1; + } + +- if (specify_current_dir(path) && !specify_current_dir(real_path)) { ++ if (util_specify_current_dir(path) && !util_specify_current_dir(real_path)) { + set_char_to_separator(&resolved[strlen(resolved)]); + resolved[strlen(resolved)] = '.'; + } + +- if (has_trailing_path_separator(path) && !has_trailing_path_separator(resolved)) { ++ if (util_has_trailing_path_separator(path) && !util_has_trailing_path_separator(resolved)) { + resolved[strlen(resolved)] = '/'; + } + +- nret = split_dir_and_base_name(path, NULL, &path_base); ++ nret = util_split_dir_and_base_name(path, NULL, &path_base); + if (nret != 0) { + ERROR("split %s failed", path); + goto cleanup; + } +- nret = split_dir_and_base_name(resolved, NULL, &resolved_base); ++ nret = util_split_dir_and_base_name(resolved, NULL, &resolved_base); + if (nret != 0) { + ERROR("split %s failed", resolved); + goto cleanup; +@@ -309,7 +309,7 @@ int resolve_host_source_path(const char *path, bool follow_link, + return -1; + } + } else { +- nret = filepath_split(path, &dirpath, &basepath); ++ nret = util_filepath_split(path, &dirpath, &basepath); + if (nret < 0) { + ERROR("Can not split path %s", path); + format_errorf(err, "Can not split path %s", path); +@@ -326,19 +326,19 @@ int resolve_host_source_path(const char *path, bool follow_link, + goto cleanup; + } + *resolved_path = util_strdup_s(resolved); +- nret = split_dir_and_base_name(path, NULL, &tmp_path_base); ++ nret = util_split_dir_and_base_name(path, NULL, &tmp_path_base); + if (nret != 0) { + ERROR("split %s failed", path); + goto cleanup; + } + +- nret = split_dir_and_base_name(resolved, NULL, &tmp_resolved_base); ++ nret = util_split_dir_and_base_name(resolved, NULL, &tmp_resolved_base); + if (nret != 0) { + ERROR("split %s failed", resolved); + goto cleanup; + } + +- if (has_trailing_path_separator(path) && strcmp(tmp_path_base, tmp_resolved_base) != 0) { ++ if (util_has_trailing_path_separator(path) && strcmp(tmp_path_base, tmp_resolved_base) != 0) { + *rebase_name = tmp_path_base; + tmp_path_base = NULL; + } +@@ -413,7 +413,7 @@ static int copy_info_destination_path_ret(struct archive_copy_info *info, + } + // is not absolutely path + if (target[0] != '\0') { +- if (split_path_dir_entry(iter_path, &parent, NULL) < 0) { ++ if (util_split_path_dir_entry(iter_path, &parent, NULL) < 0) { + goto cleanup; + } + free(iter_path); +@@ -445,7 +445,7 @@ static int copy_info_destination_path_ret(struct archive_copy_info *info, + goto cleanup; + } + +- if (split_path_dir_entry(iter_path, &dst_parent, NULL) < 0) { ++ if (util_split_path_dir_entry(iter_path, &dst_parent, NULL) < 0) { + goto cleanup; + } + +@@ -503,7 +503,7 @@ cleanup: + + static bool asserts_directory(const char *path) + { +- return has_trailing_path_separator(path) || specify_current_dir(path); ++ return util_has_trailing_path_separator(path) || util_specify_current_dir(path); + } + + static char *format_transform_of_tar(const char *srcbase, const char *dstbase) +@@ -555,10 +555,10 @@ char *prepare_archive_copy(const struct archive_copy_info *srcinfo, const struct + char *srcbase = NULL; + char *dstbase = NULL; + +- if (split_path_dir_entry(dstinfo->path, &dstdir, &dstbase) < 0) { ++ if (util_split_path_dir_entry(dstinfo->path, &dstdir, &dstbase) < 0) { + goto cleanup; + } +- if (split_path_dir_entry(srcinfo->path, NULL, &srcbase) < 0) { ++ if (util_split_path_dir_entry(srcinfo->path, NULL, &srcbase) < 0) { + goto cleanup; + } + +@@ -867,7 +867,7 @@ int tar_resource_rebase(const char *path, const char *rebase, struct io_read_wra + format_errorf(err, "lstat %s: %s", path, strerror(errno)); + return -1; + } +- if (split_path_dir_entry(path, &srcdir, &srcbase) < 0) { ++ if (util_split_path_dir_entry(path, &srcdir, &srcbase) < 0) { + ERROR("Can not split path: %s", path); + goto cleanup; + } +diff --git a/src/utils/tar/util_archive.c b/src/utils/tar/util_archive.c +index fce94e5..85f75c7 100644 +--- a/src/utils/tar/util_archive.c ++++ b/src/utils/tar/util_archive.c +@@ -13,6 +13,7 @@ + * Description: provide tar functions + ********************************************************************************/ + #define _GNU_SOURCE /* See feature_test_macros(7) */ ++#include "util_archive.h" + #include + #include + #include +@@ -27,7 +28,6 @@ + #include + + #include "stdbool.h" +-#include "util_archive.h" + #include "utils.h" + #include "isula_libutils/log.h" + #include "io_wrapper.h" +@@ -61,7 +61,7 @@ ssize_t read_content(struct archive *a, void *client_data, const void **buff) + return mydata->content->read(mydata->content->context, mydata->buff, sizeof(mydata->buff)); + } + +-static bool whiteout_convert_read(struct archive_entry *entry, const char *dst_path) ++static bool overlay_whiteout_convert_read(struct archive_entry *entry, const char *dst_path, map_t *unpacked_path_map) + { + bool do_write = true; + char *base = NULL; +@@ -143,6 +143,149 @@ static int copy_data(struct archive *ar, struct archive *aw) + } + } + ++static int remove_files_in_opq_dir(const char *dirpath, int recursive_depth, map_t *unpacked_path_map) ++{ ++ struct dirent *pdirent = NULL; ++ DIR *directory = NULL; ++ int ret = 0; ++ char fname[PATH_MAX] = { 0 }; ++ ++ if ((recursive_depth + 1) > MAX_PATH_DEPTH) { ++ ERROR("Reach max path depth: %s", dirpath); ++ return -1; ++ } ++ ++ directory = opendir(dirpath); ++ if (directory == NULL) { ++ ERROR("Failed to open %s", dirpath); ++ return -1; ++ } ++ pdirent = readdir(directory); ++ for (; pdirent != NULL; pdirent = readdir(directory)) { ++ struct stat fstat; ++ int pathname_len; ++ ++ if (!strcmp(pdirent->d_name, ".") || !strcmp(pdirent->d_name, "..")) { ++ continue; ++ } ++ ++ (void)memset(fname, 0, sizeof(fname)); ++ ++ pathname_len = snprintf(fname, PATH_MAX, "%s/%s", dirpath, pdirent->d_name); ++ if (pathname_len < 0 || pathname_len >= PATH_MAX) { ++ ERROR("Pathname too long"); ++ ret = -1; ++ continue; ++ } ++ ++ // not exist in unpacked paths map, just remove the path ++ if (map_search(unpacked_path_map, (void *)fname) == NULL) { ++ if (util_recursive_remove_path(fname) != 0) { ++ ERROR("Failed to remove path %s", fname); ++ ret = -1; ++ } ++ continue; ++ } ++ ++ if (lstat(fname, &fstat) != 0) { ++ ERROR("Failed to stat %s", fname); ++ ret = -1; ++ continue; ++ } ++ ++ if (S_ISDIR(fstat.st_mode)) { ++ if (remove_files_in_opq_dir(fname, recursive_depth + 1, unpacked_path_map) != 0) { ++ ret = -1; ++ continue; ++ } ++ } ++ } ++ ++ if (closedir(directory) != 0) { ++ ERROR("Failed to close directory %s", dirpath); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++static bool remove_whiteout_convert(struct archive_entry *entry, const char *dst_path, map_t *unpacked_path_map) ++{ ++ bool do_write = true; ++ char *base = NULL; ++ char *dir = NULL; ++ char *originalpath = NULL; ++ ++ base = util_path_base(dst_path); ++ if (base == NULL) { ++ ERROR("Failed to get base of %s", dst_path); ++ goto out; ++ } ++ ++ dir = util_path_dir(dst_path); ++ if (dir == NULL) { ++ ERROR("Failed to get dir of %s", dst_path); ++ goto out; ++ } ++ ++ if (strcmp(base, WHITEOUT_OPAQUEDIR) == 0) { ++ if (remove_files_in_opq_dir(dir, 0, unpacked_path_map) != 0) { ++ SYSERROR("Failed to remove files in opq dir %s", dir); ++ goto out; ++ } ++ do_write = false; ++ goto out; ++ } ++ ++ if (strncmp(base, WHITEOUT_PREFIX, strlen(WHITEOUT_PREFIX)) == 0) { ++ char *origin_base = &base[strlen(WHITEOUT_PREFIX)]; ++ originalpath = util_path_join(dir, origin_base); ++ if (originalpath == NULL) { ++ ERROR("Failed to get original path of %s", dst_path); ++ goto out; ++ } ++ ++ if (util_recursive_remove_path(originalpath) != 0) { ++ ERROR("Failed to delete original path %s", originalpath); ++ goto out; ++ } ++ ++ do_write = false; ++ goto out; ++ } ++ ++out: ++ free(base); ++ free(dir); ++ free(originalpath); ++ return do_write; ++} ++ ++typedef bool (*whiteout_convert_call_back_t)(struct archive_entry *entry, const char *dst_path, ++ map_t *unpacked_path_map); ++ ++struct whiteout_convert_map { ++ whiteout_format_type type; ++ whiteout_convert_call_back_t wh_cb; ++}; ++ ++struct whiteout_convert_map g_wh_cb_map[] = { { OVERLAY_WHITEOUT_FORMATE, overlay_whiteout_convert_read }, ++ { REMOVE_WHITEOUT_FORMATE, remove_whiteout_convert } ++}; ++ ++static whiteout_convert_call_back_t get_whiteout_convert_cb(whiteout_format_type whiteout_type) ++{ ++ size_t i = 0; ++ ++ for (i = 0; i < sizeof(g_wh_cb_map) / sizeof(g_wh_cb_map[0]); i++) { ++ if (whiteout_type == g_wh_cb_map[i].type) { ++ return g_wh_cb_map[i].wh_cb; ++ } ++ } ++ ++ return NULL; ++} ++ + int archive_unpack_handler(const struct io_read_wrapper *content, const char *dstdir, + const struct archive_options *options) + { +@@ -153,6 +296,15 @@ int archive_unpack_handler(const struct io_read_wrapper *content, const char *ds + struct archive_entry *entry = NULL; + char *dst_path = NULL; + int flags; ++ whiteout_convert_call_back_t wh_handle_cb = NULL; ++ map_t *unpacked_path_map = NULL; // used for hanling opaque dir, marke paths had been unpacked ++ ++ unpacked_path_map = map_new(MAP_STR_BOOL, MAP_DEFAULT_CMP_FUNC, MAP_DEFAULT_FREE_FUNC); ++ if (unpacked_path_map == NULL) { ++ ERROR("Out of memory"); ++ ret = -1; ++ goto out; ++ } + + mydata = util_common_calloc_s(sizeof(struct archive_content_data)); + if (mydata == NULL) { +@@ -187,6 +339,8 @@ int archive_unpack_handler(const struct io_read_wrapper *content, const char *ds + goto out; + } + ++ wh_handle_cb = get_whiteout_convert_cb(options->whiteout_format); ++ + for (;;) { + free(dst_path); + dst_path = NULL; +@@ -217,28 +371,42 @@ int archive_unpack_handler(const struct io_read_wrapper *content, const char *ds + goto out; + } + +- if (options->whiteout_format == OVERLAY_WHITEOUT_FORMATE && !whiteout_convert_read(entry, dst_path)) { ++ if (wh_handle_cb != NULL && !wh_handle_cb(entry, dst_path, unpacked_path_map)) { + continue; + } + + ret = archive_write_header(ext, entry); + if (ret != ARCHIVE_OK) { + ERROR("Fail to handle tar header: %s", archive_error_string(ext)); ++ ret = -1; ++ goto out; + } else if (archive_entry_size(entry) > 0) { + ret = copy_data(a, ext); + if (ret != ARCHIVE_OK) { + ERROR("Failed to do copy tar data: %s", archive_error_string(ext)); ++ ret = -1; ++ goto out; + } + } + ret = archive_write_finish_entry(ext); + if (ret != ARCHIVE_OK) { + ERROR("Failed to freeing archive entry: %s\n", archive_error_string(ext)); ++ ret = -1; ++ goto out; ++ } ++ ++ bool b = true; ++ if (!map_replace(unpacked_path_map, (void *)dst_path, (void *)(&b))) { ++ ERROR("Failed to replace unpacked path map element"); ++ ret = -1; ++ goto out; + } + } + + ret = 0; + + out: ++ map_free(unpacked_path_map); + free(dst_path); + archive_read_close(a); + archive_read_free(a); +@@ -292,7 +460,7 @@ child_out: + } + } + +- ret = wait_for_pid(pid); ++ ret = util_wait_for_pid(pid); + if (ret != 0) { + ERROR("Wait archive_untar_handler failed"); + } +@@ -605,7 +773,7 @@ child_out: + } + } + +- ret = wait_for_pid(pid); ++ ret = util_wait_for_pid(pid); + if (ret != 0) { + ERROR("tar failed"); + fcntl(pipe_for_read[0], F_SETFL, O_NONBLOCK); +diff --git a/src/utils/tar/util_archive.h b/src/utils/tar/util_archive.h +index 4c4e4a1..0e05a36 100644 +--- a/src/utils/tar/util_archive.h ++++ b/src/utils/tar/util_archive.h +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + #include "io_wrapper.h" + +@@ -30,8 +31,9 @@ extern "C" { + #endif + + typedef enum { +- NONE_WHITEOUT_FORMATE = 0, +- OVERLAY_WHITEOUT_FORMATE = 1, ++ NONE_WHITEOUT_FORMATE = 0, // handle whiteouts as normal files ++ OVERLAY_WHITEOUT_FORMATE = 1, // handle whiteouts as the way as overlay ++ REMOVE_WHITEOUT_FORMATE = 2, // handle whiteouts by removing the target files + } whiteout_format_type; + + struct archive_options { +diff --git a/src/utils/tar/util_gzip.c b/src/utils/tar/util_gzip.c +index 6475c5f..8733bcb 100644 +--- a/src/utils/tar/util_gzip.c ++++ b/src/utils/tar/util_gzip.c +@@ -13,11 +13,11 @@ + * Description: provide tar functions + ********************************************************************************/ + #define _GNU_SOURCE /* See feature_test_macros(7) */ ++#include "util_gzip.h" + #include + #include + + #include "utils.h" +-#include "util_gzip.h" + #include "isula_libutils/log.h" + #include "utils_file.h" + +diff --git a/src/utils/tar/util_gzip.h b/src/utils/tar/util_gzip.h +index 66c07c3..637997b 100644 +--- a/src/utils/tar/util_gzip.h ++++ b/src/utils/tar/util_gzip.h +@@ -15,6 +15,9 @@ + #ifndef UTILS_TAR_UTIL_GZIP_H + #define UTILS_TAR_UTIL_GZIP_H + ++#include ++#include ++ + #ifdef __cplusplus + extern "C" { + #endif +diff --git a/test/cmd/isula/CMakeLists.txt b/test/cmd/isula/CMakeLists.txt +index e30dfc6..f4701b0 100644 +--- a/test/cmd/isula/CMakeLists.txt ++++ b/test/cmd/isula/CMakeLists.txt +@@ -1,4 +1,4 @@ + project(iSulad_UT) + +-add_subdirectory(infomation) ++add_subdirectory(information) + add_subdirectory(extend) +diff --git a/test/cmd/isula/extend/pause/CMakeLists.txt b/test/cmd/isula/extend/pause/CMakeLists.txt +index 9bc48e9..0179674 100644 +--- a/test/cmd/isula/extend/pause/CMakeLists.txt ++++ b/test/cmd/isula/extend/pause/CMakeLists.txt +@@ -18,7 +18,7 @@ add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/console/console.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula/client_arguments.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/common/err_msg.c +- ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/client/libisula.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/client/connect/protocol_type.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/utils_timestamp.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/mainloop.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/error.c +diff --git a/test/cmd/isula/extend/pause/pause_ut.cc b/test/cmd/isula/extend/pause/pause_ut.cc +index 8039963..538f2d6 100644 +--- a/test/cmd/isula/extend/pause/pause_ut.cc ++++ b/test/cmd/isula/extend/pause/pause_ut.cc +@@ -78,7 +78,7 @@ TEST_F(ContainerPauseUnitTest, test_cmd_pause_main) + EXPECT_EXIT(cmd_pause_main(sizeof(argv) / sizeof(argv[0]), const_cast(argv)), + testing::ExitedWithCode(0), ""); + EXPECT_EXIT(cmd_pause_main(sizeof(argv_failure) / sizeof(argv_failure[0]), const_cast(argv_failure)), +- testing::ExitedWithCode(125), "Unkown flag found"); ++ testing::ExitedWithCode(125), "Unknown flag found"); + testing::Mock::VerifyAndClearExpectations(&m_grpcClient); + } + +diff --git a/test/cmd/isula/extend/resume/CMakeLists.txt b/test/cmd/isula/extend/resume/CMakeLists.txt +index 6e751ce..729c4d3 100644 +--- a/test/cmd/isula/extend/resume/CMakeLists.txt ++++ b/test/cmd/isula/extend/resume/CMakeLists.txt +@@ -18,7 +18,7 @@ add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/console/console.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula/client_arguments.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/common/err_msg.c +- ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/client/libisula.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/client/connect/protocol_type.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/utils_timestamp.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/mainloop.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/error.c +diff --git a/test/cmd/isula/extend/resume/resume_ut.cc b/test/cmd/isula/extend/resume/resume_ut.cc +index e317197..48ed525 100644 +--- a/test/cmd/isula/extend/resume/resume_ut.cc ++++ b/test/cmd/isula/extend/resume/resume_ut.cc +@@ -78,7 +78,7 @@ TEST_F(ContainerResumeUnitTest, test_cmd_resume_main) + EXPECT_EXIT(cmd_resume_main(sizeof(argv) / sizeof(argv[0]), const_cast(argv)), + testing::ExitedWithCode(0), ""); + EXPECT_EXIT(cmd_resume_main(sizeof(argv_failure) / sizeof(argv_failure[0]), const_cast(argv_failure)), +- testing::ExitedWithCode(125), "Unkown flag found"); ++ testing::ExitedWithCode(125), "Unknown flag found"); + testing::Mock::VerifyAndClearExpectations(&m_grpcClient); + } + +diff --git a/test/cmd/isula/infomation/CMakeLists.txt b/test/cmd/isula/information/CMakeLists.txt +similarity index 100% +rename from test/cmd/isula/infomation/CMakeLists.txt +rename to test/cmd/isula/information/CMakeLists.txt +diff --git a/test/cmd/isula/infomation/info/CMakeLists.txt b/test/cmd/isula/information/info/CMakeLists.txt +similarity index 97% +rename from test/cmd/isula/infomation/info/CMakeLists.txt +rename to test/cmd/isula/information/info/CMakeLists.txt +index 83a51d4..2f13498 100644 +--- a/test/cmd/isula/infomation/info/CMakeLists.txt ++++ b/test/cmd/isula/information/info/CMakeLists.txt +@@ -19,7 +19,7 @@ add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/console/console.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula/client_arguments.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/common/err_msg.c +- ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/client/libisula.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/client/connect/protocol_type.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/utils_timestamp.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/mainloop.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/error.c +diff --git a/test/cmd/isula/infomation/info/info_ut.cc b/test/cmd/isula/information/info/info_ut.cc +similarity index 98% +rename from test/cmd/isula/infomation/info/info_ut.cc +rename to test/cmd/isula/information/info/info_ut.cc +index 6a35e22..3b6efcb 100644 +--- a/test/cmd/isula/infomation/info/info_ut.cc ++++ b/test/cmd/isula/information/info/info_ut.cc +@@ -144,7 +144,7 @@ TEST_F(InfoUnitTest, test_cmd_info_main_all) + EXPECT_EXIT(cmd_info_main(sizeof(argv) / sizeof(argv[0]), const_cast(argv)), + testing::ExitedWithCode(0), ""); + EXPECT_EXIT(cmd_info_main(sizeof(argv_failure) / sizeof(argv_failure[0]), const_cast(argv_failure)), +- testing::ExitedWithCode(125), "Unkown flag found"); ++ testing::ExitedWithCode(125), "Unknown flag found"); + + std::string output = testing::internal::GetCapturedStdout(); + if (output.find("devicemapper") == std::string::npos) { +diff --git a/test/cmd/isula/infomation/ps/CMakeLists.txt b/test/cmd/isula/information/ps/CMakeLists.txt +similarity index 97% +rename from test/cmd/isula/infomation/ps/CMakeLists.txt +rename to test/cmd/isula/information/ps/CMakeLists.txt +index 2aee9d4..9659808 100644 +--- a/test/cmd/isula/infomation/ps/CMakeLists.txt ++++ b/test/cmd/isula/information/ps/CMakeLists.txt +@@ -18,7 +18,7 @@ add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/console/console.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula/client_arguments.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/common/err_msg.c +- ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/client/libisula.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/client/connect/protocol_type.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/utils_timestamp.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/mainloop.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/error.c +diff --git a/test/cmd/isula/infomation/ps/ps_ut.cc b/test/cmd/isula/information/ps/ps_ut.cc +similarity index 99% +rename from test/cmd/isula/infomation/ps/ps_ut.cc +rename to test/cmd/isula/information/ps/ps_ut.cc +index 643d8fa..7436e93 100644 +--- a/test/cmd/isula/infomation/ps/ps_ut.cc ++++ b/test/cmd/isula/information/ps/ps_ut.cc +@@ -159,7 +159,7 @@ TEST_F(ContainerListUnitTest, test_cmd_list_main_all) + EXPECT_EXIT(cmd_list_main(sizeof(argv) / sizeof(argv[0]), const_cast(argv)), + testing::ExitedWithCode(0), ""); + EXPECT_EXIT(cmd_list_main(sizeof(argv_failure) / sizeof(argv_failure[0]), const_cast(argv_failure)), +- testing::ExitedWithCode(125), "Unkown flag found"); ++ testing::ExitedWithCode(125), "Unknown flag found"); + testing::Mock::VerifyAndClearExpectations(&m_grpcClient); + } + +diff --git a/test/cutils/utils_string/utils_string_ut.cc b/test/cutils/utils_string/utils_string_ut.cc +index 1d5b6e4..62e6ade 100644 +--- a/test/cutils/utils_string/utils_string_ut.cc ++++ b/test/cutils/utils_string/utils_string_ut.cc +@@ -29,59 +29,57 @@ extern "C" { + + TEST(utils_string_ut, test_strings_count) + { +- ASSERT_EQ(strings_count("aaaaaaaaaaaaaaaaaaaa", 'a'), 20); +- ASSERT_EQ(strings_count("a", 'a'), 1); +- ASSERT_EQ(strings_count("", 'a'), 0); +- ASSERT_EQ(strings_count(nullptr, 'c'), 0); ++ ASSERT_EQ(util_strings_count("aaaaaaaaaaaaaaaaaaaa", 'a'), 20); ++ ASSERT_EQ(util_strings_count("a", 'a'), 1); ++ ASSERT_EQ(util_strings_count("", 'a'), 0); ++ ASSERT_EQ(util_strings_count(nullptr, 'c'), 0); + } + + TEST(utils_string_ut, test_strings_contains_any) + { +- ASSERT_EQ(strings_contains_any("1234567890abcdefgh!@", "ijklmnopq#123456789"), true); +- ASSERT_EQ(strings_contains_any("1234567890abcdefgh!@", "ijklmnopqrstuvw)(*x&-"), false); +- ASSERT_EQ(strings_contains_any("1234567890abcdefgh!@", ""), false); +- ASSERT_EQ(strings_contains_any("1234567890abcdefgh!@", nullptr), false); +- ASSERT_EQ(strings_contains_any("a", "cedefga123415"), true); +- ASSERT_EQ(strings_contains_any("", "ijklmnopq#123456789"), false); +- ASSERT_EQ(strings_contains_any(nullptr, "ijklmnopq#123456789"), false); ++ ASSERT_EQ(util_strings_contains_any("1234567890abcdefgh!@", "ijklmnopq#123456789"), true); ++ ASSERT_EQ(util_strings_contains_any("1234567890abcdefgh!@", "ijklmnopqrstuvw)(*x&-"), false); ++ ASSERT_EQ(util_strings_contains_any("1234567890abcdefgh!@", ""), false); ++ ASSERT_EQ(util_strings_contains_any("1234567890abcdefgh!@", nullptr), false); ++ ASSERT_EQ(util_strings_contains_any("a", "cedefga123415"), true); ++ ASSERT_EQ(util_strings_contains_any("", "ijklmnopq#123456789"), false); ++ ASSERT_EQ(util_strings_contains_any(nullptr, "ijklmnopq#123456789"), false); + } + +- + TEST(utils_string_ut, test_strings_to_lower) + { + char *result = nullptr; + + std::string str = "AB&^%CDE"; +- result = strings_to_lower(str.c_str()); ++ result = util_strings_to_lower(str.c_str()); + ASSERT_STRNE(result, nullptr); + ASSERT_STREQ("ab&^%cde", result); + free(result); + + str = "abcdefg12345*()%^#@"; +- result = strings_to_lower(str.c_str()); ++ result = util_strings_to_lower(str.c_str()); + ASSERT_STRNE(result, nullptr); + ASSERT_STREQ(str.c_str(), result); + free(result); + + str = "aBcDeFg12345*()%^#@"; +- result = strings_to_lower(str.c_str()); ++ result = util_strings_to_lower(str.c_str()); + ASSERT_STRNE(result, nullptr); + ASSERT_STREQ("abcdefg12345*()%^#@", result); + free(result); + + str = ""; +- result = strings_to_lower(str.c_str()); ++ result = util_strings_to_lower(str.c_str()); + ASSERT_STRNE(result, nullptr); + ASSERT_STREQ(str.c_str(), result); + free(result); + +- result = strings_to_lower(nullptr); ++ result = util_strings_to_lower(nullptr); + ASSERT_STREQ(result, nullptr); + +- + MOCK_SET(util_strdup_s, NULL); + str = "A"; +- result = strings_to_lower(str.c_str()); ++ result = util_strings_to_lower(str.c_str()); + ASSERT_STREQ(result, NULL); + MOCK_CLEAR(util_strdup_s); + } +@@ -91,40 +89,39 @@ TEST(utils_string_ut, test_strings_to_upper) + char *result = nullptr; + + std::string str = "AB&^%CDE"; +- result = strings_to_upper(str.c_str()); ++ result = util_strings_to_upper(str.c_str()); + ASSERT_STRNE(result, nullptr); + ASSERT_STREQ(str.c_str(), result); + free(result); + + str = "abcdefg12345*()%^#@"; +- result = strings_to_upper(str.c_str()); ++ result = util_strings_to_upper(str.c_str()); + ASSERT_STRNE(result, nullptr); + ASSERT_STREQ("ABCDEFG12345*()%^#@", result); + free(result); + + str = "aBcDeFg12345*()%^#@"; +- result = strings_to_upper(str.c_str()); ++ result = util_strings_to_upper(str.c_str()); + ASSERT_STRNE(result, nullptr); + ASSERT_STREQ("ABCDEFG12345*()%^#@", result); + free(result); + + str = ""; +- result = strings_to_upper(str.c_str()); ++ result = util_strings_to_upper(str.c_str()); + ASSERT_STRNE(result, nullptr); + ASSERT_STREQ(str.c_str(), result); + free(result); + +- result = strings_to_upper(nullptr); ++ result = util_strings_to_upper(nullptr); + ASSERT_STREQ(result, nullptr); + + MOCK_SET(util_strdup_s, nullptr); + str = "a"; +- result = strings_to_upper(str.c_str()); ++ result = util_strings_to_upper(str.c_str()); + ASSERT_STREQ(result, nullptr); + MOCK_CLEAR(util_strdup_s); + } + +- + TEST(utils_string_ut, test_strings_in_slice) + { + const char *array_long[] = { "abcd", "1234", nullptr, "", "&^%abc" }; +@@ -133,14 +130,14 @@ TEST(utils_string_ut, test_strings_in_slice) + const char *array_short[] = { "abcd" }; + size_t array_short_len = sizeof(array_short) / sizeof(array_short[0]); + +- ASSERT_TRUE(strings_in_slice(array_long, array_long_len, "")); +- ASSERT_FALSE(strings_in_slice(array_long, array_long_len, "abc")); +- ASSERT_FALSE(strings_in_slice(array_long, array_long_len, nullptr)); +- ASSERT_TRUE(strings_in_slice(array_short, array_short_len, "abcd")); +- ASSERT_FALSE(strings_in_slice(array_short, array_short_len, "bcd")); +- ASSERT_FALSE(strings_in_slice(array_short, array_short_len, nullptr)); +- ASSERT_FALSE(strings_in_slice(nullptr, 0, "abcd")); +- ASSERT_FALSE(strings_in_slice(nullptr, 0, nullptr)); ++ ASSERT_TRUE(util_strings_in_slice(array_long, array_long_len, "")); ++ ASSERT_FALSE(util_strings_in_slice(array_long, array_long_len, "abc")); ++ ASSERT_FALSE(util_strings_in_slice(array_long, array_long_len, nullptr)); ++ ASSERT_TRUE(util_strings_in_slice(array_short, array_short_len, "abcd")); ++ ASSERT_FALSE(util_strings_in_slice(array_short, array_short_len, "bcd")); ++ ASSERT_FALSE(util_strings_in_slice(array_short, array_short_len, nullptr)); ++ ASSERT_FALSE(util_strings_in_slice(nullptr, 0, "abcd")); ++ ASSERT_FALSE(util_strings_in_slice(nullptr, 0, nullptr)); + } + + TEST(utils_string_ut, test_util_parse_byte_size_string) +@@ -263,7 +260,6 @@ TEST(utils_string_ut, test_util_parse_byte_size_string) + ret = util_parse_byte_size_string("1a.a1kI", &converted); + ASSERT_NE(ret, 0); + +- + ret = util_parse_byte_size_string(nullptr, &converted); + ASSERT_NE(ret, 0); + +@@ -443,25 +439,25 @@ TEST(utils_string_ut, test_str_skip_str) + const char *substr = "abcdefgh"; + const char *result = nullptr; + +- result = str_skip_str(str, substr); ++ result = util_str_skip_str(str, substr); + ASSERT_STREQ(result, "ij1234567890"); + +- result = str_skip_str(str, "habc"); ++ result = util_str_skip_str(str, "habc"); + ASSERT_STREQ(result, nullptr); + +- result = str_skip_str(str, ""); ++ result = util_str_skip_str(str, ""); + ASSERT_STREQ(result, str); + +- result = str_skip_str(str, nullptr); ++ result = util_str_skip_str(str, nullptr); + ASSERT_STREQ(result, nullptr); + +- result = str_skip_str("a", "a"); ++ result = util_str_skip_str("a", "a"); + ASSERT_STREQ(result, ""); + +- result = str_skip_str("", ""); ++ result = util_str_skip_str("", ""); + ASSERT_STREQ(result, ""); + +- result = str_skip_str(nullptr, ""); ++ result = util_str_skip_str(nullptr, ""); + ASSERT_STREQ(result, nullptr); + } + +@@ -492,10 +488,10 @@ TEST(utils_string_ut, test_util_string_delchar) + + TEST(utils_string_ut, test_util_trim_newline) + { +- char s_all[ ] = { '\n', '\n', '\n', '\n', '\0' }; +- char s_tail[ ] = { '\n', 'a', '\n', 'b', '\n', '\0' }; +- char s_not_n[ ] = { 'a', '\n', 'b', 'c', '\0' }; +- char s_empty[ ] = { '\0' }; ++ char s_all[] = { '\n', '\n', '\n', '\n', '\0' }; ++ char s_tail[] = { '\n', 'a', '\n', 'b', '\n', '\0' }; ++ char s_not_n[] = { 'a', '\n', 'b', 'c', '\0' }; ++ char s_empty[] = { '\0' }; + char *s_nullptr = nullptr; + + util_trim_newline(s_all); +@@ -516,13 +512,13 @@ TEST(utils_string_ut, test_util_trim_newline) + + TEST(utils_string_ut, test_util_trim_space) + { +- char s_all[ ] = { '\f', '\n', '\r', '\t', '\v', ' ', '\0' }; +- char s_head[ ] = { '\f', '\n', '\r', 'a', 'b', 'c', '\0' }; +- char s_tail[ ] = { 'a', 'b', 'c', '\t', '\v', ' ', '\0' }; +- char s_head_tail[ ] = { '\f', 'a', 'b', 'c', '\v', ' ', '\0' }; +- char s_mid[ ] = { 'a', 'b', '\r', '\t', '\v', 'c', '\0' }; +- char s_not_space[ ] = { 'a', 'a', 'b', 'b', 'c', 'c', '\0' }; +- char s_empty[ ] = { '\0' }; ++ char s_all[] = { '\f', '\n', '\r', '\t', '\v', ' ', '\0' }; ++ char s_head[] = { '\f', '\n', '\r', 'a', 'b', 'c', '\0' }; ++ char s_tail[] = { 'a', 'b', 'c', '\t', '\v', ' ', '\0' }; ++ char s_head_tail[] = { '\f', 'a', 'b', 'c', '\v', ' ', '\0' }; ++ char s_mid[] = { 'a', 'b', '\r', '\t', '\v', 'c', '\0' }; ++ char s_not_space[] = { 'a', 'a', 'b', 'b', 'c', 'c', '\0' }; ++ char s_empty[] = { '\0' }; + char *s_nullptr = nullptr; + char *result = nullptr; + +@@ -553,14 +549,14 @@ TEST(utils_string_ut, test_util_trim_space) + + TEST(utils_string_ut, test_util_trim_quotation) + { +- char s_all[ ] = { '"', '"', '"', '\n', '"', '\0' }; +- char s_head[ ] = { '"', '"', 'a', 'b', 'c', '\0' }; +- char s_tail_n[ ] = { 'a', 'b', 'c', '\n', '\n', '\0' }; +- char s_tail_quo[ ] = { 'a', 'b', 'c', '"', '"', '\0' }; +- char s_head_tail[ ] = { '"', '"', 'a', '\n', '"', '\0' }; +- char s_mid[ ] = { 'a', 'b', '"', '\n', 'c', '\0' }; +- char s_not_space[ ] = { 'a', 'b', 'c', 'd', 'e', '\0' }; +- char s_empty[ ] = { '\0' }; ++ char s_all[] = { '"', '"', '"', '\n', '"', '\0' }; ++ char s_head[] = { '"', '"', 'a', 'b', 'c', '\0' }; ++ char s_tail_n[] = { 'a', 'b', 'c', '\n', '\n', '\0' }; ++ char s_tail_quo[] = { 'a', 'b', 'c', '"', '"', '\0' }; ++ char s_head_tail[] = { '"', '"', 'a', '\n', '"', '\0' }; ++ char s_mid[] = { 'a', 'b', '"', '\n', 'c', '\0' }; ++ char s_not_space[] = { 'a', 'b', 'c', 'd', 'e', '\0' }; ++ char s_empty[] = { '\0' }; + char *s_nullptr = nullptr; + char *result = nullptr; + +@@ -602,7 +598,7 @@ TEST(utils_string_ut, test_str_array_dup) + + char **result = nullptr; + +- result = str_array_dup(array_long, array_long_len); ++ result = util_str_array_dup(array_long, array_long_len); + ASSERT_NE(result, nullptr); + ASSERT_STREQ(result[0], "abcd"); + free(result[0]); +@@ -616,14 +612,14 @@ TEST(utils_string_ut, test_str_array_dup) + ASSERT_STREQ(result[5], nullptr); + free(result); + +- result = str_array_dup(array_short, array_short_len); ++ result = util_str_array_dup(array_short, array_short_len); + ASSERT_NE(result, nullptr); + ASSERT_STREQ(result[0], "abcd"); + free(result[0]); + ASSERT_STREQ(result[1], nullptr); + free(result); + +- result = str_array_dup(nullptr, 0); ++ result = util_str_array_dup(nullptr, 0); + ASSERT_EQ(result, nullptr); + } + +@@ -719,7 +715,7 @@ TEST(utils_string_ut, test_dup_array_of_strings) + size_t result_len = 0; + int ret; + +- ret = dup_array_of_strings(array_long, array_long_len, &result, &result_len); ++ ret = util_dup_array_of_strings(array_long, array_long_len, &result, &result_len); + ASSERT_EQ(ret, 0); + ASSERT_EQ(array_long_len, result_len); + ASSERT_NE(result, nullptr); +@@ -734,13 +730,13 @@ TEST(utils_string_ut, test_dup_array_of_strings) + free(result[4]); + free(result); + +- ret = dup_array_of_strings(array_long, array_long_len, &result, nullptr); ++ ret = util_dup_array_of_strings(array_long, array_long_len, &result, nullptr); + ASSERT_NE(ret, 0); + +- ret = dup_array_of_strings(array_long, array_long_len, nullptr, &result_len); ++ ret = util_dup_array_of_strings(array_long, array_long_len, nullptr, &result_len); + ASSERT_NE(ret, 0); + +- ret = dup_array_of_strings(array_short, array_short_len, &result, &result_len); ++ ret = util_dup_array_of_strings(array_short, array_short_len, &result, &result_len); + ASSERT_EQ(ret, 0); + ASSERT_EQ(array_short_len, result_len); + ASSERT_NE(result, nullptr); +@@ -748,11 +744,11 @@ TEST(utils_string_ut, test_dup_array_of_strings) + free(result[0]); + free(result); + +- ret = dup_array_of_strings(nullptr, 0, &result, &result_len); ++ ret = util_dup_array_of_strings(nullptr, 0, &result, &result_len); + ASSERT_EQ(ret, 0); + + MOCK_SET(calloc, nullptr); +- ret = dup_array_of_strings(array_long, array_long_len, &result, &result_len); ++ ret = util_dup_array_of_strings(array_long, array_long_len, &result, &result_len); + ASSERT_NE(ret, 0); + MOCK_CLEAR(calloc); + } +diff --git a/test/fuzz/CMakeLists.txt b/test/fuzz/CMakeLists.txt +index 80e84e9..816dd3c 100644 +--- a/test/fuzz/CMakeLists.txt ++++ b/test/fuzz/CMakeLists.txt +@@ -18,9 +18,41 @@ SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + SET(EXE0 im_oci_image_exist_fuzz) + SET(EXE1 im_config_image_exist_fuzz) + SET(EXE2 im_get_image_count_fuzz) ++SET(EXE3 test_volume_mount_spec_fuzz) ++SET(EXE4 test_volume_parse_volume_fuzz) + add_executable(${EXE0} im_oci_image_exist_fuzz.cc) + add_executable(${EXE1} im_config_image_exist_fuzz.cc) + add_executable(${EXE2} im_get_image_count_fuzz.cc) ++add_executable(${EXE3} ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/cutils/utils.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/cutils/path.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/cutils/map/map.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/cutils/map/rb_tree.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/cutils/utils_string.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/cutils/utils_array.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/cutils/utils_file.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/cutils/utils_convert.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/cutils/utils_regex.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/cutils/utils_verify.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/sha256/sha256.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/cutils/utils_mount_spec.c ++ test_volume_mount_spec_fuzz.cc ++ ) ++add_executable(${EXE4} ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/cutils/utils.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/cutils/path.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/cutils/map/map.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/cutils/map/rb_tree.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/cutils/utils_string.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/cutils/utils_array.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/cutils/utils_file.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/cutils/utils_convert.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/cutils/utils_regex.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/cutils/utils_verify.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/sha256/sha256.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/daemon/modules/spec/parse_volume.c ++ test_volume_parse_volume_fuzz.cc ++ ) + + SET(IMAGE_FUZZ_INCLUDE_DIRS + ${GTEST_INCLUDE_DIR} +@@ -36,6 +68,10 @@ SET(IMAGE_FUZZ_INCLUDE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/../../src/daemon + ${CMAKE_CURRENT_SOURCE_DIR}/../../src/daemon/modules + ${CMAKE_CURRENT_SOURCE_DIR}/../../src/daemon/modules/api ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/common ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/utils/sha256 ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/daemon/common ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../src/daemon/modules/spec + ) + + target_include_directories(${EXE0} PUBLIC +@@ -50,6 +86,14 @@ target_include_directories(${EXE2} PUBLIC + ${IMAGE_FUZZ_INCLUDE_DIRS} + ) + ++target_include_directories(${EXE3} PUBLIC ++ ${IMAGE_FUZZ_INCLUDE_DIRS} ++ ) ++ ++target_include_directories(${EXE4} PUBLIC ++ ${IMAGE_FUZZ_INCLUDE_DIRS} ++ ) ++ + set_target_properties(${EXE0} PROPERTIES LINKER_LANGUAGE CXX) + set_target_properties(${EXE0} PROPERTIES LINK_FLAGS "-fsanitize=address -fsanitize-coverage=trace-pc") + target_link_libraries(${EXE0} ${CMAKE_THREAD_LIBS_INIT} ${ISULA_LIBUTILS_LIBRARY} ${LIB_FUZZING_ENGINE} pthread rt -lisulad_img) +@@ -61,3 +105,11 @@ target_link_libraries(${EXE1} ${CMAKE_THREAD_LIBS_INIT} ${ISULA_LIBUTILS_LIBRARY + set_target_properties(${EXE2} PROPERTIES LINKER_LANGUAGE CXX) + set_target_properties(${EXE2} PROPERTIES LINK_FLAGS "-fsanitize=address -fsanitize-coverage=trace-pc") + target_link_libraries(${EXE2} ${CMAKE_THREAD_LIBS_INIT} ${ISULA_LIBUTILS_LIBRARY} ${LIB_FUZZING_ENGINE} pthread rt -lisulad_img) ++ ++set_target_properties(${EXE3} PROPERTIES LINKER_LANGUAGE CXX) ++set_target_properties(${EXE3} PROPERTIES LINK_FLAGS "-fsanitize=address -fsanitize-coverage=trace-pc") ++target_link_libraries(${EXE3} ${CMAKE_THREAD_LIBS_INIT} ${ISULA_LIBUTILS_LIBRARY} ${LIB_FUZZING_ENGINE} pthread rt -lcrypto -lyajl -lz -lisulad_img -lgcov) ++ ++set_target_properties(${EXE4} PROPERTIES LINKER_LANGUAGE CXX) ++set_target_properties(${EXE4} PROPERTIES LINK_FLAGS "-fsanitize=address -fsanitize-coverage=trace-pc") ++target_link_libraries(${EXE4} ${CMAKE_THREAD_LIBS_INIT} ${ISULA_LIBUTILS_LIBRARY} ${LIB_FUZZING_ENGINE} pthread rt -lcrypto -lyajl -lz -lisulad_img -lgcov) +diff --git a/test/fuzz/dict/volume_fuzz.dict b/test/fuzz/dict/volume_fuzz.dict +new file mode 100644 +index 0000000..8ef79c0 +--- /dev/null ++++ b/test/fuzz/dict/volume_fuzz.dict +@@ -0,0 +1,34 @@ ++":" ++"/" ++"ro" ++"rw" ++"readonly" ++"z" ++"Z" ++"nocopy" ++"=" ++"true" ++"false" ++"1" ++"0" ++"," ++"type" ++"src" ++"target" ++"source" ++"bind" ++"volume" ++"squashfs" ++"dst" ++"destination" ++"private" ++"rprivate" ++"slave" ++"rslave" ++"shared" ++"rshared" ++"bind-propagation" ++"bind-selinux-opts" ++"selinux-opts" ++"volume-nocopy" ++"empty" +diff --git a/test/fuzz/fuzz.sh b/test/fuzz/fuzz.sh +index c4a53ee..26115f6 100755 +--- a/test/fuzz/fuzz.sh ++++ b/test/fuzz/fuzz.sh +@@ -16,6 +16,7 @@ + + current_dir=$(cd $(dirname $0) && pwd) + FUZZ_OPTION="${current_dir}/corpus -dict=${current_dir}/dict/im_oci_image_exist_fuzz.dict -runs=1000000 -max_total_time=3600" ++VOLUME_FUZZ_OPTION="${current_dir}/corpus -dict=${current_dir}/dict/volume_fuzz.dict -runs=1000000 -max_total_time=3600" + + find /usr -name "libclang_rt.fuzzer-$(uname -m)*" + if [ $? != 0 ];then +@@ -31,6 +32,8 @@ fi + ${current_dir}/im_oci_image_exist_fuzz ${FUZZ_OPTION} -artifact_prefix=im_oci_image_exist_fuzz- + ${current_dir}/im_config_image_exist_fuzz ${FUZZ_OPTION} -artifact_prefix=im_config_image_exist_fuzz- + ${current_dir}/im_get_image_count_fuzz ${FUZZ_OPTION} -artifact_prefix=im_get_image_count_fuzz- ++${current_dir}/test_volume_mount_spec_fuzz ${VOLUME_FUZZ_OPTION} -artifact_prefix=test_volume_mount_spec_fuzz- ++${current_dir}/test_volume_parse_volume_fuzz ${VOLUME_FUZZ_OPTION} -artifact_prefix=test_volume_parse_volume_fuzz- + + # 查找crash文件 + +@@ -45,3 +48,24 @@ else + rm -f ${current_dir}/corpus/* + rm -f ${current_dir}/*_fuzz + fi ++ ++if [ x"$1" == x"gcov" ];then ++ umask 0022 ++ export GCOV_RESULT_PATH=/tmp/isulad-fuzz-gcov ++ ISULAD_SRC_PATH=$(pwd)/../../ ++ ++ echo "================================Generate isulad fuzz GCOV data====================================" ++ cd ${ISULAD_SRC_PATH}/build ++ lcov --directory . --capture --output-file coverage.info ++ # Remove std/build files ++ lcov --remove coverage.info '/usr/*' -o coverage.info ++ lcov --remove coverage.info 'build/*' -o coverage.info ++ lcov --remove coverage.info 'test/*' -o coverage.info ++ ++ # Generate html ++ genhtml --ignore-errors source -o $GCOV_RESULT_PATH/coverage coverage.info ++ ++ tar -zcf $ISULAD_SRC_PATH/isulad-gcov.tar.gz $GCOV_RESULT_PATH ++ ++ echo "================================Generate isulad fuzz GCOV finish====================================" ++fi +diff --git a/test/fuzz/test_volume_mount_spec_fuzz.cc b/test/fuzz/test_volume_mount_spec_fuzz.cc +new file mode 100644 +index 0000000..693ab19 +--- /dev/null ++++ b/test/fuzz/test_volume_mount_spec_fuzz.cc +@@ -0,0 +1,31 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. 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-11-03 ++ * Description: provide mount spec fuzz test ++ ******************************************************************************/ ++ ++#include ++#include ++#include "utils_mount_spec.h" ++ ++extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) ++{ ++ std::string testData(reinterpret_cast(data), size); ++ char *errmsg = NULL; ++ if (testData == "empty") { ++ util_valid_mount_spec(nullptr, &errmsg); ++ } else { ++ util_valid_mount_spec(testData.c_str(), &errmsg); ++ } ++ free(errmsg); ++ return 0; ++} +diff --git a/test/fuzz/test_volume_parse_volume_fuzz.cc b/test/fuzz/test_volume_parse_volume_fuzz.cc +new file mode 100644 +index 0000000..1c32a9f +--- /dev/null ++++ b/test/fuzz/test_volume_parse_volume_fuzz.cc +@@ -0,0 +1,31 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. 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-11-03 ++ * Description: provide parse volume fuzz test ++ ******************************************************************************/ ++ ++#include ++#include ++#include "parse_volume.h" ++ ++extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) ++{ ++ std::string testData(reinterpret_cast(data), size); ++ defs_mount *mnt = NULL; ++ if (testData == "empty") { ++ mnt = parse_volume(nullptr); ++ } else { ++ mnt = parse_volume(testData.c_str()); ++ } ++ free_defs_mount(mnt); ++ return 0; ++} +diff --git a/test/image/oci/oci_config_merge/CMakeLists.txt b/test/image/oci/oci_config_merge/CMakeLists.txt +index 7ecce47..48960ff 100644 +--- a/test/image/oci/oci_config_merge/CMakeLists.txt ++++ b/test/image/oci/oci_config_merge/CMakeLists.txt +@@ -4,6 +4,7 @@ SET(EXE oci_config_merge_ut) + + add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/image/oci/oci_config_merge.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/image/image_spec_merge.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/utils.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/utils_regex.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/utils_verify.c +@@ -11,6 +12,7 @@ add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/utils_string.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/utils_convert.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/utils_file.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/utils_timestamp.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/map/map.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/map/rb_tree.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/util_atomic.c +@@ -26,8 +28,13 @@ add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/containers_store_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/namespace_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/container_unix_mock.cc +- ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/spec//specs_mount.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/spec/parse_volume.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/spec/specs_mount.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/volume/volume.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/volume/local.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/selinux_label_mock.cc ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/storage_mock.cc ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/image_mock.cc + oci_config_merge_ut.cc) + + target_include_directories(${EXE} PUBLIC +@@ -39,14 +46,17 @@ target_include_directories(${EXE} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/map + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/config + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/common ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/volume + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/api + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/runtime/engines + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/spec/ + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/container/ + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/container/restart_manager + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/container/health_check ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/image/oci/storage + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/events + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/runtime ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/image + ${CMAKE_BINARY_DIR}/conf + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/sha256 + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/config +diff --git a/test/image/oci/registry/data/v2/ping_head b/test/image/oci/registry/data/v2/ping_head +index 46f1023..9374290 100644 +--- a/test/image/oci/registry/data/v2/ping_head ++++ b/test/image/oci/registry/data/v2/ping_head +@@ -4,5 +4,6 @@ Date: Thu, 02 Jul 2020 09:14:14 GMT + Content-Type: application/json; charset=utf-8 + Content-Length: 2 + Connection: keep-alive +-Docker-Distribution-Api-Version: registry/2.0 +- ++Docker-Distribution-Api-Version: registry/2.0 ++ ++{"errors":[{"code":"UNAUTHORIZED","message":"Unauthorized access."}]} +diff --git a/test/image/oci/registry/registry_ut.cc b/test/image/oci/registry/registry_ut.cc +index cc51818..f656a49 100644 +--- a/test/image/oci/registry/registry_ut.cc ++++ b/test/image/oci/registry/registry_ut.cc +@@ -56,7 +56,7 @@ using ::testing::Invoke; + + std::string get_dir() + { +- char abs_path[PATH_MAX]; ++ char abs_path[PATH_MAX] { 0x00 }; + int ret = readlink("/proc/self/exe", abs_path, sizeof(abs_path)); + if (ret < 0 || (size_t)ret >= sizeof(abs_path)) { + return ""; +@@ -369,7 +369,12 @@ int invokeStorageLayerCreate(const char *layer_id, storage_layer_create_opts_t * + return 0; + } + +-int invokeStorageSetHoldFlag(const char *layer_id, bool hold) ++int invokeStorageIncHoldRefs(const char *layer_id) ++{ ++ return 0; ++} ++ ++int invokeStorageDecHoldRefs(const char *layer_id) + { + return 0; + } +@@ -512,8 +517,10 @@ void mockCommonAll(MockStorage *mock, MockOciImage *oci_image_mock) + .WillRepeatedly(Invoke(invokeStorageGetImgTopLayer)); + EXPECT_CALL(*mock, StorageLayerCreate(::testing::_, ::testing::_)) + .WillRepeatedly(Invoke(invokeStorageLayerCreate)); +- EXPECT_CALL(*mock, StorageSetHoldFlag(::testing::_, ::testing::_)) +- .WillRepeatedly(Invoke(invokeStorageSetHoldFlag)); ++ EXPECT_CALL(*mock, StorageIncHoldRefs(::testing::_)) ++ .WillRepeatedly(Invoke(invokeStorageIncHoldRefs)); ++ EXPECT_CALL(*mock, StorageDecHoldRefs(::testing::_)) ++ .WillRepeatedly(Invoke(invokeStorageDecHoldRefs)); + EXPECT_CALL(*mock, StorageLayerGet(::testing::_)) + .WillRepeatedly(Invoke(invokeStorageLayerGet)); + EXPECT_CALL(*mock, StorageLayerTryRepairLowers(::testing::_, ::testing::_)) +diff --git a/test/image/oci/storage/images/storage_images_ut.cc b/test/image/oci/storage/images/storage_images_ut.cc +index 04d953a..4115e91 100644 +--- a/test/image/oci/storage/images/storage_images_ut.cc ++++ b/test/image/oci/storage/images/storage_images_ut.cc +@@ -47,7 +47,7 @@ using ::testing::_; + + std::string GetDirectory() + { +- char abs_path[PATH_MAX]; ++ char abs_path[PATH_MAX] { 0x00 }; + int ret = readlink("/proc/self/exe", abs_path, sizeof(abs_path)); + if (ret < 0 || (size_t)ret >= sizeof(abs_path)) { + return ""; +@@ -261,7 +261,7 @@ TEST_F(StorageImagesCompatibilityUnitTest, test_load_v1_image) + char store_real_path[PATH_MAX] = { 0x00 }; + struct storage_module_init_options opts; + std::string dir = GetDirectory() + "/data"; +- ASSERT_STRNE(cleanpath(dir.c_str(), store_real_path, sizeof(store_real_path)), nullptr); ++ ASSERT_STRNE(util_clean_path(dir.c_str(), store_real_path, sizeof(store_real_path)), nullptr); + + EXPECT_CALL(m_storage_mock, StorageLayersGetByCompressDigest(_)) + .WillRepeatedly(Invoke(invokeStorageLayersGetByCompressDigest)); +@@ -283,7 +283,7 @@ protected: + { + struct storage_module_init_options opts; + std::string dir = GetDirectory() + "/data"; +- ASSERT_STRNE(cleanpath(dir.c_str(), store_real_path, sizeof(store_real_path)), nullptr); ++ ASSERT_STRNE(util_clean_path(dir.c_str(), store_real_path, sizeof(store_real_path)), nullptr); + + opts.storage_root = strdup(store_real_path); + opts.driver_name = strdup("overlay"); +@@ -409,7 +409,7 @@ TEST_F(StorageImagesUnitTest, test_image_store_create) + GetDirectory() + + "/data/resources/ffc8ef7968a2acb7545006bed022001addaa262c0f760883146c4a4fae54e689/" + "=c2hhMjU2OmZmYzhlZjc5NjhhMmFjYjc1NDUwMDZiZWQwMjIwMDFhZGRhYTI2MmMwZjc2MDg4MzE0NmM0YTRmYWU1NGU2ODk="; +- ASSERT_STRNE(cleanpath(config_file.c_str(), real_path, sizeof(real_path)), "manifest"); ++ ASSERT_STRNE(util_clean_path(config_file.c_str(), real_path, sizeof(real_path)), "manifest"); + + std::ifstream t(real_path); + std::string buffer((std::istreambuf_iterator(t)), std::istreambuf_iterator()); +@@ -432,7 +432,7 @@ TEST_F(StorageImagesUnitTest, test_image_store_create) + std::string manifest_file = GetDirectory() + + "/data/resources/ffc8ef7968a2acb7545006bed022001addaa262c0f760883146c4a4fae54e689/" + + "manifest"; +- ASSERT_STRNE(cleanpath(manifest_file.c_str(), real_path, sizeof(real_path)), nullptr); ++ ASSERT_STRNE(util_clean_path(manifest_file.c_str(), real_path, sizeof(real_path)), nullptr); + + std::ifstream manifest_stream(real_path); + std::string manifest_content((std::istreambuf_iterator(manifest_stream)), std::istreambuf_iterator()); +diff --git a/test/image/oci/storage/layers/storage_driver_ut.cc b/test/image/oci/storage/layers/storage_driver_ut.cc +index 88e6f68..f99ac00 100644 +--- a/test/image/oci/storage/layers/storage_driver_ut.cc ++++ b/test/image/oci/storage/layers/storage_driver_ut.cc +@@ -42,7 +42,7 @@ using ::testing::FLAGS_gmock_catch_leaked_mocks; + + std::string GetDirectory() + { +- char abs_path[PATH_MAX]; ++ char abs_path[PATH_MAX] { 0x00 }; + int ret = readlink("/proc/self/exe", abs_path, sizeof(abs_path)); + if (ret < 0 || (size_t)ret >= sizeof(abs_path)) { + return ""; +@@ -105,7 +105,7 @@ protected: + std::string data_dir = GetDirectory() + "/data"; + struct storage_module_init_options *opts; + +- ASSERT_STRNE(cleanpath(data_dir.c_str(), data_path, sizeof(data_path)), nullptr); ++ ASSERT_STRNE(util_clean_path(data_dir.c_str(), data_path, sizeof(data_path)), nullptr); + std::string cp_command = "cp -r " + std::string(data_path) + " " + isulad_dir; + ASSERT_EQ(system(cp_command.c_str()), 0); + +diff --git a/test/image/oci/storage/layers/storage_layers_ut.cc b/test/image/oci/storage/layers/storage_layers_ut.cc +index f99c6bc..c0bc756 100644 +--- a/test/image/oci/storage/layers/storage_layers_ut.cc ++++ b/test/image/oci/storage/layers/storage_layers_ut.cc +@@ -43,7 +43,7 @@ using ::testing::_; + + std::string GetDirectory() + { +- char abs_path[PATH_MAX]; ++ char abs_path[PATH_MAX] { 0x00 }; + int ret = readlink("/proc/self/exe", abs_path, sizeof(abs_path)); + if (ret < 0 || (size_t)ret >= sizeof(abs_path)) { + return ""; +@@ -158,13 +158,13 @@ protected: + std::string run_dir = isulad_dir + "data/run"; + std::string data_dir = GetDirectory() + "/data"; + +- ASSERT_STRNE(cleanpath(data_dir.c_str(), data_path, sizeof(data_path)), nullptr); ++ ASSERT_STRNE(util_clean_path(data_dir.c_str(), data_path, sizeof(data_path)), nullptr); + std::string cp_command = "cp -r " + std::string(data_path) + " " + isulad_dir; + ASSERT_EQ(system(cp_command.c_str()), 0); + +- ASSERT_STRNE(cleanpath(root_dir.c_str(), real_path, sizeof(real_path)), nullptr); ++ ASSERT_STRNE(util_clean_path(root_dir.c_str(), real_path, sizeof(real_path)), nullptr); + opts.storage_root = strdup(real_path); +- ASSERT_STRNE(cleanpath(run_dir.c_str(), real_run_path, sizeof(real_run_path)), nullptr); ++ ASSERT_STRNE(util_clean_path(run_dir.c_str(), real_run_path, sizeof(real_run_path)), nullptr); + opts.storage_run_root = strdup(real_run_path); + opts.driver_name = strdup("overlay"); + +diff --git a/test/image/oci/storage/rootfs/storage_rootfs_ut.cc b/test/image/oci/storage/rootfs/storage_rootfs_ut.cc +index b2adc1a..a4864da 100644 +--- a/test/image/oci/storage/rootfs/storage_rootfs_ut.cc ++++ b/test/image/oci/storage/rootfs/storage_rootfs_ut.cc +@@ -35,7 +35,7 @@ std::string META_DATA_CONTENT = "metadata test"; + + std::string GetDirectory() + { +- char abs_path[PATH_MAX]; ++ char abs_path[PATH_MAX] { 0x00 }; + int ret = readlink("/proc/self/exe", abs_path, sizeof(abs_path)); + if (ret < 0 || (size_t)ret >= sizeof(abs_path)) { + return ""; +@@ -88,7 +88,7 @@ protected: + { + struct storage_module_init_options opts; + std::string dir = GetDirectory() + "/data"; +- ASSERT_STRNE(cleanpath(dir.c_str(), store_real_path, sizeof(store_real_path)), nullptr); ++ ASSERT_STRNE(util_clean_path(dir.c_str(), store_real_path, sizeof(store_real_path)), nullptr); + + opts.storage_root = strdup(store_real_path); + opts.driver_name = strdup("overlay"); +@@ -189,24 +189,6 @@ TEST_F(StorageRootfsUnitTest, test_rootfs_store_exists) + ASSERT_FALSE(rootfs_store_exists(incorrectId.c_str())); + } + +-TEST_F(StorageRootfsUnitTest, test_rootfs_store_metadata) +-{ +- std::string incorrectId { "ff67da98ab8540d713209" }; +- char *metadata = NULL; +- +- metadata = rootfs_store_metadata(ids.at(0).c_str()); +- ASSERT_STREQ(metadata, META_DATA_CONTENT.c_str()); +- free(metadata); +- metadata = NULL; +- +- metadata = rootfs_store_metadata(ids.at(1).c_str()); +- ASSERT_STREQ(metadata, "{}"); +- free(metadata); +- metadata = NULL; +- +- ASSERT_EQ(rootfs_store_metadata(incorrectId.c_str()), nullptr); +-} +- + TEST_F(StorageRootfsUnitTest, test_rootfs_store_get_all_rootfs) + { + std::string source = std::string(store_real_path) + "/overlay-containers/" + ids.at(0); +diff --git a/test/mocks/image_mock.cc b/test/mocks/image_mock.cc +index 79687fc..1460cb8 100644 +--- a/test/mocks/image_mock.cc ++++ b/test/mocks/image_mock.cc +@@ -38,3 +38,19 @@ void free_im_export_request(im_export_request *ptr) + return g_image_mock->FreeImExportRequest(ptr); + } + } ++ ++int im_mount_container_rootfs(const char *image_type, const char *image_name, const char *container_id) ++{ ++ if (g_image_mock != nullptr) { ++ return g_image_mock->ImMountContainerRootfs(image_type, image_name, container_id); ++ } ++ return 0; ++} ++ ++int im_umount_container_rootfs(const char *image_type, const char *image_name, const char *container_id) ++{ ++ if (g_image_mock != nullptr) { ++ return g_image_mock->ImUmountContainerRootfs(image_type, image_name, container_id); ++ } ++ return 0; ++} +diff --git a/test/mocks/image_mock.h b/test/mocks/image_mock.h +index 53dd22e..0c7c1e5 100644 +--- a/test/mocks/image_mock.h ++++ b/test/mocks/image_mock.h +@@ -24,6 +24,10 @@ public: + virtual ~MockImage() = default; + MOCK_METHOD1(ImContainerExport, int(const im_export_request *request)); + MOCK_METHOD1(FreeImExportRequest, void(im_export_request *ptr)); ++ MOCK_METHOD3(ImMountContainerRootfs, int(const char *image_type, const char *image_name, ++ const char *container_id)); ++ MOCK_METHOD3(ImUmountContainerRootfs, int(const char *image_type, const char *image_name, ++ const char *container_id)); + }; + + void MockImage_SetMock(MockImage *mock); +diff --git a/test/mocks/namespace_mock.cc b/test/mocks/namespace_mock.cc +index 087cf48..823791c 100644 +--- a/test/mocks/namespace_mock.cc ++++ b/test/mocks/namespace_mock.cc +@@ -24,7 +24,7 @@ void MockNamespace_SetMock(MockNamespace* mock) + g_namespace_mock = mock; + } + +-char *connected_container(const char *mode) ++char *namespace_get_connected_container(const char *mode) + { + if (g_namespace_mock != nullptr) { + return g_namespace_mock->ConnectedContainer(mode); +diff --git a/test/mocks/storage_mock.cc b/test/mocks/storage_mock.cc +index 1b50040..104b7a4 100644 +--- a/test/mocks/storage_mock.cc ++++ b/test/mocks/storage_mock.cc +@@ -137,10 +137,42 @@ void free_layer(struct layer *l) + return; + } + +-int storage_set_hold_flag(const char *layer_id, bool hold) ++int storage_inc_hold_refs(const char *layer_id) + { + if (g_storage_mock != NULL) { +- return g_storage_mock->StorageSetHoldFlag(layer_id, hold); ++ return g_storage_mock->StorageIncHoldRefs(layer_id); + } + return -1; + } ++ ++int storage_dec_hold_refs(const char *layer_id) ++{ ++ if (g_storage_mock != NULL) { ++ return g_storage_mock->StorageIncHoldRefs(layer_id); ++ } ++ return -1; ++} ++ ++char *storage_rootfs_mount(const char *container_id) ++{ ++ if (g_storage_mock != NULL) { ++ return g_storage_mock->StorageRootfsMount(container_id); ++ } ++ return NULL; ++} ++ ++int storage_rootfs_umount(const char *container_id, bool force) ++{ ++ if (g_storage_mock != NULL) { ++ return g_storage_mock->StorageRootfsUmount(container_id, force); ++ } ++ return -1; ++} ++ ++container_inspect_graph_driver *storage_get_metadata_by_container_id(const char *id) ++{ ++ if (g_storage_mock != NULL) { ++ return g_storage_mock->StorageGetMetadataByContainerId(id); ++ } ++ return NULL; ++} +diff --git a/test/mocks/storage_mock.h b/test/mocks/storage_mock.h +index 9e34907..3309c61 100644 +--- a/test/mocks/storage_mock.h ++++ b/test/mocks/storage_mock.h +@@ -37,7 +37,11 @@ public: + MOCK_METHOD1(StorageLayerGet, struct layer * (const char *layer_id)); + MOCK_METHOD2(StorageLayerTryRepairLowers, int(const char *layer_id, const char *last_layer_id)); + MOCK_METHOD1(FreeLayer, void(struct layer *l)); +- MOCK_METHOD2(StorageSetHoldFlag, int (const char *layer_id, bool hold)); ++ MOCK_METHOD1(StorageIncHoldRefs, int (const char *layer_id)); ++ MOCK_METHOD1(StorageDecHoldRefs, int (const char *layer_id)); ++ MOCK_METHOD1(StorageRootfsMount, char *(const char *container_id)); ++ MOCK_METHOD2(StorageRootfsUmount, int (const char *container_id, bool force)); ++ MOCK_METHOD1(StorageGetMetadataByContainerId, container_inspect_graph_driver * (const char *id)); + }; + + void MockStorage_SetMock(MockStorage* mock); +diff --git a/test/path/path_ut.cc b/test/path/path_ut.cc +index afd164a..ce6dcc0 100644 +--- a/test/path/path_ut.cc ++++ b/test/path/path_ut.cc +@@ -48,9 +48,7 @@ static char *getcwd_specify(char *str, size_t size) + return str; + } + +-static int create_tmp_symbolic_link(const char *path, +- const char *path_file, +- const char *path_link) ++static int create_tmp_symbolic_link(const char *path, const char *path_file, const char *path_link) + { + if (path == nullptr || path_file == nullptr || path_link == nullptr) { + return -1; +@@ -93,46 +91,46 @@ TEST(path_ut, test_cleanpath) + std::string str; + char realpath[PATH_MAX]; + +- result = cleanpath(nullptr, realpath, sizeof(realpath)); ++ result = util_clean_path(nullptr, realpath, sizeof(realpath)); + ASSERT_STREQ(result, nullptr); + + str = ""; +- result = cleanpath(str.c_str(), realpath, sizeof(realpath)); ++ result = util_clean_path(str.c_str(), realpath, sizeof(realpath)); + ASSERT_STREQ(result, nullptr); + + str = "/home/dir/../file"; +- result = cleanpath(str.c_str(), realpath, sizeof(realpath)); ++ result = util_clean_path(str.c_str(), realpath, sizeof(realpath)); + ASSERT_STREQ(result, "/home/file"); + + str = "/home/dir/./file"; +- result = cleanpath(str.c_str(), realpath, sizeof(realpath)); ++ result = util_clean_path(str.c_str(), realpath, sizeof(realpath)); + ASSERT_STREQ(result, "/home/dir/file"); + + str = "./dir/file"; + MOCK_SET_V(getcwd, getcwd_specify); +- result = cleanpath(str.c_str(), realpath, sizeof(realpath)); ++ result = util_clean_path(str.c_str(), realpath, sizeof(realpath)); + ASSERT_STREQ(result, "/home/dir/file"); + MOCK_CLEAR(getcwd); + + str = "/home/file"; +- result = cleanpath(str.c_str(), realpath, PATH_LENGTH_TEST); ++ result = util_clean_path(str.c_str(), realpath, PATH_LENGTH_TEST); + ASSERT_STREQ(result, nullptr); + + str = "/home/file"; +- result = cleanpath(str.c_str(), nullptr, 0); ++ result = util_clean_path(str.c_str(), nullptr, 0); + ASSERT_STREQ(result, nullptr); + } + + TEST(path_ut, test_specify_current_dir) + { +- ASSERT_FALSE(specify_current_dir(nullptr)); +- ASSERT_TRUE(specify_current_dir("")); +- ASSERT_TRUE(specify_current_dir("/home/.")); +- ASSERT_TRUE(specify_current_dir(".")); +- ASSERT_FALSE(specify_current_dir("/home/file")); +- ASSERT_FALSE(specify_current_dir("/home/..")); +- ASSERT_FALSE(specify_current_dir("/home")); +- ASSERT_FALSE(specify_current_dir("home")); ++ ASSERT_FALSE(util_specify_current_dir(nullptr)); ++ ASSERT_TRUE(util_specify_current_dir("")); ++ ASSERT_TRUE(util_specify_current_dir("/home/.")); ++ ASSERT_TRUE(util_specify_current_dir(".")); ++ ASSERT_FALSE(util_specify_current_dir("/home/file")); ++ ASSERT_FALSE(util_specify_current_dir("/home/..")); ++ ASSERT_FALSE(util_specify_current_dir("/home")); ++ ASSERT_FALSE(util_specify_current_dir("home")); + } + + TEST(path_ut, test_follow_symlink_in_scope) +@@ -140,35 +138,35 @@ TEST(path_ut, test_follow_symlink_in_scope) + std::string fullpath, rootpath; + char *res = nullptr; + +- res = follow_symlink_in_scope(nullptr, nullptr); ++ res = util_follow_symlink_in_scope(nullptr, nullptr); + ASSERT_STREQ(res, nullptr); + free(res); + res = nullptr; + + fullpath = ""; + rootpath = ""; +- res = follow_symlink_in_scope(fullpath.c_str(), rootpath.c_str()); ++ res = util_follow_symlink_in_scope(fullpath.c_str(), rootpath.c_str()); + ASSERT_STREQ(res, nullptr); + free(res); + res = nullptr; + + fullpath = "/home/dir/file"; + rootpath = "/home"; +- res = follow_symlink_in_scope(fullpath.c_str(), rootpath.c_str()); ++ res = util_follow_symlink_in_scope(fullpath.c_str(), rootpath.c_str()); + ASSERT_STREQ(res, "/home/dir/file"); + free(res); + res = nullptr; + + fullpath = "/home/dir/file"; + rootpath = "/home/dir/../file"; +- res = follow_symlink_in_scope(fullpath.c_str(), rootpath.c_str()); ++ res = util_follow_symlink_in_scope(fullpath.c_str(), rootpath.c_str()); + ASSERT_STREQ(res, nullptr); + free(res); + res = nullptr; + + fullpath = "/home/dir/file"; + rootpath = "/home/dir/../"; +- res = follow_symlink_in_scope(fullpath.c_str(), rootpath.c_str()); ++ res = util_follow_symlink_in_scope(fullpath.c_str(), rootpath.c_str()); + ASSERT_STREQ(res, "/home/dir/file"); + free(res); + res = nullptr; +@@ -180,7 +178,7 @@ TEST(path_ut, test_follow_symlink_in_scope) + const char *path_link = "/tmp/just_for_ut/link"; + ASSERT_EQ(create_tmp_symbolic_link(path, path_file, path_link), 0); + MOCK_SET_V(readlink, readlink_specify); +- res = follow_symlink_in_scope(fullpath.c_str(), rootpath.c_str()); ++ res = util_follow_symlink_in_scope(fullpath.c_str(), rootpath.c_str()); + ASSERT_STREQ(res, "/tmp/just_for_ut/dir/file"); + MOCK_CLEAR(readlink); + ASSERT_EQ(util_recursive_rmdir("/tmp/just_for_ut", 0), 0); +@@ -193,31 +191,31 @@ TEST(path_ut, test_split_dir_and_base_name) + char *dir = nullptr; + char *base = nullptr; + +- ASSERT_EQ(split_dir_and_base_name(nullptr, &dir, &base), -1); ++ ASSERT_EQ(util_split_dir_and_base_name(nullptr, &dir, &base), -1); + free(dir); + dir = nullptr; + free(base); + base = nullptr; + +- ASSERT_EQ(split_dir_and_base_name("", &dir, &base), 0); ++ ASSERT_EQ(util_split_dir_and_base_name("", &dir, &base), 0); + free(dir); + dir = nullptr; + free(base); + base = nullptr; + +- ASSERT_EQ(split_dir_and_base_name("/home/file", &dir, &base), 0); ++ ASSERT_EQ(util_split_dir_and_base_name("/home/file", &dir, &base), 0); + free(dir); + dir = nullptr; + free(base); + base = nullptr; + +- ASSERT_EQ(split_dir_and_base_name("/home/file", nullptr, nullptr), 0); ++ ASSERT_EQ(util_split_dir_and_base_name("/home/file", nullptr, nullptr), 0); + free(dir); + dir = nullptr; + free(base); + base = nullptr; + +- split_dir_and_base_name("/home/file", &dir, &base); ++ util_split_dir_and_base_name("/home/file", &dir, &base); + ASSERT_STREQ(dir, "/home"); + ASSERT_STREQ(base, "file"); + free(dir); +@@ -231,31 +229,31 @@ TEST(path_ut, test_filepath_split) + char *dir = nullptr; + char *base = nullptr; + +- ASSERT_EQ(filepath_split(nullptr, &dir, &base), -1); ++ ASSERT_EQ(util_filepath_split(nullptr, &dir, &base), -1); + free(dir); + dir = nullptr; + free(base); + base = nullptr; + +- ASSERT_EQ(filepath_split("", &dir, &base), 0); ++ ASSERT_EQ(util_filepath_split("", &dir, &base), 0); + free(dir); + dir = nullptr; + free(base); + base = nullptr; + +- ASSERT_EQ(filepath_split("/home/file", &dir, &base), 0); ++ ASSERT_EQ(util_filepath_split("/home/file", &dir, &base), 0); + free(dir); + dir = nullptr; + free(base); + base = nullptr; + +- ASSERT_EQ(filepath_split("/home/file", nullptr, nullptr), 0); ++ ASSERT_EQ(util_filepath_split("/home/file", nullptr, nullptr), 0); + free(dir); + dir = nullptr; + free(base); + base = nullptr; + +- filepath_split("/home/file", &dir, &base); ++ util_filepath_split("/home/file", &dir, &base); + ASSERT_STREQ(dir, "/home/"); + ASSERT_STREQ(base, "file"); + free(dir); +@@ -263,7 +261,7 @@ TEST(path_ut, test_filepath_split) + free(base); + base = nullptr; + +- filepath_split("/home/", &dir, &base); ++ util_filepath_split("/home/", &dir, &base); + ASSERT_STREQ(dir, "/home/"); + ASSERT_STREQ(base, ""); + free(dir); +@@ -276,32 +274,32 @@ TEST(path_ut, test_get_resource_path) + { + char *res = nullptr; + +- res = get_resource_path(nullptr, "./test"); ++ res = util_get_resource_path(nullptr, "./test"); + ASSERT_STREQ(res, nullptr); + free(res); + res = nullptr; + +- res = get_resource_path("", ""); ++ res = util_get_resource_path("", ""); + ASSERT_STREQ(res, nullptr); + free(res); + res = nullptr; + +- res = get_resource_path("/home", "./test"); ++ res = util_get_resource_path("/home", "./test"); + ASSERT_STREQ(res, "/home/test"); + free(res); + res = nullptr; + +- res = get_resource_path("/home/dir", "tmp/.././test"); ++ res = util_get_resource_path("/home/dir", "tmp/.././test"); + ASSERT_STREQ(res, "/home/dir/test"); + free(res); + res = nullptr; + +- res = get_resource_path("/home/dir", ".././test"); ++ res = util_get_resource_path("/home/dir", ".././test"); + ASSERT_STREQ(res, nullptr); + free(res); + res = nullptr; + +- res = get_resource_path("/home////dir", ".///./././test/file"); ++ res = util_get_resource_path("/home////dir", ".///./././test/file"); + ASSERT_STREQ(res, "/home/dir/test/file"); + free(res); + res = nullptr; +@@ -313,7 +311,7 @@ TEST(path_ut, test_resolve_path) + char *resolvedpath = nullptr; + char *abspath = nullptr; + +- ASSERT_EQ(resolve_path(nullptr, nullptr, &resolvedpath, &abspath), -1); ++ ASSERT_EQ(util_resolve_path(nullptr, nullptr, &resolvedpath, &abspath), -1); + free(resolvedpath); + resolvedpath = nullptr; + free(abspath); +@@ -321,7 +319,7 @@ TEST(path_ut, test_resolve_path) + + rootpath = ""; + path = ""; +- ASSERT_EQ(resolve_path(rootpath.c_str(), path.c_str(), &resolvedpath, &abspath), -1); ++ ASSERT_EQ(util_resolve_path(rootpath.c_str(), path.c_str(), &resolvedpath, &abspath), -1); + free(resolvedpath); + resolvedpath = nullptr; + free(abspath); +@@ -329,7 +327,7 @@ TEST(path_ut, test_resolve_path) + + rootpath = "/home"; + path = "/home/dir/test"; +- ASSERT_EQ(resolve_path(rootpath.c_str(), path.c_str(), &resolvedpath, &abspath), 0); ++ ASSERT_EQ(util_resolve_path(rootpath.c_str(), path.c_str(), &resolvedpath, &abspath), 0); + free(resolvedpath); + resolvedpath = nullptr; + free(abspath); +@@ -338,10 +336,10 @@ TEST(path_ut, test_resolve_path) + + TEST(path_ut, test_has_trailing_path_separator) + { +- ASSERT_FALSE(has_trailing_path_separator(nullptr)); +- ASSERT_FALSE(has_trailing_path_separator("")); +- ASSERT_TRUE(has_trailing_path_separator("/home/")); +- ASSERT_FALSE(has_trailing_path_separator("/home")); ++ ASSERT_FALSE(util_has_trailing_path_separator(nullptr)); ++ ASSERT_FALSE(util_has_trailing_path_separator("")); ++ ASSERT_TRUE(util_has_trailing_path_separator("/home/")); ++ ASSERT_FALSE(util_has_trailing_path_separator("/home")); + } + + TEST(path_ut, test_preserve_trailing_dot_or_separator) +@@ -349,26 +347,26 @@ TEST(path_ut, test_preserve_trailing_dot_or_separator) + std::string cleanedpath, originalpath; + char *res = nullptr; + +- res = preserve_trailing_dot_or_separator(nullptr, nullptr); ++ res = util_preserve_trailing_dot_or_separator(nullptr, nullptr); + ASSERT_STREQ(res, nullptr); + free(res); + res = nullptr; + +- res = preserve_trailing_dot_or_separator("", ""); ++ res = util_preserve_trailing_dot_or_separator("", ""); + ASSERT_STREQ(res, nullptr); + free(res); + res = nullptr; + + cleanedpath = "/home/test"; + originalpath = "/home/test/."; +- res = preserve_trailing_dot_or_separator(cleanedpath.c_str(), originalpath.c_str()); ++ res = util_preserve_trailing_dot_or_separator(cleanedpath.c_str(), originalpath.c_str()); + ASSERT_STREQ(res, "/home/test/."); + free(res); + res = nullptr; + + cleanedpath = "/home/test"; + originalpath = "/home/test/"; +- res = preserve_trailing_dot_or_separator(cleanedpath.c_str(), originalpath.c_str()); ++ res = util_preserve_trailing_dot_or_separator(cleanedpath.c_str(), originalpath.c_str()); + ASSERT_STREQ(res, "/home/test/"); + free(res); + res = nullptr; +diff --git a/test/runtime/isula/CMakeLists.txt b/test/runtime/isula/CMakeLists.txt +index 9b4b350..4305997 100644 +--- a/test/runtime/isula/CMakeLists.txt ++++ b/test/runtime/isula/CMakeLists.txt +@@ -10,6 +10,7 @@ add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_string.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_convert.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_file.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_timestamp.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/util_atomic.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/sha256/sha256.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/tar/util_gzip.c +diff --git a/test/runtime/lcr/CMakeLists.txt b/test/runtime/lcr/CMakeLists.txt +index 829027e..6f8f784 100644 +--- a/test/runtime/lcr/CMakeLists.txt ++++ b/test/runtime/lcr/CMakeLists.txt +@@ -10,6 +10,7 @@ add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_string.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_convert.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_file.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_timestamp.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/util_atomic.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/sha256/sha256.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/path.c +diff --git a/test/specs/specs/CMakeLists.txt b/test/specs/specs/CMakeLists.txt +index c9c29b2..e0f2b5b 100644 +--- a/test/specs/specs/CMakeLists.txt ++++ b/test/specs/specs/CMakeLists.txt +@@ -10,15 +10,19 @@ add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_string.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_convert.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_file.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_timestamp.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/util_atomic.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/sha256/sha256.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/path.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/map/map.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/map/rb_tree.c +- ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/spec//specs.c +- ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/spec//specs_mount.c +- ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/spec//specs_extend.c +- ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/spec//specs_security.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/volume/volume.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/volume/local.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/spec/specs.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/spec/parse_volume.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/spec/specs_mount.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/spec/specs_extend.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/spec/specs_security.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/common/err_msg.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/common/sysinfo.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd/command_parser.c +@@ -30,6 +34,8 @@ add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/engine_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/selinux_label_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/isulad_config_mock.cc ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/storage_mock.cc ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/image_mock.cc + specs_ut.cc) + + target_include_directories(${EXE} PUBLIC +@@ -44,10 +50,12 @@ target_include_directories(${EXE} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/config + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/common + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/api ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/volume + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/runtime + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/container + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/container/restart_manager + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/container/health_check ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/image/oci/storage + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/services + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/services/execution + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/spec/ +diff --git a/test/specs/specs_extend/CMakeLists.txt b/test/specs/specs_extend/CMakeLists.txt +index 6193a89..7d5c7df 100644 +--- a/test/specs/specs_extend/CMakeLists.txt ++++ b/test/specs/specs_extend/CMakeLists.txt +@@ -10,15 +10,19 @@ add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_string.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_convert.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_file.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_timestamp.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/util_atomic.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/sha256/sha256.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/path.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/map/map.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/map/rb_tree.c +- ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/spec//specs.c +- ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/spec//specs_mount.c +- ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/spec//specs_extend.c +- ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/spec//specs_security.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/volume/volume.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/volume/local.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/spec/parse_volume.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/spec/specs.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/spec/specs_mount.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/spec/specs_extend.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/spec/specs_security.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/common/err_msg.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/common/sysinfo.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd/command_parser.c +@@ -30,6 +34,8 @@ add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/engine_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/selinux_label_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/isulad_config_mock.cc ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/storage_mock.cc ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/image_mock.cc + specs_extend_ut.cc) + + target_include_directories(${EXE} PUBLIC +@@ -43,10 +49,12 @@ target_include_directories(${EXE} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd/isulad + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/config + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/common ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/volume + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/api + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/container + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/container/restart_manager + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/container/health_check ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/image/oci/storage + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/spec/ + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/modules/events + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/tar -- -2.20.1 +2.25.1 diff --git a/0000-update-from-v2.0.5-to-v2.0.6.patch b/0000-update-from-v2.0.5-to-v2.0.6.patch deleted file mode 100644 index 54b3eb2..0000000 --- a/0000-update-from-v2.0.5-to-v2.0.6.patch +++ /dev/null @@ -1,21385 +0,0 @@ -From 3fa5ff4e27ce491f9640788e1352d357e6931120 Mon Sep 17 00:00:00 2001 -From: gaohuatao -Date: Thu, 12 Nov 2020 19:13:08 +0800 -Subject: [PATCH] update from v2.0.5 to v2.0.6 - -Signed-off-by: gaohuatao ---- - CI/Dockerfile | 2 +- - CI/install_depends.sh | 1 + - CI/make-and-install.sh | 4 +- - CI/test.sh | 2 +- - CI/test_cases/container_cases/blkio_iops.sh | 74 + - CI/test_cases/container_cases/blkio_weight.sh | 76 + - .../container_cases/dev_cgroup_rule.sh | 98 ++ - CI/test_cases/container_cases/nano_cpus.sh | 113 ++ - CI/test_cases/container_cases/run.sh | 2 +- - .../container_cases/storage_opts_dm.sh | 2 +- - .../image_cases/image_load_multiplex.sh | 83 ++ - .../image_cases/multiplex_busybox.tar | Bin 0 -> 20480 bytes - CI/test_cases/image_cases/registry.sh | 22 +- - CMakeLists.txt | 12 +- - Dockerfile | 2 +- - README.md | 85 +- - cmake/checker.cmake | 16 +- - cmake/options.cmake | 9 +- - docs/build_guide.md | 6 +- - iSulad.spec | 26 +- - release_notes | 62 + - src/CMakeLists.txt | 4 +- - src/client/connect/CMakeLists.txt | 2 +- - .../connect/grpc/grpc_containers_client.cc | 95 +- - src/client/connect/isula_connect.h | 2 +- - .../{libisula.c => connect/protocol_type.c} | 209 +-- - .../{libisula.h => connect/protocol_type.h} | 204 +-- - .../connect/rest/rest_containers_client.c | 94 +- - src/cmd/CMakeLists.txt | 10 +- - src/cmd/command_parser.c | 57 +- - src/cmd/command_parser.h | 6 +- - src/cmd/isula/base/create.c | 675 +++++---- - src/cmd/isula/base/create.h | 826 ++++++----- - src/cmd/isula/base/kill.c | 2 +- - src/cmd/isula/base/rename.c | 1 - - src/cmd/isula/base/restart.c | 1 - - src/cmd/isula/base/rm.c | 3 +- - src/cmd/isula/base/run.c | 59 +- - src/cmd/isula/base/start.c | 1 - - src/cmd/isula/base/start.h | 2 +- - src/cmd/isula/base/stop.c | 1 - - src/cmd/isula/client_arguments.c | 18 + - src/cmd/isula/client_arguments.h | 25 +- - src/cmd/isula/client_console.c | 319 ++++ - src/cmd/isula/client_console.h | 52 + - src/cmd/isula/extend/events.c | 8 +- - src/cmd/isula/extend/export.c | 1 - - src/cmd/isula/extend/pause.c | 1 - - src/cmd/isula/extend/resume.c | 1 - - src/cmd/isula/extend/stats.c | 9 +- - src/cmd/isula/extend/update.c | 92 +- - src/cmd/isula/extend/update.h | 34 +- - src/cmd/isula/images/images.c | 2 +- - src/cmd/isula/images/import.c | 2 +- - src/cmd/isula/images/load.c | 1 - - src/cmd/isula/images/login.c | 3 +- - src/cmd/isula/images/login.h | 4 +- - src/cmd/isula/images/logout.c | 1 - - src/cmd/isula/images/pull.c | 1 - - src/cmd/isula/images/rmi.c | 1 - - src/cmd/isula/images/tag.c | 2 +- - src/cmd/isula/information/health.c | 1 - - src/cmd/isula/information/info.c | 1 - - src/cmd/isula/information/inspect.c | 1 - - src/cmd/isula/information/logs.c | 8 +- - src/cmd/isula/information/logs.h | 16 +- - src/cmd/isula/information/ps.c | 18 +- - src/cmd/isula/information/top.c | 1 - - src/cmd/isula/information/version.c | 1 - - src/cmd/isula/information/wait.c | 2 +- - src/cmd/isula/isula_commands.c | 239 +-- - src/cmd/isula/isula_commands.h | 27 +- - src/cmd/isula/isula_container_spec.c | 486 +++++++ - src/cmd/isula/isula_container_spec.h | 92 ++ - .../isula/isula_host_spec.c} | 1296 +++++------------ - src/cmd/isula/isula_host_spec.h | 156 ++ - src/cmd/isula/stream/attach.c | 1 - - src/cmd/isula/stream/cp.c | 6 +- - src/cmd/isula/stream/exec.c | 148 +- - src/cmd/isulad-shim/main.c | 22 +- - src/cmd/isulad-shim/process.c | 291 ++-- - src/cmd/isulad-shim/terminal.c | 8 +- - src/cmd/isulad/isulad_commands.c | 176 +-- - src/cmd/isulad/isulad_commands.h | 4 +- - src/cmd/isulad/main.c | 13 +- - src/cmd/options/CMakeLists.txt | 5 + - src/cmd/options/opt_ulimit.c | 190 +++ - .../options/opt_ulimit.h} | 23 +- - src/common/constants.h | 3 - - src/contrib/config/config.json | 1 - - src/contrib/config/daemon.json | 2 +- - .../config/systemcontainer_config.json | 1 - - src/daemon/common/CMakeLists.txt | 11 +- - src/daemon/common/selinux_label.c | 2 +- - src/daemon/common/sysinfo.c | 9 +- - src/daemon/common/sysinfo.h | 2 +- - src/daemon/config/daemon_arguments.c | 4 +- - src/daemon/config/isulad_config.c | 216 +-- - src/daemon/config/isulad_config.h | 4 +- - .../connect/grpc/grpc_server_tls_auth.cc | 4 +- - src/daemon/entry/cri/cni_network_plugin.cc | 63 +- - src/daemon/entry/cri/cri_container.cc | 37 +- - src/daemon/entry/cri/cri_helpers.cc | 45 +- - src/daemon/entry/cri/cri_sandbox.cc | 62 +- - src/daemon/entry/cri/cri_security_context.cc | 5 +- - src/daemon/executor/container_cb/execution.c | 4 +- - .../executor/container_cb/execution_create.c | 227 ++- - .../executor/container_cb/execution_extend.c | 50 +- - .../container_cb/execution_information.c | 8 +- - .../executor/container_cb/execution_network.c | 10 +- - .../executor/container_cb/execution_stream.c | 26 +- - src/daemon/executor/container_cb/list.c | 4 +- - src/daemon/executor/image_cb/image_cb.c | 4 +- - .../container/container_events_handler.c | 2 +- - .../container/container_gc/containers_gc.c | 6 +- - .../modules/container/container_state.c | 8 +- - .../container/health_check/health_check.c | 22 +- - .../modules/container/restore/restore.c | 2 +- - .../modules/container/supervisor/supervisor.c | 2 +- - src/daemon/modules/events/collector.c | 24 +- - src/daemon/modules/events/monitord.c | 44 +- - src/daemon/modules/events/monitord.h | 6 +- - .../modules/events_sender/event_sender.c | 2 +- - src/daemon/modules/image/CMakeLists.txt | 2 + - src/daemon/modules/image/embedded/db/db_all.c | 8 +- - .../modules/image/embedded/db/sqlite_common.c | 14 +- - .../image/embedded/embedded_config_merge.c | 57 +- - .../image/embedded/embedded_config_merge.h | 3 +- - src/daemon/modules/image/embedded/lim.c | 14 +- - src/daemon/modules/image/embedded/lim.h | 2 +- - src/daemon/modules/image/image.c | 24 +- - .../modules/image/image_rootfs_handler.c | 45 +- - src/daemon/modules/image/image_spec_merge.c | 84 ++ - src/daemon/modules/image/image_spec_merge.h | 30 + - .../modules/image/oci/oci_common_operators.c | 10 +- - .../modules/image/oci/oci_config_merge.c | 50 +- - src/daemon/modules/image/oci/oci_image.c | 8 +- - src/daemon/modules/image/oci/oci_import.c | 34 +- - src/daemon/modules/image/oci/oci_load.c | 331 +++-- - src/daemon/modules/image/oci/oci_load.h | 5 +- - src/daemon/modules/image/oci/oci_pull.c | 5 +- - src/daemon/modules/image/oci/registry/auths.c | 36 +- - src/daemon/modules/image/oci/registry/auths.h | 2 +- - src/daemon/modules/image/oci/registry/certs.c | 4 +- - .../modules/image/oci/registry/http_request.c | 2 +- - .../modules/image/oci/registry/registry.c | 66 +- - .../image/oci/registry/registry_apiv2.c | 15 +- - src/daemon/modules/image/oci/registry_type.c | 8 +- - src/daemon/modules/image/oci/registry_type.h | 2 +- - .../oci/storage/image_store/image_store.c | 323 ++-- - .../graphdriver/devmapper/deviceset.c | 8 +- - .../storage/layer_store/graphdriver/driver.c | 4 +- - .../storage/layer_store/graphdriver/driver.h | 7 +- - .../graphdriver/overlay2/driver_overlay2.c | 40 +- - .../graphdriver/overlay2/driver_overlay2.h | 2 +- - .../graphdriver/quota/project_quota.c | 4 +- - .../image/oci/storage/layer_store/layer.h | 2 +- - .../oci/storage/layer_store/layer_store.c | 84 +- - .../oci/storage/layer_store/layer_store.h | 5 +- - .../oci/storage/rootfs_store/rootfs_store.c | 326 ++--- - .../oci/storage/rootfs_store/rootfs_store.h | 3 - - .../modules/image/oci/storage/storage.c | 48 +- - .../modules/image/oci/storage/storage.h | 4 +- - src/daemon/modules/image/oci/utils_images.c | 28 +- - src/daemon/modules/image/oci/utils_images.h | 2 - - src/daemon/modules/plugin/plugin.c | 8 +- - src/daemon/modules/runtime/engines/engine.h | 2 + - .../modules/runtime/engines/lcr/lcr_engine.c | 2 + - .../modules/runtime/engines/lcr/lcr_rt_ops.c | 12 + - .../modules/runtime/isula/isula_rt_ops.c | 6 +- - .../modules/service/service_container.c | 6 +- - src/daemon/modules/spec/specs.c | 136 +- - src/daemon/modules/spec/specs_extend.c | 50 +- - src/daemon/modules/spec/specs_mount.c | 528 +++++-- - src/daemon/modules/spec/specs_namespace.c | 10 +- - src/daemon/modules/spec/specs_security.c | 57 +- - src/daemon/modules/spec/specs_security.h | 4 +- - src/daemon/modules/spec/verify.c | 147 +- - src/utils/cutils/map/rb_tree.c | 8 +- - src/utils/cutils/namespace.c | 6 +- - src/utils/cutils/namespace.h | 12 +- - src/utils/cutils/path.c | 56 +- - src/utils/cutils/path.h | 25 +- - src/utils/cutils/utils.c | 430 +----- - src/utils/cutils/utils.h | 66 +- - src/utils/cutils/utils_convert.c | 52 + - src/utils/cutils/utils_convert.h | 4 +- - src/utils/cutils/utils_file.c | 24 +- - src/utils/cutils/utils_file.h | 8 +- - src/utils/cutils/utils_fs.c | 41 +- - src/utils/cutils/utils_fs.h | 3 +- - src/utils/cutils/utils_regex.c | 5 +- - src/utils/cutils/utils_string.c | 61 +- - src/utils/cutils/utils_string.h | 22 +- - src/utils/cutils/utils_timestamp.c | 145 +- - src/utils/cutils/utils_timestamp.h | 47 +- - src/utils/cutils/utils_verify.c | 101 +- - src/utils/cutils/utils_verify.h | 17 + - src/utils/http/parser.c | 2 +- - src/utils/http/rest_common.c | 5 +- - src/utils/sha256/sha256.c | 2 +- - src/utils/sha256/sha256.h | 2 +- - src/utils/tar/isulad_tar.c | 28 +- - src/utils/tar/util_archive.c | 4 +- - test/cmd/isula/CMakeLists.txt | 2 +- - test/cmd/isula/extend/pause/CMakeLists.txt | 2 +- - test/cmd/isula/extend/pause/pause_ut.cc | 2 +- - test/cmd/isula/extend/resume/CMakeLists.txt | 2 +- - test/cmd/isula/extend/resume/resume_ut.cc | 2 +- - .../CMakeLists.txt | 0 - .../info/CMakeLists.txt | 2 +- - .../info/info_ut.cc | 2 +- - .../ps/CMakeLists.txt | 2 +- - .../{infomation => information}/ps/ps_ut.cc | 2 +- - test/cutils/utils_string/utils_string_ut.cc | 136 +- - .../image/oci/oci_config_merge/CMakeLists.txt | 3 + - test/image/oci/registry/registry_ut.cc | 15 +- - .../oci/storage/images/storage_images_ut.cc | 10 +- - .../oci/storage/layers/storage_driver_ut.cc | 4 +- - .../oci/storage/layers/storage_layers_ut.cc | 8 +- - .../oci/storage/rootfs/storage_rootfs_ut.cc | 22 +- - test/mocks/namespace_mock.cc | 2 +- - test/mocks/storage_mock.cc | 12 +- - test/mocks/storage_mock.h | 3 +- - test/path/path_ut.cc | 102 +- - test/runtime/isula/CMakeLists.txt | 1 + - test/runtime/lcr/CMakeLists.txt | 1 + - test/specs/specs/CMakeLists.txt | 1 + - test/specs/specs_extend/CMakeLists.txt | 1 + - 229 files changed, 6590 insertions(+), 5326 deletions(-) - create mode 100644 CI/test_cases/container_cases/blkio_iops.sh - create mode 100644 CI/test_cases/container_cases/blkio_weight.sh - create mode 100644 CI/test_cases/container_cases/dev_cgroup_rule.sh - create mode 100644 CI/test_cases/container_cases/nano_cpus.sh - create mode 100755 CI/test_cases/image_cases/image_load_multiplex.sh - create mode 100644 CI/test_cases/image_cases/multiplex_busybox.tar - rename src/client/{libisula.c => connect/protocol_type.c} (84%) - rename src/client/{libisula.h => connect/protocol_type.h} (80%) - create mode 100644 src/cmd/isula/client_console.c - create mode 100644 src/cmd/isula/client_console.h - create mode 100644 src/cmd/isula/isula_container_spec.c - create mode 100644 src/cmd/isula/isula_container_spec.h - rename src/{client/connect/pack_config.c => cmd/isula/isula_host_spec.c} (51%) - create mode 100644 src/cmd/isula/isula_host_spec.h - create mode 100644 src/cmd/options/CMakeLists.txt - create mode 100644 src/cmd/options/opt_ulimit.c - rename src/{client/connect/pack_config.h => cmd/options/opt_ulimit.h} (65%) - create mode 100644 src/daemon/modules/image/image_spec_merge.c - create mode 100644 src/daemon/modules/image/image_spec_merge.h - rename test/cmd/isula/{infomation => information}/CMakeLists.txt (100%) - rename test/cmd/isula/{infomation => information}/info/CMakeLists.txt (97%) - rename test/cmd/isula/{infomation => information}/info/info_ut.cc (98%) - rename test/cmd/isula/{infomation => information}/ps/CMakeLists.txt (97%) - rename test/cmd/isula/{infomation => information}/ps/ps_ut.cc (99%) - -diff --git a/CI/Dockerfile b/CI/Dockerfile -index d953da9..b6f2e2c 100644 ---- a/CI/Dockerfile -+++ b/CI/Dockerfile -@@ -8,7 +8,7 @@ - # - IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR - # - PURPOSE. - # - See the Mulan PSL v2 for more details. --##- @Description: prepare compile container envrionment -+##- @Description: prepare compile container environment - ##- @Author: lifeng - ##- @Create: 2020-01-10 - ####################################################################### -diff --git a/CI/install_depends.sh b/CI/install_depends.sh -index 97fefa7..61dd67d 100755 ---- a/CI/install_depends.sh -+++ b/CI/install_depends.sh -@@ -113,6 +113,7 @@ if [ -d ./runc ];then - fi - git clone https://gitee.com/src-openeuler/runc.git - cd runc -+git checkout -q origin/openEuler-20.03-LTS - ./apply-patch - mkdir -p .gopath/src/github.com/opencontainers - export GOPATH=`pwd`/.gopath -diff --git a/CI/make-and-install.sh b/CI/make-and-install.sh -index a3d4888..c53cdc6 100755 ---- a/CI/make-and-install.sh -+++ b/CI/make-and-install.sh -@@ -89,7 +89,7 @@ cmake -DLIB_INSTALL_DIR=${restbuilddir}/lib -DCMAKE_INSTALL_PREFIX=${restbuilddi - make -j $(nproc) - make install - sed -i 's/"log-driver": "stdout"/"log-driver": "file"/g' ${restbuilddir}/etc/isulad/daemon.json --sed -i "/registry-mirrors/a\ \"https://hub-mirror.c.163.com\"" ${restbuilddir}/etc/isulad/daemon.json -+sed -i "/registry-mirrors/a\ \"https://3laho3y3.mirror.aliyuncs.com\"" ${restbuilddir}/etc/isulad/daemon.json - - #build grpc version - cd $ISULAD_COPY_PATH -@@ -104,4 +104,4 @@ fi - make -j $(nproc) - make install - sed -i 's/"log-driver": "stdout"/"log-driver": "file"/g' ${builddir}/etc/isulad/daemon.json --sed -i "/registry-mirrors/a\ \"https://hub-mirror.c.163.com\"" ${builddir}/etc/isulad/daemon.json -+sed -i "/registry-mirrors/a\ \"https://3laho3y3.mirror.aliyuncs.com\"" ${builddir}/etc/isulad/daemon.json -diff --git a/CI/test.sh b/CI/test.sh -index d21ca89..36427b9 100755 ---- a/CI/test.sh -+++ b/CI/test.sh -@@ -42,6 +42,6 @@ elif [ "x$subcmd" == "xget" ];then - sleep 2 - done - else -- echo "unknwon subcmd $subcmd" -+ echo "unknown subcmd $subcmd" - exit 1 - fi -diff --git a/CI/test_cases/container_cases/blkio_iops.sh b/CI/test_cases/container_cases/blkio_iops.sh -new file mode 100644 -index 0000000..58d3d7f ---- /dev/null -+++ b/CI/test_cases/container_cases/blkio_iops.sh -@@ -0,0 +1,74 @@ -+#!/bin/bash -+# -+# attributes: isulad basic blkio iops -+# concurrent: NA -+# spend time: 5 -+ -+####################################################################### -+##- @Copyright (C) Huawei Technologies., 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. -+##- @Description:CI -+##- @Author: lifeng -+##- @Create: 2020-09-03 -+####################################################################### -+ -+declare -r curr_path=$(dirname $(readlink -f "$0")) -+source ../helpers.sh -+ -+function test_blkio_iops_spec() -+{ -+ local ret=0 -+ local image="busybox" -+ local test="container blkio iops test => (${FUNCNAME[@]})" -+ -+ msg_info "${test} starting..." -+ -+ isula pull ${image} -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to pull image: ${image}" && return ${FAILURE} -+ -+ isula images | grep busybox -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - missing list image: ${image}" && ((ret++)) -+ -+ isula run -itd --device-read-iops /dev/loop0:-1 $image /bin/sh 2>&1 | grep "Number must be unsigned 64 bytes integer" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check Number must be unsigned 64 bytes integer" && ((ret++)) -+ -+ isula run -itd --device-write-iops /dev/loop0:-1 $image /bin/sh 2>&1 | grep "Number must be unsigned 64 bytes integer" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check Number must be unsigned 64 bytes integer" && ((ret++)) -+ -+ isula run -itd --device-write-iops /dev/loop0:2b $image /bin/sh 2>&1 | grep "Number must be unsigned 64 bytes integer" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check Number must be unsigned 64 bytes integer" && ((ret++)) -+ -+ c_id=`isula run -itd --device-read-iops /dev/loop0:123 --device-read-iops /dev/zero:111 --device-write-iops /dev/loop0:567 --device-write-iops /dev/zero:321 busybox sh` -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run container with image: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/blkio/blkio.throttle.read_iops_device" | grep "7:0 123" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check container with image: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/blkio/blkio.throttle.read_iops_device" | grep "1:5 111" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check container with image: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/blkio/blkio.throttle.write_iops_device" | grep "7:0 567" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check container with image: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/blkio/blkio.throttle.write_iops_device" | grep "1:5 321" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check container with image: ${image}" && ((ret++)) -+ -+ isula rm -f $c_id -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to rm container ${c_id}" && ((ret++)) -+ -+ msg_info "${test} finished with return ${ret}..." -+ return ${ret} -+} -+ -+declare -i ans=0 -+ -+test_blkio_iops_spec || ((ans++)) -+ -+show_result ${ans} "${curr_path}/${0}" -diff --git a/CI/test_cases/container_cases/blkio_weight.sh b/CI/test_cases/container_cases/blkio_weight.sh -new file mode 100644 -index 0000000..6d69960 ---- /dev/null -+++ b/CI/test_cases/container_cases/blkio_weight.sh -@@ -0,0 +1,76 @@ -+#!/bin/bash -+# -+# attributes: isulad basic blkio weight -+# concurrent: NA -+# spend time: 5 -+ -+####################################################################### -+##- @Copyright (C) Huawei Technologies., 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. -+##- @Description:CI -+##- @Author: lifeng -+##- @Create: 2020-09-03 -+####################################################################### -+ -+declare -r curr_path=$(dirname $(readlink -f "$0")) -+source ../helpers.sh -+ -+function test_blkio_weight_spec() -+{ -+ local ret=0 -+ local image="busybox" -+ local test="container blkio weight test => (${FUNCNAME[@]})" -+ -+ msg_info "${test} starting..." -+ -+ isula pull ${image} -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to pull image: ${image}" && return ${FAILURE} -+ -+ isula images | grep busybox -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - missing list image: ${image}" && ((ret++)) -+ -+ isula run -itd --blkio-weight 1001 $image /bin/sh 2>&1 | grep "Range of blkio weight is from 10 to 1000" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check Range of blkio weight is from 10 to 1000" && ((ret++)) -+ -+ isula run -itd --blkio-weight -1 $image /bin/sh 2>&1 | grep "Numerical result out of range" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check Range of blkio weight is from 10 to 1000" && ((ret++)) -+ -+ isula run -itd --blkio-weight-device /dev/zero:1001 $image /bin/sh 2>&1 | grep "Invalid weight for device" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Invalid weight for device" && ((ret++)) -+ -+ isula run -itd --blkio-weight-device /dev/zero:-1 $image /bin/sh 2>&1 | grep "Invalid weight for device" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Invalid weight for device" && ((ret++)) -+ -+ c_id=`isula run -itd --blkio-weight 200 ${image} sh` -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run container with image: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/blkio/blkio.weight" | grep "200" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check container blkio.weight: 200" && ((ret++)) -+ -+ isula update --blkio-weight 300 $c_id -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to update container blkio.weight" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/blkio/blkio.weight" | grep "300" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check container blkio.weight: 300" && ((ret++)) -+ -+ isula rm -f $c_id -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to rm container ${c_id}" && ((ret++)) -+ -+ msg_info "${test} finished with return ${ret}..." -+ return ${ret} -+} -+ -+declare -i ans=0 -+ -+if [ -f "/sys/fs/cgroup/blkio/blkio.weight" ];then -+ test_blkio_weight_spec || ((ans++)) -+fi -+ -+show_result ${ans} "${curr_path}/${0}" -diff --git a/CI/test_cases/container_cases/dev_cgroup_rule.sh b/CI/test_cases/container_cases/dev_cgroup_rule.sh -new file mode 100644 -index 0000000..46f0a2a ---- /dev/null -+++ b/CI/test_cases/container_cases/dev_cgroup_rule.sh -@@ -0,0 +1,98 @@ -+#!/bin/bash -+# -+# attributes: isulad basic device cgroup rule -+# concurrent: NA -+# spend time: 5 -+ -+####################################################################### -+##- @Copyright (C) Huawei Technologies., 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. -+##- @Description:CI -+##- @Author: lifeng -+##- @Create: 2020-09-03 -+####################################################################### -+ -+declare -r curr_path=$(dirname $(readlink -f "$0")) -+source ../helpers.sh -+ -+function test_cpu_dev_cgoup_rule_spec() -+{ -+ local ret=0 -+ local image="busybox" -+ local test="container device cgroup rule test => (${FUNCNAME[@]})" -+ -+ msg_info "${test} starting..." -+ -+ isula pull ${image} -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to pull image: ${image}" && return ${FAILURE} -+ -+ isula images | grep busybox -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - missing list image: ${image}" && ((ret++)) -+ -+ isula run -itd --device-cgroup-rule='b *:*' busybox 2>&1 | grep "Invalid value" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Invalid value" && ((ret++)) -+ -+ isula run -itd --device-cgroup-rule='d *:*' busybox 2>&1 | grep "Invalid value" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Invalid value" && ((ret++)) -+ -+ isula run -itd --device-cgroup-rule='d *:* xxx' busybox 2>&1 | grep "Invalid value" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Invalid value" && ((ret++)) -+ -+ c_id=`isula run -itd --device-cgroup-rule='b 11:22 rmw' --device-cgroup-rule='c *:23 rmw' --device-cgroup-rule='c 33:* rm' busybox sh` -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run container with image: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/devices/devices.list" | grep "b 11:22 rwm" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check b 11:22 rmw: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/devices/devices.list" | grep "c \*:23 rwm" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check c *:23 rmw: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/devices/devices.list" | grep "c 33:\* rm" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check c 33:* rm: ${image}" && ((ret++)) -+ -+ isula restart -t 0 $c_id -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to restart container: $c_id" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/devices/devices.list" | grep "b 11:22 rwm" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check b 11:22 rmw: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/devices/devices.list" | grep "c \*:23 rwm" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check c *:23 rmw: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/devices/devices.list" | grep "c 33:\* rm" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check c 33:* rm: ${image}" && ((ret++)) -+ -+ isula rm -f $c_id -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to rm container ${c_id}" && ((ret++)) -+ -+ c_id=`isula run -itd --device-cgroup-rule='a 11:22 rmw' busybox sh` -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run container with image: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/devices/devices.list" | grep "a \*:\* rwm" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check a *:* rwm: ${image}" && ((ret++)) -+ -+ isula restart -t 0 $c_id -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to restart container: $c_id" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/devices/devices.list" | grep "a \*:\* rwm" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check a *:* rwm: ${image}" && ((ret++)) -+ -+ isula rm -f $c_id -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to rm container ${c_id}" && ((ret++)) -+ -+ msg_info "${test} finished with return ${ret}..." -+ return ${ret} -+} -+ -+declare -i ans=0 -+ -+test_cpu_dev_cgoup_rule_spec || ((ans++)) -+ -+show_result ${ans} "${curr_path}/${0}" -diff --git a/CI/test_cases/container_cases/nano_cpus.sh b/CI/test_cases/container_cases/nano_cpus.sh -new file mode 100644 -index 0000000..fd69c5d ---- /dev/null -+++ b/CI/test_cases/container_cases/nano_cpus.sh -@@ -0,0 +1,113 @@ -+#!/bin/bash -+# -+# attributes: isulad basic nano iops -+# concurrent: NA -+# spend time: 5 -+ -+####################################################################### -+##- @Copyright (C) Huawei Technologies., 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. -+##- @Description:CI -+##- @Author: lifeng -+##- @Create: 2020-09-03 -+####################################################################### -+ -+declare -r curr_path=$(dirname $(readlink -f "$0")) -+source ../helpers.sh -+ -+function test_cpu_nano_spec() -+{ -+ local ret=0 -+ local image="busybox" -+ local test="container blkio nano test => (${FUNCNAME[@]})" -+ -+ msg_info "${test} starting..." -+ -+ isula pull ${image} -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to pull image: ${image}" && return ${FAILURE} -+ -+ isula images | grep busybox -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - missing list image: ${image}" && ((ret++)) -+ -+ isula run -itd --cpus 1.5 --cpu-period 20000 $image /bin/sh 2>&1 | grep "Nano CPUs and CPU Period cannot both be set" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Nano CPUs and CPU Period cannot both be set" && ((ret++)) -+ -+ isula run -itd --cpus 1.5 --cpu-quota 20000 $image /bin/sh 2>&1 | grep "Nano CPUs and CPU Quota cannot both be set" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Nano CPUs and CPU Quota cannot both be set" && ((ret++)) -+ -+ c_id=`isula run -itd --cpus 1.5 busybox sh` -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run container with image: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us" | grep "150000" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_quota_us: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us" | grep "100000" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_period_us: ${image}" && ((ret++)) -+ -+ isula restart -t 0 $c_id -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to restart container: $c_id" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us" | grep "150000" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_quota_us: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us" | grep "100000" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_period_us: ${image}" && ((ret++)) -+ -+ isula update --cpus 1.3 --cpu-period 20000 $c_id 2>&1 | grep "Nano CPUs and CPU Period cannot both be set" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Nano CPUs and CPU Period cannot both be set" && ((ret++)) -+ -+ isula update --cpus 1.3 --cpu-quota 20000 $c_id 2>&1 | grep "Nano CPUs and CPU Quota cannot both be set" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Nano CPUs and CPU Quota cannot both be set" && ((ret++)) -+ -+ isula update --cpu-period 20000 $c_id 2>&1 | grep "CPU Period cannot be updated as NanoCPUs has already been set" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - CPU Period cannot be updated as NanoCPUs has already been set" && ((ret++)) -+ -+ isula update --cpu-quota 20000 $c_id 2>&1 | grep "CPU Quota cannot be updated as NanoCPUs has already been set" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - CPU Quota cannot be updated as NanoCPUs has already been set" && ((ret++)) -+ -+ isula update --cpus 1.3 $c_id -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Failed to update cpus" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us" | grep "130000" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_quota_us: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us" | grep "100000" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_period_us: ${image}" && ((ret++)) -+ -+ isula restart -t 0 $c_id -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to restart container: $c_id" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us" | grep "130000" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_quota_us: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us" | grep "100000" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_period_us: ${image}" && ((ret++)) -+ -+ isula rm -f $c_id -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to rm container ${c_id}" && ((ret++)) -+ -+ c_id=`isula run -itd --cpu-period 20000 --cpu-quota 10000 busybox sh` -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run container with image: ${image}" && ((ret++)) -+ -+ isula update --cpus 1.4 $c_id 2>&1 | grep "Nano CPUs cannot be updated as CPU Period has already been set" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Nano CPUs cannot be updated as CPU Period has already been set" && ((ret++)) -+ -+ isula rm -f $c_id -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to rm container ${c_id}" && ((ret++)) -+ -+ msg_info "${test} finished with return ${ret}..." -+ return ${ret} -+} -+ -+declare -i ans=0 -+ -+test_cpu_nano_spec || ((ans++)) -+ -+show_result ${ans} "${curr_path}/${0}" -diff --git a/CI/test_cases/container_cases/run.sh b/CI/test_cases/container_cases/run.sh -index 85f6e55..357fcd0 100755 ---- a/CI/test_cases/container_cases/run.sh -+++ b/CI/test_cases/container_cases/run.sh -@@ -50,7 +50,7 @@ function do_test_t() - - echo AA > /tmp/test_run_env - -- isula run --name $containername -itd -e AAA=BB -e BAA --env-file /tmp/test_run_env busybox -+ isula run --name $containername -itd --user 100:100 -e AAA=BB -e BAA --env-file /tmp/test_run_env busybox - fn_check_eq "$?" "0" "run failed" - testcontainer $containername running - -diff --git a/CI/test_cases/container_cases/storage_opts_dm.sh b/CI/test_cases/container_cases/storage_opts_dm.sh -index 705eaad..e0f476f 100755 ---- a/CI/test_cases/container_cases/storage_opts_dm.sh -+++ b/CI/test_cases/container_cases/storage_opts_dm.sh -@@ -84,7 +84,7 @@ function do_test() - { - local ret=0 - -- local test="devicemapper dm.mkfsarg adn dm.mountopt params test => (${FUNCNAME[@]})" -+ local test="devicemapper dm.mkfsarg and dm.mountopt params test => (${FUNCNAME[@]})" - msg_info "${test} starting..." - - isula pull $image_busybox -diff --git a/CI/test_cases/image_cases/image_load_multiplex.sh b/CI/test_cases/image_cases/image_load_multiplex.sh -new file mode 100755 -index 0000000..719d8e7 ---- /dev/null -+++ b/CI/test_cases/image_cases/image_load_multiplex.sh -@@ -0,0 +1,83 @@ -+#!/bin/bash -+# -+# attributes: isulad basic image -+# concurrent: NA -+# spend time: 22 -+ -+####################################################################### -+##- @Copyright (C) Huawei Technologies., 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. -+##- @Description:CI -+##- @Author: gaohuatao -+##- @Create: 2020-10-12 -+####################################################################### -+ -+declare -r curr_path=$(dirname $(readlink -f "$0")) -+source ../helpers.sh -+base_image="${curr_path}/busybox.tar" -+multiplex_image="${curr_path}/multiplex_busybox.tar" -+ -+function test_multiplex_layers_image_load() -+{ -+ local ret=0 -+ local test="isula load image with multiplex layers test => (${FUNCNAME[@]})" -+ -+ msg_info "${test} starting..." -+ -+ # remove all images related to busybox -+ isula rmi `isula images | grep busybox | awk '{print $3}'` -+ -+ # load image lacking layers -+ isula load -i $multiplex_image -+ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - load image success, expect fail: ${multiplex_image}" && ((ret++)) -+ -+ isula images | grep "multiplex_busybox" -+ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - get image: multiplex_busybox, expect no such image" && ((ret++)) -+ -+ # load base image -+ isula load -i $base_image -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - load image failed: ${base_image} with" && ((ret++)) -+ -+ isula images | grep busybox -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - missing list base image: busybox" && ((ret++)) -+ -+ # load image with base image loaded -+ isula load -i $multiplex_image -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - load image failed: ${multiplex_image}" && ((ret++)) -+ -+ container_name=multiplex_container -+ isula run -tid --name $container_name multiplex_busybox:latest /bin/sh -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - isula run failed" && ((ret++)) -+ -+ isula exec $container_name sh -c 'ls /gao' -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - no such file /gao" && ((ret++)) -+ -+ isula rm -f $container_name -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - rm container failed" && ((ret++)) -+ -+ base_id=`isula inspect -f '{{.image.id}}' busybox:latest` -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - fail to inspect image: busybox:latest" && ((ret++)) -+ -+ mult_id=`isula inspect -f '{{.image.id}}' multiplex_busybox:latest` -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - fail to inspect image: multiplex_busybox:latest" && ((ret++)) -+ -+ isula rmi $base_id $mult_id -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to remove image ${base_id} and ${mult_id}" && ((ret++)) -+ -+ msg_info "${test} finished with return ${ret}..." -+ return ${ret} -+} -+ -+declare -i ans=0 -+ -+test_multiplex_layers_image_load || ((ans++)) -+ -+show_result ${ans} "${curr_path}/${0}" -+ -diff --git a/CI/test_cases/image_cases/multiplex_busybox.tar b/CI/test_cases/image_cases/multiplex_busybox.tar -new file mode 100644 -index 0000000000000000000000000000000000000000..e55144cc2ffecb6996937acbce41172e5412733a -GIT binary patch -literal 20480 -zcmeI2TTdHD6vuh)r?93ktz_)EUo7>30#YI+B}!BZm*6unALjLYOYa2od -z*hw%b5wk{k=RW&8GqZF4c+EwkXOJ7y?J5C!6jn0fAB6ETT&PmWJ5~HcXgajd^1H(k;G!aI)kYxe$ -zz_G#7a&45rYW)D}4E&|`r;2W23Llc}{}{t&1NMKr|N71IgFo)>ZD)VU`OSHM8HQB0 -zbvgeR_9v9X{Kt1!xw(`lKL5$!Q7CWDUa6*y64=1}|F@~im3>+>|0%=j=KO~pK$`z6 -zp>8Pg0_6dX(0w-nsE;PLj%5pVNy()NGEya(WyS<%jp5XCqnV=IDl1(GGSdQ!Kp~5a -zo;Z(%VgmLV7V7eKv~BD<)@=p03H;GRtVdXlC>>CxmC%N(f4Zzy+1k8}^$FZ%`6(J* -zpl4OnmUbMWJmlD`#*pDt_|GQRib!H4Ydx(AeabRcqg29++&43 -z1`|XpDT~aL5PWdlf#r<0+6O2Jd%|8`_J+N#!JYcF*>Aj^bXIBWDUf_9&G}nIF*5{Kd??%}o$3gk~G%uh>i{K0EVzDef>!VQl_b@I##Jb5V -zurMNKfZ0GoOHXjDz%cni?PzO%mbcNj)4CgPb{r%J8&+UxROIFKBbse!HGF#2Y~cN0 -z*z;Hqz>B_%-kSG6gY+Bke{la~djH?WbCdC>w%TNMx7LM0*jerWUD=;;*b9R4AQ*d0 -z`-3aGPTyIV-VJiNE}hz2L8Qn;AQ4Cez9RyIAuP7kSy-PVaf)Yf1D=?SBzU7E+&OMD -z!bPU3^Tsh9tfM+3*hfnx)_!nb|DRF*ng7p022T3lBaD*^bjR*Gc}PEyr<+8OB!b)_ -zf_#OPwn8sC%bT{ULGL=cxGBzIxsB-|B_m=+LJeTA59_&>d@jx{bi5M>B`?LQ-nQ>8 -zg{qysy`@g2xrgINnngje3Pd?U2#zGim}S^H5tO%@k)Sw;#W-3=qE^AfnK2wxayGmv|( -zX(WBrxiA@sCKsqZpL9yf{8<`!w2)`nNgg2W=t|CW5nv1ES-=?_1jG5TWZDX91dB2Q -z!4|Z>C>&7)8%lyR(Nk+duT>O|jSbYg6b1w3hIo;|2OFZ5RiF$Tsci&(m_#T~trRY5 -z?S!SCN~SQ$6q6E8nWdoUc$V~?huR7ZhIO1&O%Ag=kIloh()q=!{D1Q4YSMP+6ma~~bcZ?jJ{X$KetMWum1^Atfx&QW%RB>P -zulM7=wY_!opTmzmx;)DZ^gjwOp5*_1EAOu<2m86*<+&-^h!Ozr{nzkDIkczq-Na|B -z%V@c@z~Ac7;nf)gG=JYE>sn>Uv*WaSea&!6c@u#|AQ4Ce5`jb@5l93Q -zfkYq?NCXmrL?97J1QLNnAQ4Ce5`jb@5l93QfkYq?NCXmrL?97J1QLNnAQ4Ce9*Mwz -DD^Trr - -literal 0 -HcmV?d00001 - -diff --git a/CI/test_cases/image_cases/registry.sh b/CI/test_cases/image_cases/registry.sh -index 7507d22..042b1f4 100755 ---- a/CI/test_cases/image_cases/registry.sh -+++ b/CI/test_cases/image_cases/registry.sh -@@ -39,8 +39,8 @@ function isula_pull() - isula inspect busybox - fn_check_eq "$?" "0" "isula inspect busybox" - -- isula pull hub-mirror.c.163.com/library/busybox -- fn_check_eq "$?" "0" "isula pull hub-mirror.c.163.com/library/busybox" -+ isula pull 3laho3y3.mirror.aliyuncs.com/library/busybox -+ fn_check_eq "$?" "0" "isula pull 3laho3y3.mirror.aliyuncs.com/library/busybox" - - rm -f /etc/isulad/daemon.json.bak - cp /etc/isulad/daemon.json /etc/isulad/daemon.json.bak -@@ -59,7 +59,7 @@ function isula_pull() - cp /etc/isulad/daemon.json.bak /etc/isulad/daemon.json - rm -f /etc/isulad/daemon.json.bak - -- isula rmi hub-mirror.c.163.com/library/busybox -+ isula rmi 3laho3y3.mirror.aliyuncs.com/library/busybox - - check_valgrind_log - fn_check_eq "$?" "0" "stop isulad with check valgrind" -@@ -70,12 +70,12 @@ function isula_pull() - - function isula_login() - { -- isula login -u test -p test hub-mirror.c.163.com -- fn_check_eq "$?" "0" "isula login -u test -p test hub-mirror.c.163.com" -+ isula login -u test -p test 3laho3y3.mirror.aliyuncs.com -+ fn_check_eq "$?" "0" "isula login -u test -p test 3laho3y3.mirror.aliyuncs.com" - - # double login for memory leak check -- isula login -u test -p test hub-mirror.c.163.com -- fn_check_eq "$?" "0" "isula login -u test -p test hub-mirror.c.163.com" -+ isula login -u test -p test 3laho3y3.mirror.aliyuncs.com -+ fn_check_eq "$?" "0" "isula login -u test -p test 3laho3y3.mirror.aliyuncs.com" - - # use username/password to pull busybox for memmory leak check - isula pull busybox -@@ -84,12 +84,12 @@ function isula_login() - - function isula_logout() - { -- isula logout hub-mirror.c.163.com -- fn_check_eq "$?" "0" "isula logout hub-mirror.c.163.com" -+ isula logout 3laho3y3.mirror.aliyuncs.com -+ fn_check_eq "$?" "0" "isula logout 3laho3y3.mirror.aliyuncs.com" - - # double logout for memory leak check -- isula logout hub-mirror.c.163.com -- fn_check_eq "$?" "0" "isula logout hub-mirror.c.163.com" -+ isula logout 3laho3y3.mirror.aliyuncs.com -+ fn_check_eq "$?" "0" "isula logout 3laho3y3.mirror.aliyuncs.com" - } - - function do_test_t() -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 7226ba9..94cc244 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -9,7 +9,7 @@ include(cmake/set_build_flags.cmake) - - #set(CMAKE_C_COMPILER "gcc" CACHE PATH "c compiler") - --set(GIT_COMMIT_HASH "f84000843bf2ba98adea547721b235e3b77168e1") -+set(GIT_COMMIT_HASH "375d59895aab13dc8d6606e2764783a2d4b9d161") - message("-- commit id: " ${GIT_COMMIT_HASH}) - add_definitions(-DISULAD_GIT_COMMIT="${GIT_COMMIT_HASH}") - -@@ -89,16 +89,6 @@ ENDIF(ENABLE_UT) - # install all files - install(FILES ${CMAKE_BINARY_DIR}/conf/isulad.pc - DESTINATION ${LIB_INSTALL_DIR_DEFAULT}/pkgconfig PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ GROUP_WRITE) --install(FILES src/client/libisula.h -- DESTINATION include/isulad) --install(FILES src/client/connect/isula_connect.h -- DESTINATION include/isulad) --install(FILES src/utils/cutils/utils_timestamp.h -- DESTINATION include/isulad) --install(FILES src/utils/cutils/error.h -- DESTINATION include/isulad) --install(FILES src/daemon/modules/runtime/engines/engine.h -- DESTINATION include/isulad) - install(FILES src/daemon/modules/api/image_api.h - DESTINATION include/isulad) - -diff --git a/Dockerfile b/Dockerfile -index d65e355..20e714c 100644 ---- a/Dockerfile -+++ b/Dockerfile -@@ -8,7 +8,7 @@ - # - IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR - # - PURPOSE. - # - See the Mulan PSL v2 for more details. --##- @Description: prepare compile container envrionment -+##- @Description: prepare compile container environment - ##- @Author: lifeng - ##- @Create: 2020-01-10 - ####################################################################### -diff --git a/README.md b/README.md -index 934f6ee..08467dd 100644 ---- a/README.md -+++ b/README.md -@@ -9,13 +9,24 @@ - ### Installing - To install iSulad, you can use `rpm` or `yum` package manager command with `openEuler` repository. - --Install iSulad with yum -+Or write repository file by hand: -+ -+```sh -+cat << EOF > /etc/yum.repos.d/openEuler.repo -+[openEuler] -+baseurl=https://repo.openeuler.org/openEuler-20.03-LTS/OS/\$basearch -+enabled=1 -+EOF -+``` -+ -+Install iSulad with yum: -+ - ```sh - yum install -y iSulad - ``` - - ### Run --We provide `systemd` service to start `iSulad` -+We provide `systemd` service to start `iSulad`: - ```sh - systemctl start isulad # run the server with systemd command - ``` -@@ -25,43 +36,51 @@ You can use direct command to start `iSulad` server: - $ sudo isulad # run the server with default socket name and default log level and images manage function - ``` - ### Operations on containers: --`iSulad` provides command line `isulad` to talk with server. --Here are some sample commands to manager containers. - --List all containers in your own environment: --```sh --# list containers --$ sudo isula ps -a --``` -+For more informations on how to use `iSulad`, please refer to the [guide](https://openeuler.org/en/docs/20.03_LTS/docs/Container/isulad-container-engine.html) - --Create a container with busybox named `test` --```sh --# create a container 'test' with image busybox --$ sudo isula create -t -n test busybox --``` -+`iSulad` provides two operate interfaces to manager images and containers. -+ -+- CLI, `iSulad` provides `isula` as client CLI -+ -+ Here are some sample commands to manager containers. -+ -+ List all containers in your own environment: -+ ```sh -+ # list containers -+ $ sudo isula ps -a -+ ``` -+ -+ Create a container with busybox named `test`: -+ ```sh -+ # create a container 'test' with image busybox -+ $ sudo isula create -t -n test busybox -+ ``` -+ -+ Start this container `test`: -+ ```sh -+ # start the container 'test' -+ $ sudo isula start test -+ ``` -+ Kill the container `test`: -+ ```sh -+ # kill the container 'test': -+ $ sudo isula kill test -+ ``` -+ Remove the container `test`: -+ ```sh -+ # remove the container 'test' -+ $ sudo isula rm test -+ ``` -+ -+- CRI interface, `iSulad` can be integrated with `kubernetes` through CRI interface -+ -+ How to integrate with `kubernetes` please refer to [integration.md](./docs/integration.md) - --Start this container `test` --```sh --# start the container 'test' --$ sudo isula start test --``` --Kill the container `test` --```sh --# kill the container 'test' --$ sudo isula kill test --``` --Remove the container `test` --```sh --# remove the container 'test' --$ sudo isula rm test --``` - - ### Build from source - Build requirements for developers are listed in [build_guide](./docs/build_guide.md) - --### Integration --Integrate with `kubernetes` are listed in [integration.md](./docs/integration.md) -- - ## Performance - - #### Machine configuration -@@ -79,7 +98,7 @@ ARM machine: - - | Configuration | Information | - | ------------- | ------------- | --| OS | Euleros | -+| OS | openEuler | - | Kernel | linux 4.19.90 | - | CPU | 64 cores | - | Memory | 196 GB | -diff --git a/cmake/checker.cmake b/cmake/checker.cmake -index 112fb17..5ba4c63 100644 ---- a/cmake/checker.cmake -+++ b/cmake/checker.cmake -@@ -90,13 +90,15 @@ find_library(CURL_LIBRARY curl - HINTS ${PC_CURL_LIBDIR} ${PC_CURL_LIBRARY_DIRS}) - _CHECK(CURL_LIBRARY "CURL_LIBRARY-NOTFOUND" "libcurl.so") - --pkg_check_modules(PC_SELINUX "libselinux>=2.0") --find_path(SELINUX_INCLUDE_DIR "selinux/selinux.h" -- HINTS ${PC_SELINUX_INCLUDEDIR} ${PC_SELINUX_INCLUDE_DIRS}) --_CHECK(SELINUX_INCLUDE_DIR "SELINUX_INCLUDE_DIR-NOTFOUND" "selinux/selinux.h") --find_library(SELINUX_LIBRARY selinux -- HINTS ${PC_SELINUX_LIBDIR} ${PC_SELINUX_LIBRARY_DIRS}) --_CHECK(SELINUX_LIBRARY "SELINUX_LIBRARY-NOTFOUND" "libselinux.so") -+if (ENABLE_SELINUX) -+ pkg_check_modules(PC_SELINUX "libselinux>=2.0") -+ find_path(SELINUX_INCLUDE_DIR "selinux/selinux.h" -+ HINTS ${PC_SELINUX_INCLUDEDIR} ${PC_SELINUX_INCLUDE_DIRS}) -+ _CHECK(SELINUX_INCLUDE_DIR "SELINUX_INCLUDE_DIR-NOTFOUND" "selinux/selinux.h") -+ find_library(SELINUX_LIBRARY selinux -+ HINTS ${PC_SELINUX_LIBDIR} ${PC_SELINUX_LIBRARY_DIRS}) -+ _CHECK(SELINUX_LIBRARY "SELINUX_LIBRARY-NOTFOUND" "libselinux.so") -+endif() - - # check iSula libutils - pkg_check_modules(PC_ISULA_LIBUTILS REQUIRED "lcr") -diff --git a/cmake/options.cmake b/cmake/options.cmake -index d8f5824..e0a2a33 100644 ---- a/cmake/options.cmake -+++ b/cmake/options.cmake -@@ -33,7 +33,7 @@ endif() - - option(VERSION "set isulad version" ON) - if (VERSION STREQUAL "ON") -- set(ISULAD_VERSION "2.0.5") -+ set(ISULAD_VERSION "2.0.6") - endif() - - option(DEBUG "set isulad gcc option" ON) -@@ -60,3 +60,10 @@ if (ENABLE_EMBEDDED STREQUAL "ON") - add_definitions(-DENABLE_EMBEDDED_IMAGE=1) - set(ENABLE_EMBEDDED_IMAGE 1) - endif() -+ -+option(ENABLE_SELINUX "enable isulad daemon selinux option" ON) -+if (ENABLE_SELINUX STREQUAL "ON") -+ add_definitions(-DENABLE_SELINUX=1) -+ set(ENABLE_SELINUX 1) -+endif() -+ -diff --git a/docs/build_guide.md b/docs/build_guide.md -index b401bb5..912139f 100644 ---- a/docs/build_guide.md -+++ b/docs/build_guide.md -@@ -19,6 +19,10 @@ $ sudo apt install -y libtool automake autoconf cmake make pkg-config libyajl-de - ## Build and install other dependencies from source - These dependencies may not be provided by your package manager. So you need to build them from source. - -+Please use the protobuf and grpc came with your distribution, if not exists then need to build them from source. -+ -+Note: grpc-1.22 can not support GCC 9+. -+ - ### set ldconfig and pkgconfig - ``` - $ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH -@@ -93,7 +97,7 @@ $ sudo -E make install - $ sudo -E ldconfig - ``` - --## Build and install specific versions dependencies from source -+## Build and install specific versions dependencies from source - iSulad depend on some specific versions dependencies. - - ### build and install lxc -diff --git a/iSulad.spec b/iSulad.spec -index 25baadc..35bd125 100644 ---- a/iSulad.spec -+++ b/iSulad.spec -@@ -1,5 +1,5 @@ --%global _version 2.0.5 --%global _release 20200903.171615.gitf8400084 -+%global _version 2.0.6 -+%global _release 20201014.143412.git375d5989 - %global is_systemd 1 - - Name: iSulad -@@ -74,13 +74,11 @@ install -d $RPM_BUILD_ROOT/%{_bindir} - install -m 0755 ./src/isula %{buildroot}/%{_bindir}/isula - install -m 0755 ./src/isulad-shim %{buildroot}/%{_bindir}/isulad-shim - install -m 0755 ./src/isulad %{buildroot}/%{_bindir}/isulad -+chrpath -d ./src/isula -+chrpath -d ./src/isulad-shim -+chrpath -d ./src/isulad - - install -d $RPM_BUILD_ROOT/%{_includedir}/isulad --install -m 0644 ../src/client/libisula.h %{buildroot}/%{_includedir}/isulad/libisula.h --install -m 0644 ../src/client/connect/isula_connect.h %{buildroot}/%{_includedir}/isulad/isula_connect.h --install -m 0644 ../src/utils/cutils/utils_timestamp.h %{buildroot}/%{_includedir}/isulad/utils_timestamp.h --install -m 0644 ../src/utils/cutils/error.h %{buildroot}/%{_includedir}/isulad/error.h --install -m 0644 ../src/daemon/modules/runtime/engines/engine.h %{buildroot}/%{_includedir}/isulad/engine.h - install -m 0644 ../src/daemon/modules/api/image_api.h %{buildroot}/%{_includedir}/isulad/image_api.h - - install -d $RPM_BUILD_ROOT/%{_sysconfdir}/isulad -@@ -127,8 +125,8 @@ fi - fi - - %post --if ! getent group isulad > /dev/null; then -- groupadd --system isulad -+if ! getent group isula > /dev/null; then -+ groupadd --system isula - fi - - if [ "$1" = "1" ]; then -@@ -159,8 +157,8 @@ fi - %endif - fi - --if ! getent group isulad > /dev/null; then -- groupadd --system isulad -+if ! getent group isula > /dev/null; then -+ groupadd --system isula - fi - - %preun -@@ -215,6 +213,12 @@ fi - %endif - - %changelog -+* Tue Sep 10 2020 openEuler Buildteam - 2.0.5-20200910.140350.git72990229 -+- Type:enhancement -+- ID:NA -+- SUG:NA -+- DESC: add chrpath -+ - * Mon Aug 03 2020 openEuler Buildteam - 2.0.3-20200803.130854.git0c7dc28a - - Type:enhancement - - ID:NA -diff --git a/release_notes b/release_notes -index 2913d63..2789c97 100644 ---- a/release_notes -+++ b/release_notes -@@ -1,3 +1,65 @@ -+2020-10-14 lifeng release 2.0.6 -+ - !764 add CI for image load multiplex From: @gaohuatao Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !765 clean code: refact utils and add prefix util_ From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian -+ - !756 iSulad: isula load support layer reusing From: @gaohuatao Reviewed-by: Signed-off-by: -+ - !762 resize: refact client resize From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian -+ - !759 clean code: reduce redundant code in isula_host_spec.c From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian -+ - !760 fix load only part of certs error From: @wangfengtu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !757 layer: fix memory leak errors From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian -+ - !755 avoid using HEAD_ONLY option when pulling image From: @wangfengtu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !754 use reference count to avoid flag be cleared by mistake From: @wangfengtu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !749 refact: refact client pack config progress From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian -+ - !750 modify default group value "isulad" to "isula" From: @gaohuatao Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !725 iSulad: add isula group From: @gaohuatao Reviewed-by: @jingxiaolu,@lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !746 umount: skip umount if rootfs not exist From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian -+ - !743 remove dir of rw layer while create failed From: @duguhaotian Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !742 fix macro defination conflict with sqlite3.h in openeuler From: @wangfengtu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !741 iSulad: bugfix, convert size_t type to int From: @zh_xiaoyu Reviewed-by: @duguhaotian,@lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !740 fix coredump when load image with uid From: @jingwoo Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian -+ - !739 iSulad: fix memeory out From: @zh_xiaoyu Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian -+ - !737 Docs/build_guide.md: comment gcc version From: @long-dai Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !724 Fix spell issue From: @long-dai Reviewed-by: Signed-off-by: -+ - !738 Readme: remove useless description From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian -+ - !736 Docs: clean up white noise From: @long-dai Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !735 pass context to uitls scan subdir From: @duguhaotian Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !734 isulad-shim: fix code review issues From: @leizhongkai Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !733 improve code From: @duguhaotian Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !726 CI: fix spell issue From: @long-dai Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !723 README: unify punctuation From: @long-dai Reviewed-by: @lifeng2221dd1,@lifeng2221dd1 Signed-off-by: @lifeng2221dd1,@lifeng2221dd1 -+ - !731 CI: update registry from 163 to ali From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian -+ - !730 fix bugs From: @wangfengtu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !722 README: add openEuler repository From: @long-dai Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !721 readme: add refer to openeuler guide From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian -+ - !720 clean code: add more log for invalid input From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian -+ - !719 fix bad formatting placeholder in http parse module From: @jingwoo Reviewed-by: @duguhaotian,@lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !718 fix coredump when pull image with lock ${driver}-image dir From: @jingwoo Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !716 fix layer remain caused by hold flag not clean From: @wangfengtu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !717 clear invalid data From: @duguhaotian Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !715 add compilation macro isolation for selinux related code From: @jingwoo Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !714 fix pull failure caused by link conflict From: @wangfengtu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !713 readme: fix readme From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian -+ - !712 config: remove unused config From: @lifeng2221dd1 Reviewed-by: @duguhaotian Signed-off-by: @duguhaotian -+ - !711 fix code review From: @wangfengtu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !710 fix: delete rootfs dir when rootfs load failed From: @jingwoo Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !708 fix: security-opt parsing access out of bounds From: @jingwoo Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !709 fix memory leak From: @wangfengtu Reviewed-by: @lifeng2221dd1 Signed-off-by: @lifeng2221dd1 -+ - !707 dev_cgroup_rule: add support device cgroup rule Merge pull request !707 from lifeng_isula/blk -+ - !706 iSulad : logs command add option timestamps Merge pull request !706 from YoungJQ/logs -+ - !705 add chrpath Merge pull request !705 from YoungJQ/logs -+ - !704 CI: add testcases for nano CPUs Merge pull request !704 from lifeng_isula/blk -+ - !702 cpus: add support nano cpus Merge pull request !702 from lifeng_isula/blk -+ - !700 cpu_rt: add support cpurt runtime period Merge pull request !700 from lifeng_isula/blk -+ - !701 iSulad: add LIB_ISULAD_IMG_SO for libisulad_img.so to avoid func do_integration_of_images_check() Merge pull request !701 from zhangxiaoyu/master -+ - !699 update readme Merge pull request !699 from haozi007/master -+ - !698 blkio: add support blk read/write iops Merge pull request !698 from lifeng_isula/blk -+ - !697 add testcase for --user option Merge pull request !697 from JingWoo/master -+ - !696 iSulad: initialization buf before readlink() Merge pull request !696 from zhangxiaoyu/master -+ - !695 overlay: fix magic define error Merge pull request !695 from lifeng_isula/master -+ -+ dev stats: -+ - 228 files changed, 6526 insertions(+), 5324 deletions(-) -+ - contributors: lifeng68, WangFengTu, wujing, Long Dai, haozi007, gaohuatao, zhangxiaoyu, YoungJQ, leizhongkai -+ - 2020-09-03 lifeng release 2.0.5 - - !693 Set mount rootfs highest mode Merge pull request !693 from gaohuatao/update - - !692 log: fix log level to warn Merge pull request !692 from lifeng_isula/master -diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt -index 2158658..4127e5a 100644 ---- a/src/CMakeLists.txt -+++ b/src/CMakeLists.txt -@@ -145,9 +145,9 @@ endif() - - # ------ install binary -------- - install(TARGETS libisula -- LIBRARY DESTINATION ${LIB_INSTALL_DIR_DEFAULT} PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE) -+ LIBRARY DESTINATION ${LIB_INSTALL_DIR_DEFAULT} PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) - install(TARGETS isula -- RUNTIME DESTINATION bin PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE) -+ RUNTIME DESTINATION bin PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) - install(TARGETS isulad-shim - RUNTIME DESTINATION bin PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE) - install(TARGETS isulad -diff --git a/src/client/connect/CMakeLists.txt b/src/client/connect/CMakeLists.txt -index 5289f5b..60a3429 100644 ---- a/src/client/connect/CMakeLists.txt -+++ b/src/client/connect/CMakeLists.txt -@@ -1,6 +1,6 @@ - set(local_client_connect_srcs - ${CMAKE_CURRENT_SOURCE_DIR}/isula_connect.c -- ${CMAKE_CURRENT_SOURCE_DIR}/pack_config.c -+ ${CMAKE_CURRENT_SOURCE_DIR}/protocol_type.c - ) - - set(local_client_connect_incs ${CMAKE_CURRENT_SOURCE_DIR}) -diff --git a/src/client/connect/grpc/grpc_containers_client.cc b/src/client/connect/grpc/grpc_containers_client.cc -index fa0d7e4..e511a6a 100644 ---- a/src/client/connect/grpc/grpc_containers_client.cc -+++ b/src/client/connect/grpc/grpc_containers_client.cc -@@ -18,7 +18,6 @@ - #include "isula_libutils/container_copy_to_request.h" - #include "isula_libutils/container_exec_request.h" - #include "isulad_tar.h" --#include "pack_config.h" - #include "stoppable_thread.h" - #include "utils.h" - #include -@@ -173,10 +172,6 @@ public: - - auto request_to_grpc(const isula_create_request *request, CreateRequest *grequest) -> int override - { -- int ret = 0; -- char *host_json = nullptr; -- char *config_json = nullptr; -- - if (request == nullptr) { - return -1; - } -@@ -193,23 +188,14 @@ public: - if (request->runtime != nullptr) { - grequest->set_runtime(request->runtime); - } -- ret = generate_hostconfig(request->hostconfig, &host_json); -- if (ret != 0) { -- ERROR("Failed to pack host config"); -- return EINVALIDARGS; -- } -- grequest->set_hostconfig(host_json); - -- free(host_json); -- -- ret = generate_container_config(request->config, &config_json); -- if (ret != 0) { -- ERROR("Failed to pack custom config"); -- return EINVALIDARGS; -+ if (request->container_spec_json != NULL) { -+ grequest->set_customconfig(request->container_spec_json); - } -- grequest->set_customconfig(config_json); - -- free(config_json); -+ if (request->host_spec_json != NULL) { -+ grequest->set_hostconfig(request->host_spec_json); -+ } - - return 0; - } -@@ -697,7 +683,6 @@ public: - } - }; - -- - class ContainerRestart : public ClientBase { - public: -@@ -1082,8 +1067,8 @@ public: - return 0; - } - -- auto grpc_call(ClientContext *context, const InspectContainerRequest &req, -- InspectContainerResponse *reply) -> Status override -+ auto grpc_call(ClientContext *context, const InspectContainerRequest &req, InspectContainerResponse *reply) -+ -> Status override - { - return stub_->Inspect(context, req, reply); - } -@@ -1186,8 +1171,8 @@ public: - ERROR("Too many summary info!"); - return -1; - } -- response->container_summary = static_cast(util_common_calloc_s( -- sizeof(struct isula_container_summary_info *) * static_cast(num))); -+ response->container_summary = static_cast( -+ util_common_calloc_s(sizeof(struct isula_container_summary_info *) * static_cast(num))); - if (response->container_summary == nullptr) { - ERROR("out of memory"); - response->cc = ISULAD_ERR_MEMOUT; -@@ -1209,10 +1194,11 @@ public: - } - - private: -- static auto get_container_summary_from_grpc(isula_list_response *response, ListResponse *gresponse, int index) -> int -+ static auto get_container_summary_from_grpc(isula_list_response *response, ListResponse *gresponse, int index) -+ -> int - { -- response->container_summary[index] = -- static_cast(util_common_calloc_s(sizeof(struct isula_container_summary_info))); -+ response->container_summary[index] = static_cast( -+ util_common_calloc_s(sizeof(struct isula_container_summary_info))); - if (response->container_summary[index] == nullptr) { - ERROR("out of memory"); - response->cc = ISULAD_ERR_MEMOUT; -@@ -1224,15 +1210,15 @@ private: - response->container_summary[index]->id = util_strdup_s(id); - const char *name = !in.name().empty() ? in.name().c_str() : "-"; - response->container_summary[index]->name = util_strdup_s(name); -- response->container_summary[index]->runtime = !in.runtime().empty() ? util_strdup_s(in.runtime().c_str()) -- : nullptr; -+ response->container_summary[index]->runtime = !in.runtime().empty() ? util_strdup_s(in.runtime().c_str()) : -+ nullptr; - response->container_summary[index]->has_pid = static_cast(static_cast(in.pid()) != 0); - response->container_summary[index]->pid = static_cast(in.pid()); - response->container_summary[index]->status = static_cast(in.status()); -- response->container_summary[index]->image = !in.image().empty() ? util_strdup_s(in.image().c_str()) -- : util_strdup_s("none"); -- response->container_summary[index]->command = !in.command().empty() ? util_strdup_s(in.command().c_str()) -- : util_strdup_s("-"); -+ response->container_summary[index]->image = !in.image().empty() ? util_strdup_s(in.image().c_str()) : -+ util_strdup_s("none"); -+ response->container_summary[index]->command = !in.command().empty() ? util_strdup_s(in.command().c_str()) : -+ util_strdup_s("-"); - const char *starttime = !in.startat().empty() ? in.startat().c_str() : "-"; - response->container_summary[index]->startat = util_strdup_s(starttime); - -@@ -1246,8 +1232,8 @@ private: - if (!in.health_state().empty()) { - healthState = "(" + in.health_state() + ")"; - } -- response->container_summary[index]->health_state = !healthState.empty() ? util_strdup_s(healthState.c_str()) -- : nullptr; -+ response->container_summary[index]->health_state = !healthState.empty() ? util_strdup_s(healthState.c_str()) : -+ nullptr; - response->container_num++; - - return 0; -@@ -1604,33 +1590,18 @@ public: - auto request_to_grpc(const isula_update_request *request, UpdateRequest *grequest) -> int override - { - int ret = 0; -- char *json = nullptr; - - if (request == nullptr) { - return -1; - } - -- isula_host_config_t hostconfig; -- (void)memset(&hostconfig, 0, sizeof(hostconfig)); -- -- if (request->updateconfig != nullptr) { -- hostconfig.restart_policy = request->updateconfig->restart_policy; -- hostconfig.cr = request->updateconfig->cr; -- } -- ret = generate_hostconfig(&hostconfig, &json); -- if (ret != 0) { -- ERROR("Failed to generate hostconfig json"); -- ret = -1; -- goto cleanup; -+ if (request->host_spec_json != NULL) { -+ grequest->set_hostconfig(request->host_spec_json); - } -- -- grequest->set_hostconfig(json); - if (request->name != nullptr) { - grequest->set_id(request->name); - } - --cleanup: -- free(json); - return ret; - } - -@@ -1688,8 +1659,8 @@ public: - { - int size = gresponse->containers_size(); - if (size > 0) { -- response->container_stats = -- static_cast(util_common_calloc_s(size * sizeof(struct isula_container_info))); -+ response->container_stats = static_cast( -+ util_common_calloc_s(size * sizeof(struct isula_container_info))); - if (response->container_stats == nullptr) { - ERROR("Out of memory"); - return -1; -@@ -1771,7 +1742,8 @@ public: - - std::unique_ptr> reader(stub_->Events(&context, req)); - while (reader->Read(&event)) { -- isula_event = static_cast(util_common_calloc_s(sizeof(container_events_format_t))); -+ isula_event = -+ static_cast(util_common_calloc_s(sizeof(container_events_format_t))); - if (isula_event == nullptr) { - ERROR("Out of memory"); - response->server_errono = ISULAD_ERR_EXEC; -@@ -1863,7 +1835,7 @@ private: - struct CopyFromContainerContext { - CopyFromContainerRequest request; - ClientContext context; -- ClientReader *reader{}; -+ ClientReader *reader {}; - }; - - // Note: len of buf can not smaller than ARCHIVE_BLOCK_SIZE -@@ -2008,7 +1980,8 @@ public: - explicit CopyToContainerWriteToServerTask( - const struct io_read_wrapper *reader, - std::shared_ptr> stream) -- : m_reader(reader), m_stream(std::move(std::move(stream))) -+ : m_reader(reader) -+ , m_stream(std::move(std::move(stream))) - { - } - ~CopyToContainerWriteToServerTask() = default; -@@ -2026,7 +1999,7 @@ public: - while (!stopRequested()) { - ssize_t have_read_len = m_reader->read(m_reader->context, buf, len); - CopyToContainerRequest request; -- request.set_data((const void*)buf, static_cast(have_read_len)); -+ request.set_data((const void *)buf, static_cast(have_read_len)); - if (!m_stream->Write(request)) { - DEBUG("Server may be exited, stop send data"); - break; -@@ -2095,9 +2068,8 @@ out: - return ret; - } - -- auto run(const struct isula_copy_to_container_request *request, -- struct isula_copy_to_container_response *response) -> int -- override -+ auto run(const struct isula_copy_to_container_request *request, struct isula_copy_to_container_response *response) -+ -> int override - { - ClientContext context; - if (set_custom_header_metadata(context, request, response) != 0) { -@@ -2262,4 +2234,3 @@ auto grpc_containers_client_ops_init(isula_connect_ops *ops) -> int - - return 0; - } -- -diff --git a/src/client/connect/isula_connect.h b/src/client/connect/isula_connect.h -index 8e9fed5..a24336d 100644 ---- a/src/client/connect/isula_connect.h -+++ b/src/client/connect/isula_connect.h -@@ -15,8 +15,8 @@ - #ifndef CLIENT_CONNECT_ISULA_CONNECT_H - #define CLIENT_CONNECT_ISULA_CONNECT_H - --#include "libisula.h" - #include "connect.h" -+#include "protocol_type.h" - - #ifdef __cplusplus - extern "C" { -diff --git a/src/client/libisula.c b/src/client/connect/protocol_type.c -similarity index 84% -rename from src/client/libisula.c -rename to src/client/connect/protocol_type.c -index 12b7ac5..19310a0 100644 ---- a/src/client/libisula.c -+++ b/src/client/connect/protocol_type.c -@@ -8,17 +8,16 @@ - * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR - * PURPOSE. - * See the Mulan PSL v2 for more details. -- * Author: tanyifeng -- * Create: 2018-11-08 -+ * Author: lifeng -+ * Create: 2020-10-12 - * Description: provide container isula library functions - ******************************************************************************/ -+#include "protocol_type.h" - #include - #include --#include - #include - #include - --#include "libisula.h" - #include "isula_libutils/log.h" - #include "utils.h" - #include "utils_array.h" -@@ -93,7 +92,7 @@ struct isula_filters *isula_filters_parse_args(const char **array, size_t len) - } - *valuepos++ = '\0'; - filters->values[filters->len] = util_strdup_s(util_trim_space(valuepos)); -- lowerkey = strings_to_lower(util_trim_space(copy)); -+ lowerkey = util_strings_to_lower(util_trim_space(copy)); - free(copy); - if (lowerkey == NULL) { - free(filters->values[filters->len]); -@@ -227,157 +226,6 @@ void isula_info_response_free(struct isula_info_response *response) - free(response); - } - --void isula_ns_change_files_free(isula_host_config_t *hostconfig) --{ -- if (hostconfig == NULL) { -- return; -- } -- -- util_free_array_by_len(hostconfig->ns_change_files, hostconfig->ns_change_files_len); -- hostconfig->ns_change_files = NULL; -- hostconfig->ns_change_files_len = 0; --} -- --void isula_host_config_storage_opts_free(isula_host_config_t *hostconfig) --{ -- if (hostconfig == NULL) { -- return; -- } -- -- free_json_map_string_string(hostconfig->storage_opts); -- hostconfig->storage_opts = NULL; --} -- --void isula_host_config_sysctl_free(isula_host_config_t *hostconfig) --{ -- if (hostconfig == NULL) { -- return; -- } -- -- free_json_map_string_string(hostconfig->sysctls); -- hostconfig->sysctls = NULL; --} -- --/* isula host config free */ --void isula_host_config_free(isula_host_config_t *hostconfig) --{ -- if (hostconfig == NULL) { -- return; -- } -- -- util_free_array_by_len(hostconfig->cap_add, hostconfig->cap_add_len); -- hostconfig->cap_add = NULL; -- hostconfig->cap_add_len = 0; -- -- util_free_array_by_len(hostconfig->cap_drop, hostconfig->cap_drop_len); -- hostconfig->cap_drop = NULL; -- hostconfig->cap_drop_len = 0; -- -- free_json_map_string_string(hostconfig->storage_opts); -- hostconfig->storage_opts = NULL; -- -- free_json_map_string_string(hostconfig->sysctls); -- hostconfig->sysctls = NULL; -- -- util_free_array_by_len(hostconfig->devices, hostconfig->devices_len); -- hostconfig->devices = NULL; -- hostconfig->devices_len = 0; -- -- util_free_array_by_len(hostconfig->hugetlbs, hostconfig->hugetlbs_len); -- hostconfig->hugetlbs = NULL; -- hostconfig->hugetlbs_len = 0; -- -- free(hostconfig->network_mode); -- hostconfig->network_mode = NULL; -- -- free(hostconfig->ipc_mode); -- hostconfig->ipc_mode = NULL; -- -- free(hostconfig->pid_mode); -- hostconfig->pid_mode = NULL; -- -- free(hostconfig->uts_mode); -- hostconfig->uts_mode = NULL; -- -- free(hostconfig->userns_mode); -- hostconfig->userns_mode = NULL; -- -- free(hostconfig->user_remap); -- hostconfig->user_remap = NULL; -- -- util_free_array_by_len(hostconfig->ulimits, hostconfig->ulimits_len); -- hostconfig->ulimits = NULL; -- hostconfig->ulimits_len = 0; -- -- free(hostconfig->restart_policy); -- hostconfig->restart_policy = NULL; -- -- free(hostconfig->host_channel); -- hostconfig->host_channel = NULL; -- -- free(hostconfig->hook_spec); -- hostconfig->hook_spec = NULL; -- -- free(hostconfig->env_target_file); -- hostconfig->env_target_file = NULL; -- -- free(hostconfig->cgroup_parent); -- hostconfig->cgroup_parent = NULL; -- -- util_free_array_by_len(hostconfig->binds, hostconfig->binds_len); -- hostconfig->binds = NULL; -- hostconfig->binds_len = 0; -- -- util_free_array_by_len(hostconfig->blkio_weight_device, hostconfig->blkio_weight_device_len); -- hostconfig->blkio_weight_device = NULL; -- hostconfig->blkio_weight_device_len = 0; -- -- container_cgroup_resources_free(hostconfig->cr); -- hostconfig->cr = NULL; -- -- free(hostconfig); --} -- --/* isula container config free */ --void isula_container_config_free(isula_container_config_t *config) --{ -- if (config == NULL) { -- return; -- } -- -- util_free_array_by_len(config->env, config->env_len); -- config->env = NULL; -- config->env_len = 0; -- -- free(config->hostname); -- config->hostname = NULL; -- -- free(config->user); -- config->user = NULL; -- -- util_free_array_by_len(config->mounts, config->mounts_len); -- config->mounts = NULL; -- config->mounts_len = 0; -- -- util_free_array_by_len(config->cmd, config->cmd_len); -- config->cmd = NULL; -- config->cmd_len = 0; -- -- free(config->entrypoint); -- config->entrypoint = NULL; -- -- free(config->log_driver); -- config->log_driver = NULL; -- -- free_json_map_string_string(config->annotations); -- config->annotations = NULL; -- -- free(config->workdir); -- config->workdir = NULL; -- -- free(config); --} -- - /* isula create request free */ - void isula_create_request_free(struct isula_create_request *request) - { -@@ -397,11 +245,12 @@ void isula_create_request_free(struct isula_create_request *request) - free(request->runtime); - request->runtime = NULL; - -- isula_host_config_free(request->hostconfig); -- request->hostconfig = NULL; -+ free(request->container_spec_json); -+ request->container_spec_json = NULL; -+ -+ free(request->host_spec_json); -+ request->host_spec_json = NULL; - -- isula_container_config_free(request->config); -- request->config = NULL; - free(request); - } - -@@ -489,6 +338,9 @@ void isula_top_response_free(struct isula_top_response *response) - free(response->titles); - response->titles = NULL; - -+ free(response->errmsg); -+ response->errmsg = NULL; -+ - if (response->processes_len && response->processes != NULL) { - size_t i; - for (i = 0; i < response->processes_len; i++) { -@@ -806,22 +658,6 @@ void isula_kill_response_free(struct isula_kill_response *response) - free(response); - } - --/* isula update config free */ --void isula_update_config_free(isula_update_config_t *config) --{ -- if (config == NULL) { -- return; -- } -- -- free(config->restart_policy); -- config->restart_policy = NULL; -- -- container_cgroup_resources_free(config->cr); -- config->cr = NULL; -- -- free(config); --} -- - /* isula update request free */ - void isula_update_request_free(struct isula_update_request *request) - { -@@ -832,8 +668,8 @@ void isula_update_request_free(struct isula_update_request *request) - free(request->name); - request->name = NULL; - -- isula_update_config_free(request->updateconfig); -- request->updateconfig = NULL; -+ free(request->host_spec_json); -+ request->host_spec_json = NULL; - - free(request); - } -@@ -1453,21 +1289,6 @@ void isula_logs_response_free(struct isula_logs_response *response) - free(response); - } - --/* container cgroup resources free */ --void container_cgroup_resources_free(container_cgroup_resources_t *cr) --{ -- if (cr == NULL) { -- return; -- } -- free(cr->cpuset_cpus); -- cr->cpuset_cpus = NULL; -- -- free(cr->cpuset_mems); -- cr->cpuset_mems = NULL; -- -- free(cr); --} -- - void container_events_format_free(container_events_format_t *value) - { - size_t i; -@@ -1491,4 +1312,4 @@ void container_events_format_free(container_events_format_t *value) - value->annotations = NULL; - - free(value); --} -\ No newline at end of file -+} -diff --git a/src/client/libisula.h b/src/client/connect/protocol_type.h -similarity index 80% -rename from src/client/libisula.h -rename to src/client/connect/protocol_type.h -index 62954f9..f8f18c0 100644 ---- a/src/client/libisula.h -+++ b/src/client/connect/protocol_type.h -@@ -8,12 +8,12 @@ - * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR - * PURPOSE. - * See the Mulan PSL v2 for more details. -- * Author: tanyifeng -- * Create: 2018-11-08 -- * Description: provide container isula library definition -+ * Author: lifeng -+ * Create: 2020-10-12 -+ * Description: provide container isula protocol definition - ******************************************************************************/ --#ifndef CLIENT_LIBISULA_H --#define CLIENT_LIBISULA_H -+#ifndef CLIENT_CONNECT_PROTOCOL_H -+#define CLIENT_CONNECT_PROTOCOL_H - - #include - #include -@@ -22,7 +22,6 @@ - #include "constants.h" - #include "io_wrapper.h" - #include "isula_libutils/container_path_stat.h" --#include "isula_libutils/json_common.h" - #include "utils_timestamp.h" - - #ifdef __cplusplus -@@ -35,179 +34,13 @@ struct isula_filters { - size_t len; - }; - --typedef struct isula_container_config { -- char **env; -- size_t env_len; -- -- char **label; -- size_t label_len; -- -- char *hostname; -- -- char *user; -- -- bool attach_stdin; -- -- bool attach_stdout; -- -- bool attach_stderr; -- -- bool open_stdin; -- -- bool tty; -- -- bool readonly; -- -- bool all_devices; -- -- bool system_container; -- char *ns_change_opt; -- -- char **mounts; -- size_t mounts_len; -- -- char *entrypoint; -- -- char **cmd; -- size_t cmd_len; -- -- char *log_driver; -- -- json_map_string_string *annotations; -- -- char *workdir; -- -- char *health_cmd; -- -- int64_t health_interval; -- -- int health_retries; -- -- int64_t health_timeout; -- -- int64_t health_start_period; -- -- bool no_healthcheck; -- -- bool exit_on_unhealthy; -- -- char **accel; -- size_t accel_len; --} isula_container_config_t; -- --typedef struct container_cgroup_resources { -- uint16_t blkio_weight; -- int64_t cpu_shares; -- int64_t cpu_period; -- int64_t cpu_quota; -- int64_t cpu_realtime_period; -- int64_t cpu_realtime_runtime; -- char *cpuset_cpus; -- char *cpuset_mems; -- int64_t memory; -- int64_t memory_swap; -- int64_t memory_reservation; -- int64_t kernel_memory; -- int64_t pids_limit; -- int64_t files_limit; -- int64_t oom_score_adj; -- int64_t swappiness; --} container_cgroup_resources_t; -- --typedef struct isula_host_config { -- char **devices; -- size_t devices_len; -- -- char **hugetlbs; -- size_t hugetlbs_len; -- -- char **group_add; -- size_t group_add_len; -- -- char *network_mode; -- -- char *ipc_mode; -- -- char *pid_mode; -- -- char *uts_mode; -- -- char *userns_mode; -- -- char *user_remap; -- -- char **ulimits; -- size_t ulimits_len; -- -- char *restart_policy; -- -- char *host_channel; -- -- char **cap_add; -- size_t cap_add_len; -- -- char **cap_drop; -- size_t cap_drop_len; -- -- json_map_string_string *storage_opts; -- -- json_map_string_string *sysctls; -- -- char **dns; -- size_t dns_len; -- -- char **dns_options; -- size_t dns_options_len; -- -- char **dns_search; -- size_t dns_search_len; -- -- char **extra_hosts; -- size_t extra_hosts_len; -- -- char *hook_spec; -- -- char **binds; -- size_t binds_len; -- -- char **blkio_weight_device; -- size_t blkio_weight_device_len; -- -- char **blkio_throttle_read_bps_device; -- size_t blkio_throttle_read_bps_device_len; -- -- char **blkio_throttle_write_bps_device; -- size_t blkio_throttle_write_bps_device_len; -- -- bool privileged; -- bool system_container; -- char **ns_change_files; -- size_t ns_change_files_len; -- bool auto_remove; -- -- bool oom_kill_disable; -- -- int64_t shm_size; -- -- bool readonly_rootfs; -- -- char *env_target_file; -- -- char *cgroup_parent; -- -- container_cgroup_resources_t *cr; -- -- char **security; -- size_t security_len; --} isula_host_config_t; -- - struct isula_create_request { - char *name; - char *rootfs; - char *image; - char *runtime; -- isula_host_config_t *hostconfig; -- isula_container_config_t *config; -+ char *host_spec_json; -+ char *container_spec_json; - }; - - struct isula_create_response { -@@ -576,14 +409,9 @@ struct isula_info_response { - char *errmsg; - }; - --typedef struct isula_update_config { -- char *restart_policy; -- container_cgroup_resources_t *cr; --} isula_update_config_t; -- - struct isula_update_request { - char *name; -- isula_update_config_t *updateconfig; -+ char *host_spec_json; - }; - - struct isula_update_response { -@@ -747,12 +575,8 @@ struct isula_resize_response { - char *errmsg; - }; - --void container_cgroup_resources_free(container_cgroup_resources_t *cr); -- - void container_events_format_free(container_events_format_t *value); - --Container_Status isulastastr2sta(const char *state); -- - struct isula_filters *isula_filters_parse_args(const char **array, size_t len); - - void isula_filters_free(struct isula_filters *filters); -@@ -767,16 +591,6 @@ void isula_info_request_free(struct isula_info_request *request); - - void isula_info_response_free(struct isula_info_response *response); - --void isula_ns_change_files_free(isula_host_config_t *hostconfig); -- --void isula_host_config_storage_opts_free(isula_host_config_t *hostconfig); -- --void isula_host_config_sysctl_free(isula_host_config_t *hostconfig); -- --void isula_host_config_free(isula_host_config_t *hostconfig); -- --void isula_container_config_free(isula_container_config_t *config); -- - void isula_create_request_free(struct isula_create_request *request); - - void isula_create_response_free(struct isula_create_response *response); -@@ -825,8 +639,6 @@ void isula_kill_request_free(struct isula_kill_request *request); - - void isula_kill_response_free(struct isula_kill_response *response); - --void isula_update_config_free(isula_update_config_t *config); -- - void isula_update_request_free(struct isula_update_request *request); - - void isula_update_response_free(struct isula_update_response *response); -diff --git a/src/client/connect/rest/rest_containers_client.c b/src/client/connect/rest/rest_containers_client.c -index e697861..3b5918a 100644 ---- a/src/client/connect/rest/rest_containers_client.c -+++ b/src/client/connect/rest/rest_containers_client.c -@@ -18,7 +18,6 @@ - #include "isula_libutils/log.h" - #include "isula_connect.h" - #include "container.rest.h" --#include "pack_config.h" - #include "rest_common.h" - #include "rest_containers_client.h" - -@@ -37,18 +36,12 @@ static int create_request_to_rest(const struct isula_create_request *lc_request, - goto out; - } - -- ret = generate_hostconfig(lc_request->hostconfig, &crequest->hostconfig); -- if (ret != 0) { -- ERROR("Failed to pack host config"); -- ret = EINVALIDARGS; -- goto out; -+ if (lc_request->host_spec_json != NULL) { -+ crequest->hostconfig = util_strdup_s(lc_request->host_spec_json); - } - -- ret = generate_container_config(lc_request->config, &crequest->customconfig); -- if (ret != 0) { -- ERROR("Failed to pack custom config"); -- ret = EINVALIDARGS; -- goto out; -+ if (lc_request->container_spec_json != NULL) { -+ crequest->customconfig = util_strdup_s(lc_request->container_spec_json); - } - - if (lc_request->name != NULL) { -@@ -402,29 +395,33 @@ static int unpack_container_info_for_list_response(container_list_response *cres - response->container_num = num; - response->container_summary = summary_info; - for (i = 0; i < num; i++) { -- summary_info[i] = -- (struct isula_container_summary_info *)util_common_calloc_s(sizeof(struct isula_container_summary_info)); -+ summary_info[i] = (struct isula_container_summary_info *)util_common_calloc_s( -+ sizeof(struct isula_container_summary_info)); - if (summary_info[i] == NULL) { - ERROR("Out of memory"); - return -1; - } -- summary_info[i]->id = cresponse->containers[i]->id ? util_strdup_s(cresponse->containers[i]->id) -- : util_strdup_s("-"); -- summary_info[i]->name = cresponse->containers[i]->name ? util_strdup_s(cresponse->containers[i]->name) -- : util_strdup_s("-"); -- summary_info[i]->runtime = cresponse->containers[i]->runtime ? util_strdup_s(cresponse->containers[i]->runtime) -- : util_strdup_s("-"); -+ summary_info[i]->id = cresponse->containers[i]->id ? util_strdup_s(cresponse->containers[i]->id) : -+ util_strdup_s("-"); -+ summary_info[i]->name = cresponse->containers[i]->name ? util_strdup_s(cresponse->containers[i]->name) : -+ util_strdup_s("-"); -+ summary_info[i]->runtime = cresponse->containers[i]->runtime ? -+ util_strdup_s(cresponse->containers[i]->runtime) : -+ util_strdup_s("-"); - summary_info[i]->has_pid = cresponse->containers[i]->pid != 0; - summary_info[i]->pid = cresponse->containers[i]->pid; - summary_info[i]->status = cresponse->containers[i]->status; -- summary_info[i]->image = cresponse->containers[i]->image ? util_strdup_s(cresponse->containers[i]->image) -- : util_strdup_s("-"); -- summary_info[i]->command = cresponse->containers[i]->command ? util_strdup_s(cresponse->containers[i]->command) -- : util_strdup_s("-"); -- summary_info[i]->startat = cresponse->containers[i]->startat ? util_strdup_s(cresponse->containers[i]->startat) -- : util_strdup_s("-"); -+ summary_info[i]->image = cresponse->containers[i]->image ? util_strdup_s(cresponse->containers[i]->image) : -+ util_strdup_s("-"); -+ summary_info[i]->command = cresponse->containers[i]->command ? -+ util_strdup_s(cresponse->containers[i]->command) : -+ util_strdup_s("-"); -+ summary_info[i]->startat = cresponse->containers[i]->startat ? -+ util_strdup_s(cresponse->containers[i]->startat) : -+ util_strdup_s("-"); - summary_info[i]->finishat = cresponse->containers[i]->finishat ? -- util_strdup_s(cresponse->containers[i]->finishat) : util_strdup_s("-"); -+ util_strdup_s(cresponse->containers[i]->finishat) : -+ util_strdup_s("-"); - summary_info[i]->exit_code = cresponse->containers[i]->exit_code; - summary_info[i]->restart_count = (unsigned int)cresponse->containers[i]->restartcount; - summary_info[i]->created = cresponse->containers[i]->created; -@@ -675,8 +672,8 @@ out: - } - - /* rest container list */ --static int rest_container_list(const struct isula_list_request *ll_request, -- struct isula_list_response *ll_response, void *arg) -+static int rest_container_list(const struct isula_list_request *ll_request, struct isula_list_response *ll_response, -+ void *arg) - { - char *body = NULL; - int ret = 0; -@@ -741,8 +738,8 @@ out: - } - - /* rest container wait */ --static int rest_container_wait(const struct isula_wait_request *lw_request, -- struct isula_wait_response *lw_response, void *arg) -+static int rest_container_wait(const struct isula_wait_request *lw_request, struct isula_wait_response *lw_response, -+ void *arg) - { - char *body = NULL; - int ret = 0; -@@ -842,8 +839,8 @@ out: - } - - /* rest container stop */ --static int rest_container_stop(const struct isula_stop_request *ls_request, -- struct isula_stop_response *ls_response, void *arg) -+static int rest_container_stop(const struct isula_stop_request *ls_request, struct isula_stop_response *ls_response, -+ void *arg) - { - char *body = NULL; - int ret = 0; -@@ -976,14 +973,10 @@ out: - static int update_request_to_rest(const struct isula_update_request *lu_request, char **body, size_t *body_len) - { - container_update_request *crequest = NULL; -- isula_host_config_t srcconfig; - struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 }; - parser_error err = NULL; -- char *srcconfigjson = NULL; - int ret = 0; - -- (void)memset(&srcconfig, 0, sizeof(srcconfig)); -- - crequest = util_common_calloc_s(sizeof(container_update_request)); - if (crequest == NULL) { - ERROR("Out of memory"); -@@ -991,22 +984,14 @@ static int update_request_to_rest(const struct isula_update_request *lu_request, - goto out; - } - -- if (lu_request->updateconfig != NULL) { -- srcconfig.restart_policy = lu_request->updateconfig->restart_policy; -- srcconfig.cr = lu_request->updateconfig->cr; -- } -- ret = generate_hostconfig(&srcconfig, &srcconfigjson); -- if (ret != 0) { -- ERROR("Failed to generate hostconfig json"); -- ret = -1; -- goto out; -- } -- crequest->host_config = srcconfigjson; -- - if (lu_request->name != NULL) { - crequest->name = util_strdup_s(lu_request->name); - } - -+ if (lu_request->host_spec_json != NULL) { -+ crequest->host_config = util_strdup_s(lu_request->host_spec_json); -+ } -+ - *body = container_update_request_generate_json(crequest, &ctx, &err); - if (*body == NULL) { - ERROR("Failed to generate update request json:%s", err); -@@ -1261,8 +1246,8 @@ out: - } - - /* rest container pause */ --static int rest_container_pause(const struct isula_pause_request *lp_request, -- struct isula_pause_response *lp_response, void *arg) -+static int rest_container_pause(const struct isula_pause_request *lp_request, struct isula_pause_response *lp_response, -+ void *arg) - { - char *body = NULL; - int ret = 0; -@@ -1361,8 +1346,8 @@ out: - } - - /* rest container kill */ --static int rest_container_kill(const struct isula_kill_request *lk_request, -- struct isula_kill_response *lk_response, void *arg) -+static int rest_container_kill(const struct isula_kill_request *lk_request, struct isula_kill_response *lk_response, -+ void *arg) - { - char *body = NULL; - int ret = 0; -@@ -1716,8 +1701,8 @@ out: - } - - /* rest container exec */ --static int rest_container_exec(const struct isula_exec_request *le_request, -- struct isula_exec_response *le_response, void *arg) -+static int rest_container_exec(const struct isula_exec_request *le_request, struct isula_exec_response *le_response, -+ void *arg) - { - char *body = NULL; - int ret = 0; -@@ -1773,4 +1758,3 @@ int rest_containers_client_ops_init(isula_connect_ops *ops) - - return 0; - } -- -diff --git a/src/cmd/CMakeLists.txt b/src/cmd/CMakeLists.txt -index 845cb0f..3d3e881 100644 ---- a/src/cmd/CMakeLists.txt -+++ b/src/cmd/CMakeLists.txt -@@ -1,13 +1,15 @@ - # get current directory sources files - aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} comm_srcs) - -+add_subdirectory(options) -+ - add_subdirectory(isula) --set(ISULA_SRCS ${comm_srcs} ${CMD_ISULA_SRCS} PARENT_SCOPE) --set(ISULA_INCS ${CMAKE_CURRENT_SOURCE_DIR} ${CMD_ISULA_INCS} PARENT_SCOPE) -+set(ISULA_SRCS ${comm_srcs} ${OPT_SRCS} ${CMD_ISULA_SRCS} PARENT_SCOPE) -+set(ISULA_INCS ${CMAKE_CURRENT_SOURCE_DIR} ${OPT_INCS} ${CMD_ISULA_INCS} PARENT_SCOPE) - - add_subdirectory(isulad) --set(ISULAD_SRCS ${comm_srcs} ${CMD_ISULAD_SRCS} PARENT_SCOPE) --set(ISULAD_INCS ${CMAKE_CURRENT_SOURCE_DIR} ${CMD_ISULAD_INCS} PARENT_SCOPE) -+set(ISULAD_SRCS ${comm_srcs} ${OPT_SRCS} ${CMD_ISULAD_SRCS} PARENT_SCOPE) -+set(ISULAD_INCS ${CMAKE_CURRENT_SOURCE_DIR} ${OPT_INCS} ${CMD_ISULAD_INCS} PARENT_SCOPE) - - add_subdirectory(isulad-shim) - set(ISULAD_SHIM_SRCS ${CMD_ISULAD_SHIM_SRCS} PARENT_SCOPE) -diff --git a/src/cmd/command_parser.c b/src/cmd/command_parser.c -index 33a1f37..f72c1b4 100644 ---- a/src/cmd/command_parser.c -+++ b/src/cmd/command_parser.c -@@ -21,6 +21,7 @@ - #include - #include - #include -+#include - - #include "constants.h" - #include "utils.h" -@@ -29,6 +30,7 @@ - #include "utils_convert.h" - #include "utils_string.h" - #include "utils_verify.h" -+#include "utils_timestamp.h" - - void command_help_isulad_head() - { -@@ -242,7 +244,7 @@ static int command_get_option_data(command_t *self, command_option_t *option, co - case CMD_OPT_TYPE_CALLBACK: - return command_get_callback_option_data(self, option, opt_arg); - default: -- COMMAND_ERROR("Unkown command option type:%d", (int)(option->type)); -+ COMMAND_ERROR("Unknown command option type:%d", (int)(option->type)); - return -1; - } - } -@@ -304,7 +306,7 @@ static int command_parse_short_arg(command_t *self, const char *arg) - } while (found && opt_arg != NULL); - - if (opt_arg != NULL) { -- COMMAND_ERROR("Unkown flag found:'%c'", opt_arg[0]); -+ COMMAND_ERROR("Unknown flag found:'%c'", opt_arg[0]); - exit(EINVALIDARGS); - } - return 0; -@@ -328,7 +330,7 @@ static int command_parse_long_arg(command_t *self, const char *arg) - continue; - } - -- opt_arg = str_skip_str(arg, opt->large); -+ opt_arg = util_str_skip_str(arg, opt->large); - if (opt_arg == NULL) { - continue; - } -@@ -347,7 +349,7 @@ static int command_parse_long_arg(command_t *self, const char *arg) - } - return 0; - } -- COMMAND_ERROR("Unkown flag found:'--%s'\n", arg); -+ COMMAND_ERROR("Unknown flag found:'--%s'\n", arg); - exit(EINVALIDARGS); - } - -@@ -501,7 +503,7 @@ int command_convert_nanoseconds(command_option_t *option, const char *arg) - if (option == NULL) { - return -1; - } -- if (util_parse_time_str_to_nanoseconds(arg, option->data)) { -+ if (util_time_str_to_nanoseconds(arg, option->data)) { - COMMAND_ERROR("Invalid value \"%s\" for flag --%s", arg, option->large); - return EINVALIDARGS; - } -@@ -551,3 +553,48 @@ int command_convert_swappiness(command_option_t *option, const char *arg) - } - return 0; - } -+ -+int command_convert_nanocpus(command_option_t *option, const char *arg) -+{ -+ int ret = 0; -+ char *dup = NULL; -+ -+ if (option == NULL) { -+ return -1; -+ } -+ -+ if (!isdigit(arg[0])) { -+ COMMAND_ERROR("Invalid value \"%s\" for flag --%s", arg, option->large); -+ return EINVALIDARGS; -+ } -+ -+ dup = util_strdup_s(arg); -+ if (dup == NULL) { -+ COMMAND_ERROR("Invalid value \"%s\" for flag --%s", arg, option->large); -+ return EINVALIDARGS; -+ } -+ -+ if (util_parse_size_int_and_float(arg, 1e9, option->data)) { -+ COMMAND_ERROR("Invalid value \"%s\" for flag --%s", arg, option->large); -+ ret = EINVALIDARGS; -+ goto out; -+ } -+ -+out: -+ free(dup); -+ return ret; -+} -+ -+int command_convert_device_cgroup_rules(command_option_t *option, const char *arg) -+{ -+ if (option == NULL) { -+ return -1; -+ } -+ -+ if (!util_valid_device_cgroup_rule(arg)) { -+ COMMAND_ERROR("Invalid value \"%s\" for flag --%s", arg, option->large); -+ return EINVALIDARGS; -+ } -+ -+ return command_append_array(option, arg); -+} -diff --git a/src/cmd/command_parser.h b/src/cmd/command_parser.h -index cdf3e1e..5f4cedc 100644 ---- a/src/cmd/command_parser.h -+++ b/src/cmd/command_parser.h -@@ -100,10 +100,12 @@ int command_convert_membytes(command_option_t *option, const char *arg); - - int command_convert_memswapbytes(command_option_t *option, const char *arg); - --int check_default_ulimit_type(const char *type); -- - int command_convert_swappiness(command_option_t *option, const char *arg); - -+int command_convert_nanocpus(command_option_t *option, const char *arg); -+ -+int command_convert_device_cgroup_rules(command_option_t *option, const char *arg); -+ - #ifdef __cplusplus - } - #endif -diff --git a/src/cmd/isula/base/create.c b/src/cmd/isula/base/create.c -index 583664a..12903ce 100644 ---- a/src/cmd/isula/base/create.c -+++ b/src/cmd/isula/base/create.c -@@ -12,6 +12,7 @@ - * Create: 2017-11-22 - * Description: provide container create functions - ******************************************************************************/ -+#include "create.h" - #include - #include - #include -@@ -32,17 +33,18 @@ - #include "isula_libutils/log.h" - #include "utils.h" - #include "utils_string.h" --#include "create.h" - #include "isula_connect.h" - #include "path.h" - #include "pull.h" - #include "constants.h" - #include "connect.h" --#include "libisula.h" -+ - #include "utils_array.h" - #include "utils_convert.h" - #include "utils_file.h" - #include "utils_verify.h" -+#include "isula_container_spec.h" -+#include "isula_host_spec.h" - - const char g_cmd_create_desc[] = "Create a new container"; - const char g_cmd_create_usage[] = "create [OPTIONS] --external-rootfs=PATH|IMAGE [COMMAND] [ARG...]"; -@@ -142,9 +144,18 @@ static int request_pack_host_config_cgroup(const struct client_arguments *args, - return -1; - } - -+ hostconfig->cr = util_common_calloc_s(sizeof(container_cgroup_resources_t)); -+ if (hostconfig->cr == NULL) { -+ COMMAND_ERROR("Memory out"); -+ return -1; -+ } -+ - /* blkio weight */ - hostconfig->cr->blkio_weight = args->cr.blkio_weight; - -+ /* nano cpus */ -+ hostconfig->cr->nano_cpus = args->cr.nano_cpus; -+ - /* cpu shares */ - hostconfig->cr->cpu_shares = args->cr.cpu_shares; - -@@ -161,10 +172,10 @@ static int request_pack_host_config_cgroup(const struct client_arguments *args, - hostconfig->cr->cpu_realtime_runtime = args->cr.cpu_rt_runtime; - - /* cpuset-cpus */ -- hostconfig->cr->cpuset_cpus = args->cr.cpuset_cpus; -+ hostconfig->cr->cpuset_cpus = util_strdup_s(args->cr.cpuset_cpus); - - /* cpuset memory */ -- hostconfig->cr->cpuset_mems = args->cr.cpuset_mems; -+ hostconfig->cr->cpuset_mems = util_strdup_s(args->cr.cpuset_mems); - - /* oom_score_adj */ - hostconfig->cr->oom_score_adj = args->cr.oom_score_adj; -@@ -188,54 +199,7 @@ static int request_pack_host_config_cgroup(const struct client_arguments *args, - return 0; - } - --static int util_env_set_isulad_enable_plugins(char ***penv, const size_t *penv_len, const char *names) --{ -- size_t env_len; -- size_t len = 0; -- char *val = NULL; -- char *kv = NULL; -- char **env = NULL; -- const char *arr[10] = { NULL }; -- -- if (penv == NULL || penv_len == NULL || names == NULL) { -- return -1; -- } -- -- env = *penv; -- env_len = *penv_len; -- -- arr[0] = ISULAD_ENABLE_PLUGINS; -- arr[1] = "="; -- arr[2] = names; -- len = 3; -- -- val = util_env_get_val(env, env_len, ISULAD_ENABLE_PLUGINS, strlen(ISULAD_ENABLE_PLUGINS)); -- if (val != NULL && strlen(val) != 0) { -- arr[3] = ISULAD_ENABLE_PLUGINS_SEPERATOR; -- arr[4] = val; -- len = 5; -- } -- -- kv = util_string_join("", arr, len); -- if (kv == NULL) { -- goto failed; -- } -- -- if (util_env_set_val(penv, penv_len, ISULAD_ENABLE_PLUGINS, strlen(ISULAD_ENABLE_PLUGINS), kv)) { -- goto failed; -- } -- -- free(val); -- free(kv); -- return 0; -- --failed: -- free(val); -- free(kv); -- return -1; --} -- --static int request_pack_custom_env(struct client_arguments *args, isula_container_config_t *conf) -+static int request_pack_custom_env(const struct client_arguments *args, isula_container_config_t *conf) - { - int ret = 0; - char *pe = NULL; -@@ -244,7 +208,7 @@ static int request_pack_custom_env(struct client_arguments *args, isula_containe - if (args->custom_conf.env != NULL) { - size_t i; - for (i = 0; i < util_array_len((const char **)(args->custom_conf.env)); i++) { -- if (util_validate_env(args->custom_conf.env[i], &new_env) != 0) { -+ if (util_valid_env(args->custom_conf.env[i], &new_env) != 0) { - COMMAND_ERROR("Invalid environment %s", args->custom_conf.env[i]); - ret = -1; - goto out; -@@ -263,25 +227,6 @@ static int request_pack_custom_env(struct client_arguments *args, isula_containe - conf->env_len = util_array_len((const char **)(conf->env)); - } - -- if (args->custom_conf.accel != NULL) { -- pe = util_env_get_val(conf->env, conf->env_len, ISULAD_ENABLE_PLUGINS, strlen(ISULAD_ENABLE_PLUGINS)); -- if (pe == NULL) { -- if (util_array_append(&conf->env, ISULAD_ENABLE_PLUGINS "=")) { -- COMMAND_ERROR("init env ISULAD_ENABLE_PLUGINS failed"); -- ret = -1; -- goto out; -- } -- } -- conf->env_len = util_array_len((const char **)(conf->env)); -- conf->accel = args->custom_conf.accel; -- conf->accel_len = util_array_len((const char **)(args->custom_conf.accel)); -- if (util_env_set_isulad_enable_plugins(&conf->env, &conf->env_len, ISULAD_ISULA_ADAPTER)) { -- COMMAND_ERROR("init accel env failed"); -- ret = -1; -- goto out; -- } -- } -- - out: - free(pe); - free(new_env); -@@ -315,7 +260,7 @@ static int read_env_from_file(const char *path, size_t file_size, isula_containe - continue; - } - buf[len - 1] = '\0'; -- if (util_validate_env(buf, &new_env) != 0) { -+ if (util_valid_env(buf, &new_env) != 0) { - ret = -1; - goto out; - } -@@ -408,7 +353,7 @@ out: - return ret; - } - --static int request_pack_custom_label(struct client_arguments *args, isula_container_config_t *conf) -+static int request_pack_custom_label(const struct client_arguments *args, isula_container_config_t *conf) - { - int ret = 0; - size_t i; -@@ -429,8 +374,6 @@ static int request_pack_custom_label(struct client_arguments *args, isula_contai - goto out; - } - } -- util_free_array(args->custom_conf.label); -- args->custom_conf.label = conf->label; /* make sure args->custom_conf.label point to valid memory. */ - conf->label_len = util_array_len((const char **)(conf->label)); - - out: -@@ -527,7 +470,7 @@ out: - static void request_pack_custom_user(const struct client_arguments *args, isula_container_config_t *conf) - { - if (args->custom_conf.user != NULL) { -- conf->user = args->custom_conf.user; -+ conf->user = util_strdup_s(args->custom_conf.user); - } - - return; -@@ -536,7 +479,7 @@ static void request_pack_custom_user(const struct client_arguments *args, isula_ - static void request_pack_custom_hostname(const struct client_arguments *args, isula_container_config_t *conf) - { - if (args->custom_conf.hostname != NULL) { -- conf->hostname = args->custom_conf.hostname; -+ conf->hostname = util_strdup_s(args->custom_conf.hostname); - } - - return; -@@ -560,39 +503,50 @@ static void request_pack_custom_system_container(const struct client_arguments * - /* ns change opt */ - if (!args->custom_conf.privileged) { - if (args->custom_conf.ns_change_opt != NULL) { -- conf->ns_change_opt = args->custom_conf.ns_change_opt; -+ conf->ns_change_opt = util_strdup_s(args->custom_conf.ns_change_opt); - } - } - - return; - } - --static void request_pack_custom_mounts(const struct client_arguments *args, isula_container_config_t *conf) -+static int request_pack_custom_mounts(const struct client_arguments *args, isula_container_config_t *conf) - { -- if (args->custom_conf.mounts != NULL) { -- conf->mounts_len = util_array_len((const char **)(args->custom_conf.mounts)); -- conf->mounts = args->custom_conf.mounts; -+ if (args->custom_conf.mounts == NULL) { -+ return 0; - } -- return; -+ -+ if (util_dup_array_of_strings((const char **)args->custom_conf.mounts, -+ util_array_len((const char **)(args->custom_conf.mounts)), &conf->mounts, -+ &conf->mounts_len) != 0) { -+ COMMAND_ERROR("Failed to dup mounts info"); -+ return -1; -+ } -+ -+ return 0; - } - - static void request_pack_custom_entrypoint(const struct client_arguments *args, isula_container_config_t *conf) - { - if (args->custom_conf.entrypoint != NULL) { -- conf->entrypoint = args->custom_conf.entrypoint; -+ conf->entrypoint = util_strdup_s(args->custom_conf.entrypoint); - } - - return; - } - --static void request_pack_custom_args(const struct client_arguments *args, isula_container_config_t *conf) -+static int request_pack_custom_args(const struct client_arguments *args, isula_container_config_t *conf) - { -- if (args->argc != 0 && args->argv != NULL) { -- conf->cmd_len = (size_t)(args->argc); -- conf->cmd = (char **)args->argv; -+ if (args->argc == 0) { -+ return 0; - } - -- return; -+ if (util_dup_array_of_strings((const char **)args->argv, args->argc, &conf->cmd, &conf->cmd_len) != 0) { -+ COMMAND_ERROR("Failed to dup command"); -+ return -1; -+ } -+ -+ return 0; - } - - static void request_pack_custom_log_options(const struct client_arguments *args, isula_container_config_t *conf) -@@ -600,42 +554,11 @@ static void request_pack_custom_log_options(const struct client_arguments *args, - conf->log_driver = util_strdup_s(args->log_driver); - } - --static int request_pack_custom_log_accel(struct client_arguments *args, isula_container_config_t *conf) --{ -- int ret = 0; -- char *accargs = NULL; -- -- if (conf->accel != NULL) { -- accargs = util_string_join(ISULAD_ISULA_ACCEL_ARGS_SEPERATOR, (const char **)conf->accel, conf->accel_len); -- -- if (conf->annotations == NULL) { -- conf->annotations = util_common_calloc_s(sizeof(json_map_string_string)); -- if (conf->annotations == NULL) { -- COMMAND_ERROR("alloc annotations failed for accel"); -- ret = -1; -- goto out; -- } -- } -- -- ret = append_json_map_string_string(conf->annotations, ISULAD_ISULA_ACCEL_ARGS, accargs); -- if (ret != 0) { -- COMMAND_ERROR("init accel annotations failed accel=%s", accargs); -- ret = -1; -- goto out; -- } -- UTIL_FREE_AND_SET_NULL(accargs); -- } -- --out: -- free(accargs); -- return ret; --} -- - static void request_pack_custom_work_dir(const struct client_arguments *args, isula_container_config_t *conf) - { - /* work dir in container */ - if (args->custom_conf.workdir != NULL) { -- conf->workdir = args->custom_conf.workdir; -+ conf->workdir = util_strdup_s(args->custom_conf.workdir); - } - - return; -@@ -655,7 +578,7 @@ static void request_pack_custom_tty(const struct client_arguments *args, isula_c - static void request_pack_custom_health_check(const struct client_arguments *args, isula_container_config_t *conf) - { - if (args->custom_conf.health_cmd != NULL) { -- conf->health_cmd = args->custom_conf.health_cmd; -+ conf->health_cmd = util_strdup_s(args->custom_conf.health_cmd); - } - /* health check */ - conf->health_interval = args->custom_conf.health_interval; -@@ -668,30 +591,57 @@ static void request_pack_custom_health_check(const struct client_arguments *args - return; - } - --static int request_pack_custom_conf(struct client_arguments *args, isula_container_config_t *conf) -+static int request_pack_custom_annotations(const struct client_arguments *args, isula_container_config_t *conf) - { -- if (args == NULL) { -+ if (args->annotations == NULL) { -+ return 0; -+ } -+ -+ conf->annotations = util_common_calloc_s(sizeof(json_map_string_string)); -+ if (conf->annotations == NULL) { -+ COMMAND_ERROR("Out of memory"); -+ return -1; -+ } -+ -+ if (dup_json_map_string_string(args->annotations, conf->annotations) != 0) { -+ COMMAND_ERROR("Failed to dup map"); - return -1; - } - -+ return 0; -+} -+ -+static isula_container_config_t *request_pack_custom_conf(const struct client_arguments *args) -+{ -+ isula_container_config_t *conf = NULL; -+ -+ if (args == NULL) { -+ return NULL; -+ } -+ -+ conf = util_common_calloc_s(sizeof(isula_container_config_t)); -+ if (conf == NULL) { -+ return NULL; -+ } -+ - /* append environment variables from env file */ - if (request_pack_custom_env_file(args, conf) != 0) { -- return -1; -+ goto error_out; - } - - /* make sure --env has higher priority than --env-file */ - if (request_pack_custom_env(args, conf) != 0) { -- return -1; -+ goto error_out; - } - - /* append labels from label file */ - if (request_pack_custom_label_file(args, conf) != 0) { -- return -1; -+ goto error_out; - } - - /* make sure --label has higher priority than --label-file */ - if (request_pack_custom_label(args, conf) != 0) { -- return -1; -+ goto error_out; - } - - /* user and group */ -@@ -706,22 +656,23 @@ static int request_pack_custom_conf(struct client_arguments *args, isula_contain - request_pack_custom_system_container(args, conf); - - /* mounts to mount filesystem */ -- request_pack_custom_mounts(args, conf); -+ if (request_pack_custom_mounts(args, conf) != 0) { -+ goto error_out; -+ } - - /* entrypoint */ - request_pack_custom_entrypoint(args, conf); - - /* command args */ -- request_pack_custom_args(args, conf); -+ if (request_pack_custom_args(args, conf) != 0) { -+ goto error_out; -+ } - - /* console log options */ - request_pack_custom_log_options(args, conf); - -- conf->annotations = args->annotations; -- args->annotations = NULL; -- -- if (request_pack_custom_log_accel(args, conf) != 0) { -- return -1; -+ if (request_pack_custom_annotations(args, conf) != 0) { -+ goto error_out; - } - - /* work dir in container */ -@@ -731,7 +682,11 @@ static int request_pack_custom_conf(struct client_arguments *args, isula_contain - - request_pack_custom_health_check(args, conf); - -- return 0; -+ return conf; -+ -+error_out: -+ isula_container_config_free(conf); -+ return NULL; - } - - static int request_pack_host_ns_change_files(const struct client_arguments *args, isula_host_config_t *hostconfig) -@@ -786,182 +741,310 @@ static int request_pack_host_ns_change_files(const struct client_arguments *args - return ret; - } - --static void request_pack_host_caps(const struct client_arguments *args, isula_host_config_t *hostconfig) -+static int request_pack_host_caps(const struct client_arguments *args, isula_host_config_t *hostconfig) - { - /* cap add */ - if (args->custom_conf.cap_adds != NULL) { -- hostconfig->cap_add_len = util_array_len((const char **)(args->custom_conf.cap_adds)); -- hostconfig->cap_add = args->custom_conf.cap_adds; -+ if (util_dup_array_of_strings((const char **)(args->custom_conf.cap_adds), -+ util_array_len((const char **)(args->custom_conf.cap_adds)), &hostconfig->cap_add, -+ &hostconfig->cap_add_len) != 0) { -+ COMMAND_ERROR("Failed to dup cap adds"); -+ return -1; -+ } - } - /* cap drop */ - if (args->custom_conf.cap_drops != NULL) { -- hostconfig->cap_drop_len = util_array_len((const char **)(args->custom_conf.cap_drops)); -- hostconfig->cap_drop = args->custom_conf.cap_drops; -+ if (util_dup_array_of_strings((const char **)(args->custom_conf.cap_drops), -+ util_array_len((const char **)(args->custom_conf.cap_drops)), -+ &hostconfig->cap_drop, &hostconfig->cap_drop_len) != 0) { -+ COMMAND_ERROR("Failed to dup cap drops"); -+ return -1; -+ } - } -+ -+ return 0; - } - --static void request_pack_host_group_add(const struct client_arguments *args, isula_host_config_t *hostconfig) -+static int request_pack_host_group_add(const struct client_arguments *args, isula_host_config_t *hostconfig) - { - /* group add */ - if (args->custom_conf.group_add != NULL) { -- hostconfig->group_add_len = util_array_len((const char **)(args->custom_conf.group_add)); -- hostconfig->group_add = args->custom_conf.group_add; -+ if (util_dup_array_of_strings((const char **)(args->custom_conf.group_add), -+ util_array_len((const char **)(args->custom_conf.group_add)), -+ &hostconfig->group_add, &hostconfig->group_add_len) != 0) { -+ COMMAND_ERROR("Failed to dup group adds"); -+ return -1; -+ } - } -+ -+ return 0; - } - --static void request_pack_host_extra_hosts(const struct client_arguments *args, isula_host_config_t *hostconfig) -+static int request_pack_host_extra_hosts(const struct client_arguments *args, isula_host_config_t *hostconfig) - { - /* extra hosts */ - if (args->custom_conf.extra_hosts != NULL) { -- hostconfig->extra_hosts_len = util_array_len((const char **)(args->custom_conf.extra_hosts)); -- hostconfig->extra_hosts = args->custom_conf.extra_hosts; -+ if (util_dup_array_of_strings((const char **)(args->custom_conf.extra_hosts), -+ util_array_len((const char **)(args->custom_conf.extra_hosts)), -+ &hostconfig->extra_hosts, &hostconfig->extra_hosts_len) != 0) { -+ COMMAND_ERROR("Failed to dup extra hosts"); -+ return -1; -+ } - } -+ -+ return 0; - } - --static void request_pack_host_dns(const struct client_arguments *args, isula_host_config_t *hostconfig) -+static int request_pack_host_dns(const struct client_arguments *args, isula_host_config_t *hostconfig) - { - /* dns */ - if (args->custom_conf.dns != NULL) { -- hostconfig->dns_len = util_array_len((const char **)(args->custom_conf.dns)); -- hostconfig->dns = args->custom_conf.dns; -+ if (util_dup_array_of_strings((const char **)(args->custom_conf.dns), -+ util_array_len((const char **)(args->custom_conf.dns)), &hostconfig->dns, -+ &hostconfig->dns_len) != 0) { -+ COMMAND_ERROR("Failed to dup dns"); -+ return -1; -+ } - } - - /* dns options */ - if (args->custom_conf.dns_options != NULL) { -- hostconfig->dns_options_len = util_array_len((const char **)(args->custom_conf.dns_options)); -- hostconfig->dns_options = args->custom_conf.dns_options; -+ if (util_dup_array_of_strings((const char **)(args->custom_conf.dns_options), -+ util_array_len((const char **)(args->custom_conf.dns_options)), -+ &hostconfig->dns_options, &hostconfig->dns_options_len) != 0) { -+ COMMAND_ERROR("Failed to dup dns options"); -+ return -1; -+ } - } - - /* dns search */ - if (args->custom_conf.dns_search != NULL) { -- hostconfig->dns_search_len = util_array_len((const char **)(args->custom_conf.dns_search)); -- hostconfig->dns_search = args->custom_conf.dns_search; -+ if (util_dup_array_of_strings((const char **)(args->custom_conf.dns_search), -+ util_array_len((const char **)(args->custom_conf.dns_search)), -+ &hostconfig->dns_search, &hostconfig->dns_search_len) != 0) { -+ COMMAND_ERROR("Failed to dup dns search"); -+ return -1; -+ } - } -+ -+ return 0; - } - --static void request_pack_host_ulimit(const struct client_arguments *args, isula_host_config_t *hostconfig) -+inline static int request_pack_host_ulimit(const struct client_arguments *args, isula_host_config_t *hostconfig) - { - /* ulimit options */ - if (args->custom_conf.ulimits != NULL) { -- hostconfig->ulimits_len = util_array_len((const char **)(args->custom_conf.ulimits)); -- hostconfig->ulimits = args->custom_conf.ulimits; -+ if (util_dup_array_of_strings((const char **)(args->custom_conf.ulimits), -+ util_array_len((const char **)(args->custom_conf.ulimits)), &hostconfig->ulimits, -+ &hostconfig->ulimits_len) != 0) { -+ COMMAND_ERROR("Failed to dup ulimits"); -+ return -1; -+ } - } -+ -+ return 0; - } - --static void request_pack_host_weight_devices(const struct client_arguments *args, isula_host_config_t *hostconfig) -+inline static int request_pack_host_weight_devices(const struct client_arguments *args, isula_host_config_t *hostconfig) - { - /* blkio weight devices */ - if (args->custom_conf.weight_devices != NULL) { -- hostconfig->blkio_weight_device_len = util_array_len((const char **)(args->custom_conf.weight_devices)); -- hostconfig->blkio_weight_device = args->custom_conf.weight_devices; -+ if (util_dup_array_of_strings((const char **)(args->custom_conf.weight_devices), -+ util_array_len((const char **)(args->custom_conf.weight_devices)), -+ &hostconfig->blkio_weight_device, &hostconfig->blkio_weight_device_len) != 0) { -+ COMMAND_ERROR("Failed to dup weight devices"); -+ return -1; -+ } - } -+ -+ return 0; - } - --static void request_pack_host_device_read_bps(const struct client_arguments *args, isula_host_config_t *hostconfig) -+inline static int request_pack_host_device_read_bps(const struct client_arguments *args, -+ isula_host_config_t *hostconfig) - { - if (args->custom_conf.blkio_throttle_read_bps_device != NULL) { -- hostconfig->blkio_throttle_read_bps_device_len = -- util_array_len((const char **)(args->custom_conf.blkio_throttle_read_bps_device)); -- hostconfig->blkio_throttle_read_bps_device = args->custom_conf.blkio_throttle_read_bps_device; -+ if (util_dup_array_of_strings((const char **)(args->custom_conf.blkio_throttle_read_bps_device), -+ util_array_len((const char **)(args->custom_conf.blkio_throttle_read_bps_device)), -+ &hostconfig->blkio_throttle_read_bps_device, -+ &hostconfig->blkio_throttle_read_bps_device_len) != 0) { -+ COMMAND_ERROR("Failed to dup blkio_throttle_read_bps_device"); -+ return -1; -+ } - } -+ -+ return 0; - } - --static void request_pack_host_device_write_bps(const struct client_arguments *args, isula_host_config_t *hostconfig) -+inline static int request_pack_host_device_write_bps(const struct client_arguments *args, -+ isula_host_config_t *hostconfig) - { - if (args->custom_conf.blkio_throttle_write_bps_device != NULL) { -- hostconfig->blkio_throttle_write_bps_device_len = -- util_array_len((const char **)(args->custom_conf.blkio_throttle_write_bps_device)); -- hostconfig->blkio_throttle_write_bps_device = args->custom_conf.blkio_throttle_write_bps_device; -+ if (util_dup_array_of_strings((const char **)(args->custom_conf.blkio_throttle_write_bps_device), -+ util_array_len((const char **)(args->custom_conf.blkio_throttle_write_bps_device)), -+ &hostconfig->blkio_throttle_write_bps_device, -+ &hostconfig->blkio_throttle_write_bps_device_len) != 0) { -+ COMMAND_ERROR("Failed to dup blkio_throttle_write_bps_device"); -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+inline static int request_pack_host_device_read_iops(const struct client_arguments *args, -+ isula_host_config_t *hostconfig) -+{ -+ if (args->custom_conf.blkio_throttle_read_iops_device != NULL) { -+ if (util_dup_array_of_strings((const char **)(args->custom_conf.blkio_throttle_read_iops_device), -+ util_array_len((const char **)(args->custom_conf.blkio_throttle_read_iops_device)), -+ &hostconfig->blkio_throttle_read_iops_device, -+ &hostconfig->blkio_throttle_read_iops_device_len) != 0) { -+ COMMAND_ERROR("Failed to dup blkio_throttle_read_iops_device"); -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+inline static int request_pack_host_device_write_iops(const struct client_arguments *args, -+ isula_host_config_t *hostconfig) -+{ -+ if (args->custom_conf.blkio_throttle_write_iops_device != NULL) { -+ if (util_dup_array_of_strings( -+ (const char **)(args->custom_conf.blkio_throttle_write_iops_device), -+ util_array_len((const char **)(args->custom_conf.blkio_throttle_write_iops_device)), -+ &hostconfig->blkio_throttle_write_iops_device, -+ &hostconfig->blkio_throttle_write_iops_device_len) != 0) { -+ COMMAND_ERROR("Failed to dup blkio_throttle_write_iops_device"); -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+inline static int request_pack_host_device_cgroup_rules(const struct client_arguments *args, -+ isula_host_config_t *hostconfig) -+{ -+ if (args->custom_conf.device_cgroup_rules != NULL) { -+ if (util_dup_array_of_strings((const char **)(args->custom_conf.device_cgroup_rules), -+ util_array_len((const char **)(args->custom_conf.device_cgroup_rules)), -+ &hostconfig->device_cgroup_rules, &hostconfig->device_cgroup_rules_len) != 0) { -+ COMMAND_ERROR("Failed to dup device_cgroup_rules"); -+ return -1; -+ } - } -+ -+ return 0; - } - --static void request_pack_host_blockio(const struct client_arguments *args, isula_host_config_t *hostconfig) -+inline static int request_pack_host_blockio(const struct client_arguments *args, isula_host_config_t *hostconfig) - { -- request_pack_host_weight_devices(args, hostconfig); -- request_pack_host_device_read_bps(args, hostconfig); -- request_pack_host_device_write_bps(args, hostconfig); -+ return (request_pack_host_weight_devices(args, hostconfig) || request_pack_host_device_read_bps(args, hostconfig) || -+ request_pack_host_device_write_bps(args, hostconfig) || -+ request_pack_host_device_read_iops(args, hostconfig) || -+ request_pack_host_device_write_iops(args, hostconfig)); - } - --static void request_pack_host_devices(const struct client_arguments *args, isula_host_config_t *hostconfig) -+inline static int request_pack_host_devices(const struct client_arguments *args, isula_host_config_t *hostconfig) - { - /* devices */ - if (args->custom_conf.devices != NULL) { -- hostconfig->devices_len = util_array_len((const char **)(args->custom_conf.devices)); -- hostconfig->devices = args->custom_conf.devices; -+ if (util_dup_array_of_strings((const char **)(args->custom_conf.devices), -+ util_array_len((const char **)(args->custom_conf.devices)), &hostconfig->devices, -+ &hostconfig->devices_len) != 0) { -+ COMMAND_ERROR("Failed to dup devices"); -+ return -1; -+ } - } -+ -+ return 0; - } - --static void request_pack_host_hugepage_limits(const struct client_arguments *args, isula_host_config_t *hostconfig) -+inline static int request_pack_host_hugepage_limits(const struct client_arguments *args, -+ isula_host_config_t *hostconfig) - { - /* hugepage limits */ - if (args->custom_conf.hugepage_limits != NULL) { -- hostconfig->hugetlbs_len = util_array_len((const char **)(args->custom_conf.hugepage_limits)); -- hostconfig->hugetlbs = args->custom_conf.hugepage_limits; -+ if (util_dup_array_of_strings((const char **)(args->custom_conf.hugepage_limits), -+ util_array_len((const char **)(args->custom_conf.hugepage_limits)), -+ &hostconfig->hugetlbs, &hostconfig->hugetlbs_len) != 0) { -+ COMMAND_ERROR("Failed to dup hugepage_limits"); -+ return -1; -+ } - } -+ -+ return 0; - } - --static void request_pack_host_binds(const struct client_arguments *args, isula_host_config_t *hostconfig) -+inline static int request_pack_host_binds(const struct client_arguments *args, isula_host_config_t *hostconfig) - { - /* volumes to binds */ - if (args->custom_conf.volumes != NULL) { -- hostconfig->binds_len = (size_t)util_array_len((const char **)(args->custom_conf.volumes)); -- hostconfig->binds = args->custom_conf.volumes; -+ if (util_dup_array_of_strings((const char **)(args->custom_conf.volumes), -+ util_array_len((const char **)(args->custom_conf.volumes)), &hostconfig->binds, -+ &hostconfig->binds_len) != 0) { -+ COMMAND_ERROR("Failed to dup volumes"); -+ return -1; -+ } - } -+ -+ return 0; - } - --static void request_pack_host_hook_spec(const struct client_arguments *args, isula_host_config_t *hostconfig) -+inline static void request_pack_host_hook_spec(const struct client_arguments *args, isula_host_config_t *hostconfig) - { - /* hook-spec file */ -- if (args->custom_conf.hook_spec != NULL) { -- hostconfig->hook_spec = args->custom_conf.hook_spec; -- } -+ hostconfig->hook_spec = util_strdup_s(args->custom_conf.hook_spec); - } - --static void request_pack_host_restart_policy(const struct client_arguments *args, isula_host_config_t *hostconfig) -+inline static void request_pack_host_restart_policy(const struct client_arguments *args, -+ isula_host_config_t *hostconfig) - { -- if (args->restart != NULL) { -- hostconfig->restart_policy = args->restart; -- } -+ hostconfig->restart_policy = util_strdup_s(args->restart); - } - - static void request_pack_host_namespaces(const struct client_arguments *args, isula_host_config_t *hostconfig) - { -- if (args->host_channel != NULL) { -- hostconfig->host_channel = args->host_channel; -- } -+ hostconfig->network_mode = util_strdup_s(args->custom_conf.share_ns[NAMESPACE_NET]); - -- if (args->custom_conf.share_ns[NAMESPACE_NET] != NULL) { -- hostconfig->network_mode = args->custom_conf.share_ns[NAMESPACE_NET]; -- } -- if (args->custom_conf.share_ns[NAMESPACE_IPC] != NULL) { -- hostconfig->ipc_mode = args->custom_conf.share_ns[NAMESPACE_IPC]; -- } -- if (args->custom_conf.share_ns[NAMESPACE_USER] != NULL) { -- hostconfig->userns_mode = args->custom_conf.share_ns[NAMESPACE_USER]; -- } -- if (args->custom_conf.share_ns[NAMESPACE_UTS] != NULL) { -- hostconfig->uts_mode = args->custom_conf.share_ns[NAMESPACE_UTS]; -- } -- if (args->custom_conf.share_ns[NAMESPACE_PID] != NULL) { -- hostconfig->pid_mode = args->custom_conf.share_ns[NAMESPACE_PID]; -- } -+ hostconfig->ipc_mode = util_strdup_s(args->custom_conf.share_ns[NAMESPACE_IPC]); -+ -+ hostconfig->userns_mode = util_strdup_s(args->custom_conf.share_ns[NAMESPACE_USER]); -+ -+ hostconfig->uts_mode = util_strdup_s(args->custom_conf.share_ns[NAMESPACE_UTS]); -+ -+ hostconfig->pid_mode = util_strdup_s(args->custom_conf.share_ns[NAMESPACE_PID]); - } - --static void request_pack_host_security(const struct client_arguments *args, isula_host_config_t *hostconfig) -+inline static int request_pack_host_security(const struct client_arguments *args, isula_host_config_t *hostconfig) - { - /* security opt */ - if (args->custom_conf.security != NULL) { -- hostconfig->security_len = util_array_len((const char **)(args->custom_conf.security)); -- hostconfig->security = args->custom_conf.security; -+ if (util_dup_array_of_strings((const char **)(args->custom_conf.security), -+ util_array_len((const char **)(args->custom_conf.security)), -+ &hostconfig->security, &hostconfig->security_len) != 0) { -+ COMMAND_ERROR("Failed to dup security"); -+ return -1; -+ } - } -+ -+ return 0; - } - --static int request_pack_host_config(const struct client_arguments *args, isula_host_config_t *hostconfig) -+static isula_host_config_t *request_pack_host_config(const struct client_arguments *args) - { -- int ret = 0; -+ isula_host_config_t *hostconfig = NULL; - - if (args == NULL) { -- return -1; -+ return NULL; -+ } -+ -+ hostconfig = util_common_calloc_s(sizeof(isula_host_config_t)); -+ if (hostconfig == NULL) { -+ return NULL; - } - - /* privileged */ -@@ -977,7 +1060,7 @@ static int request_pack_host_config(const struct client_arguments *args, isula_h - hostconfig->shm_size = args->custom_conf.shm_size; - - /* user remap */ -- hostconfig->user_remap = args->custom_conf.user_remap; -+ hostconfig->user_remap = util_strdup_s(args->custom_conf.user_remap); - - /* auto remove */ - hostconfig->auto_remove = args->custom_conf.auto_remove; -@@ -986,50 +1069,64 @@ static int request_pack_host_config(const struct client_arguments *args, isula_h - hostconfig->readonly_rootfs = args->custom_conf.readonly; - - /* env target file */ -- hostconfig->env_target_file = args->custom_conf.env_target_file; -+ hostconfig->env_target_file = util_strdup_s(args->custom_conf.env_target_file); - - /* cgroup parent */ -- hostconfig->cgroup_parent = args->custom_conf.cgroup_parent; -+ hostconfig->cgroup_parent = util_strdup_s(args->custom_conf.cgroup_parent); - -- ret = request_pack_host_config_cgroup(args, hostconfig); -- if (ret != 0) { -- return ret; -+ if (request_pack_host_config_cgroup(args, hostconfig) != 0) { -+ goto error_out; - } - - /* storage options */ -- ret = request_pack_host_config_storage_opts(args, hostconfig); -- if (ret != 0) { -- return ret; -+ if (request_pack_host_config_storage_opts(args, hostconfig) != 0) { -+ goto error_out; - } - - /* sysctls */ -- ret = request_pack_host_config_sysctls(args, hostconfig); -- if (ret != 0) { -- return ret; -+ if (request_pack_host_config_sysctls(args, hostconfig) != 0) { -+ goto error_out; - } - -- ret = request_pack_host_ns_change_files(args, hostconfig); -- if (ret != 0) { -- return ret; -+ if (request_pack_host_ns_change_files(args, hostconfig) != 0) { -+ goto error_out; - } - -- request_pack_host_caps(args, hostconfig); -+ if (request_pack_host_caps(args, hostconfig) != 0) { -+ goto error_out; -+ } - -- request_pack_host_group_add(args, hostconfig); -+ if (request_pack_host_group_add(args, hostconfig) != 0) { -+ goto error_out; -+ } - -- request_pack_host_extra_hosts(args, hostconfig); -+ if (request_pack_host_extra_hosts(args, hostconfig) != 0) { -+ goto error_out; -+ } - -- request_pack_host_dns(args, hostconfig); -+ if (request_pack_host_dns(args, hostconfig) != 0) { -+ goto error_out; -+ } - -- request_pack_host_ulimit(args, hostconfig); -+ if (request_pack_host_ulimit(args, hostconfig) != 0) { -+ goto error_out; -+ } - -- request_pack_host_blockio(args, hostconfig); -+ if (request_pack_host_blockio(args, hostconfig) != 0) { -+ goto error_out; -+ } - -- request_pack_host_devices(args, hostconfig); -+ if (request_pack_host_devices(args, hostconfig) != 0) { -+ goto error_out; -+ } - -- request_pack_host_hugepage_limits(args, hostconfig); -+ if (request_pack_host_hugepage_limits(args, hostconfig) != 0) { -+ goto error_out; -+ } - -- request_pack_host_binds(args, hostconfig); -+ if (request_pack_host_binds(args, hostconfig) != 0) { -+ goto error_out; -+ } - - request_pack_host_hook_spec(args, hostconfig); - -@@ -1037,9 +1134,21 @@ static int request_pack_host_config(const struct client_arguments *args, isula_h - - request_pack_host_namespaces(args, hostconfig); - -- request_pack_host_security(args, hostconfig); -+ hostconfig->host_channel = util_strdup_s(args->host_channel); - -- return ret; -+ if (request_pack_host_security(args, hostconfig) != 0) { -+ goto error_out; -+ } -+ -+ if (request_pack_host_device_cgroup_rules(args, hostconfig) != 0) { -+ goto error_out; -+ } -+ -+ return hostconfig; -+ -+error_out: -+ isula_host_config_free(hostconfig); -+ return NULL; - } - - #define IMAGE_NOT_FOUND_ERROR "No such image" -@@ -1116,57 +1225,52 @@ out: - return ret; - } - --static void free_alloced_memory_in_host_config(isula_host_config_t *hostconfig) --{ -- isula_ns_change_files_free(hostconfig); -- isula_host_config_storage_opts_free(hostconfig); -- isula_host_config_sysctl_free(hostconfig); --} -- --static void free_alloced_memory_in_config(isula_container_config_t *custom_conf) --{ -- if (custom_conf == NULL) { -- return; -- } -- -- free_json_map_string_string(custom_conf->annotations); -- custom_conf->annotations = NULL; -- -- free(custom_conf->log_driver); -- custom_conf->log_driver = NULL; --} -- - /* - * Create a create request message and call RPC - */ - int client_create(struct client_arguments *args) - { - int ret = 0; -- struct isula_create_request request = { 0 }; -+ struct isula_create_request *request = NULL; - struct isula_create_response *response = NULL; -- isula_container_config_t custom_conf = { 0 }; -- isula_host_config_t host_config = { 0 }; -- container_cgroup_resources_t cr = { 0 }; -- -- request.name = args->name; -- request.rootfs = args->create_rootfs; -- request.runtime = args->runtime; -- request.image = args->image_name; -- request.hostconfig = &host_config; -- request.config = &custom_conf; -- host_config.cr = &cr; -- -- ret = request_pack_custom_conf(args, request.config); -- if (ret != 0) { -+ isula_container_config_t *container_spec = NULL; -+ isula_host_config_t *host_spec = NULL; -+ -+ request = util_common_calloc_s(sizeof(struct isula_create_request)); -+ if (request == NULL) { -+ COMMAND_ERROR("Memery out"); -+ ret = -1; - goto out; - } - -- ret = request_pack_host_config(args, request.hostconfig); -- if (ret != 0) { -+ request->name = util_strdup_s(args->name); -+ request->rootfs = util_strdup_s(args->create_rootfs); -+ request->runtime = util_strdup_s(args->runtime); -+ request->image = util_strdup_s(args->image_name); -+ -+ container_spec = request_pack_custom_conf(args); -+ if (container_spec == 0) { -+ ret = -1; -+ goto out; -+ } -+ -+ if (generate_container_config(container_spec, &request->container_spec_json) != 0) { -+ ret = -1; -+ goto out; -+ } -+ -+ host_spec = request_pack_host_config(args); -+ if (host_spec == 0) { -+ ret = -1; -+ goto out; -+ } -+ -+ if (generate_hostconfig(host_spec, &request->host_spec_json) != 0) { -+ ret = -1; - goto out; - } - -- ret = client_try_to_create(args, &request, &response); -+ ret = client_try_to_create(args, request, &response); - if (ret != 0) { - goto out; - } -@@ -1180,9 +1284,10 @@ int client_create(struct client_arguments *args) - goto out; - } - out: -- free_alloced_memory_in_host_config(request.hostconfig); -- free_alloced_memory_in_config(request.config); -+ isula_host_config_free(host_spec); -+ isula_container_config_free(container_spec); - isula_create_response_free(response); -+ isula_create_request_free(request); - return ret; - } - -@@ -1741,7 +1846,7 @@ static int parse_mount_item_dst(const char *value, struct valid_mounts_state *st - return MOUNT_STATE_CHECK_INVALID_ARG; - } - -- if (!cleanpath(value, dstpath, sizeof(dstpath))) { -+ if (!util_clean_path(value, dstpath, sizeof(dstpath))) { - COMMAND_ERROR("Invalid mount specification '%s'.Can't translate destination path to clean path", state->mount); - return MOUNT_STATE_CHECK_INVALID_ARG; - } -@@ -2139,7 +2244,7 @@ static int create_namespaces_checker(const struct client_arguments *args) - const char *net_mode = args->custom_conf.share_ns[NAMESPACE_NET]; - - if (args->custom_conf.share_ns[NAMESPACE_NET]) { -- if (!is_host(net_mode) && !is_container(net_mode) && !is_none(net_mode)) { -+ if (!namespace_is_host(net_mode) && !namespace_is_container(net_mode) && !namespace_is_none(net_mode)) { - COMMAND_ERROR("Unsupported network mode %s", net_mode); - ret = -1; - goto out; -@@ -2228,7 +2333,7 @@ static bool do_create_check_sysctl(const char *sysctl) - if (p != NULL) { - *p = '\0'; - if (strcmp("kernel.pid_max", sysctl) == 0) { -- if (!pid_max_kernel_namespaced()) { -+ if (!util_check_pid_max_kernel_namespaced()) { - COMMAND_ERROR("Sysctl '%s' is not kernel namespaced, it cannot be changed", sysctl); - restore_to_equate(p); - return false; -@@ -2237,7 +2342,7 @@ static bool do_create_check_sysctl(const char *sysctl) - return true; - } - } -- if (!check_sysctl_valid(sysctl)) { -+ if (!util_valid_sysctl(sysctl)) { - restore_to_equate(p); - COMMAND_ERROR("Sysctl '%s' is not whitelist", sysctl); - return false; -@@ -2286,7 +2391,7 @@ static int create_check_env_target_file(const struct client_arguments *args) - COMMAND_ERROR("external rootfs not specified"); - return 0; - } -- if (realpath_in_scope(args->external_rootfs, env_target_file, &env_path) < 0) { -+ if (util_realpath_in_scope(args->external_rootfs, env_target_file, &env_path) < 0) { - COMMAND_ERROR("env target file '%s' real path must be under '%s'", env_target_file, args->external_rootfs); - ret = -1; - goto out; -diff --git a/src/cmd/isula/base/create.h b/src/cmd/isula/base/create.h -index d8733e0..79f6378 100644 ---- a/src/cmd/isula/base/create.h -+++ b/src/cmd/isula/base/create.h -@@ -26,396 +26,442 @@ - extern "C" { - #endif - --#define CREATE_OPTIONS(cmdargs) \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "accel", \ -- 0, \ -- &(cmdargs).custom_conf.accel, \ -- "Accelerator bindings (format: [=][@[,]])", \ -- command_append_array }, \ -- { CMD_OPT_TYPE_BOOL, \ -- false, \ -- "read-only", \ -- 0, \ -- &(cmdargs).custom_conf.readonly, \ -- "Make container rootfs readonly", \ -- NULL }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "cap-add", \ -- 0, \ -- &(cmdargs).custom_conf.cap_adds, \ -- "Add Linux capabilities ('ALL' to add all capabilities)", \ -- command_append_array }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "cap-drop", \ -- 0, \ -- &(cmdargs).custom_conf.cap_drops, \ -- "Drop Linux capabilities ('ALL' to drop all capabilities)", \ -- command_append_array }, \ -- { CMD_OPT_TYPE_CALLBACK, false, "cpu-shares", 0, &(cmdargs).cr.cpu_shares, "CPU shares (relative weight)", \ -- command_convert_llong }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "cpu-period", \ -- 0, \ -- &(cmdargs).cr.cpu_period, \ -- "Limit CPU CFS (Completely Fair Scheduler) period", \ -- command_convert_llong }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "cpu-quota", \ -- 0, \ -- &(cmdargs).cr.cpu_quota, \ -- "Limit CPU CFS (Completely Fair Scheduler) quota", \ -- command_convert_llong }, \ -- { CMD_OPT_TYPE_STRING, \ -- false, \ -- "cpuset-cpus", \ -- 0, \ -- &(cmdargs).cr.cpuset_cpus, \ -- "CPUs in which to allow execution (e.g. 0-3, 0,1)", \ -- NULL }, \ -- { CMD_OPT_TYPE_STRING, \ -- false, \ -- "cpuset-mems", \ -- 0, \ -- &(cmdargs).cr.cpuset_mems, \ -- "MEMs in which to allow execution (0-3, 0,1)", \ -- NULL }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "device-read-bps", \ -- 0, \ -- &(cmdargs).custom_conf.blkio_throttle_read_bps_device, \ -- "Limit read rate (bytes per second) from a device (default [])", \ -- command_append_array }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "device-write-bps", \ -- 0, \ -- &(cmdargs).custom_conf.blkio_throttle_write_bps_device, \ -- "Limit write rate (bytes per second) to a device (default [])", \ -- command_append_array }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "oom-score-adj", \ -- 0, \ -- &(cmdargs).cr.oom_score_adj, \ -- "Tune host's OOM preferences (-1000 to 1000)", \ -- command_convert_llong }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "device", \ -- 0, \ -- &(cmdargs).custom_conf.devices, \ -- "Add a host device to the container", \ -- command_append_array }, \ -- { CMD_OPT_TYPE_CALLBACK, false, "env", 'e', &(cmdargs).custom_conf.env, "Set environment variables", \ -- command_append_array }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "env-file", \ -- 0, \ -- &(cmdargs).custom_conf.env_file, \ -- "Read in a file of environment variables", \ -- command_append_array }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "label", \ -- 'l', \ -- &(cmdargs).custom_conf.label, \ -- "Set metadata on container (default [])", \ -- command_append_array }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "label-file", \ -- 0, \ -- &(cmdargs).custom_conf.label_file, \ -- "Read in a line delimited file of labels (default [])", \ -- command_append_array }, \ -- { CMD_OPT_TYPE_STRING_DUP, \ -- false, \ -- "entrypoint", \ -- 0, \ -- &(cmdargs).custom_conf.entrypoint, \ -- "Entrypoint to run when starting the container", \ -- NULL }, \ -- { CMD_OPT_TYPE_STRING, \ -- false, \ -- "external-rootfs", \ -- 0, \ -- &(cmdargs).external_rootfs, \ -- "Specify the custom rootfs that is not managed by isulad for the container, directory or block device", \ -- NULL }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "files-limit", \ -- 0, \ -- &(cmdargs).custom_conf.files_limit, \ -- "Tune container files limit (set -1 for unlimited)", \ -- command_convert_llong }, \ -- { CMD_OPT_TYPE_STRING_DUP, \ -- false, \ -- "hook-spec", \ -- 0, \ -- &(cmdargs).custom_conf.hook_spec, \ -- "File containing hook definition(prestart, poststart, poststop)", \ -- NULL }, \ -- { CMD_OPT_TYPE_STRING_DUP, false, "hostname", 'h', &(cmdargs).custom_conf.hostname, \ -- "Container host name", NULL }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "add-host", \ -- 0, \ -- &(cmdargs).custom_conf.extra_hosts, \ -- "Add a custom host-to-IP mapping (host:ip)", \ -- command_append_array }, \ -- { CMD_OPT_TYPE_CALLBACK, false, "dns", 0, &(cmdargs).custom_conf.dns, "Set custom DNS servers", \ -- command_append_array }, \ -- { CMD_OPT_TYPE_CALLBACK, false, "dns-opt", 0, &(cmdargs).custom_conf.dns_options, "Set DNS options", \ -- command_append_array }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "dns-search", \ -- 0, \ -- &(cmdargs).custom_conf.dns_search, \ -- "Set custom DNS search domains", \ -- command_append_array }, \ -- { CMD_OPT_TYPE_STRING, \ -- false, \ -- "user-remap", \ -- 0, \ -- &(cmdargs).custom_conf.user_remap, \ -- "Set user remap for container", \ -- NULL }, \ -- { CMD_OPT_TYPE_STRING_DUP, false, "ipc", 0, &(cmdargs).custom_conf.share_ns[NAMESPACE_IPC], \ -- "IPC namespace to use", NULL }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "shm-size", \ -- 0, \ -- &(cmdargs).custom_conf.shm_size, \ -- "Size of /dev/shm, default value is 64MB", \ -- command_convert_membytes }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "kernel-memory", \ -- 0, \ -- &(cmdargs).cr.kernel_memory_limit, \ -- "Kernel memory limit", \ -- command_convert_membytes }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "hugetlb-limit", \ -- 0, \ -- &(cmdargs).custom_conf.hugepage_limits, \ -- "Huge page limit (format: [size:], e.g. --hugetlb-limit 2MB:32MB)", \ -- command_append_array }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "log-driver", \ -- 0, \ -- &(cmdargs), \ -- "Container log driver, support syslog and json-file", \ -- callback_log_driver }, \ -- { CMD_OPT_TYPE_CALLBACK, false, "log-opt", 0, &(cmdargs), "Container log options, value formate: key=value", \ -- callback_log_opt }, \ -- { CMD_OPT_TYPE_CALLBACK, false, "memory", 'm', &(cmdargs).cr.memory_limit, "Memory limit", \ -- command_convert_membytes }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "memory-reservation", \ -- 0, \ -- &(cmdargs).cr.memory_reservation, \ -- "Memory soft limit", \ -- command_convert_membytes }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "memory-swap", \ -- 0, \ -- &(cmdargs).cr.memory_swap, \ -- "Swap limit equal to memory plus swap: '-1' to enable unlimited swap", \ -- command_convert_memswapbytes }, \ -- { CMD_OPT_TYPE_CALLBACK, false, \ -- "memory-swappiness", 0, \ -- &(cmdargs).cr.swappiness, "Tune container memory swappiness (0 to 100) (default -1)", \ -- command_convert_swappiness }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "mount", \ -- 0, \ -- &(cmdargs).custom_conf.mounts, \ -- "Attach a filesystem mount to the service", \ -- command_append_array }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "group-add", \ -- 0, \ -- &(cmdargs).custom_conf.group_add, \ -- "Add additional groups to join", \ -- command_append_array }, \ -- { CMD_OPT_TYPE_STRING_DUP, false, "name", 'n', &(cmdargs).name, "Name of the container", NULL }, \ -- { CMD_OPT_TYPE_STRING_DUP, \ -- false, \ -- "net", \ -- 0, \ -- &(cmdargs).custom_conf.share_ns[NAMESPACE_NET], \ -- "Connect a container to a network", \ -- NULL }, \ -- { CMD_OPT_TYPE_STRING_DUP, false, "pid", 0, &(cmdargs).custom_conf.share_ns[NAMESPACE_PID], \ -- "PID namespace to use", NULL }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "pids-limit", \ -- 0, \ -- &(cmdargs).custom_conf.pids_limit, \ -- "Tune container pids limit (set -1 for unlimited)", \ -- command_convert_llong }, \ -- { CMD_OPT_TYPE_BOOL, \ -- false, \ -- "privileged", \ -- 0, \ -- &(cmdargs).custom_conf.privileged, \ -- "Give extended privileges to this container", \ -- NULL }, \ -- { CMD_OPT_TYPE_BOOL, false, "tty", 't', &(cmdargs).custom_conf.tty, "Allocate a pseudo-TTY", NULL }, \ -- { CMD_OPT_TYPE_STRING, \ -- false, \ -- "restart", \ -- 0, \ -- &(cmdargs).restart, \ -- "Restart policy to apply when a container exits(no, always, on-reboot, on-failure[:max-retries])", \ -- NULL }, \ -- { CMD_OPT_TYPE_STRING, \ -- false, \ -- "host-channel", \ -- 0, \ -- &(cmdargs).host_channel, \ -- "Create share memory between host and container", \ -- NULL }, \ -- { CMD_OPT_TYPE_STRING, \ -- false, \ -- "runtime", \ -- 'R', \ -- &(cmdargs).runtime, \ -- "Runtime to use for containers(default: lcr)", \ -- NULL }, \ -- { CMD_OPT_TYPE_STRING_DUP, \ -- false, \ -- "user", \ -- 'u', \ -- &(cmdargs).custom_conf.user, \ -- "Username or UID (format: [:])", \ -- NULL }, \ -- { CMD_OPT_TYPE_STRING_DUP, false, "uts", 0, &(cmdargs).custom_conf.share_ns[NAMESPACE_UTS], \ -- "UTS namespace to use", NULL }, \ -- { CMD_OPT_TYPE_CALLBACK, false, "volume", 'v', &(cmdargs).custom_conf.volumes, "Bind mount a volume", \ -- command_append_array }, \ -- { CMD_OPT_TYPE_CALLBACK, false, "annotation", 0, &(cmdargs), "Set annotations on a container", \ -- callback_annotation }, \ -- { CMD_OPT_TYPE_STRING_DUP, \ -- false, \ -- "workdir", \ -- 0, \ -- &(cmdargs).custom_conf.workdir, \ -- "Working directory inside the container", \ -- NULL }, \ -- { CMD_OPT_TYPE_BOOL, \ -- false, \ -- "system-container", \ -- 0, \ -- &(cmdargs).custom_conf.system_container, \ -- "Extend some features only needed by running system container", \ -- NULL }, \ -- { CMD_OPT_TYPE_BOOL, false, "oom-kill-disable", 0, &(cmdargs).custom_conf.oom_kill_disable, \ -- "Disable OOM Killer", NULL }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "security-opt", \ -- 0, \ -- &(cmdargs).custom_conf.security, \ -- "Security Options (default [])", \ -- command_append_array }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "storage-opt", \ -- 0, \ -- &(cmdargs).custom_conf.storage_opts, \ -- "Storage driver options for the container", \ -- command_append_array }, \ -- { CMD_OPT_TYPE_STRING_DUP, false, "health-cmd", 0, &(cmdargs).custom_conf.health_cmd, \ -- "Command to run to check health", NULL }, \ -- { CMD_OPT_TYPE_CALLBACK, false, "sysctl", 0, &(cmdargs).custom_conf.sysctls, "Sysctl options", \ -- command_append_array }, \ -- { CMD_OPT_TYPE_STRING_DUP, \ -- false, \ -- "env-target-file", \ -- 0, \ -- &(cmdargs).custom_conf.env_target_file, \ -- "Export env to target file path in rootfs", \ -- NULL }, \ -- { CMD_OPT_TYPE_STRING_DUP, \ -- false, \ -- "cgroup-parent", \ -- 0, \ -- &(cmdargs).custom_conf.cgroup_parent, \ -- "Optional parent cgroup for the container", \ -- NULL }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "health-interval", \ -- 0, \ -- &(cmdargs).custom_conf.health_interval, \ -- "Time between running the check (ms|s|m|h) (default 30s)", \ -- command_convert_nanoseconds }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "health-retries", \ -- 0, \ -- &(cmdargs).custom_conf.health_retries, \ -- "Consecutive failures needed to report unhealthy (default 3)", \ -- command_convert_int }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "health-timeout", \ -- 0, \ -- &(cmdargs).custom_conf.health_timeout, \ -- "Maximum time to allow one check to run (ms|s|m|h) (default 30s)", \ -- command_convert_nanoseconds }, \ -- { CMD_OPT_TYPE_CALLBACK, \ -- false, \ -- "health-start-period", \ -- 0, \ -- &(cmdargs).custom_conf.health_start_period, \ -- "Start period for the container to initialize before starting health-retries countdown (ms|s|m|h) " \ -- "(default 0s)", \ -- command_convert_nanoseconds }, \ -- { CMD_OPT_TYPE_BOOL, \ -- false, \ -- "no-healthcheck", \ -- 0, \ -- &(cmdargs).custom_conf.no_healthcheck, \ -- "Disable any container-specified HEALTHCHECK", \ -- NULL }, \ -- { CMD_OPT_TYPE_BOOL, \ -- false, \ -- "health-exit-on-unhealthy", \ -- 0, \ -- &(cmdargs).custom_conf.exit_on_unhealthy, \ -- "Kill the container when it is detected to be unhealthy", \ -- NULL }, \ -- { CMD_OPT_TYPE_STRING, \ -- false, \ -- "ns-change-opt", \ -- 0, \ -- &(cmdargs).custom_conf.ns_change_opt, \ -- "Namespaced kernel param options for system container (default [])", \ -- NULL }, \ -- { CMD_OPT_TYPE_CALLBACK, false, "ulimit", 0, &(cmdargs).custom_conf.ulimits, "Ulimit options (default [])", \ -- command_append_array }, -+#define CREATE_OPTIONS(cmdargs) \ -+ { \ -+ CMD_OPT_TYPE_BOOL, \ -+ false, \ -+ "read-only", \ -+ 0, \ -+ &(cmdargs).custom_conf.readonly, \ -+ "Make container rootfs readonly", \ -+ NULL \ -+ }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "cap-add", \ -+ 0, \ -+ &(cmdargs).custom_conf.cap_adds, \ -+ "Add Linux capabilities ('ALL' to add all capabilities)", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "cap-drop", \ -+ 0, \ -+ &(cmdargs).custom_conf.cap_drops, \ -+ "Drop Linux capabilities ('ALL' to drop all capabilities)", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_CALLBACK, false, "cpu-shares", 0, &(cmdargs).cr.cpu_shares, "CPU shares (relative weight)", \ -+ command_convert_llong }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "cpu-period", \ -+ 0, \ -+ &(cmdargs).cr.cpu_period, \ -+ "Limit CPU CFS (Completely Fair Scheduler) period", \ -+ command_convert_llong }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "cpu-quota", \ -+ 0, \ -+ &(cmdargs).cr.cpu_quota, \ -+ "Limit CPU CFS (Completely Fair Scheduler) quota", \ -+ command_convert_llong }, \ -+ { CMD_OPT_TYPE_STRING, \ -+ false, \ -+ "cpuset-cpus", \ -+ 0, \ -+ &(cmdargs).cr.cpuset_cpus, \ -+ "CPUs in which to allow execution (e.g. 0-3, 0,1)", \ -+ NULL }, \ -+ { CMD_OPT_TYPE_STRING, \ -+ false, \ -+ "cpuset-mems", \ -+ 0, \ -+ &(cmdargs).cr.cpuset_mems, \ -+ "MEMs in which to allow execution (0-3, 0,1)", \ -+ NULL }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "device-read-bps", \ -+ 0, \ -+ &(cmdargs).custom_conf.blkio_throttle_read_bps_device, \ -+ "Limit read rate (bytes per second) from a device (default []),format: :[], Number is a positive integer", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "device-write-bps", \ -+ 0, \ -+ &(cmdargs).custom_conf.blkio_throttle_write_bps_device, \ -+ "Limit write rate (bytes per second) to a device (default []),format: :[], Number is a positive integer", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "oom-score-adj", \ -+ 0, \ -+ &(cmdargs).cr.oom_score_adj, \ -+ "Tune host's OOM preferences (-1000 to 1000)", \ -+ command_convert_llong }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "device", \ -+ 0, \ -+ &(cmdargs).custom_conf.devices, \ -+ "Add a host device to the container", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_CALLBACK, false, "env", 'e', &(cmdargs).custom_conf.env, "Set environment variables", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "env-file", \ -+ 0, \ -+ &(cmdargs).custom_conf.env_file, \ -+ "Read in a file of environment variables", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "label", \ -+ 'l', \ -+ &(cmdargs).custom_conf.label, \ -+ "Set metadata on container (default [])", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "label-file", \ -+ 0, \ -+ &(cmdargs).custom_conf.label_file, \ -+ "Read in a line delimited file of labels (default [])", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_STRING_DUP, \ -+ false, \ -+ "entrypoint", \ -+ 0, \ -+ &(cmdargs).custom_conf.entrypoint, \ -+ "Entrypoint to run when starting the container", \ -+ NULL }, \ -+ { CMD_OPT_TYPE_STRING, \ -+ false, \ -+ "external-rootfs", \ -+ 0, \ -+ &(cmdargs).external_rootfs, \ -+ "Specify the custom rootfs that is not managed by isulad for the container, directory or block device", \ -+ NULL }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "files-limit", \ -+ 0, \ -+ &(cmdargs).custom_conf.files_limit, \ -+ "Tune container files limit (set -1 for unlimited)", \ -+ command_convert_llong }, \ -+ { CMD_OPT_TYPE_STRING_DUP, \ -+ false, \ -+ "hook-spec", \ -+ 0, \ -+ &(cmdargs).custom_conf.hook_spec, \ -+ "File containing hook definition(prestart, poststart, poststop)", \ -+ NULL }, \ -+ { CMD_OPT_TYPE_STRING_DUP, false, "hostname", 'h', &(cmdargs).custom_conf.hostname, \ -+ "Container host name", NULL }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "add-host", \ -+ 0, \ -+ &(cmdargs).custom_conf.extra_hosts, \ -+ "Add a custom host-to-IP mapping (host:ip)", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_CALLBACK, false, "dns", 0, &(cmdargs).custom_conf.dns, "Set custom DNS servers", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_CALLBACK, false, "dns-opt", 0, &(cmdargs).custom_conf.dns_options, "Set DNS options", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "dns-search", \ -+ 0, \ -+ &(cmdargs).custom_conf.dns_search, \ -+ "Set custom DNS search domains", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_STRING, \ -+ false, \ -+ "user-remap", \ -+ 0, \ -+ &(cmdargs).custom_conf.user_remap, \ -+ "Set user remap for container", \ -+ NULL }, \ -+ { CMD_OPT_TYPE_STRING_DUP, false, "ipc", 0, &(cmdargs).custom_conf.share_ns[NAMESPACE_IPC], \ -+ "IPC namespace to use", NULL }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "shm-size", \ -+ 0, \ -+ &(cmdargs).custom_conf.shm_size, \ -+ "Size of /dev/shm, default value is 64MB", \ -+ command_convert_membytes }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "kernel-memory", \ -+ 0, \ -+ &(cmdargs).cr.kernel_memory_limit, \ -+ "Kernel memory limit", \ -+ command_convert_membytes }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "hugetlb-limit", \ -+ 0, \ -+ &(cmdargs).custom_conf.hugepage_limits, \ -+ "Huge page limit (format: [size:], e.g. --hugetlb-limit 2MB:32MB)", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "log-driver", \ -+ 0, \ -+ &(cmdargs), \ -+ "Container log driver, support syslog and json-file", \ -+ callback_log_driver }, \ -+ { CMD_OPT_TYPE_CALLBACK, false, "log-opt", 0, &(cmdargs), "Container log options, value formate: key=value", \ -+ callback_log_opt }, \ -+ { CMD_OPT_TYPE_CALLBACK, false, "memory", 'm', &(cmdargs).cr.memory_limit, "Memory limit", \ -+ command_convert_membytes }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "memory-reservation", \ -+ 0, \ -+ &(cmdargs).cr.memory_reservation, \ -+ "Memory soft limit", \ -+ command_convert_membytes }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "memory-swap", \ -+ 0, \ -+ &(cmdargs).cr.memory_swap, \ -+ "Swap limit equal to memory plus swap: '-1' to enable unlimited swap", \ -+ command_convert_memswapbytes }, \ -+ { CMD_OPT_TYPE_CALLBACK, false, \ -+ "memory-swappiness", 0, \ -+ &(cmdargs).cr.swappiness, "Tune container memory swappiness (0 to 100) (default -1)", \ -+ command_convert_swappiness }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "mount", \ -+ 0, \ -+ &(cmdargs).custom_conf.mounts, \ -+ "Attach a filesystem mount to the service", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "group-add", \ -+ 0, \ -+ &(cmdargs).custom_conf.group_add, \ -+ "Add additional groups to join", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_STRING_DUP, false, "name", 'n', &(cmdargs).name, "Name of the container", NULL }, \ -+ { CMD_OPT_TYPE_STRING_DUP, \ -+ false, \ -+ "net", \ -+ 0, \ -+ &(cmdargs).custom_conf.share_ns[NAMESPACE_NET], \ -+ "Connect a container to a network", \ -+ NULL }, \ -+ { CMD_OPT_TYPE_STRING_DUP, false, "pid", 0, &(cmdargs).custom_conf.share_ns[NAMESPACE_PID], \ -+ "PID namespace to use", NULL }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "pids-limit", \ -+ 0, \ -+ &(cmdargs).custom_conf.pids_limit, \ -+ "Tune container pids limit (set -1 for unlimited)", \ -+ command_convert_llong }, \ -+ { CMD_OPT_TYPE_BOOL, \ -+ false, \ -+ "privileged", \ -+ 0, \ -+ &(cmdargs).custom_conf.privileged, \ -+ "Give extended privileges to this container", \ -+ NULL }, \ -+ { CMD_OPT_TYPE_BOOL, false, "tty", 't', &(cmdargs).custom_conf.tty, "Allocate a pseudo-TTY", NULL }, \ -+ { CMD_OPT_TYPE_STRING, \ -+ false, \ -+ "restart", \ -+ 0, \ -+ &(cmdargs).restart, \ -+ "Restart policy to apply when a container exits(no, always, on-reboot, on-failure[:max-retries])", \ -+ NULL }, \ -+ { CMD_OPT_TYPE_STRING, \ -+ false, \ -+ "host-channel", \ -+ 0, \ -+ &(cmdargs).host_channel, \ -+ "Create share memory between host and container", \ -+ NULL }, \ -+ { CMD_OPT_TYPE_STRING, \ -+ false, \ -+ "runtime", \ -+ 'R', \ -+ &(cmdargs).runtime, \ -+ "Runtime to use for containers(default: lcr)", \ -+ NULL }, \ -+ { CMD_OPT_TYPE_STRING_DUP, \ -+ false, \ -+ "user", \ -+ 'u', \ -+ &(cmdargs).custom_conf.user, \ -+ "Username or UID (format: [:])", \ -+ NULL }, \ -+ { CMD_OPT_TYPE_STRING_DUP, false, "uts", 0, &(cmdargs).custom_conf.share_ns[NAMESPACE_UTS], \ -+ "UTS namespace to use", NULL }, \ -+ { CMD_OPT_TYPE_CALLBACK, false, "volume", 'v', &(cmdargs).custom_conf.volumes, "Bind mount a volume", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_CALLBACK, false, "annotation", 0, &(cmdargs), "Set annotations on a container", \ -+ callback_annotation }, \ -+ { CMD_OPT_TYPE_STRING_DUP, \ -+ false, \ -+ "workdir", \ -+ 0, \ -+ &(cmdargs).custom_conf.workdir, \ -+ "Working directory inside the container", \ -+ NULL }, \ -+ { CMD_OPT_TYPE_BOOL, \ -+ false, \ -+ "system-container", \ -+ 0, \ -+ &(cmdargs).custom_conf.system_container, \ -+ "Extend some features only needed by running system container", \ -+ NULL }, \ -+ { CMD_OPT_TYPE_BOOL, false, "oom-kill-disable", 0, &(cmdargs).custom_conf.oom_kill_disable, \ -+ "Disable OOM Killer", NULL }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "security-opt", \ -+ 0, \ -+ &(cmdargs).custom_conf.security, \ -+ "Security Options (default [])", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "storage-opt", \ -+ 0, \ -+ &(cmdargs).custom_conf.storage_opts, \ -+ "Storage driver options for the container", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_STRING_DUP, false, "health-cmd", 0, &(cmdargs).custom_conf.health_cmd, \ -+ "Command to run to check health", NULL }, \ -+ { CMD_OPT_TYPE_CALLBACK, false, "sysctl", 0, &(cmdargs).custom_conf.sysctls, "Sysctl options", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_STRING_DUP, \ -+ false, \ -+ "env-target-file", \ -+ 0, \ -+ &(cmdargs).custom_conf.env_target_file, \ -+ "Export env to target file path in rootfs", \ -+ NULL }, \ -+ { CMD_OPT_TYPE_STRING_DUP, \ -+ false, \ -+ "cgroup-parent", \ -+ 0, \ -+ &(cmdargs).custom_conf.cgroup_parent, \ -+ "Optional parent cgroup for the container", \ -+ NULL }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "health-interval", \ -+ 0, \ -+ &(cmdargs).custom_conf.health_interval, \ -+ "Time between running the check (ms|s|m|h) (default 30s)", \ -+ command_convert_nanoseconds }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "health-retries", \ -+ 0, \ -+ &(cmdargs).custom_conf.health_retries, \ -+ "Consecutive failures needed to report unhealthy (default 3)", \ -+ command_convert_int }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "health-timeout", \ -+ 0, \ -+ &(cmdargs).custom_conf.health_timeout, \ -+ "Maximum time to allow one check to run (ms|s|m|h) (default 30s)", \ -+ command_convert_nanoseconds }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "health-start-period", \ -+ 0, \ -+ &(cmdargs).custom_conf.health_start_period, \ -+ "Start period for the container to initialize before starting health-retries countdown (ms|s|m|h) " \ -+ "(default 0s)", \ -+ command_convert_nanoseconds }, \ -+ { CMD_OPT_TYPE_BOOL, \ -+ false, \ -+ "no-healthcheck", \ -+ 0, \ -+ &(cmdargs).custom_conf.no_healthcheck, \ -+ "Disable any container-specified HEALTHCHECK", \ -+ NULL }, \ -+ { CMD_OPT_TYPE_BOOL, \ -+ false, \ -+ "health-exit-on-unhealthy", \ -+ 0, \ -+ &(cmdargs).custom_conf.exit_on_unhealthy, \ -+ "Kill the container when it is detected to be unhealthy", \ -+ NULL }, \ -+ { CMD_OPT_TYPE_STRING, \ -+ false, \ -+ "ns-change-opt", \ -+ 0, \ -+ &(cmdargs).custom_conf.ns_change_opt, \ -+ "Namespaced kernel param options for system container (default [])", \ -+ NULL }, \ -+ { CMD_OPT_TYPE_CALLBACK, false, "ulimit", 0, &(cmdargs).custom_conf.ulimits, "Ulimit options (default [])", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "blkio-weight", \ -+ 0, \ -+ &(cmdargs).cr.blkio_weight, \ -+ "Block IO (relative weight), between 10 and 1000, or 0 to disable (default 0)", \ -+ command_convert_u16 }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "blkio-weight-device", \ -+ 0, \ -+ &(cmdargs).custom_conf.weight_devices, \ -+ "Block IO weight (relative device weight) (default []), format: DEVICE_NAME:WEIGHT, weight value between 10 and 1000, or 0 to disable (default 0)", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "device-read-iops", \ -+ 0, \ -+ &(cmdargs).custom_conf.blkio_throttle_read_iops_device, \ -+ "Limit read rate (IO per second) from a device (format: :),number is unsigned 64 bytes integer", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "device-write-iops", \ -+ 0, \ -+ &(cmdargs).custom_conf.blkio_throttle_write_iops_device, \ -+ "Limit write rate (IO per second) to a device (format: :),number is unsigned 64 bytes integer.", \ -+ command_append_array }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "cpu-rt-period", \ -+ 0, \ -+ &((cmdargs).cr).cpu_rt_period, \ -+ "Limit CPU real-time period in microseconds.", \ -+ command_convert_llong }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "cpu-rt-runtime", \ -+ 0, \ -+ &((cmdargs).cr).cpu_rt_runtime, \ -+ "Limit CPU real-time runtime in microseconds.", \ -+ command_convert_llong }, \ -+ { CMD_OPT_TYPE_CALLBACK, false, "cpus", 0, &((cmdargs).cr).nano_cpus, "Number of CPUs.", \ -+ command_convert_nanocpus }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "device-cgroup-rule", \ -+ 0, \ -+ &(cmdargs).custom_conf.device_cgroup_rules, \ -+ "Add a rule to the cgroup allowed devices list.", \ -+ command_convert_device_cgroup_rules }, - - #define CREATE_EXTEND_OPTIONS(cmdargs) \ - { CMD_OPT_TYPE_BOOL, \ -diff --git a/src/cmd/isula/base/kill.c b/src/cmd/isula/base/kill.c -index da1e3ce..e2e532a 100644 ---- a/src/cmd/isula/base/kill.c -+++ b/src/cmd/isula/base/kill.c -@@ -21,7 +21,7 @@ - #include "isula_libutils/log.h" - #include "isula_connect.h" - #include "connect.h" --#include "libisula.h" -+ - #include "utils.h" - #include "utils_verify.h" - -diff --git a/src/cmd/isula/base/rename.c b/src/cmd/isula/base/rename.c -index 652e091..aafc9bd 100644 ---- a/src/cmd/isula/base/rename.c -+++ b/src/cmd/isula/base/rename.c -@@ -22,7 +22,6 @@ - #include "isula_connect.h" - #include "command_parser.h" - #include "connect.h" --#include "libisula.h" - - const char g_cmd_rename_desc[] = "Rename a container"; - const char g_cmd_rename_usage[] = "rename [OPTIONS] OLD_NAME NEW_NAME"; -diff --git a/src/cmd/isula/base/restart.c b/src/cmd/isula/base/restart.c -index 2d58d33..f91ee3b 100644 ---- a/src/cmd/isula/base/restart.c -+++ b/src/cmd/isula/base/restart.c -@@ -21,7 +21,6 @@ - #include "utils.h" - #include "isula_connect.h" - #include "connect.h" --#include "libisula.h" - - const char g_cmd_restart_desc[] = "Restart one or more containers"; - const char g_cmd_restart_usage[] = "restart [OPTIONS] CONTAINER [CONTAINER...]"; -diff --git a/src/cmd/isula/base/rm.c b/src/cmd/isula/base/rm.c -index eeff9aa..f54fc22 100644 ---- a/src/cmd/isula/base/rm.c -+++ b/src/cmd/isula/base/rm.c -@@ -20,11 +20,10 @@ - #include "client_arguments.h" - #include "isula_libutils/log.h" - #include "isula_connect.h" --#include "isula_commands.h" - #include "console.h" - #include "utils.h" - #include "connect.h" --#include "libisula.h" -+ - #include "utils_file.h" - - const char g_cmd_delete_desc[] = "Remove one or more containers"; -diff --git a/src/cmd/isula/base/run.c b/src/cmd/isula/base/run.c -index fa71abb..3225dbf 100644 ---- a/src/cmd/isula/base/run.c -+++ b/src/cmd/isula/base/run.c -@@ -15,7 +15,6 @@ - #include - #include - #include --#include // IWYU pragma: keep - #include - #include - #include -@@ -30,7 +29,7 @@ - #include "error.h" - #include "connect.h" - #include "create.h" --#include "libisula.h" -+ - #include "start.h" - #include "wait.h" - -@@ -175,59 +174,6 @@ out: - return ret; - } - --static void *run_console_resize_thread(void *arg) --{ -- int ret = 0; -- const struct client_arguments *args = arg; -- static struct winsize s_pre_wsz; -- struct winsize wsz; -- -- if (!isatty(STDIN_FILENO)) { -- goto out; -- } -- -- ret = pthread_detach(pthread_self()); -- if (ret != 0) { -- CRIT("Start: set thread detach fail"); -- goto out; -- } -- -- while (true) { -- sleep(1); // check the windows size per 1s -- ret = ioctl(STDIN_FILENO, TIOCGWINSZ, &wsz); -- if (ret < 0) { -- WARN("Failed to get window size"); -- continue; -- } -- if (wsz.ws_row == s_pre_wsz.ws_row && wsz.ws_col == s_pre_wsz.ws_col) { -- continue; -- } -- ret = do_resize_run_console(args, wsz.ws_row, wsz.ws_col); -- if (ret != 0) { -- continue; -- } -- s_pre_wsz.ws_row = wsz.ws_row; -- s_pre_wsz.ws_col = wsz.ws_col; -- } -- --out: -- return NULL; --} -- --int run_client_console_resize_thread(struct client_arguments *args) --{ -- int res = 0; -- pthread_t a_thread; -- -- res = pthread_create(&a_thread, NULL, run_console_resize_thread, (void *)(args)); -- if (res != 0) { -- CRIT("Thread creation failed"); -- return -1; -- } -- -- return 0; --} -- - int cmd_run_main(int argc, const char **argv) - { - int ret = 0; -@@ -241,6 +187,7 @@ int cmd_run_main(int argc, const char **argv) - } - g_cmd_run_args.custom_conf.attach_stdout = true; - g_cmd_run_args.custom_conf.attach_stderr = true; -+ g_cmd_run_args.resize_cb = do_resize_run_console; - - g_cmd_run_args.progname = argv[0]; - g_cmd_run_args.subcommand = argv[1]; -@@ -270,7 +217,7 @@ int cmd_run_main(int argc, const char **argv) - } - - if (g_cmd_run_args.custom_conf.tty && isatty(STDIN_FILENO)) { -- (void)run_client_console_resize_thread(&g_cmd_run_args); -+ (void)start_client_console_resize_thread(&g_cmd_run_args); - } - - if (strncmp(g_cmd_run_args.socket, "tcp://", strlen("tcp://")) == 0) { -diff --git a/src/cmd/isula/base/start.c b/src/cmd/isula/base/start.c -index 8ed491e..59cd05c 100644 ---- a/src/cmd/isula/base/start.c -+++ b/src/cmd/isula/base/start.c -@@ -30,7 +30,6 @@ - #include "isula_commands.h" - #include "command_parser.h" - #include "connect.h" --#include "libisula.h" - - const char g_cmd_start_desc[] = "Start one or more stopped containers"; - const char g_cmd_start_usage[] = "start [OPTIONS] CONTAINER [CONTAINER...]"; -diff --git a/src/cmd/isula/base/start.h b/src/cmd/isula/base/start.h -index 112f14a..8633c9c 100644 ---- a/src/cmd/isula/base/start.h -+++ b/src/cmd/isula/base/start.h -@@ -19,7 +19,7 @@ - #include - - #include "client_arguments.h" --#include "isula_commands.h" -+#include "client_console.h" - - #ifdef __cplusplus - extern "C" { -diff --git a/src/cmd/isula/base/stop.c b/src/cmd/isula/base/stop.c -index c4fa666..e52db79 100644 ---- a/src/cmd/isula/base/stop.c -+++ b/src/cmd/isula/base/stop.c -@@ -22,7 +22,6 @@ - #include "utils.h" - #include "isula_connect.h" - #include "connect.h" --#include "libisula.h" - - const char g_cmd_stop_desc[] = "Stop one or more containers"; - const char g_cmd_stop_usage[] = "stop [OPTIONS] CONTAINER [CONTAINER...]"; -diff --git a/src/cmd/isula/client_arguments.c b/src/cmd/isula/client_arguments.c -index 7160ea7..ad6ba40 100644 ---- a/src/cmd/isula/client_arguments.c -+++ b/src/cmd/isula/client_arguments.c -@@ -148,6 +148,9 @@ void client_arguments_free(struct client_arguments *args) - return; - } - -+ util_free_sensitive_string(args->username); -+ util_free_sensitive_string(args->password); -+ - free(args->name); - args->name = NULL; - -@@ -238,6 +241,21 @@ void client_arguments_free(struct client_arguments *args) - - free(args->key_file); - args->key_file = NULL; -+ -+ util_free_array(custom_conf->blkio_throttle_read_bps_device); -+ custom_conf->blkio_throttle_read_bps_device = NULL; -+ -+ util_free_array(custom_conf->blkio_throttle_write_bps_device); -+ custom_conf->blkio_throttle_write_bps_device = NULL; -+ -+ util_free_array(custom_conf->blkio_throttle_read_iops_device); -+ custom_conf->blkio_throttle_read_iops_device = NULL; -+ -+ util_free_array(custom_conf->blkio_throttle_write_iops_device); -+ custom_conf->blkio_throttle_write_iops_device = NULL; -+ -+ util_free_array(custom_conf->device_cgroup_rules); -+ custom_conf->device_cgroup_rules = NULL; - } - - /* print common help */ -diff --git a/src/cmd/isula/client_arguments.h b/src/cmd/isula/client_arguments.h -index ccd7b03..0ecdb21 100644 ---- a/src/cmd/isula/client_arguments.h -+++ b/src/cmd/isula/client_arguments.h -@@ -20,6 +20,8 @@ - #include - #include - #include -+#include // IWYU pragma: keep -+#include - - #include "command_parser.h" - #include "isula_libutils/json_common.h" -@@ -34,6 +36,8 @@ extern "C" { - /* max arguments can be specify in client */ - #define MAX_CLIENT_ARGS 1000 - -+#define CLIENT_RUNDIR "/var/run/isula" -+ - struct client_arguments; - struct custom_configs; - -@@ -183,9 +187,6 @@ struct custom_configs { - /* oom kill disable */ - bool oom_kill_disable; - -- /* create/run accel options */ -- char **accel; -- - /* env target file */ - char *env_target_file; - -@@ -197,6 +198,15 @@ struct custom_configs { - - /* device write bps */ - char **blkio_throttle_write_bps_device; -+ -+ /* device read iops */ -+ char **blkio_throttle_read_iops_device; -+ -+ /* device write iops */ -+ char **blkio_throttle_write_iops_device; -+ -+ /* device cgroup rules */ -+ char **device_cgroup_rules; - }; - - struct args_cgroup_resources { -@@ -214,8 +224,13 @@ struct args_cgroup_resources { - int64_t memory_reservation; - int64_t kernel_memory_limit; - int64_t swappiness; -+ int64_t nano_cpus; - }; - -+struct client_arguments; -+ -+typedef int (*do_resize_call_back_t)(const struct client_arguments *args, unsigned int height, unsigned int width); -+ - struct client_arguments { - const char *progname; /* main progname name */ - const char *subcommand; /* sub command name */ -@@ -283,6 +298,7 @@ struct client_arguments { - - // logs - bool follow; -+ bool timestamps; - /* - * tail < 0: show all logs - * tail = 0: do not show log -@@ -325,6 +341,9 @@ struct client_arguments { - char *ca_file; - char *cert_file; - char *key_file; -+ -+ do_resize_call_back_t resize_cb; -+ struct winsize s_pre_wsz; - }; - - #define LOG_OPTIONS(log) { CMD_OPT_TYPE_BOOL_FALSE, false, "debug", 'D', &(log).quiet, "Enable debug mode", NULL }, -diff --git a/src/cmd/isula/client_console.c b/src/cmd/isula/client_console.c -new file mode 100644 -index 0000000..d6d82f7 ---- /dev/null -+++ b/src/cmd/isula/client_console.c -@@ -0,0 +1,319 @@ -+/****************************************************************************** -+ * Copyright (c) Huawei Technologies Co., Ltd. 2017-2019. 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: lifeng -+ * Create: 2020-10-20 -+ * Description: provide container command functions -+ ******************************************************************************/ -+#include "client_console.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "client_arguments.h" -+#include "isula_libutils/log.h" -+#include "utils.h" -+#include "console.h" -+#include "utils_file.h" -+ -+/* free command fifo names */ -+void free_command_fifo_config(struct command_fifo_config *fifos) -+{ -+ if (fifos != NULL) { -+ if (fifos->stdin_path != NULL) { -+ free(fifos->stdin_path); -+ fifos->stdin_path = NULL; -+ } -+ if (fifos->stdout_path != NULL) { -+ free(fifos->stdout_path); -+ fifos->stdout_path = NULL; -+ } -+ if (fifos->stderr_path != NULL) { -+ free(fifos->stderr_path); -+ fifos->stderr_path = NULL; -+ } -+ if (fifos->stdin_name != NULL) { -+ free(fifos->stdin_name); -+ fifos->stdin_name = NULL; -+ } -+ if (fifos->stdout_name != NULL) { -+ free(fifos->stdout_name); -+ fifos->stdout_name = NULL; -+ } -+ if (fifos->stderr_name != NULL) { -+ free(fifos->stderr_name); -+ fifos->stderr_name = NULL; -+ } -+ free(fifos); -+ } -+} -+ -+/* delete command fifo */ -+void delete_command_fifo(struct command_fifo_config *fifos) -+{ -+ int ret; -+ -+ if (fifos == NULL) { -+ return; -+ } -+ -+ ret = console_fifo_delete(fifos->stdin_name); -+ if (ret) { -+ WARN("Delete fifo failed: %s", fifos->stdin_name); -+ } -+ ret = console_fifo_delete(fifos->stdout_name); -+ if (ret) { -+ WARN("Delete fifo failed: %s", fifos->stdout_name); -+ } -+ ret = console_fifo_delete(fifos->stderr_name); -+ if (ret) { -+ WARN("Delete fifo failed: %s", fifos->stderr_name); -+ } -+ ret = util_recursive_rmdir(fifos->stdin_path, 0); -+ if (ret) { -+ WARN("Remove directory failed: %s", fifos->stdin_path); -+ } -+ ret = util_recursive_rmdir(fifos->stdout_path, 0); -+ if (ret) { -+ WARN("Remove directory failed: %s", fifos->stdout_path); -+ } -+ ret = util_recursive_rmdir(fifos->stderr_path, 0); -+ if (ret) { -+ WARN("Remove directory failed: %s", fifos->stderr_path); -+ } -+ -+ free_command_fifo_config(fifos); -+} -+ -+static int do_create_console_fifo(const char *subpath, const char *stdflag, char **out_fifo_dir, char **out_fifo_name) -+{ -+ int ret = 0; -+ char fifo_dir[PATH_MAX] = { 0 }; -+ char fifo_name[PATH_MAX] = { 0 }; -+ -+ ret = console_fifo_name(CLIENT_RUNDIR, subpath, stdflag, fifo_name, sizeof(fifo_name), fifo_dir, sizeof(fifo_dir), -+ true); -+ if (ret != 0) { -+ ERROR("Failed to get console fifo name."); -+ ret = -1; -+ goto out; -+ } -+ -+ if (console_fifo_create(fifo_name)) { -+ ERROR("Failed to create console fifo."); -+ ret = -1; -+ goto out; -+ } -+ -+ *out_fifo_dir = util_strdup_s(fifo_dir); -+ *out_fifo_name = util_strdup_s(fifo_name); -+ -+out: -+ return ret; -+} -+ -+int create_console_fifos(bool attach_stdin, bool attach_stdout, bool attach_stderr, const char *name, const char *type, -+ struct command_fifo_config **pconsole_fifos) -+{ -+ int ret = 0; -+ char subpath[PATH_MAX] = { 0 }; -+ struct command_fifo_config *fifos = NULL; -+ -+ fifos = util_common_calloc_s(sizeof(struct command_fifo_config)); -+ if (fifos == NULL) { -+ ERROR("Failed to malloc memory for FIFO names."); -+ return -1; -+ } -+ -+ ret = snprintf(subpath, sizeof(subpath), "%s/%s-%u-%u", name, type, (unsigned int)getpid(), -+ (unsigned int)pthread_self()); -+ if (ret < 0 || (size_t)ret >= sizeof(subpath)) { -+ ERROR("Path is too long"); -+ goto cleanup; -+ } -+ -+ if (attach_stdin) { -+ ret = do_create_console_fifo(subpath, "in", &fifos->stdin_path, &fifos->stdin_name); -+ if (ret != 0) { -+ goto cleanup; -+ } -+ INFO("FIFO:%s create for start success.", fifos->stdin_name); -+ } -+ -+ if (attach_stdout) { -+ ret = do_create_console_fifo(subpath, "out", &fifos->stdout_path, &fifos->stdout_name); -+ if (ret != 0) { -+ goto cleanup; -+ } -+ INFO("FIFO:%s create for start success.", fifos->stdout_name); -+ } -+ -+ if (attach_stderr) { -+ ret = do_create_console_fifo(subpath, "err", &fifos->stderr_path, &fifos->stderr_name); -+ if (ret != 0) { -+ goto cleanup; -+ } -+ INFO("FIFO:%s create for start success.", fifos->stderr_name); -+ } -+ -+ *pconsole_fifos = fifos; -+ return 0; -+ -+cleanup: -+ console_fifo_delete(fifos->stdin_name); -+ console_fifo_delete(fifos->stdout_name); -+ console_fifo_delete(fifos->stderr_name); -+ free_command_fifo_config(fifos); -+ return -1; -+} -+ -+struct console_loop_thread_args { -+ struct command_fifo_config *fifo_config; -+ bool tty; -+}; -+ -+static void *client_console_loop_thread(void *arg) -+{ -+ int ret = 0; -+ int fifoinfd = -1; -+ int fifooutfd = -1; -+ int fifoerrfd = -1; -+ const struct console_loop_thread_args *args = arg; -+ bool tty = args->tty; -+ struct command_fifo_config *fifo_config = args->fifo_config; -+ sem_t *wait_open = fifo_config->wait_open; -+ sem_t *wait_exit = fifo_config->wait_exit; -+ -+ ret = pthread_detach(pthread_self()); -+ if (ret != 0) { -+ CRIT("Start: set thread detach fail"); -+ goto err1; -+ } -+ -+ if (fifo_config->stdin_name) { -+ if (console_fifo_open_withlock(fifo_config->stdin_name, &fifoinfd, O_RDWR | O_NONBLOCK)) { -+ ERROR("Start: failed to open console fifo."); -+ goto err2; -+ } -+ INFO("FIFO:%s open success for start.", fifo_config->stdin_name); -+ } -+ -+ if (fifo_config->stdout_name) { -+ if (console_fifo_open(fifo_config->stdout_name, &fifooutfd, O_RDONLY | O_NONBLOCK)) { -+ ERROR("Failed to open console fifo."); -+ goto err2; -+ } -+ INFO("FIFO:%s open success for start.", fifo_config->stdout_name); -+ } -+ -+ if (fifo_config->stderr_name) { -+ if (console_fifo_open(fifo_config->stderr_name, &fifoerrfd, O_RDONLY | O_NONBLOCK)) { -+ ERROR("Start: failed to open console fifo."); -+ goto err2; -+ } -+ INFO("FIFO:%s open success for start.", fifo_config->stderr_name); -+ } -+ -+ sem_post(wait_open); -+ console_loop_with_std_fd(0, 1, 2, fifoinfd, fifooutfd, fifoerrfd, 1, tty); -+ -+err2: -+ if (fifoinfd >= 0) { -+ console_fifo_close(fifoinfd); -+ } -+ if (fifooutfd >= 0) { -+ console_fifo_close(fifooutfd); -+ } -+ if (fifoerrfd >= 0) { -+ console_fifo_close(fifoerrfd); -+ } -+err1: -+ sem_post(wait_open); -+ sem_post(wait_exit); -+ return NULL; -+} -+ -+int start_client_console_thread(struct command_fifo_config *console_fifos, bool tty) -+{ -+ int res = 0; -+ pthread_t a_thread; -+ struct console_loop_thread_args args; -+ -+ args.fifo_config = console_fifos; -+ args.tty = tty; -+ res = pthread_create(&a_thread, NULL, client_console_loop_thread, (void *)(&args)); -+ if (res != 0) { -+ CRIT("Thread creation failed"); -+ return -1; -+ } -+ -+ sem_wait(console_fifos->wait_open); -+ -+ return 0; -+} -+ -+static void *client_console_resize_thread(void *arg) -+{ -+ int ret = 0; -+ struct client_arguments *args = arg; -+ struct winsize wsz = { 0 }; -+ -+ if (!isatty(STDIN_FILENO)) { -+ goto out; -+ } -+ -+ ret = pthread_detach(pthread_self()); -+ if (ret != 0) { -+ CRIT("Start: set thread detach fail"); -+ goto out; -+ } -+ -+ while (true) { -+ sleep(1); // check the windows size per 1s -+ ret = ioctl(STDIN_FILENO, TIOCGWINSZ, &wsz); -+ if (ret < 0) { -+ WARN("Failed to get window size"); -+ continue; -+ } -+ if (wsz.ws_row == args->s_pre_wsz.ws_row && wsz.ws_col == args->s_pre_wsz.ws_col) { -+ continue; -+ } -+ if (args->resize_cb != NULL) { -+ ret = args->resize_cb(args, wsz.ws_row, wsz.ws_col); -+ if (ret != 0) { -+ continue; -+ } -+ args->s_pre_wsz.ws_row = wsz.ws_row; -+ args->s_pre_wsz.ws_col = wsz.ws_col; -+ } -+ } -+ -+out: -+ return NULL; -+} -+ -+int start_client_console_resize_thread(struct client_arguments *args) -+{ -+ int res = 0; -+ pthread_t a_thread; -+ -+ res = pthread_create(&a_thread, NULL, client_console_resize_thread, (void *)(args)); -+ if (res != 0) { -+ CRIT("Thread creation failed"); -+ return -1; -+ } -+ -+ return 0; -+} -\ No newline at end of file -diff --git a/src/cmd/isula/client_console.h b/src/cmd/isula/client_console.h -new file mode 100644 -index 0000000..c264820 ---- /dev/null -+++ b/src/cmd/isula/client_console.h -@@ -0,0 +1,52 @@ -+/****************************************************************************** -+ * Copyright (c) Huawei Technologies Co., Ltd. 2017-2019. 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: lifeng -+ * Create: 2020-10-20 -+ * Description: provide client console functions -+ ******************************************************************************/ -+#ifndef CMD_ISULA_CLIENT_CONSOLE_H -+#define CMD_ISULA_CLIENT_CONSOLE_H -+ -+#include -+#include -+#include "client_arguments.h" -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+struct command_fifo_config { -+ char *stdin_path; -+ char *stdout_path; -+ char *stderr_path; -+ char *stdin_name; -+ char *stdout_name; -+ char *stderr_name; -+ sem_t *wait_open; -+ sem_t *wait_exit; -+}; -+ -+int create_console_fifos(bool attach_stdin, bool attach_stdout, bool attach_stderr, const char *name, const char *type, -+ struct command_fifo_config **pconsole_fifos); -+ -+int start_client_console_thread(struct command_fifo_config *console_fifos, bool tty); -+ -+void free_command_fifo_config(struct command_fifo_config *fifos); -+ -+void delete_command_fifo(struct command_fifo_config *fifos); -+ -+int start_client_console_resize_thread(struct client_arguments *args); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif // CMD_ISULA_ISULA_COMMANDS_H -diff --git a/src/cmd/isula/extend/events.c b/src/cmd/isula/extend/events.c -index 3040e28..3a10200 100644 ---- a/src/cmd/isula/extend/events.c -+++ b/src/cmd/isula/extend/events.c -@@ -22,7 +22,7 @@ - #include "isula_libutils/log.h" - #include "isula_connect.h" - #include "connect.h" --#include "libisula.h" -+ - #include "utils.h" - #include "utils_timestamp.h" - -@@ -132,7 +132,7 @@ static void print_events_callback(const container_events_format_t *event) - return; - } - -- if (!get_time_buffer(&(event->timestamp), timebuffer, sizeof(timebuffer))) { -+ if (!util_get_time_buffer(&(event->timestamp), timebuffer, sizeof(timebuffer))) { - (void)strcpy(timebuffer, "-"); - } - -@@ -176,13 +176,13 @@ static int client_event(struct client_arguments *args) - goto out; - } - -- if (args->since && !get_timestamp(args->since, &request.since)) { -+ if (args->since && !util_get_timestamp(args->since, &request.since)) { - COMMAND_ERROR("Failed to get since timestamp"); - ret = -1; - goto out; - } - -- if (args->until && !get_timestamp(args->until, &request.until)) { -+ if (args->until && !util_get_timestamp(args->until, &request.until)) { - COMMAND_ERROR("Failed to get until timestamp"); - ret = -1; - goto out; -diff --git a/src/cmd/isula/extend/export.c b/src/cmd/isula/extend/export.c -index fd3bb4d..476cf77 100644 ---- a/src/cmd/isula/extend/export.c -+++ b/src/cmd/isula/extend/export.c -@@ -26,7 +26,6 @@ - #include "isula_libutils/log.h" - #include "isula_connect.h" - #include "connect.h" --#include "libisula.h" - - const char g_cmd_export_desc[] = "export container"; - const char g_cmd_export_usage[] = "export [command options] [ID|NAME]"; -diff --git a/src/cmd/isula/extend/pause.c b/src/cmd/isula/extend/pause.c -index f4db507..4d508e7 100644 ---- a/src/cmd/isula/extend/pause.c -+++ b/src/cmd/isula/extend/pause.c -@@ -24,7 +24,6 @@ - #include "isula_connect.h" - #include "command_parser.h" - #include "connect.h" --#include "libisula.h" - - const char g_cmd_pause_desc[] = "Pause all processes within one or more containers"; - const char g_cmd_pause_usage[] = "pause [OPTIONS] CONTAINER [CONTAINER...]"; -diff --git a/src/cmd/isula/extend/resume.c b/src/cmd/isula/extend/resume.c -index 0a020b6..c3c4376 100644 ---- a/src/cmd/isula/extend/resume.c -+++ b/src/cmd/isula/extend/resume.c -@@ -24,7 +24,6 @@ - #include "isula_connect.h" - #include "command_parser.h" - #include "connect.h" --#include "libisula.h" - - const char g_cmd_resume_desc[] = "Unpause all processes within one or more containers"; - const char g_cmd_resume_usage[] = "unpause [OPTIONS] CONTAINER [CONTAINER...]"; -diff --git a/src/cmd/isula/extend/stats.c b/src/cmd/isula/extend/stats.c -index da0ce03..14c6159 100644 ---- a/src/cmd/isula/extend/stats.c -+++ b/src/cmd/isula/extend/stats.c -@@ -26,7 +26,6 @@ - #include "isula_libutils/log.h" - #include "isula_connect.h" - #include "connect.h" --#include "libisula.h" - - #define ESC "\033" - #define TERMCLEAR ESC "[H" ESC "[J" -@@ -140,8 +139,8 @@ static void stats_print(const struct isula_container_info *stats) - static void stats_print_original_data_header(void) - { - printf("%-16s %-10s %-10s %-20s %-20s %-15s %-15s %-15s %-15s %-15s %-15s %-15s %-40s", "ID", "PIDS", "Status", -- "CpuUseNanos", "CpuSystemUse", "OnlineCpus", "BlkioRead", "BlkioWrite", "MemUsed", "MemLimit", -- "KmemUsed", "CacheUsage", "NAME"); -+ "CpuUseNanos", "CpuSystemUse", "OnlineCpus", "BlkioRead", "BlkioWrite", "MemUsed", "MemLimit", "KmemUsed", -+ "CacheUsage", "NAME"); - printf("\n"); - } - -@@ -157,8 +156,8 @@ static void stats_print_original_data(const struct isula_container_info *stats) - - printf("%-16s %-10llu %-10s %-20lu %-20lu %-15u %-15lu %-15lu %-15lu %-15lu %-15lu %-15lu %-40s", short_id, - (unsigned long long)stats->pids_current, stats->status, stats->cpu_use_nanos, stats->cpu_system_use, -- stats->online_cpus, stats->blkio_read, stats->blkio_write, stats->mem_used, stats->mem_limit, stats->kmem_used, -- stats->cache, stats->name); -+ stats->online_cpus, stats->blkio_read, stats->blkio_write, stats->mem_used, stats->mem_limit, -+ stats->kmem_used, stats->cache, stats->name); - - free(short_id); - } -diff --git a/src/cmd/isula/extend/update.c b/src/cmd/isula/extend/update.c -index 84240a1..da472b0 100644 ---- a/src/cmd/isula/extend/update.c -+++ b/src/cmd/isula/extend/update.c -@@ -12,17 +12,18 @@ - * Create: 2018-11-08 - * Description: provide container update functions - ******************************************************************************/ --#include -+#include "update.h" -+ - #include - #include - - #include "client_arguments.h" --#include "update.h" - #include "utils.h" - #include "isula_libutils/log.h" - #include "isula_connect.h" - #include "connect.h" --#include "libisula.h" -+ -+#include "isula_host_spec.h" - - const char g_cmd_update_desc[] = "Update configuration of one or more containers"; - const char g_cmd_update_usage[] = "update [OPTIONS] CONTAINER [CONTAINER...]"; -@@ -31,57 +32,88 @@ struct client_arguments g_cmd_update_args = { - .restart = NULL, - }; - --static int pack_update_request(const struct client_arguments *args, struct isula_update_request *request) -+static isula_host_config_t *pack_update_request(const struct client_arguments *args) - { -- int ret = 0; -+ isula_host_config_t *host_config = NULL; - -- request->updateconfig->restart_policy = args->restart; -+ host_config = util_common_calloc_s(sizeof(isula_host_config_t)); -+ if (host_config == NULL) { -+ COMMAND_ERROR("Memeory out"); -+ goto error_out; -+ } -+ host_config->restart_policy = util_strdup_s(args->restart); - -- request->updateconfig->cr->blkio_weight = args->cr.blkio_weight; -+ host_config->cr = util_common_calloc_s(sizeof(container_cgroup_resources_t)); -+ if (host_config->cr == NULL) { -+ COMMAND_ERROR("Memeory out"); -+ goto error_out; -+ } - -- request->updateconfig->cr->cpu_shares = args->cr.cpu_shares; -+ host_config->cr->blkio_weight = args->cr.blkio_weight; - -- request->updateconfig->cr->cpu_period = args->cr.cpu_period; -+ host_config->cr->nano_cpus = args->cr.nano_cpus; - -- request->updateconfig->cr->cpu_quota = args->cr.cpu_quota; -+ host_config->cr->cpu_shares = args->cr.cpu_shares; - -- request->updateconfig->cr->cpuset_cpus = args->cr.cpuset_cpus; -+ host_config->cr->cpu_period = args->cr.cpu_period; - -- request->updateconfig->cr->cpuset_mems = args->cr.cpuset_mems; -+ host_config->cr->cpu_quota = args->cr.cpu_quota; - -- request->updateconfig->cr->memory = args->cr.memory_limit; -+ host_config->cr->cpu_realtime_period = args->cr.cpu_rt_period; - -- request->updateconfig->cr->memory_swap = args->cr.memory_swap; -+ host_config->cr->cpu_realtime_runtime = args->cr.cpu_rt_runtime; - -- request->updateconfig->cr->memory_reservation = args->cr.memory_reservation; -+ host_config->cr->cpuset_cpus = util_strdup_s(args->cr.cpuset_cpus); - -- request->updateconfig->cr->kernel_memory = args->cr.kernel_memory_limit; -+ host_config->cr->cpuset_mems = util_strdup_s(args->cr.cpuset_mems); - -- return ret; -+ host_config->cr->memory = args->cr.memory_limit; -+ -+ host_config->cr->memory_swap = args->cr.memory_swap; -+ -+ host_config->cr->memory_reservation = args->cr.memory_reservation; -+ -+ host_config->cr->kernel_memory = args->cr.kernel_memory_limit; -+ -+ return host_config; -+ -+error_out: -+ isula_host_config_free(host_config); -+ return NULL; - } - - static int client_update(const struct client_arguments *args) - { - int ret = 0; - isula_connect_ops *ops = NULL; -- container_cgroup_resources_t cr = { 0 }; -- isula_update_config_t updateconfig = { 0 }; -- struct isula_update_request request = { 0 }; -+ isula_host_config_t *host_spec = NULL; -+ struct isula_update_request *request = NULL; - struct isula_update_response *response = NULL; - client_connect_config_t config = { 0 }; - -+ request = util_common_calloc_s(sizeof(struct isula_update_request)); -+ if (request == NULL) { -+ ERROR("Out of memory"); -+ ret = -1; -+ goto out; -+ } -+ - response = util_common_calloc_s(sizeof(struct isula_update_response)); - if (response == NULL) { - ERROR("Out of memory"); -- return -1; -+ ret = -1; -+ goto out; - } - -- updateconfig.cr = &cr; -- request.updateconfig = &updateconfig; -- request.name = args->name; -+ request->name = util_strdup_s(args->name); - -- ret = pack_update_request(args, &request); -- if (ret) { -+ host_spec = pack_update_request(args); -+ if (host_spec == NULL) { -+ ret = -1; -+ goto out; -+ } -+ -+ if (generate_hostconfig(host_spec, &request->host_spec_json) != 0) { - ret = -1; - goto out; - } -@@ -94,13 +126,15 @@ static int client_update(const struct client_arguments *args) - } - - config = get_connect_config(args); -- ret = ops->container.update(&request, response, &config); -+ ret = ops->container.update(request, response, &config); - if (ret) { - client_print_error(response->cc, response->server_errono, response->errmsg); - goto out; - } - - out: -+ isula_host_config_free(host_spec); -+ isula_update_request_free(request); - isula_update_response_free(response); - return ret; - } -@@ -111,8 +145,8 @@ int cmd_update_main(int argc, const char **argv) - int i = 0; - struct isula_libutils_log_config lconf = { 0 }; - command_t cmd; -- struct command_option options[] = { LOG_OPTIONS(lconf) UPDATE_OPTIONS(g_cmd_update_args), -- COMMON_OPTIONS(g_cmd_update_args) -+ struct command_option options[] = { LOG_OPTIONS(lconf) UPDATE_OPTIONS(g_cmd_update_args) -+ COMMON_OPTIONS(g_cmd_update_args) - }; - - isula_libutils_default_log_config(argv[0], &lconf); -diff --git a/src/cmd/isula/extend/update.h b/src/cmd/isula/extend/update.h -index 361f10b..a527b46 100644 ---- a/src/cmd/isula/extend/update.h -+++ b/src/cmd/isula/extend/update.h -@@ -79,10 +79,36 @@ extern "C" { - &(cmdargs).cr.memory_swap, \ - "Swap limit equal to memory plus swap: '-1' to enable unlimited swap", \ - command_convert_memswapbytes }, \ -- { \ -- CMD_OPT_TYPE_STRING, false, "restart", 0, &(cmdargs).restart, \ -- "Restart policy to apply when a container exits", NULL \ -- } -+ { CMD_OPT_TYPE_STRING, \ -+ false, \ -+ "restart", \ -+ 0, \ -+ &(cmdargs).restart, \ -+ "Restart policy to apply when a container exits", \ -+ NULL }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "blkio-weight", \ -+ 0, \ -+ &(cmdargs).cr.blkio_weight, \ -+ "Block IO (relative weight), between 10 and 1000, or 0 to disable (default 0)", \ -+ command_convert_u16 }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "cpu-rt-period", \ -+ 0, \ -+ &((cmdargs).cr).cpu_rt_period, \ -+ "Limit CPU real-time period in microseconds.", \ -+ command_convert_llong }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "cpu-rt-runtime", \ -+ 0, \ -+ &((cmdargs).cr).cpu_rt_runtime, \ -+ "Limit CPU real-time runtime in microseconds.", \ -+ command_convert_llong }, \ -+ { CMD_OPT_TYPE_CALLBACK, false, "cpus", 0, &((cmdargs).cr).nano_cpus, "Number of CPUs.", \ -+ command_convert_nanocpus }, - - extern const char g_cmd_update_desc[]; - extern const char g_cmd_update_usage[]; -diff --git a/src/cmd/isula/images/images.c b/src/cmd/isula/images/images.c -index c028bc7..f60e750 100644 ---- a/src/cmd/isula/images/images.c -+++ b/src/cmd/isula/images/images.c -@@ -28,7 +28,7 @@ - #include "isula_libutils/log.h" - #include "command_parser.h" - #include "connect.h" --#include "libisula.h" -+ - #include "utils_array.h" - #include "utils_file.h" - #include "utils_verify.h" -diff --git a/src/cmd/isula/images/import.c b/src/cmd/isula/images/import.c -index 5d84274..2dcc648 100644 ---- a/src/cmd/isula/images/import.c -+++ b/src/cmd/isula/images/import.c -@@ -27,7 +27,7 @@ - #include "isula_libutils/log.h" - #include "command_parser.h" - #include "connect.h" --#include "libisula.h" -+ - #include "utils_verify.h" - - const char g_cmd_import_desc[] = "Import the contents from a tarball to create a filesystem image"; -diff --git a/src/cmd/isula/images/load.c b/src/cmd/isula/images/load.c -index c804ebf..343d8d6 100644 ---- a/src/cmd/isula/images/load.c -+++ b/src/cmd/isula/images/load.c -@@ -26,7 +26,6 @@ - #include "isula_connect.h" - #include "isula_libutils/log.h" - #include "connect.h" --#include "libisula.h" - - #ifdef ENABLE_EMBEDDED_IMAGE - const char g_cmd_load_desc[] = "load an image from a manifest or a tar archive"; -diff --git a/src/cmd/isula/images/login.c b/src/cmd/isula/images/login.c -index 32d6ea9..9255035 100644 ---- a/src/cmd/isula/images/login.c -+++ b/src/cmd/isula/images/login.c -@@ -24,7 +24,6 @@ - #include "isula_connect.h" - #include "isula_libutils/log.h" - #include "connect.h" --#include "libisula.h" - - const char g_cmd_login_desc[] = "Log in to a Docker registry"; - const char g_cmd_login_usage[] = "login [OPTIONS] SERVER"; -@@ -216,6 +215,8 @@ int cmd_login_main(int argc, const char **argv) - } - - ret = client_login(&g_cmd_login_args); -+ util_free_sensitive_string(g_cmd_login_args.username); -+ util_free_sensitive_string(g_cmd_login_args.password); - if (ret != 0) { - exit(exit_code); - } -diff --git a/src/cmd/isula/images/login.h b/src/cmd/isula/images/login.h -index dad619a..5f9a676 100644 ---- a/src/cmd/isula/images/login.h -+++ b/src/cmd/isula/images/login.h -@@ -25,8 +25,8 @@ extern "C" { - #endif - - #define LOGIN_OPTIONS(cmdargs) \ -- { CMD_OPT_TYPE_STRING, false, "username", 'u', &(cmdargs).username, "Username", NULL }, \ -- { CMD_OPT_TYPE_STRING, false, "password", 'p', &(cmdargs).password, "Password", NULL }, \ -+ { CMD_OPT_TYPE_STRING_DUP, false, "username", 'u', &(cmdargs).username, "Username", NULL }, \ -+ { CMD_OPT_TYPE_STRING_DUP, false, "password", 'p', &(cmdargs).password, "Password", NULL }, \ - { CMD_OPT_TYPE_BOOL, \ - false, \ - "password-stdin", \ -diff --git a/src/cmd/isula/images/logout.c b/src/cmd/isula/images/logout.c -index 12645d4..8efec1e 100644 ---- a/src/cmd/isula/images/logout.c -+++ b/src/cmd/isula/images/logout.c -@@ -23,7 +23,6 @@ - #include "isula_libutils/log.h" - #include "command_parser.h" - #include "connect.h" --#include "libisula.h" - - const char g_cmd_logout_desc[] = "Log out from a Docker registry"; - const char g_cmd_logout_usage[] = "logout SERVER"; -diff --git a/src/cmd/isula/images/pull.c b/src/cmd/isula/images/pull.c -index fff8898..b72b030 100644 ---- a/src/cmd/isula/images/pull.c -+++ b/src/cmd/isula/images/pull.c -@@ -23,7 +23,6 @@ - #include "isula_libutils/log.h" - #include "command_parser.h" - #include "connect.h" --#include "libisula.h" - - const char g_cmd_pull_desc[] = "Pull an image or a repository from a registry"; - const char g_cmd_pull_usage[] = "pull [OPTIONS] NAME[:TAG|@DIGEST]"; -diff --git a/src/cmd/isula/images/rmi.c b/src/cmd/isula/images/rmi.c -index 70ff660..53ea734 100644 ---- a/src/cmd/isula/images/rmi.c -+++ b/src/cmd/isula/images/rmi.c -@@ -23,7 +23,6 @@ - #include "isula_connect.h" - #include "isula_libutils/log.h" - #include "connect.h" --#include "libisula.h" - - const char g_cmd_rmi_desc[] = "Remove one or more images"; - const char g_cmd_rmi_usage[] = "rmi [OPTIONS] IMAGE [IMAGE...]"; -diff --git a/src/cmd/isula/images/tag.c b/src/cmd/isula/images/tag.c -index 822030c..e5a8670 100644 ---- a/src/cmd/isula/images/tag.c -+++ b/src/cmd/isula/images/tag.c -@@ -23,7 +23,7 @@ - #include "isula_libutils/log.h" - #include "command_parser.h" - #include "connect.h" --#include "libisula.h" -+ - #include "utils_verify.h" - - const char g_cmd_tag_desc[] = "Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE"; -diff --git a/src/cmd/isula/information/health.c b/src/cmd/isula/information/health.c -index 417c543..17a51f9 100644 ---- a/src/cmd/isula/information/health.c -+++ b/src/cmd/isula/information/health.c -@@ -23,7 +23,6 @@ - #include "isula_connect.h" - #include "connect.h" - #include "constants.h" --#include "libisula.h" - - const char g_cmd_health_check_desc[] = "iSulad health check"; - const char g_cmd_health_check_usage[] = "health [command options]"; -diff --git a/src/cmd/isula/information/info.c b/src/cmd/isula/information/info.c -index 955d58d..07cad9d 100644 ---- a/src/cmd/isula/information/info.c -+++ b/src/cmd/isula/information/info.c -@@ -25,7 +25,6 @@ - #include "isula_connect.h" - #include "command_parser.h" - #include "connect.h" --#include "libisula.h" - - const char g_cmd_info_desc[] = "Display system-wide information"; - const char g_cmd_info_usage[] = "info"; -diff --git a/src/cmd/isula/information/inspect.c b/src/cmd/isula/information/inspect.c -index 8341640..76caaba 100644 ---- a/src/cmd/isula/information/inspect.c -+++ b/src/cmd/isula/information/inspect.c -@@ -25,7 +25,6 @@ - #include "isula_connect.h" - #include "utils.h" - #include "connect.h" --#include "libisula.h" - - const char g_cmd_inspect_desc[] = "Return low-level information on a container or image"; - const char g_cmd_inspect_usage[] = "inspect [options] CONTAINER|IMAGE [CONTAINER|IMAGE...]"; -diff --git a/src/cmd/isula/information/logs.c b/src/cmd/isula/information/logs.c -index 0f603c2..2ddd16e 100644 ---- a/src/cmd/isula/information/logs.c -+++ b/src/cmd/isula/information/logs.c -@@ -23,7 +23,7 @@ - #include "isula_libutils/log.h" - #include "isula_connect.h" - #include "connect.h" --#include "libisula.h" -+ - #include "utils.h" - #include "utils_convert.h" - -@@ -67,7 +67,7 @@ static int do_logs(const struct client_arguments *args) - request->runtime = util_strdup_s(args->runtime); - request->follow = args->follow; - request->tail = (int64_t)args->tail; -- -+ request->timestamps = args->timestamps; - config = get_connect_config(args); - ret = ops->container.logs(request, response, &config); - if (ret != 0) { -@@ -105,8 +105,8 @@ static int cmd_logs_init(int argc, const char **argv) - return ECOMMON; - } - g_cmd_logs_args.progname = argv[0]; -- struct command_option options[] = { LOG_OPTIONS(lconf) LOGS_OPTIONS(g_cmd_logs_args), -- COMMON_OPTIONS(g_cmd_logs_args) -+ struct command_option options[] = { LOG_OPTIONS(lconf) LOGS_OPTIONS(g_cmd_logs_args) -+ COMMON_OPTIONS(g_cmd_logs_args) - }; - - command_init(&cmd, options, sizeof(options) / sizeof(options[0]), argc, (const char **)argv, g_cmd_logs_desc, -diff --git a/src/cmd/isula/information/logs.h b/src/cmd/isula/information/logs.h -index 477d3aa..05717a6 100644 ---- a/src/cmd/isula/information/logs.h -+++ b/src/cmd/isula/information/logs.h -@@ -25,12 +25,16 @@ - extern "C" { - #endif - --#define LOGS_OPTIONS(cmdargs) \ -- { CMD_OPT_TYPE_BOOL, false, "follow", 'f', &(cmdargs).follow, "Follow log output", NULL }, \ -- { \ -- CMD_OPT_TYPE_CALLBACK, false, "tail", 0, &(cmdargs).tail, "Number of lines to show from the end of the logs", \ -- callback_tail \ -- } -+#define LOGS_OPTIONS(cmdargs) \ -+ { CMD_OPT_TYPE_BOOL, false, "follow", 'f', &(cmdargs).follow, "Follow log output", NULL }, \ -+ { CMD_OPT_TYPE_CALLBACK, \ -+ false, \ -+ "tail", \ -+ 0, \ -+ &(cmdargs).tail, \ -+ "Number of lines to show from the end of the logs", \ -+ callback_tail }, \ -+ { CMD_OPT_TYPE_BOOL, false, "timestamps", 't', &(cmdargs).timestamps, "Show timestamps", NULL }, - - extern const char g_cmd_logs_desc[]; - extern const char g_cmd_logs_usage[]; -diff --git a/src/cmd/isula/information/ps.c b/src/cmd/isula/information/ps.c -index 860ae01..a824ac3 100644 ---- a/src/cmd/isula/information/ps.c -+++ b/src/cmd/isula/information/ps.c -@@ -26,7 +26,7 @@ - #include "isula_connect.h" - #include "connect.h" - #include "constants.h" --#include "libisula.h" -+ - #include "utils_array.h" - #include "utils_string.h" - #include "utils_timestamp.h" -@@ -121,7 +121,7 @@ static int append_field(struct filters *ff, struct filter_field *field) - old_size = ff->field_len * sizeof(struct filters); - new_size = old_size + sizeof(struct filters); - -- if (mem_realloc((void **)(&tmp_fields), new_size, ff->fields, old_size) != 0) { -+ if (util_mem_realloc((void **)(&tmp_fields), new_size, ff->fields, old_size) != 0) { - ERROR("Out of memory"); - return -1; - } -@@ -209,8 +209,8 @@ static int mix_container_status(const struct isula_container_summary_info *in, c - char finishat_duration[TIME_DURATION_MAX_LEN] = { 0 }; - char *start_at = NULL; - char *finish_at = NULL; -- time_format_duration(in->startat, startat_duration, sizeof(startat_duration)); -- time_format_duration_ago(in->finishat, finishat_duration, sizeof(finishat_duration)); -+ util_time_format_duration(in->startat, startat_duration, sizeof(startat_duration)); -+ util_time_format_duration_ago(in->finishat, finishat_duration, sizeof(finishat_duration)); - start_at = in->startat ? startat_duration : "-"; - finish_at = in->finishat ? finishat_duration : "-"; - -@@ -344,7 +344,7 @@ static int get_created_time_buffer(int64_t created, char *timebuffer, size_t len - ERROR("Failed to get timestamp"); - return -1; - } -- if (!get_time_buffer(×tamp, timebuffer, len)) { -+ if (!util_get_time_buffer(×tamp, timebuffer, len)) { - ERROR("Failed to get timebuffer from timestamp"); - return -1; - } -@@ -359,7 +359,7 @@ static void print_created_field(int64_t created, unsigned int length) - if (get_created_time_buffer(created, timebuffer, MAX_TIMESTAMP_LEN) != 0) { - return; - } -- if (time_format_duration_ago(timebuffer, created_duration, sizeof(created_duration)) != 0) { -+ if (util_time_format_duration_ago(timebuffer, created_duration, sizeof(created_duration)) != 0) { - return; - } - printf("%-*s", (int)length, created_duration); -@@ -405,11 +405,11 @@ static void print_extern_container_info_item(const struct isula_container_summar - printf("%-*u", (int)length->rscont_length, in->restart_count); - } else if (strcmp(name, "StartAt") == 0) { - char startat_duration[TIME_DURATION_MAX_LEN] = { 0 }; -- time_format_duration(in->startat, startat_duration, sizeof(startat_duration)); -+ util_time_format_duration(in->startat, startat_duration, sizeof(startat_duration)); - printf("%-*s", (int)length->startat_length, in->startat ? startat_duration : "-"); - } else if (strcmp(name, "FinishAt") == 0) { - char finishat_duration[TIME_DURATION_MAX_LEN] = { 0 }; -- time_format_duration(in->finishat, finishat_duration, sizeof(finishat_duration)); -+ util_time_format_duration(in->finishat, finishat_duration, sizeof(finishat_duration)); - printf("%-*s", (int)length->finishat_length, in->finishat ? finishat_duration : "-"); - } else if (strcmp(name, "Runtime") == 0) { - printf("%-*s", (int)length->runtime_length, in->runtime ? in->runtime : "lcr"); -@@ -531,7 +531,7 @@ static void calculate_time_str_length(const char *str, unsigned int *length) - size_t len = 0; - char time_duration[TIME_DURATION_MAX_LEN]; - -- if (time_format_duration_ago(str, time_duration, sizeof(time_duration)) < 0) { -+ if (util_time_format_duration_ago(str, time_duration, sizeof(time_duration)) < 0) { - ERROR("Format time duration failed"); - } - -diff --git a/src/cmd/isula/information/top.c b/src/cmd/isula/information/top.c -index bb0fa45..5d0e3f0 100644 ---- a/src/cmd/isula/information/top.c -+++ b/src/cmd/isula/information/top.c -@@ -25,7 +25,6 @@ - #include "attach.h" - #include "command_parser.h" - #include "connect.h" --#include "libisula.h" - - const char g_cmd_top_desc[] = "Display the running processes of a container"; - const char g_cmd_top_usage[] = "top [OPTIONS] CONTAINER [ps OPTIONS]"; -diff --git a/src/cmd/isula/information/version.c b/src/cmd/isula/information/version.c -index 36e985b..62ee564 100644 ---- a/src/cmd/isula/information/version.c -+++ b/src/cmd/isula/information/version.c -@@ -25,7 +25,6 @@ - #include "command_parser.h" - #include "connect.h" - #include "constants.h" --#include "libisula.h" - - const char g_cmd_version_desc[] = "Display information about isula"; - const char g_cmd_version_usage[] = "version"; -diff --git a/src/cmd/isula/information/wait.c b/src/cmd/isula/information/wait.c -index 5926536..90a018f 100644 ---- a/src/cmd/isula/information/wait.c -+++ b/src/cmd/isula/information/wait.c -@@ -23,7 +23,7 @@ - #include "command_parser.h" - #include "connect.h" - #include "constants.h" --#include "libisula.h" -+ - #include "utils.h" - - const char g_cmd_wait_desc[] = "Block until one or more containers stop, then print their exit codes"; -diff --git a/src/cmd/isula/isula_commands.c b/src/cmd/isula/isula_commands.c -index 8208aa3..2f3298d 100644 ---- a/src/cmd/isula/isula_commands.c -+++ b/src/cmd/isula/isula_commands.c -@@ -17,17 +17,16 @@ - #include - #include - #include --#include - #include - #include - #include - #include -+#include - - #include "client_arguments.h" - #include "config.h" - #include "isula_libutils/log.h" - #include "utils.h" --#include "console.h" - #include "constants.h" - #include "utils_file.h" - #include "utils_string.h" -@@ -199,239 +198,3 @@ int run_command(struct command *commands, int argc, const char **argv) - printf("run `%s --help` for a list of sub-commands\n", argv[0]); - return 1; - } -- --/* free command fifo names */ --void free_command_fifo_config(struct command_fifo_config *fifos) --{ -- if (fifos != NULL) { -- if (fifos->stdin_path != NULL) { -- free(fifos->stdin_path); -- fifos->stdin_path = NULL; -- } -- if (fifos->stdout_path != NULL) { -- free(fifos->stdout_path); -- fifos->stdout_path = NULL; -- } -- if (fifos->stderr_path != NULL) { -- free(fifos->stderr_path); -- fifos->stderr_path = NULL; -- } -- if (fifos->stdin_name != NULL) { -- free(fifos->stdin_name); -- fifos->stdin_name = NULL; -- } -- if (fifos->stdout_name != NULL) { -- free(fifos->stdout_name); -- fifos->stdout_name = NULL; -- } -- if (fifos->stderr_name != NULL) { -- free(fifos->stderr_name); -- fifos->stderr_name = NULL; -- } -- free(fifos); -- } --} -- --/* delete command fifo */ --void delete_command_fifo(struct command_fifo_config *fifos) --{ -- int ret; -- -- if (fifos == NULL) { -- return; -- } -- -- ret = console_fifo_delete(fifos->stdin_name); -- if (ret) { -- WARN("Delete fifo failed: %s", fifos->stdin_name); -- } -- ret = console_fifo_delete(fifos->stdout_name); -- if (ret) { -- WARN("Delete fifo failed: %s", fifos->stdout_name); -- } -- ret = console_fifo_delete(fifos->stderr_name); -- if (ret) { -- WARN("Delete fifo failed: %s", fifos->stderr_name); -- } -- ret = util_recursive_rmdir(fifos->stdin_path, 0); -- if (ret) { -- WARN("Remove directory failed: %s", fifos->stdin_path); -- } -- ret = util_recursive_rmdir(fifos->stdout_path, 0); -- if (ret) { -- WARN("Remove directory failed: %s", fifos->stdout_path); -- } -- ret = util_recursive_rmdir(fifos->stderr_path, 0); -- if (ret) { -- WARN("Remove directory failed: %s", fifos->stderr_path); -- } -- -- free_command_fifo_config(fifos); --} -- --static int do_create_console_fifo(const char *subpath, const char *stdflag, char **out_fifo_dir, char **out_fifo_name) --{ -- int ret = 0; -- char fifo_dir[PATH_MAX] = { 0 }; -- char fifo_name[PATH_MAX] = { 0 }; -- -- ret = console_fifo_name(CLIENT_RUNDIR, subpath, stdflag, fifo_name, sizeof(fifo_name), fifo_dir, sizeof(fifo_dir), -- true); -- if (ret != 0) { -- ERROR("Failed to get console fifo name."); -- ret = -1; -- goto out; -- } -- -- if (console_fifo_create(fifo_name)) { -- ERROR("Failed to create console fifo."); -- ret = -1; -- goto out; -- } -- -- *out_fifo_dir = util_strdup_s(fifo_dir); -- *out_fifo_name = util_strdup_s(fifo_name); -- --out: -- return ret; --} -- --int create_console_fifos(bool attach_stdin, bool attach_stdout, bool attach_stderr, const char *name, const char *type, -- struct command_fifo_config **pconsole_fifos) --{ -- int ret = 0; -- char subpath[PATH_MAX] = { 0 }; -- struct command_fifo_config *fifos = NULL; -- -- fifos = util_common_calloc_s(sizeof(struct command_fifo_config)); -- if (fifos == NULL) { -- ERROR("Failed to malloc memory for FIFO names."); -- return -1; -- } -- -- ret = snprintf(subpath, sizeof(subpath), "%s/%s-%u-%u", name, type, (unsigned int)getpid(), -- (unsigned int)pthread_self()); -- if (ret < 0 || (size_t)ret >= sizeof(subpath)) { -- ERROR("Path is too long"); -- goto cleanup; -- } -- -- if (attach_stdin) { -- ret = do_create_console_fifo(subpath, "in", &fifos->stdin_path, &fifos->stdin_name); -- if (ret != 0) { -- goto cleanup; -- } -- INFO("FIFO:%s create for start success.", fifos->stdin_name); -- } -- -- if (attach_stdout) { -- ret = do_create_console_fifo(subpath, "out", &fifos->stdout_path, &fifos->stdout_name); -- if (ret != 0) { -- goto cleanup; -- } -- INFO("FIFO:%s create for start success.", fifos->stdout_name); -- } -- -- if (attach_stderr) { -- ret = do_create_console_fifo(subpath, "err", &fifos->stderr_path, &fifos->stderr_name); -- if (ret != 0) { -- goto cleanup; -- } -- INFO("FIFO:%s create for start success.", fifos->stderr_name); -- } -- -- *pconsole_fifos = fifos; -- return 0; -- --cleanup: -- console_fifo_delete(fifos->stdin_name); -- console_fifo_delete(fifos->stdout_name); -- console_fifo_delete(fifos->stderr_name); -- free_command_fifo_config(fifos); -- return -1; --} -- --struct console_loop_thread_args { -- struct command_fifo_config *fifo_config; -- bool tty; --}; -- --static void *client_console_loop_thread(void *arg) --{ -- int ret = 0; -- int fifoinfd = -1; -- int fifooutfd = -1; -- int fifoerrfd = -1; -- const struct console_loop_thread_args *args = arg; -- bool tty = args->tty; -- struct command_fifo_config *fifo_config = args->fifo_config; -- sem_t *wait_open = fifo_config->wait_open; -- sem_t *wait_exit = fifo_config->wait_exit; -- -- ret = pthread_detach(pthread_self()); -- if (ret != 0) { -- CRIT("Start: set thread detach fail"); -- goto err1; -- } -- -- if (fifo_config->stdin_name) { -- if (console_fifo_open_withlock(fifo_config->stdin_name, &fifoinfd, O_RDWR | O_NONBLOCK)) { -- ERROR("Start: failed to open console fifo."); -- goto err2; -- } -- INFO("FIFO:%s open success for start.", fifo_config->stdin_name); -- } -- -- if (fifo_config->stdout_name) { -- if (console_fifo_open(fifo_config->stdout_name, &fifooutfd, O_RDONLY | O_NONBLOCK)) { -- ERROR("Failed to open console fifo."); -- goto err2; -- } -- INFO("FIFO:%s open success for start.", fifo_config->stdout_name); -- } -- -- if (fifo_config->stderr_name) { -- if (console_fifo_open(fifo_config->stderr_name, &fifoerrfd, O_RDONLY | O_NONBLOCK)) { -- ERROR("Start: failed to open console fifo."); -- goto err2; -- } -- INFO("FIFO:%s open success for start.", fifo_config->stderr_name); -- } -- -- sem_post(wait_open); -- console_loop_with_std_fd(0, 1, 2, fifoinfd, fifooutfd, fifoerrfd, 1, tty); -- --err2: -- if (fifoinfd >= 0) { -- console_fifo_close(fifoinfd); -- } -- if (fifooutfd >= 0) { -- console_fifo_close(fifooutfd); -- } -- if (fifoerrfd >= 0) { -- console_fifo_close(fifoerrfd); -- } --err1: -- sem_post(wait_open); -- sem_post(wait_exit); -- return NULL; --} -- --int start_client_console_thread(struct command_fifo_config *console_fifos, bool tty) --{ -- int res = 0; -- pthread_t a_thread; -- struct console_loop_thread_args args; -- -- args.fifo_config = console_fifos; -- args.tty = tty; -- res = pthread_create(&a_thread, NULL, client_console_loop_thread, (void *)(&args)); -- if (res != 0) { -- CRIT("Thread creation failed"); -- return -1; -- } -- -- sem_wait(console_fifos->wait_open); -- -- return 0; --} -diff --git a/src/cmd/isula/isula_commands.h b/src/cmd/isula/isula_commands.h -index 7ac2501..1e9e166 100644 ---- a/src/cmd/isula/isula_commands.h -+++ b/src/cmd/isula/isula_commands.h -@@ -15,7 +15,6 @@ - #ifndef CMD_ISULA_ISULA_COMMANDS_H - #define CMD_ISULA_ISULA_COMMANDS_H - --#include - #include - - #include "client_arguments.h" -@@ -24,15 +23,13 @@ - extern "C" { - #endif - --#define CLIENT_RUNDIR "/var/run/isula" -- - // A command is described by: - // @name: The name which should be passed as a second parameter - // @executor: The function that will be executed if the command - // matches. Receives the argc of the program minus two, and - // the rest os argv - // @description: Brief description, will show in help messages --// @longdesc: Long descripton to show when you run `help ` -+// @longdesc: Long description to show when you run `help ` - struct command { - const char * const name; - int (*executor)(int, const char **); -@@ -41,26 +38,6 @@ struct command { - struct client_arguments *args; - }; - --struct command_fifo_config { -- char *stdin_path; -- char *stdout_path; -- char *stderr_path; -- char *stdin_name; -- char *stdout_name; -- char *stderr_name; -- sem_t *wait_open; -- sem_t *wait_exit; --}; -- --int create_console_fifos(bool attach_stdin, bool attach_stdout, bool attach_stderr, const char *name, const char *type, -- struct command_fifo_config **pconsole_fifos); -- --int start_client_console_thread(struct command_fifo_config *console_fifos, bool tty); -- --void free_command_fifo_config(struct command_fifo_config *fifos); -- --void delete_command_fifo(struct command_fifo_config *fifos); -- - // Gets a pointer to a command, to allow implementing custom behavior - // returns null if not found. - // -@@ -68,7 +45,7 @@ void delete_command_fifo(struct command_fifo_config *fifos); - const struct command *command_by_name(const struct command *cmds, const char * const name); - - // Default help command if implementation doesn't prvide one --int commmand_default_help(const char * const program_name, struct command *commands, int argc, const char **argv); -+int command_default_help(const char * const program_name, struct command *commands, int argc, const char **argv); - - int run_command(struct command *commands, int argc, const char **argv); - -diff --git a/src/cmd/isula/isula_container_spec.c b/src/cmd/isula/isula_container_spec.c -new file mode 100644 -index 0000000..2893eb9 ---- /dev/null -+++ b/src/cmd/isula/isula_container_spec.c -@@ -0,0 +1,486 @@ -+/****************************************************************************** -+ * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. 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: lifeng -+ * Create: 2020-09-28 -+ * Description: provide generate container spec in client -+ ******************************************************************************/ -+#include "isula_container_spec.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "isula_libutils/log.h" -+#include "utils.h" -+#include "isula_libutils/container_config.h" -+#include "utils_array.h" -+#include "utils_string.h" -+#include "utils_verify.h" -+ -+static int pack_container_custom_config_args(container_config *container_spec, -+ const isula_container_config_t *custom_conf) -+{ -+ int ret = 0; -+ int i; -+ -+ /* entrypoint */ -+ if (util_valid_str(custom_conf->entrypoint)) { -+ container_spec->entrypoint = util_common_calloc_s(sizeof(char *)); -+ if (container_spec->entrypoint == NULL) { -+ ret = -1; -+ goto out; -+ } -+ container_spec->entrypoint[0] = util_strdup_s(custom_conf->entrypoint); -+ container_spec->entrypoint_len++; -+ } -+ -+ /* commands */ -+ if ((custom_conf->cmd_len != 0 && custom_conf->cmd)) { -+ if (custom_conf->cmd_len > SIZE_MAX / sizeof(char *)) { -+ COMMAND_ERROR("The length of cmd is too long!"); -+ ret = -1; -+ goto out; -+ } -+ container_spec->cmd = util_common_calloc_s(custom_conf->cmd_len * sizeof(char *)); -+ if (container_spec->cmd == NULL) { -+ ret = -1; -+ goto out; -+ } -+ for (i = 0; i < (int)custom_conf->cmd_len; i++) { -+ container_spec->cmd[container_spec->cmd_len] = util_strdup_s(custom_conf->cmd[i]); -+ container_spec->cmd_len++; -+ } -+ } -+ -+out: -+ return ret; -+} -+ -+static int pack_container_custom_config_mounts(container_config *container_spec, -+ const isula_container_config_t *custom_conf) -+{ -+ int ret = 0; -+ int i = 0; -+ -+ /* mounts to mount filesystem */ -+ if (custom_conf->mounts != NULL && custom_conf->mounts_len > 0) { -+ if (custom_conf->mounts_len > SIZE_MAX / sizeof(char *)) { -+ COMMAND_ERROR("Too many mounts to mount filesystem!"); -+ ret = -1; -+ goto out; -+ } -+ container_spec->mounts = util_common_calloc_s(custom_conf->mounts_len * sizeof(char *)); -+ if (container_spec->mounts == NULL) { -+ ret = -1; -+ goto out; -+ } -+ for (i = 0; i < (int)custom_conf->mounts_len; i++) { -+ container_spec->mounts[container_spec->mounts_len] = util_strdup_s(custom_conf->mounts[i]); -+ container_spec->mounts_len++; -+ } -+ } -+out: -+ return ret; -+} -+ -+static int pack_container_custom_config_array(container_config *container_spec, -+ const isula_container_config_t *custom_conf) -+{ -+ int ret = 0; -+ int i = 0; -+ -+ /* environment variables */ -+ if (custom_conf->env_len != 0 && custom_conf->env) { -+ if (custom_conf->env_len > SIZE_MAX / sizeof(char *)) { -+ COMMAND_ERROR("Too many environment variables"); -+ return -1; -+ } -+ container_spec->env = util_common_calloc_s(custom_conf->env_len * sizeof(char *)); -+ if (container_spec->env == NULL) { -+ ret = -1; -+ goto out; -+ } -+ for (i = 0; i < (int)custom_conf->env_len; i++) { -+ container_spec->env[container_spec->env_len] = util_strdup_s(custom_conf->env[i]); -+ container_spec->env_len++; -+ } -+ } -+ -+out: -+ return ret; -+} -+ -+static int get_label_key_value(const char *label, char **key, char **value) -+{ -+ int ret = 0; -+ char **arr = util_string_split_n(label, '=', 2); -+ if (arr == NULL) { -+ ERROR("Failed to split input label"); -+ ret = -1; -+ goto out; -+ } -+ -+ *key = util_strdup_s(arr[0]); -+ if (util_array_len((const char **)arr) == 1) { -+ *value = util_strdup_s(""); -+ } else { -+ *value = util_strdup_s(arr[1]); -+ } -+ -+out: -+ util_free_array(arr); -+ return ret; -+} -+ -+static int pack_container_custom_config_labels(container_config *container_spec, -+ const isula_container_config_t *custom_conf) -+{ -+ int ret = 0; -+ int i; -+ char *key = NULL; -+ char *value = NULL; -+ -+ if (custom_conf->label_len == 0 || custom_conf->label == NULL) { -+ return 0; -+ } -+ -+ /* labels */ -+ container_spec->labels = util_common_calloc_s(sizeof(json_map_string_string)); -+ if (container_spec->labels == NULL) { -+ ERROR("Out of memory"); -+ ret = -1; -+ goto out; -+ } -+ -+ for (i = 0; i < custom_conf->label_len; i++) { -+ if (get_label_key_value(custom_conf->label[i], &key, &value) != 0) { -+ ERROR("Failed to get key and value of label"); -+ ret = -1; -+ goto out; -+ } -+ -+ if (append_json_map_string_string(container_spec->labels, key, value)) { -+ ERROR("Append map failed"); -+ ret = -1; -+ goto out; -+ } -+ free(key); -+ key = NULL; -+ free(value); -+ value = NULL; -+ } -+ -+out: -+ free(key); -+ free(value); -+ return ret; -+} -+ -+static bool have_health_check(const isula_container_config_t *custom_conf) -+{ -+ bool have_health_settings = false; -+ -+ if ((custom_conf->health_cmd != NULL && strlen(custom_conf->health_cmd) != 0) || -+ custom_conf->health_interval != 0 || custom_conf->health_timeout != 0 || -+ custom_conf->health_start_period != 0 || custom_conf->health_retries != 0) { -+ have_health_settings = true; -+ } -+ -+ return have_health_settings; -+} -+ -+static int pack_custom_no_health_check(container_config *container_spec, bool have_health_settings, -+ defs_health_check *health_config) -+{ -+ int ret = 0; -+ -+ if (have_health_settings) { -+ COMMAND_ERROR("--no-healthcheck conflicts with --health-* options"); -+ ret = -1; -+ goto out; -+ } -+ health_config->test = util_common_calloc_s(sizeof(char *)); -+ if (health_config->test == NULL) { -+ ret = -1; -+ goto out; -+ } -+ health_config->test[health_config->test_len++] = util_strdup_s("NONE"); -+ container_spec->healthcheck = health_config; -+ -+out: -+ return ret; -+} -+ -+static int pack_custom_with_health_check(container_config *container_spec, const isula_container_config_t *custom_conf, -+ bool have_health_settings, defs_health_check *health_config) -+{ -+ int ret = 0; -+ -+ if (custom_conf->health_cmd != NULL && strlen(custom_conf->health_cmd) != 0) { -+ health_config->test = util_common_calloc_s(2 * sizeof(char *)); -+ if (health_config->test == NULL) { -+ ret = -1; -+ goto out; -+ } -+ health_config->test[health_config->test_len++] = util_strdup_s("CMD-SHELL"); -+ health_config->test[health_config->test_len++] = util_strdup_s(custom_conf->health_cmd); -+ } else { -+ COMMAND_ERROR("--health-cmd required!"); -+ ret = -1; -+ goto out; -+ } -+ health_config->interval = custom_conf->health_interval; -+ health_config->timeout = custom_conf->health_timeout; -+ health_config->start_period = custom_conf->health_start_period; -+ health_config->retries = custom_conf->health_retries; -+ health_config->exit_on_unhealthy = custom_conf->exit_on_unhealthy; -+ if (container_spec->healthcheck != NULL) { -+ free_defs_health_check(container_spec->healthcheck); -+ } -+ container_spec->healthcheck = health_config; -+ -+out: -+ return ret; -+} -+ -+static int pack_container_custom_config_health(container_config *container_spec, -+ const isula_container_config_t *custom_conf) -+{ -+ int ret = 0; -+ bool have_health_settings = false; -+ defs_health_check *health_config = NULL; -+ -+ if (container_spec == NULL || custom_conf == NULL) { -+ return 0; -+ } -+ -+ have_health_settings = have_health_check(custom_conf); -+ -+ health_config = util_common_calloc_s(sizeof(defs_health_check)); -+ if (health_config == NULL) { -+ ret = -1; -+ goto out; -+ } -+ -+ if (custom_conf->no_healthcheck) { -+ ret = pack_custom_no_health_check(container_spec, have_health_settings, health_config); -+ if (ret != 0) { -+ goto out; -+ } -+ } else if (have_health_settings) { -+ ret = pack_custom_with_health_check(container_spec, custom_conf, have_health_settings, health_config); -+ if (ret != 0) { -+ goto out; -+ } -+ } else { -+ goto out; -+ } -+ -+ return ret; -+ -+out: -+ free_defs_health_check(health_config); -+ return ret; -+} -+ -+static int pack_container_custom_config_annotation(container_config *container_spec, -+ const isula_container_config_t *custom_conf) -+{ -+ int ret = 0; -+ size_t j; -+ -+ container_spec->annotations = util_common_calloc_s(sizeof(json_map_string_string)); -+ if (container_spec->annotations == NULL) { -+ ERROR("Out of memory"); -+ ret = -1; -+ goto out; -+ } -+ if (custom_conf->annotations != NULL) { -+ for (j = 0; j < custom_conf->annotations->len; j++) { -+ if (append_json_map_string_string(container_spec->annotations, custom_conf->annotations->keys[j], -+ custom_conf->annotations->values[j])) { -+ ERROR("Append map failed"); -+ ret = -1; -+ goto out; -+ } -+ } -+ } -+out: -+ return ret; -+} -+ -+static int pack_container_custom_config_pre(container_config *container_spec, -+ const isula_container_config_t *custom_conf) -+{ -+ int ret = 0; -+ -+ ret = pack_container_custom_config_args(container_spec, custom_conf); -+ if (ret != 0) { -+ goto out; -+ } -+ -+ ret = pack_container_custom_config_mounts(container_spec, custom_conf); -+ if (ret != 0) { -+ goto out; -+ } -+ -+ ret = pack_container_custom_config_array(container_spec, custom_conf); -+ if (ret != 0) { -+ goto out; -+ } -+ -+ ret = pack_container_custom_config_labels(container_spec, custom_conf); -+ if (ret != 0) { -+ goto out; -+ } -+ -+ ret = pack_container_custom_config_health(container_spec, custom_conf); -+ if (ret != 0) { -+ goto out; -+ } -+out: -+ return ret; -+} -+ -+/* translate create_custom_config to container_config */ -+static int pack_container_custom_config(container_config *container_spec, const isula_container_config_t *custom_conf) -+{ -+ int ret = -1; -+ -+ if (container_spec == NULL || custom_conf == NULL) { -+ return ret; -+ } -+ -+ ret = pack_container_custom_config_pre(container_spec, custom_conf); -+ if (ret != 0) { -+ goto out; -+ } -+ -+ if (custom_conf->hostname != NULL) { -+ container_spec->hostname = util_strdup_s(custom_conf->hostname); -+ } -+ container_spec->log_driver = util_strdup_s(custom_conf->log_driver); -+ -+ /* console config */ -+ container_spec->tty = custom_conf->tty; -+ container_spec->open_stdin = custom_conf->open_stdin; -+ container_spec->attach_stdin = custom_conf->attach_stdin; -+ container_spec->attach_stdout = custom_conf->attach_stdout; -+ container_spec->attach_stderr = custom_conf->attach_stderr; -+ -+ /* user and group */ -+ if (custom_conf->user != NULL) { -+ container_spec->user = util_strdup_s(custom_conf->user); -+ } -+ -+ /* settings for system container */ -+ if (custom_conf->system_container) { -+ container_spec->system_container = custom_conf->system_container; -+ } -+ -+ if (custom_conf->ns_change_opt != NULL) { -+ container_spec->ns_change_opt = util_strdup_s(custom_conf->ns_change_opt); -+ } -+ -+ ret = pack_container_custom_config_annotation(container_spec, custom_conf); -+ if (ret != 0) { -+ goto out; -+ } -+ -+ if (custom_conf->workdir != NULL) { -+ container_spec->working_dir = util_strdup_s(custom_conf->workdir); -+ } -+ -+out: -+ return ret; -+} -+ -+int generate_container_config(const isula_container_config_t *custom_conf, char **container_config_str) -+{ -+ int ret = 0; -+ container_config *container_spec = NULL; -+ struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 }; -+ parser_error err = NULL; -+ -+ /* step 1: malloc the container config */ -+ container_spec = util_common_calloc_s(sizeof(container_config)); -+ if (container_spec == NULL) { -+ ERROR("Memory out"); -+ ret = -1; -+ goto out; -+ } -+ -+ /* step 2: pack the container custom config */ -+ ret = pack_container_custom_config(container_spec, custom_conf); -+ if (ret != 0) { -+ ERROR("Failed to pack the container custom config"); -+ ret = -1; -+ goto out; -+ } -+ -+ /* step 3: generate the config string */ -+ *container_config_str = container_config_generate_json(container_spec, &ctx, &err); -+ if (*container_config_str == NULL) { -+ ERROR("Failed to generate OCI specification json string"); -+ ret = -1; -+ goto out; -+ } -+ -+out: -+ free_container_config(container_spec); -+ free(err); -+ -+ return ret; -+} -+ -+/* isula container config free */ -+void isula_container_config_free(isula_container_config_t *config) -+{ -+ if (config == NULL) { -+ return; -+ } -+ -+ util_free_array_by_len(config->env, config->env_len); -+ config->env = NULL; -+ config->env_len = 0; -+ -+ free(config->hostname); -+ config->hostname = NULL; -+ -+ free(config->user); -+ config->user = NULL; -+ -+ util_free_array_by_len(config->mounts, config->mounts_len); -+ config->mounts = NULL; -+ config->mounts_len = 0; -+ -+ util_free_array_by_len(config->cmd, config->cmd_len); -+ config->cmd = NULL; -+ config->cmd_len = 0; -+ -+ free(config->entrypoint); -+ config->entrypoint = NULL; -+ -+ free(config->log_driver); -+ config->log_driver = NULL; -+ -+ free_json_map_string_string(config->annotations); -+ config->annotations = NULL; -+ -+ free(config->workdir); -+ config->workdir = NULL; -+ -+ free(config); -+} -\ No newline at end of file -diff --git a/src/cmd/isula/isula_container_spec.h b/src/cmd/isula/isula_container_spec.h -new file mode 100644 -index 0000000..1a1b616 ---- /dev/null -+++ b/src/cmd/isula/isula_container_spec.h -@@ -0,0 +1,92 @@ -+/****************************************************************************** -+ * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. 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: lifeng -+ * Create: 2020-09-28 -+ * Description: provide generate container spec in client -+ ******************************************************************************/ -+#ifndef CMD_ISULA_GENERATE_CONTAINER_SPEC_H -+#define CMD_ISULA_GENERATE_CONTAINER_SPEC_H -+ -+#include -+#include -+#include -+#include "isula_libutils/json_common.h" -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+typedef struct isula_container_config { -+ char **env; -+ size_t env_len; -+ -+ char **label; -+ size_t label_len; -+ -+ char *hostname; -+ -+ char *user; -+ -+ bool attach_stdin; -+ -+ bool attach_stdout; -+ -+ bool attach_stderr; -+ -+ bool open_stdin; -+ -+ bool tty; -+ -+ bool readonly; -+ -+ bool all_devices; -+ -+ bool system_container; -+ char *ns_change_opt; -+ -+ char **mounts; -+ size_t mounts_len; -+ -+ char *entrypoint; -+ -+ char **cmd; -+ size_t cmd_len; -+ -+ char *log_driver; -+ -+ json_map_string_string *annotations; -+ -+ char *workdir; -+ -+ char *health_cmd; -+ -+ int64_t health_interval; -+ -+ int health_retries; -+ -+ int64_t health_timeout; -+ -+ int64_t health_start_period; -+ -+ bool no_healthcheck; -+ -+ bool exit_on_unhealthy; -+ -+} isula_container_config_t; -+ -+int generate_container_config(const isula_container_config_t *custom_conf, char **container_config_str); -+ -+void isula_container_config_free(isula_container_config_t *config); -+#ifdef __cplusplus -+} -+#endif -+ -+#endif -diff --git a/src/client/connect/pack_config.c b/src/cmd/isula/isula_host_spec.c -similarity index 51% -rename from src/client/connect/pack_config.c -rename to src/cmd/isula/isula_host_spec.c -index fbcd7b4..9c51e73 100644 ---- a/src/client/connect/pack_config.c -+++ b/src/cmd/isula/isula_host_spec.c -@@ -8,10 +8,12 @@ - * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR - * PURPOSE. - * See the Mulan PSL v2 for more details. -- * Author: tanyifeng -- * Create: 2018-11-08 -- * Description: provide container package configure functions -+ * Author: lifeng -+ * Create: 2020-09-28 -+ * Description: provide generate host spec in client - ******************************************************************************/ -+#include "isula_host_spec.h" -+ - #include - #include - #include -@@ -25,17 +27,16 @@ - #include - - #include "isula_libutils/log.h" --#include "pack_config.h" - #include "isula_libutils/host_config.h" - #include "utils.h" - #include "isula_libutils/parse_common.h" - #include "path.h" --#include "isula_libutils/container_config.h" - #include "utils_array.h" - #include "utils_convert.h" - #include "utils_file.h" - #include "utils_string.h" - #include "utils_verify.h" -+#include "opt_ulimit.h" - - static bool parse_restart_policy(const char *policy, host_config_restart_policy **rp) - { -@@ -79,32 +80,13 @@ cleanup: - - static int pack_host_config_ns_change_files(host_config *dstconfig, const isula_host_config_t *srcconfig) - { -- int ret = 0; -- size_t i = 0; -- -- if (dstconfig == NULL || srcconfig == NULL) { -+ if (util_dup_array_of_strings((const char **)srcconfig->ns_change_files, srcconfig->ns_change_files_len, -+ &dstconfig->ns_change_files, &dstconfig->ns_change_files_len) != 0) { -+ COMMAND_ERROR("Failed to dup ns change files"); - return -1; - } - -- if (srcconfig->ns_change_files_len != 0 && srcconfig->ns_change_files != NULL) { -- if (srcconfig->ns_change_files_len > SIZE_MAX / sizeof(char *)) { -- COMMAND_ERROR("Too many capabilities to add!"); -- ret = -1; -- goto out; -- } -- dstconfig->ns_change_files = util_common_calloc_s(srcconfig->ns_change_files_len * sizeof(char *)); -- if (dstconfig->ns_change_files == NULL) { -- ret = -1; -- goto out; -- } -- for (i = 0; i < srcconfig->ns_change_files_len; i++) { -- dstconfig->ns_change_files[dstconfig->ns_change_files_len] = util_strdup_s(srcconfig->ns_change_files[i]); -- dstconfig->ns_change_files_len++; -- } -- } -- --out: -- return ret; -+ return 0; - } - - static int pack_host_config_cap_add(host_config *dstconfig, const isula_host_config_t *srcconfig) -@@ -113,21 +95,10 @@ static int pack_host_config_cap_add(host_config *dstconfig, const isula_host_con - size_t i = 0; - - /* cap-add */ -- if (srcconfig->cap_add_len != 0 && srcconfig->cap_add != NULL) { -- if (srcconfig->cap_add_len > SIZE_MAX / sizeof(char *)) { -- COMMAND_ERROR("Too many capabilities to add!"); -- ret = -1; -- goto out; -- } -- dstconfig->cap_add = util_common_calloc_s(srcconfig->cap_add_len * sizeof(char *)); -- if (dstconfig->cap_add == NULL) { -- ret = -1; -- goto out; -- } -- for (i = 0; i < srcconfig->cap_add_len; i++) { -- dstconfig->cap_add[dstconfig->cap_add_len] = util_strdup_s(srcconfig->cap_add[i]); -- dstconfig->cap_add_len++; -- } -+ if (util_dup_array_of_strings((const char **)srcconfig->cap_add, srcconfig->cap_add_len, &dstconfig->cap_add, -+ &dstconfig->cap_add_len) != 0) { -+ COMMAND_ERROR("Failed to dup cap add"); -+ return -1; - } - - for (i = 0; i < dstconfig->cap_add_len; i++) { -@@ -152,21 +123,10 @@ static int pack_host_config_cap_drop(host_config *dstconfig, const isula_host_co - size_t i = 0; - - /* cap-drops */ -- if (srcconfig->cap_drop_len != 0 && srcconfig->cap_drop != NULL) { -- if (srcconfig->cap_drop_len > SIZE_MAX / sizeof(char *)) { -- COMMAND_ERROR("Too many capabilities to drop!"); -- ret = -1; -- goto out; -- } -- dstconfig->cap_drop = util_common_calloc_s(srcconfig->cap_drop_len * sizeof(char *)); -- if (dstconfig->cap_drop == NULL) { -- ret = -1; -- goto out; -- } -- for (i = 0; i < srcconfig->cap_drop_len; i++) { -- dstconfig->cap_drop[dstconfig->cap_drop_len] = util_strdup_s(srcconfig->cap_drop[i]); -- dstconfig->cap_drop_len++; -- } -+ if (util_dup_array_of_strings((const char **)srcconfig->cap_drop, srcconfig->cap_drop_len, &dstconfig->cap_drop, -+ &dstconfig->cap_drop_len) != 0) { -+ COMMAND_ERROR("Failed to dup cap drop"); -+ return -1; - } - - for (i = 0; i < dstconfig->cap_drop_len; i++) { -@@ -208,119 +168,43 @@ out: - - static int pack_host_network_extra_hosts(host_config *dstconfig, const isula_host_config_t *srcconfig) - { -- int ret = 0; -- size_t i = 0; -- - /* extra hosts */ -- if (srcconfig->extra_hosts_len != 0 && srcconfig->extra_hosts != NULL) { -- if (srcconfig->extra_hosts_len > SIZE_MAX / sizeof(char *)) { -- COMMAND_ERROR("Too many extra hosts to add!"); -- ret = -1; -- goto out; -- } -- dstconfig->extra_hosts = util_common_calloc_s(srcconfig->extra_hosts_len * sizeof(char *)); -- if (dstconfig->extra_hosts == NULL) { -- ret = -1; -- goto out; -- } -- for (i = 0; i < srcconfig->extra_hosts_len; i++) { -- dstconfig->extra_hosts[dstconfig->extra_hosts_len] = util_strdup_s(srcconfig->extra_hosts[i]); -- dstconfig->extra_hosts_len++; -- } -+ if (util_dup_array_of_strings((const char **)srcconfig->extra_hosts, srcconfig->extra_hosts_len, -+ &dstconfig->extra_hosts, &dstconfig->extra_hosts_len) != 0) { -+ COMMAND_ERROR("Failed to dup extra hosts"); -+ return -1; - } --out: -- return ret; -+ -+ return 0; - } - - static int pack_host_network_dns(host_config *dstconfig, const isula_host_config_t *srcconfig) - { -- int ret = 0; -- size_t i = 0; -- -- /* dns */ -- if (srcconfig->dns_len != 0 && srcconfig->dns != NULL) { -- if (srcconfig->dns_len > SIZE_MAX / sizeof(char *)) { -- COMMAND_ERROR("Too many dns to add!"); -- ret = -1; -- goto out; -- } -- dstconfig->dns = util_common_calloc_s(srcconfig->dns_len * sizeof(char *)); -- if (dstconfig->dns == NULL) { -- ret = -1; -- goto out; -- } -- for (i = 0; i < srcconfig->dns_len; i++) { -- dstconfig->dns[dstconfig->dns_len] = util_strdup_s(srcconfig->dns[i]); -- dstconfig->dns_len++; -- } -+ if (util_dup_array_of_strings((const char **)srcconfig->dns, srcconfig->dns_len, &dstconfig->dns, -+ &dstconfig->dns_len) != 0) { -+ COMMAND_ERROR("Failed to dup dns"); -+ return -1; - } - --out: -- return ret; --} -- --static int pack_host_network_dns_options(host_config *dstconfig, const isula_host_config_t *srcconfig) --{ -- int ret = 0; -- size_t i = 0; -- -- /* dns options */ -- if (srcconfig->dns_options_len != 0 && srcconfig->dns_options != NULL) { -- if (srcconfig->dns_options_len > SIZE_MAX / sizeof(char *)) { -- COMMAND_ERROR("Too many dns options to add!"); -- ret = -1; -- goto out; -- } -- dstconfig->dns_options = util_common_calloc_s(srcconfig->dns_options_len * sizeof(char *)); -- if (dstconfig->dns_options == NULL) { -- ret = -1; -- goto out; -- } -- for (i = 0; i < srcconfig->dns_options_len; i++) { -- dstconfig->dns_options[dstconfig->dns_options_len] = util_strdup_s(srcconfig->dns_options[i]); -- dstconfig->dns_options_len++; -- } -+ if (util_dup_array_of_strings((const char **)srcconfig->dns_options, srcconfig->dns_options_len, -+ &dstconfig->dns_options, &dstconfig->dns_options_len) != 0) { -+ COMMAND_ERROR("Failed to dup dns options"); -+ return -1; - } - --out: -- return ret; --} -- --static int pack_host_network_dns_search(host_config *dstconfig, const isula_host_config_t *srcconfig) --{ -- int ret = 0; -- size_t i = 0; -- -- /* dns search */ -- if (srcconfig->dns_search_len != 0 && srcconfig->dns_search != NULL) { -- if (srcconfig->dns_search_len > SIZE_MAX / sizeof(char *)) { -- COMMAND_ERROR("Too many dns search to add!"); -- ret = -1; -- goto out; -- } -- dstconfig->dns_search = util_common_calloc_s(srcconfig->dns_search_len * sizeof(char *)); -- if (dstconfig->dns_search == NULL) { -- ret = -1; -- goto out; -- } -- for (i = 0; i < srcconfig->dns_search_len; i++) { -- dstconfig->dns_search[dstconfig->dns_search_len] = util_strdup_s(srcconfig->dns_search[i]); -- dstconfig->dns_search_len++; -- } -+ if (util_dup_array_of_strings((const char **)srcconfig->dns_search, srcconfig->dns_search_len, -+ &dstconfig->dns_search, &dstconfig->dns_search_len) != 0) { -+ COMMAND_ERROR("Failed to dup dns search"); -+ return -1; - } - --out: -- return ret; -+ return 0; - } - - static int pack_host_config_network(host_config *dstconfig, const isula_host_config_t *srcconfig) - { - int ret = 0; - -- if (dstconfig == NULL) { -- return -1; -- } -- - ret = pack_host_network_extra_hosts(dstconfig, srcconfig); - if (ret != 0) { - goto out; -@@ -331,16 +215,6 @@ static int pack_host_config_network(host_config *dstconfig, const isula_host_con - goto out; - } - -- ret = pack_host_network_dns_options(dstconfig, srcconfig); -- if (ret != 0) { -- goto out; -- } -- -- ret = pack_host_network_dns_search(dstconfig, srcconfig); -- if (ret != 0) { -- goto out; -- } -- - out: - return ret; - } -@@ -356,9 +230,8 @@ static int check_parsed_device(const host_config_devices_element *device_map) - } - - if (!util_file_exists(device_map->path_on_host)) { -- COMMAND_ERROR( -- "Error gathering device information while adding device \"%s\",stat %s:no such file or directory", -- device_map->path_on_host, device_map->path_on_host); -+ COMMAND_ERROR("Error gathering device information while adding device \"%s\",stat %s:no such file or directory", -+ device_map->path_on_host, device_map->path_on_host); - ret = -1; - goto out; - } -@@ -428,169 +301,6 @@ erro_out: - return NULL; - } - --static int check_ulimit_input(const char *val) --{ -- int ret = 0; -- if (val == NULL || strcmp(val, "") == 0) { -- COMMAND_ERROR("ulimit argument can't be empty"); -- ret = -1; -- goto out; -- } -- -- if (val[0] == '=' || val[strlen(val) - 1] == '=') { -- COMMAND_ERROR("Invalid ulimit argument: \"%s\", delimiter '=' can't" -- " be the first or the last character", val); -- ret = -1; -- } -- --out: -- return ret; --} -- --static void get_ulimit_split_parts(const char *val, char ***parts, size_t *parts_len, char deli) --{ -- *parts = util_string_split_multi(val, deli); -- if (*parts == NULL) { -- COMMAND_ERROR("Out of memory"); -- return; -- } -- *parts_len = util_array_len((const char **)(*parts)); --} -- --static int parse_soft_hard_ulimit(const char *val, char **limitvals, size_t limitvals_len, int64_t *soft, int64_t *hard) --{ -- int ret = 0; -- // parse soft -- ret = util_safe_llong(limitvals[0], (long long *)soft); -- if (ret < 0) { -- COMMAND_ERROR("Invalid ulimit soft value: \"%s\", parse int64 failed: %s", val, strerror(-ret)); -- ret = -1; -- goto out; -- } -- -- // parse hard if exists -- if (limitvals_len > 1) { -- ret = util_safe_llong(limitvals[1], (long long *)hard); -- if (ret < 0) { -- COMMAND_ERROR("Invalid ulimit hard value: \"%s\", parse int64 failed: %s", val, strerror(-ret)); -- ret = -1; -- goto out; -- } -- -- if (*soft > *hard) { -- COMMAND_ERROR("Ulimit soft limit must be less than or equal to hard limit: %lld > %lld", -- (long long int)(*soft), (long long int)(*hard)); -- ret = -1; -- goto out; -- } -- } else { -- *hard = *soft; // default to soft in case no hard was set -- } --out: -- return ret; --} -- --static int check_ulimit_type(const char *type) --{ -- int ret = 0; -- char **tmptype = NULL; -- char *ulimit_valid_type[] = { -- // "as", // Disabled since this doesn't seem usable with the way Docker inits a container. -- "core", "cpu", "data", "fsize", "locks", "memlock", "msgqueue", "nice", -- "nofile", "nproc", "rss", "rtprio", "rttime", "sigpending", "stack", NULL -- }; -- -- for (tmptype = ulimit_valid_type; *tmptype != NULL; tmptype++) { -- if (strcmp(type, *tmptype) == 0) { -- break; -- } -- } -- -- if (*tmptype == NULL) { -- COMMAND_ERROR("Invalid ulimit type: %s", type); -- ret = -1; -- } -- return ret; --} -- --static host_config_ulimits_element *parse_ulimit(const char *val) --{ -- int ret = 0; -- int64_t soft = 0; -- int64_t hard = 0; -- size_t parts_len = 0; -- size_t limitvals_len = 0; -- char **parts = NULL; -- char **limitvals = NULL; -- host_config_ulimits_element *ulimit = NULL; -- -- ret = check_ulimit_input(val); -- if (ret != 0) { -- return NULL; -- } -- -- get_ulimit_split_parts(val, &parts, &parts_len, '='); -- if (parts == NULL) { -- ERROR("Out of memory"); -- return NULL; -- } else if (parts_len != 2) { -- COMMAND_ERROR("Invalid ulimit argument: %s", val); -- ret = -1; -- goto out; -- } -- -- ret = check_ulimit_type(parts[0]); -- if (ret != 0) { -- ret = -1; -- goto out; -- } -- -- if (parts[1][0] == ':' || parts[1][strlen(parts[1]) - 1] == ':') { -- COMMAND_ERROR("Invalid ulimit value: \"%s\", delimiter ':' can't be the first" -- " or the last character", val); -- ret = -1; -- goto out; -- } -- -- // parse value -- get_ulimit_split_parts(parts[1], &limitvals, &limitvals_len, ':'); -- if (limitvals == NULL) { -- ret = -1; -- goto out; -- } -- -- if (limitvals_len > 2) { -- COMMAND_ERROR("Too many limit value arguments - %s, can only have up to two, `soft[:hard]`", -- parts[1]); -- ret = -1; -- goto out; -- } -- -- ret = parse_soft_hard_ulimit(val, limitvals, limitvals_len, &soft, &hard); -- if (ret < 0) { -- goto out; -- } -- -- ulimit = util_common_calloc_s(sizeof(host_config_ulimits_element)); -- if (ulimit == NULL) { -- ret = -1; -- goto out; -- } -- ulimit->name = util_strdup_s(parts[0]); -- ulimit->hard = hard; -- ulimit->soft = soft; -- --out: -- util_free_array(parts); -- util_free_array(limitvals); -- if (ret != 0) { -- free_host_config_ulimits_element(ulimit); -- ulimit = NULL; -- } -- -- return ulimit; --} -- - static void pack_cgroup_resources_cpu(host_config *dstconfig, const isula_host_config_t *srcconfig) - { - /* cgroup blkio weight */ -@@ -598,6 +308,11 @@ static void pack_cgroup_resources_cpu(host_config *dstconfig, const isula_host_c - dstconfig->blkio_weight = srcconfig->cr->blkio_weight; - } - -+ /* cpus */ -+ if (srcconfig->cr->nano_cpus != 0) { -+ dstconfig->nano_cpus = srcconfig->cr->nano_cpus; -+ } -+ - /* cpu shares */ - if (srcconfig->cr->cpu_shares) { - dstconfig->cpu_shares = srcconfig->cr->cpu_shares; -@@ -703,7 +418,7 @@ static int pack_hostconfig_ulimits(host_config *dstconfig, const isula_host_conf - bool exists = false; - host_config_ulimits_element *tmp = NULL; - -- tmp = parse_ulimit(srcconfig->ulimits[i]); -+ tmp = parse_opt_ulimit(srcconfig->ulimits[i]); - if (tmp == NULL) { - ret = -1; - goto out; -@@ -739,19 +454,19 @@ static int pack_hostconfig_cgroup(host_config *dstconfig, const isula_host_confi - return ret; - } - --static host_config_blkio_weight_device_element *pack_blkio_weight_devices(const char *devices) -+static defs_blkio_weight_device *pack_blkio_weight_devices(const char *devices) - { - char **tmp_str = NULL; - unsigned int weight = 0; - size_t tmp_str_len = 0; -- host_config_blkio_weight_device_element *weight_dev = NULL; -+ defs_blkio_weight_device *weight_dev = NULL; - - if (devices == NULL || !strcmp(devices, "")) { - COMMAND_ERROR("Weight devices can't be empty"); - return NULL; - } - -- weight_dev = util_common_calloc_s(sizeof(host_config_blkio_weight_device_element)); -+ weight_dev = util_common_calloc_s(sizeof(defs_blkio_weight_device)); - if (weight_dev == NULL) { - ERROR("Out of memory"); - return NULL; -@@ -793,11 +508,11 @@ static host_config_blkio_weight_device_element *pack_blkio_weight_devices(const - - erro_out: - util_free_array(tmp_str); -- free_host_config_blkio_weight_device_element(weight_dev); -+ free_defs_blkio_weight_device(weight_dev); - return NULL; - } - --static int parse_blkio_throttle_bps_device(const char *device, char **path, const uint64_t *rate) -+static int parse_blkio_throttle_bps_device(const char *device, char **path, uint64_t *rate) - { - int ret = 0; - char **split = NULL; -@@ -817,7 +532,8 @@ static int parse_blkio_throttle_bps_device(const char *device, char **path, cons - - if (util_parse_byte_size_string(split[1], (int64_t *)rate) != 0) { - COMMAND_ERROR("invalid rate for device: %s. The correct format is :[]." -- " Number must be a positive integer. Unit is optional and can be kb, mb, or gb", device); -+ " Number must be a positive integer. Unit is optional and can be kb, mb, or gb", -+ device); - ret = -1; - goto out; - } -@@ -829,19 +545,19 @@ out: - } - - // validate that the specified string has a valid device-rate format. --static host_config_blkio_device_read_bps_element *pack_throttle_read_bps_device(const char *device) -+static defs_blkio_device *pack_throttle_bps_device(const char *device) - { - char *path = NULL; - uint64_t rate = 0; -- host_config_blkio_device_read_bps_element *read_bps_dev = NULL; -+ defs_blkio_device *bps_dev = NULL; - - if (device == NULL || !strcmp(device, "")) { - COMMAND_ERROR("blkio throttle read bps device can't be empty"); - return NULL; - } - -- read_bps_dev = util_common_calloc_s(sizeof(host_config_blkio_device_read_bps_element)); -- if (read_bps_dev == NULL) { -+ bps_dev = util_common_calloc_s(sizeof(defs_blkio_device)); -+ if (bps_dev == NULL) { - ERROR("Out of memory"); - return NULL; - } -@@ -850,47 +566,88 @@ static host_config_blkio_device_read_bps_element *pack_throttle_read_bps_device( - goto error_out; - } - -- read_bps_dev->path = path; -- read_bps_dev->rate = rate; -+ bps_dev->path = path; -+ bps_dev->rate = rate; - -- return read_bps_dev; -+ return bps_dev; - - error_out: - free(path); -- free_host_config_blkio_device_read_bps_element(read_bps_dev); -+ free_defs_blkio_device(bps_dev); - return NULL; - } - -+static int parse_blkio_throttle_iops_device(const char *device, char **path, uint64_t *rate) -+{ -+ int ret = 0; -+ char **split = NULL; -+ -+ split = util_string_split_multi(device, ':'); -+ if (split == NULL || util_array_len((const char **)split) != 2) { -+ COMMAND_ERROR("bad format: %s", device); -+ ret = -1; -+ goto out; -+ } -+ -+ if (strncmp(split[0], "/dev/", strlen("/dev/")) != 0) { -+ COMMAND_ERROR("bad format for device path: %s", device); -+ ret = -1; -+ goto out; -+ } -+ -+ if (!util_valid_positive_interger(split[1])) { -+ COMMAND_ERROR("invalid rate for device: %s. The correct format is :." -+ " Number must be unsigned 64 bytes integer.", -+ device); -+ ret = -1; -+ goto out; -+ } -+ -+ if (util_safe_uint64(split[1], rate) != 0) { -+ COMMAND_ERROR("invalid rate for device: %s. The correct format is :." -+ " Number must be unsigned 64 bytes integer.", -+ device); -+ ret = -1; -+ goto out; -+ } -+ -+ *path = util_strdup_s(split[0]); -+ -+out: -+ util_free_array(split); -+ return ret; -+} -+ - // validate that the specified string has a valid device-rate format. --static host_config_blkio_device_write_bps_element *pack_throttle_write_bps_device(const char *device) -+static defs_blkio_device *pack_throttle_iops_device(const char *device) - { - char *path = NULL; - uint64_t rate = 0; -- host_config_blkio_device_write_bps_element *write_bps_dev = NULL; -+ defs_blkio_device *iops_dev = NULL; - - if (device == NULL || !strcmp(device, "")) { -- COMMAND_ERROR("blkio throttle write bps device can't be empty"); -+ COMMAND_ERROR("blkio throttle read bps device can't be empty"); - return NULL; - } - -- write_bps_dev = util_common_calloc_s(sizeof(host_config_blkio_device_write_bps_element)); -- if (write_bps_dev == NULL) { -+ iops_dev = util_common_calloc_s(sizeof(defs_blkio_device)); -+ if (iops_dev == NULL) { - ERROR("Out of memory"); - return NULL; - } - -- if (parse_blkio_throttle_bps_device(device, &path, &rate) != 0) { -+ if (parse_blkio_throttle_iops_device(device, &path, &rate) != 0) { - goto error_out; - } - -- write_bps_dev->path = path; -- write_bps_dev->rate = rate; -+ iops_dev->path = path; -+ iops_dev->rate = rate; - -- return write_bps_dev; -+ return iops_dev; - - error_out: - free(path); -- free_host_config_blkio_device_write_bps_element(write_bps_dev); -+ free_defs_blkio_device(iops_dev); - return NULL; - } - -@@ -1034,7 +791,7 @@ static bool parse_host_path(const char *input, const char *token, host_config_ho - COMMAND_ERROR("Host channel host path should be absolute: %s", token); - return false; - } -- if (cleanpath(token, real_path, sizeof(real_path)) == NULL) { -+ if (util_clean_path(token, real_path, sizeof(real_path)) == NULL) { - ERROR("Failed to clean path: '%s'", token); - return false; - } -@@ -1058,7 +815,7 @@ static bool parse_container_path(const char *input, const char *token, host_conf - COMMAND_ERROR("Host channel container path should be absolute: %s", token); - return false; - } -- if (cleanpath(token, real_path, sizeof(real_path)) == NULL) { -+ if (util_clean_path(token, real_path, sizeof(real_path)) == NULL) { - ERROR("Failed to clean path: '%s'", token); - return false; - } -@@ -1178,25 +935,10 @@ erro_out: - } - static int append_no_new_privileges_to_security_opts(host_config *dstconfig) - { -- int ret = 0; -- size_t new_size, old_size; -- char **tmp_security_opt = NULL; -- -- if (dstconfig->security_opt_len > (SIZE_MAX / sizeof(char *)) - 1) { -- COMMAND_ERROR("Out of memory"); -- return -1; -- } -- new_size = (dstconfig->security_opt_len + 1) * sizeof(char *); -- old_size = dstconfig->security_opt_len * sizeof(char *); -- ret = mem_realloc((void **)(&tmp_security_opt), new_size, (void *)dstconfig->security_opt, old_size); -- if (ret != 0) { -- COMMAND_ERROR("Out of memory"); -- return ret; -- } -- dstconfig->security_opt = tmp_security_opt; -- dstconfig->security_opt[dstconfig->security_opt_len++] = util_strdup_s("no-new-privileges"); -+ dstconfig->security_opt[dstconfig->security_opt_len] = util_strdup_s("no-new-privileges"); -+ dstconfig->security_opt_len++; - -- return ret; -+ return 0; - } - - static int append_seccomp_to_security_opts(const char *full_opt, const char *seccomp_file, host_config *dstconfig) -@@ -1218,8 +960,7 @@ static int append_seccomp_to_security_opts(const char *full_opt, const char *sec - - seccomp_spec = get_seccomp_security_opt_spec(seccomp_file); - if (seccomp_spec == NULL) { -- ERROR("Failed to parse docker format seccomp specification file \"%s\", error message: %s", -- seccomp_file, err); -+ ERROR("Failed to parse docker format seccomp specification file \"%s\", error message: %s", seccomp_file, err); - COMMAND_ERROR("failed to parse seccomp file: %s", seccomp_file); - ret = -1; - goto out; -@@ -1262,29 +1003,15 @@ out: - return ret; - } - -+#ifdef ENABLE_SELINUX - static int append_selinux_label_to_security_opts(const char *selinux_label, host_config *dstconfig) - { -- int ret = 0; -- size_t new_size; -- size_t old_size; -- char **tmp_security_opt = NULL; -- -- if (dstconfig->security_opt_len > (SIZE_MAX / sizeof(char *)) - 1) { -- COMMAND_ERROR("Too large security options"); -- return -1; -- } -- new_size = (dstconfig->security_opt_len + 1) * sizeof(char *); -- old_size = dstconfig->security_opt_len * sizeof(char *); -- ret = mem_realloc((void **)(&tmp_security_opt), new_size, (void *)dstconfig->security_opt, old_size); -- if (ret != 0) { -- COMMAND_ERROR("Out of memory"); -- return ret; -- } -- dstconfig->security_opt = tmp_security_opt; -- dstconfig->security_opt[dstconfig->security_opt_len++] = util_strdup_s(selinux_label); -+ dstconfig->security_opt[dstconfig->security_opt_len] = util_strdup_s(selinux_label); -+ dstconfig->security_opt_len++; - -- return ret; -+ return 0; - } -+#endif - - static int parse_security_opts(const isula_host_config_t *srcconfig, host_config *dstconfig) - { -@@ -1303,8 +1030,10 @@ static int parse_security_opts(const isula_host_config_t *srcconfig, host_config - } else { - if (strcmp(items[0], "seccomp") == 0) { - ret = append_seccomp_to_security_opts(srcconfig->security[i], items[1], dstconfig); -+#ifdef ENABLE_SELINUX - } else if (strcmp(items[0], "label") == 0) { - ret = append_selinux_label_to_security_opts(srcconfig->security[i], dstconfig); -+#endif - } else { - ret = -1; - } -@@ -1325,61 +1054,55 @@ out: - return ret; - } - --int generate_storage_opts(host_config **dstconfig, const isula_host_config_t *srcconfig) -+int generate_storage_opts(host_config *dstconfig, const isula_host_config_t *srcconfig) - { - int ret = 0; -- size_t j; - -- if (srcconfig->storage_opts == NULL || dstconfig == NULL) { -+ if (srcconfig->storage_opts == NULL) { - goto out; - } - -- (*dstconfig)->storage_opt = util_common_calloc_s(sizeof(json_map_string_string)); -- if ((*dstconfig)->storage_opt == NULL) { -+ dstconfig->storage_opt = util_common_calloc_s(sizeof(json_map_string_string)); -+ if (dstconfig->storage_opt == NULL) { - ret = -1; - goto out; - } -- for (j = 0; j < srcconfig->storage_opts->len; j++) { -- ret = append_json_map_string_string((*dstconfig)->storage_opt, -- srcconfig->storage_opts->keys[j], -- srcconfig->storage_opts->values[j]); -- if (ret != 0) { -- ERROR("Append map failed"); -- ret = -1; -- goto out; -- } -- } - --out: -+ if (dup_json_map_string_string(srcconfig->storage_opts, dstconfig->storage_opt) != 0) { -+ COMMAND_ERROR("Failed to dup storage opts"); -+ ret = -1; -+ goto out; -+ } -+ -+out: - return ret; - } - --static int generate_sysctls(host_config **dstconfig, const isula_host_config_t *srcconfig) -+static int generate_sysctls(host_config *dstconfig, const isula_host_config_t *srcconfig) - { - int ret = 0; -- size_t j; - -- if (srcconfig->sysctls == NULL || dstconfig == NULL) { -+ if (srcconfig->sysctls == NULL) { - goto out; - } - -- (*dstconfig)->sysctls = util_common_calloc_s(sizeof(json_map_string_string)); -- if ((*dstconfig)->sysctls == NULL) { -+ dstconfig->sysctls = util_common_calloc_s(sizeof(json_map_string_string)); -+ if (dstconfig->sysctls == NULL) { - ret = -1; - goto out; - } -- for (j = 0; j < srcconfig->sysctls->len; j++) { -- ret = append_json_map_string_string((*dstconfig)->sysctls, srcconfig->sysctls->keys[j], -- srcconfig->sysctls->values[j]); -- if (ret < 0) { -- goto out; -- } -+ -+ if (dup_json_map_string_string(srcconfig->sysctls, dstconfig->sysctls) != 0) { -+ COMMAND_ERROR("Failed to dup sysctls"); -+ ret = -1; -+ goto out; - } -+ - out: - return ret; - } - --int generate_devices(host_config **dstconfig, const isula_host_config_t *srcconfig) -+int generate_devices(host_config *dstconfig, const isula_host_config_t *srcconfig) - { - int ret = 0; - size_t i = 0; -@@ -1393,26 +1116,26 @@ int generate_devices(host_config **dstconfig, const isula_host_config_t *srcconf - ret = -1; - goto out; - } -- (*dstconfig)->devices = util_common_calloc_s(sizeof(host_config_devices_element *) * srcconfig->devices_len); -- if ((*dstconfig)->devices == NULL) { -+ dstconfig->devices = util_common_calloc_s(sizeof(host_config_devices_element *) * srcconfig->devices_len); -+ if (dstconfig->devices == NULL) { - ret = -1; - goto out; - } - for (i = 0; i < srcconfig->devices_len; i++) { -- (*dstconfig)->devices[i] = parse_device(srcconfig->devices[i]); -- if ((*dstconfig)->devices[i] == NULL) { -+ dstconfig->devices[i] = parse_device(srcconfig->devices[i]); -+ if (dstconfig->devices[i] == NULL) { - ERROR("Failed to parse devices:%s", srcconfig->devices[i]); - ret = -1; - goto out; - } - -- (*dstconfig)->devices_len++; -+ dstconfig->devices_len++; - } - out: - return ret; - } - --static int generate_blkio_weight_device(host_config **dstconfig, const isula_host_config_t *srcconfig) -+static int generate_blkio_weight_device(host_config *dstconfig, const isula_host_config_t *srcconfig) - { - int ret = 0; - size_t i = 0; -@@ -1421,118 +1144,153 @@ static int generate_blkio_weight_device(host_config **dstconfig, const isula_hos - goto out; - } - -- if (srcconfig->blkio_weight_device_len > SIZE_MAX / sizeof(host_config_blkio_weight_device_element *)) { -- ERROR("Too many blkio weight devies to get!"); -+ dstconfig->blkio_weight_device = -+ util_smart_calloc_s(sizeof(defs_blkio_weight_device *), srcconfig->blkio_weight_device_len); -+ if (dstconfig->blkio_weight_device == NULL) { - ret = -1; - goto out; - } - -- (*dstconfig)->blkio_weight_device = -- util_common_calloc_s(srcconfig->blkio_weight_device_len * sizeof(host_config_blkio_weight_device_element *)); -- if ((*dstconfig)->blkio_weight_device == NULL) { -- ret = -1; -- goto out; -- } - for (i = 0; i < srcconfig->blkio_weight_device_len; i++) { -- (*dstconfig)->blkio_weight_device[(*dstconfig)->blkio_weight_device_len] = -+ dstconfig->blkio_weight_device[dstconfig->blkio_weight_device_len] = - pack_blkio_weight_devices(srcconfig->blkio_weight_device[i]); -- if ((*dstconfig)->blkio_weight_device[(*dstconfig)->blkio_weight_device_len] == NULL) { -+ if (dstconfig->blkio_weight_device[dstconfig->blkio_weight_device_len] == NULL) { - ERROR("Failed to get blkio weight devies"); - ret = -1; - goto out; - } - -- (*dstconfig)->blkio_weight_device_len++; -+ dstconfig->blkio_weight_device_len++; - } - out: - return ret; - } - --static int generate_blkio_throttle_read_bps_device(host_config **dstconfig, const isula_host_config_t *srcconfig) -+static int generate_blkio_throttle_read_bps_device(host_config *dstconfig, const isula_host_config_t *srcconfig) - { - int ret = 0; - size_t i = 0; - -- if (dstconfig == NULL || *dstconfig == NULL) { -+ if (srcconfig->blkio_throttle_read_bps_device == NULL || srcconfig->blkio_throttle_read_bps_device_len == 0) { - goto out; - } - -- if (srcconfig->blkio_throttle_read_bps_device == NULL || srcconfig->blkio_throttle_read_bps_device_len == 0) { -+ dstconfig->blkio_device_read_bps = -+ util_smart_calloc_s(sizeof(defs_blkio_device *), srcconfig->blkio_throttle_read_bps_device_len); -+ if (dstconfig->blkio_device_read_bps == NULL) { -+ ret = -1; - goto out; - } - -- if (srcconfig->blkio_throttle_read_bps_device_len > -- SIZE_MAX / sizeof(host_config_blkio_device_read_bps_element *)) { -- ERROR("Too many blkio throttle read bps devies to get!"); -- ret = -1; -+ for (i = 0; i < srcconfig->blkio_throttle_read_bps_device_len; i++) { -+ dstconfig->blkio_device_read_bps[dstconfig->blkio_device_read_bps_len] = -+ pack_throttle_bps_device(srcconfig->blkio_throttle_read_bps_device[i]); -+ if (dstconfig->blkio_device_read_bps[dstconfig->blkio_device_read_bps_len] == NULL) { -+ ERROR("Failed to get blkio throttle read bps devices"); -+ ret = -1; -+ goto out; -+ } -+ -+ dstconfig->blkio_device_read_bps_len++; -+ } -+out: -+ return ret; -+} -+ -+static int generate_blkio_throttle_write_bps_device(host_config *dstconfig, const isula_host_config_t *srcconfig) -+{ -+ int ret = 0; -+ size_t i = 0; -+ -+ if (srcconfig->blkio_throttle_write_bps_device == NULL || srcconfig->blkio_throttle_write_bps_device_len == 0) { - goto out; - } - -- (*dstconfig)->blkio_device_read_bps = -- util_common_calloc_s(srcconfig->blkio_throttle_read_bps_device_len * -- sizeof(host_config_blkio_device_read_bps_element *)); -- if ((*dstconfig)->blkio_device_read_bps == NULL) { -+ dstconfig->blkio_device_write_bps = -+ util_smart_calloc_s(sizeof(defs_blkio_device *), srcconfig->blkio_throttle_write_bps_device_len); -+ if (dstconfig->blkio_device_write_bps == NULL) { - ret = -1; - goto out; - } -- for (i = 0; i < srcconfig->blkio_throttle_read_bps_device_len; i++) { -- (*dstconfig)->blkio_device_read_bps[(*dstconfig)->blkio_device_read_bps_len] = -- pack_throttle_read_bps_device(srcconfig->blkio_throttle_read_bps_device[i]); -- if ((*dstconfig)->blkio_device_read_bps[(*dstconfig)->blkio_device_read_bps_len] == NULL) { -- ERROR("Failed to get blkio throttle read bps devices"); -+ -+ for (i = 0; i < srcconfig->blkio_throttle_write_bps_device_len; i++) { -+ dstconfig->blkio_device_write_bps[dstconfig->blkio_device_write_bps_len] = -+ pack_throttle_bps_device(srcconfig->blkio_throttle_write_bps_device[i]); -+ if (dstconfig->blkio_device_write_bps[dstconfig->blkio_device_write_bps_len] == NULL) { -+ ERROR("Failed to get blkio throttle write bps devices"); - ret = -1; - goto out; - } - -- (*dstconfig)->blkio_device_read_bps_len++; -+ dstconfig->blkio_device_write_bps_len++; - } - out: - return ret; - } - --static int generate_blkio_throttle_write_bps_device(host_config **dstconfig, const isula_host_config_t *srcconfig) -+static int generate_blkio_throttle_read_iops_device(host_config *dstconfig, const isula_host_config_t *srcconfig) - { - int ret = 0; - size_t i = 0; - -- if (dstconfig == NULL || *dstconfig == NULL) { -+ if (srcconfig->blkio_throttle_read_iops_device == NULL || srcconfig->blkio_throttle_read_iops_device_len == 0) { - goto out; - } - -- if (srcconfig->blkio_throttle_write_bps_device == NULL || srcconfig->blkio_throttle_write_bps_device_len == 0) { -+ dstconfig->blkio_device_read_iops = -+ util_smart_calloc_s(sizeof(defs_blkio_device *), srcconfig->blkio_throttle_read_iops_device_len); -+ if (dstconfig->blkio_device_read_iops == NULL) { -+ ret = -1; - goto out; - } - -+ for (i = 0; i < srcconfig->blkio_throttle_read_iops_device_len; i++) { -+ dstconfig->blkio_device_read_iops[dstconfig->blkio_device_read_iops_len] = -+ pack_throttle_iops_device(srcconfig->blkio_throttle_read_iops_device[i]); -+ if (dstconfig->blkio_device_read_iops[dstconfig->blkio_device_read_iops_len] == NULL) { -+ ERROR("Failed to get blkio throttle read iops devices"); -+ ret = -1; -+ goto out; -+ } - -- if (srcconfig->blkio_throttle_write_bps_device_len > -- SIZE_MAX / sizeof(host_config_blkio_device_write_bps_element *)) { -- ERROR("Too many blkio throttle write bps devies to get!"); -- ret = -1; -+ dstconfig->blkio_device_read_iops_len++; -+ } -+out: -+ return ret; -+} -+ -+static int generate_blkio_throttle_write_iops_device(host_config *dstconfig, const isula_host_config_t *srcconfig) -+{ -+ int ret = 0; -+ size_t i = 0; -+ -+ if (srcconfig->blkio_throttle_write_iops_device == NULL || srcconfig->blkio_throttle_write_iops_device_len == 0) { - goto out; - } - -- (*dstconfig)->blkio_device_write_bps = util_common_calloc_s(srcconfig->blkio_throttle_write_bps_device_len * -- sizeof(host_config_blkio_device_write_bps_element *)); -- if ((*dstconfig)->blkio_device_write_bps == NULL) { -+ dstconfig->blkio_device_write_iops = -+ util_smart_calloc_s(sizeof(defs_blkio_device *), srcconfig->blkio_throttle_write_iops_device_len); -+ if (dstconfig->blkio_device_write_iops == NULL) { - ret = -1; - goto out; - } -- for (i = 0; i < srcconfig->blkio_throttle_write_bps_device_len; i++) { -- (*dstconfig)->blkio_device_write_bps[(*dstconfig)->blkio_device_write_bps_len] = -- pack_throttle_write_bps_device(srcconfig->blkio_throttle_write_bps_device[i]); -- if ((*dstconfig)->blkio_device_write_bps[(*dstconfig)->blkio_device_write_bps_len] == NULL) { -- ERROR("Failed to get blkio throttle write bps devices"); -+ -+ for (i = 0; i < srcconfig->blkio_throttle_write_iops_device_len; i++) { -+ dstconfig->blkio_device_write_iops[dstconfig->blkio_device_write_iops_len] = -+ pack_throttle_iops_device(srcconfig->blkio_throttle_write_iops_device[i]); -+ if (dstconfig->blkio_device_write_iops[dstconfig->blkio_device_write_iops_len] == NULL) { -+ ERROR("Failed to get blkio throttle write iops devices"); - ret = -1; - goto out; - } - -- (*dstconfig)->blkio_device_write_bps_len++; -+ dstconfig->blkio_device_write_iops_len++; - } - out: - return ret; - } - --static int generate_blkio(host_config **dstconfig, const isula_host_config_t *srcconfig) -+static int generate_blkio(host_config *dstconfig, const isula_host_config_t *srcconfig) - { - int ret; - -@@ -1541,6 +1299,7 @@ static int generate_blkio(host_config **dstconfig, const isula_host_config_t *sr - if (ret < 0) { - goto out; - } -+ - /* blkio throttle read bps devies */ - ret = generate_blkio_throttle_read_bps_device(dstconfig, srcconfig); - if (ret < 0) { -@@ -1553,11 +1312,23 @@ static int generate_blkio(host_config **dstconfig, const isula_host_config_t *sr - goto out; - } - -+ /* blkio throttle read iops devies */ -+ ret = generate_blkio_throttle_read_iops_device(dstconfig, srcconfig); -+ if (ret < 0) { -+ goto out; -+ } -+ -+ /* blkio throttle write iops devies */ -+ ret = generate_blkio_throttle_write_iops_device(dstconfig, srcconfig); -+ if (ret < 0) { -+ goto out; -+ } -+ - out: - return ret; - } - --int generate_hugetlb_limits(host_config **dstconfig, const isula_host_config_t *srcconfig) -+int generate_hugetlb_limits(host_config *dstconfig, const isula_host_config_t *srcconfig) - { - int ret = 0; - size_t i = 0; -@@ -1572,83 +1343,59 @@ int generate_hugetlb_limits(host_config **dstconfig, const isula_host_config_t * - goto out; - } - -- (*dstconfig)->hugetlbs = util_common_calloc_s(srcconfig->hugetlbs_len * sizeof(host_config_hugetlbs_element *)); -- if ((*dstconfig)->hugetlbs == NULL) { -+ dstconfig->hugetlbs = util_common_calloc_s(srcconfig->hugetlbs_len * sizeof(host_config_hugetlbs_element *)); -+ if (dstconfig->hugetlbs == NULL) { - ret = -1; - goto out; - } - for (i = 0; i < srcconfig->hugetlbs_len; i++) { -- (*dstconfig)->hugetlbs[(*dstconfig)->hugetlbs_len] = pase_hugetlb_limit(srcconfig->hugetlbs[i]); -- if ((*dstconfig)->hugetlbs[(*dstconfig)->hugetlbs_len] == NULL) { -+ dstconfig->hugetlbs[dstconfig->hugetlbs_len] = pase_hugetlb_limit(srcconfig->hugetlbs[i]); -+ if (dstconfig->hugetlbs[dstconfig->hugetlbs_len] == NULL) { - ERROR("Failed to get hugepage limits"); - ret = -1; - goto out; - } - -- (*dstconfig)->hugetlbs_len++; -+ dstconfig->hugetlbs_len++; - } - out: - return ret; - } - --int generate_binds(host_config **dstconfig, const isula_host_config_t *srcconfig) -+int generate_binds(host_config *dstconfig, const isula_host_config_t *srcconfig) - { -- int ret = 0; -- size_t i = 0; -- -- if (srcconfig->binds == NULL || srcconfig->binds_len == 0) { -- goto out; -+ if (util_dup_array_of_strings((const char **)srcconfig->binds, srcconfig->binds_len, &dstconfig->binds, -+ &dstconfig->binds_len) != 0) { -+ COMMAND_ERROR("Failed to dup binds"); -+ return -1; - } - -- if (srcconfig->binds_len > SIZE_MAX / sizeof(char *)) { -- COMMAND_ERROR("Too many binds to mount!"); -- ret = -1; -- goto out; -- } -+ return 0; -+} - -- (*dstconfig)->binds = util_common_calloc_s(srcconfig->binds_len * sizeof(char *)); -- if ((*dstconfig)->binds == NULL) { -- ret = -1; -- goto out; -- } -- for (i = 0; i < srcconfig->binds_len; i++) { -- (*dstconfig)->binds[(*dstconfig)->binds_len] = util_strdup_s(srcconfig->binds[i]); -- (*dstconfig)->binds_len++; -+int generate_device_cgroup_rules(host_config *dstconfig, const isula_host_config_t *srcconfig) -+{ -+ if (util_dup_array_of_strings((const char **)srcconfig->device_cgroup_rules, srcconfig->device_cgroup_rules_len, -+ &dstconfig->device_cgroup_rules, &dstconfig->device_cgroup_rules_len) != 0) { -+ COMMAND_ERROR("Failed to dup device cgroup rules"); -+ return -1; - } - --out: -- return ret; -+ return 0; - } - --int generate_groups(host_config **dstconfig, const isula_host_config_t *srcconfig) -+int generate_groups(host_config *dstconfig, const isula_host_config_t *srcconfig) - { -- int ret = 0; -- size_t i = 0; -- -- if (srcconfig->group_add == NULL || srcconfig->group_add_len == 0 || dstconfig == NULL) { -- goto out; -- } -- -- if (srcconfig->group_add_len > SIZE_MAX / sizeof(char *)) { -- COMMAND_ERROR("Too many groups to add!"); -- ret = -1; -- goto out; -+ if (util_dup_array_of_strings((const char **)srcconfig->group_add, srcconfig->group_add_len, &dstconfig->group_add, -+ &dstconfig->group_add_len) != 0) { -+ COMMAND_ERROR("Failed to dup device group add"); -+ return -1; - } - -- (*dstconfig)->group_add = util_common_calloc_s(srcconfig->group_add_len * sizeof(char *)); -- if ((*dstconfig)->group_add == NULL) { -- ret = -1; -- goto out; -- } -- for (i = 0; i < srcconfig->group_add_len; i++) { -- (*dstconfig)->group_add[(*dstconfig)->group_add_len] = util_strdup_s(srcconfig->group_add[i]); -- (*dstconfig)->group_add_len++; -- } --out: -- return ret; -+ return 0; - } - --int generate_security(host_config **dstconfig, const isula_host_config_t *srcconfig) -+int generate_security(host_config *dstconfig, const isula_host_config_t *srcconfig) - { - int ret = 0; - -@@ -1662,13 +1409,13 @@ int generate_security(host_config **dstconfig, const isula_host_config_t *srccon - goto out; - } - -- (*dstconfig)->security_opt = util_common_calloc_s(srcconfig->security_len * sizeof(char *)); -- if ((*dstconfig)->security_opt == NULL) { -+ dstconfig->security_opt = util_common_calloc_s(srcconfig->security_len * sizeof(char *)); -+ if (dstconfig->security_opt == NULL) { - ret = -1; - goto out; - } - -- if (parse_security_opts(srcconfig, (*dstconfig)) != 0) { -+ if (parse_security_opts(srcconfig, dstconfig) != 0) { - ret = -1; - goto out; - } -@@ -1703,12 +1450,12 @@ static int pack_host_config_common(host_config *dstconfig, const isula_host_conf - goto out; - } - -- ret = generate_storage_opts(&dstconfig, srcconfig); -+ ret = generate_storage_opts(dstconfig, srcconfig); - if (ret < 0) { - goto out; - } - -- ret = generate_sysctls(&dstconfig, srcconfig); -+ ret = generate_sysctls(dstconfig, srcconfig); - if (ret < 0) { - goto out; - } -@@ -1719,40 +1466,47 @@ static int pack_host_config_common(host_config *dstconfig, const isula_host_conf - } - - /* devices which will be populated into container */ -- ret = generate_devices(&dstconfig, srcconfig); -+ ret = generate_devices(dstconfig, srcconfig); - if (ret < 0) { - goto out; - } - - /* blkio device */ -- ret = generate_blkio(&dstconfig, srcconfig); -+ ret = generate_blkio(dstconfig, srcconfig); - if (ret < 0) { - goto out; - } - - /* hugepage limits */ -- ret = generate_hugetlb_limits(&dstconfig, srcconfig); -+ ret = generate_hugetlb_limits(dstconfig, srcconfig); - if (ret < 0) { - goto out; - } - - /* binds to mount */ -- ret = generate_binds(&dstconfig, srcconfig); -+ ret = generate_binds(dstconfig, srcconfig); - if (ret < 0) { - goto out; - } - - /* groups to add */ -- ret = generate_groups(&dstconfig, srcconfig); -+ ret = generate_groups(dstconfig, srcconfig); - if (ret < 0) { - goto out; - } - - /* security opt */ -- ret = generate_security(&dstconfig, srcconfig); -+ ret = generate_security(dstconfig, srcconfig); -+ if (ret < 0) { -+ goto out; -+ } -+ -+ /* device cgroup rules*/ -+ ret = generate_device_cgroup_rules(dstconfig, srcconfig); - if (ret < 0) { - goto out; - } -+ - out: - return ret; - } -@@ -1764,7 +1518,7 @@ int generate_hostconfig(const isula_host_config_t *srcconfig, char **hostconfigs - host_config *dstconfig = NULL; - struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 }; - -- dstconfig = util_common_calloc_s(sizeof(*dstconfig)); -+ dstconfig = util_common_calloc_s(sizeof(host_config)); - if (dstconfig == NULL) { - ret = -1; - goto out; -@@ -1823,421 +1577,155 @@ out: - return ret; - } - --static int pack_container_custom_config_args(container_config *container_spec, -- const isula_container_config_t *custom_conf) -+void isula_ns_change_files_free(isula_host_config_t *hostconfig) - { -- int ret = 0; -- int i; -- -- /* entrypoint */ -- if (util_valid_str(custom_conf->entrypoint)) { -- container_spec->entrypoint = util_common_calloc_s(sizeof(char *)); -- if (container_spec->entrypoint == NULL) { -- ret = -1; -- goto out; -- } -- container_spec->entrypoint[0] = util_strdup_s(custom_conf->entrypoint); -- container_spec->entrypoint_len++; -- } -- -- /* commands */ -- if ((custom_conf->cmd_len != 0 && custom_conf->cmd)) { -- if (custom_conf->cmd_len > SIZE_MAX / sizeof(char *)) { -- COMMAND_ERROR("The length of cmd is too long!"); -- ret = -1; -- goto out; -- } -- container_spec->cmd = util_common_calloc_s(custom_conf->cmd_len * sizeof(char *)); -- if (container_spec->cmd == NULL) { -- ret = -1; -- goto out; -- } -- for (i = 0; i < (int)custom_conf->cmd_len; i++) { -- container_spec->cmd[container_spec->cmd_len] = util_strdup_s(custom_conf->cmd[i]); -- container_spec->cmd_len++; -- } -- } -- --out: -- return ret; --} -- --static int pack_container_custom_config_mounts(container_config *container_spec, -- const isula_container_config_t *custom_conf) --{ -- int ret = 0; -- int i = 0; -- -- /* mounts to mount filesystem */ -- if (custom_conf->mounts != NULL && custom_conf->mounts_len > 0) { -- if (custom_conf->mounts_len > SIZE_MAX / sizeof(char *)) { -- COMMAND_ERROR("Too many mounts to mount filesystem!"); -- ret = -1; -- goto out; -- } -- container_spec->mounts = util_common_calloc_s(custom_conf->mounts_len * sizeof(char *)); -- if (container_spec->mounts == NULL) { -- ret = -1; -- goto out; -- } -- for (i = 0; i < (int)custom_conf->mounts_len; i++) { -- container_spec->mounts[container_spec->mounts_len] = util_strdup_s(custom_conf->mounts[i]); -- container_spec->mounts_len++; -- } -- } --out: -- return ret; --} -- --static int pack_container_custom_config_array(container_config *container_spec, -- const isula_container_config_t *custom_conf) --{ -- int ret = 0; -- int i = 0; -- -- /* environment variables */ -- if (custom_conf->env_len != 0 && custom_conf->env) { -- if (custom_conf->env_len > SIZE_MAX / sizeof(char *)) { -- COMMAND_ERROR("Too many environment variables"); -- return -1; -- } -- container_spec->env = util_common_calloc_s(custom_conf->env_len * sizeof(char *)); -- if (container_spec->env == NULL) { -- ret = -1; -- goto out; -- } -- for (i = 0; i < (int)custom_conf->env_len; i++) { -- container_spec->env[container_spec->env_len] = util_strdup_s(custom_conf->env[i]); -- container_spec->env_len++; -- } -- } -- --out: -- return ret; --} -- --static int get_label_key_value(const char *label, char **key, char **value) --{ -- int ret = 0; -- char **arr = util_string_split_n(label, '=', 2); -- if (arr == NULL) { -- ERROR("Failed to split input label"); -- ret = -1; -- goto out; -- } -- -- *key = util_strdup_s(arr[0]); -- if (util_array_len((const char **)arr) == 1) { -- *value = util_strdup_s(""); -- } else { -- *value = util_strdup_s(arr[1]); -+ if (hostconfig == NULL) { -+ return; - } - --out: -- util_free_array(arr); -- return ret; -+ util_free_array_by_len(hostconfig->ns_change_files, hostconfig->ns_change_files_len); -+ hostconfig->ns_change_files = NULL; -+ hostconfig->ns_change_files_len = 0; - } - --static int pack_container_custom_config_labels(container_config *container_spec, -- const isula_container_config_t *custom_conf) -+void isula_host_config_storage_opts_free(isula_host_config_t *hostconfig) - { -- int ret = 0; -- int i; -- char *key = NULL; -- char *value = NULL; -- -- if (custom_conf->label_len == 0 || custom_conf->label == NULL) { -- return 0; -- } -- -- /* labels */ -- container_spec->labels = util_common_calloc_s(sizeof(json_map_string_string)); -- if (container_spec->labels == NULL) { -- ERROR("Out of memory"); -- ret = -1; -- goto out; -- } -- -- for (i = 0; i < custom_conf->label_len; i++) { -- if (get_label_key_value(custom_conf->label[i], &key, &value) != 0) { -- ERROR("Failed to get key and value of label"); -- ret = -1; -- goto out; -- } -- -- if (append_json_map_string_string(container_spec->labels, key, value)) { -- ERROR("Append map failed"); -- ret = -1; -- goto out; -- } -- free(key); -- key = NULL; -- free(value); -- value = NULL; -+ if (hostconfig == NULL) { -+ return; - } - --out: -- free(key); -- free(value); -- return ret; -+ free_json_map_string_string(hostconfig->storage_opts); -+ hostconfig->storage_opts = NULL; - } - --static bool have_health_check(const isula_container_config_t *custom_conf) -+void isula_host_config_sysctl_free(isula_host_config_t *hostconfig) - { -- bool have_health_settings = false; -- -- if ((custom_conf->health_cmd != NULL && strlen(custom_conf->health_cmd) != 0) || -- custom_conf->health_interval != 0 || custom_conf->health_timeout != 0 || -- custom_conf->health_start_period != 0 || custom_conf->health_retries != 0) { -- have_health_settings = true; -+ if (hostconfig == NULL) { -+ return; - } - -- return have_health_settings; -+ free_json_map_string_string(hostconfig->sysctls); -+ hostconfig->sysctls = NULL; - } - --static int pack_custom_no_health_check(container_config *container_spec, bool have_health_settings, -- defs_health_check *health_config) -+/* container cgroup resources free */ -+static void container_cgroup_resources_free(container_cgroup_resources_t *cr) - { -- int ret = 0; -- -- if (have_health_settings) { -- COMMAND_ERROR("--no-healthcheck conflicts with --health-* options"); -- ret = -1; -- goto out; -- } -- health_config->test = util_common_calloc_s(sizeof(char *)); -- if (health_config->test == NULL) { -- ret = -1; -- goto out; -+ if (cr == NULL) { -+ return; - } -- health_config->test[health_config->test_len++] = util_strdup_s("NONE"); -- container_spec->healthcheck = health_config; -- --out: -- return ret; --} -+ free(cr->cpuset_cpus); -+ cr->cpuset_cpus = NULL; - --static int pack_custom_with_health_check(container_config *container_spec, -- const isula_container_config_t *custom_conf, bool have_health_settings, -- defs_health_check *health_config) --{ -- int ret = 0; -+ free(cr->cpuset_mems); -+ cr->cpuset_mems = NULL; - -- if (custom_conf->health_cmd != NULL && strlen(custom_conf->health_cmd) != 0) { -- health_config->test = util_common_calloc_s(2 * sizeof(char *)); -- if (health_config->test == NULL) { -- ret = -1; -- goto out; -- } -- health_config->test[health_config->test_len++] = util_strdup_s("CMD-SHELL"); -- health_config->test[health_config->test_len++] = util_strdup_s(custom_conf->health_cmd); -- } else { -- COMMAND_ERROR("--health-cmd required!"); -- ret = -1; -- goto out; -- } -- health_config->interval = custom_conf->health_interval; -- health_config->timeout = custom_conf->health_timeout; -- health_config->start_period = custom_conf->health_start_period; -- health_config->retries = custom_conf->health_retries; -- health_config->exit_on_unhealthy = custom_conf->exit_on_unhealthy; -- if (container_spec->healthcheck != NULL) { -- free_defs_health_check(container_spec->healthcheck); -- } -- container_spec->healthcheck = health_config; -- --out: -- return ret; -+ free(cr); - } - --static int pack_container_custom_config_health(container_config *container_spec, -- const isula_container_config_t *custom_conf) -+/* isula host config free */ -+void isula_host_config_free(isula_host_config_t *hostconfig) - { -- int ret = 0; -- bool have_health_settings = false; -- defs_health_check *health_config = NULL; -- -- if (container_spec == NULL || custom_conf == NULL) { -- return 0; -- } -- -- have_health_settings = have_health_check(custom_conf); -- -- health_config = util_common_calloc_s(sizeof(defs_health_check)); -- if (health_config == NULL) { -- ret = -1; -- goto out; -- } -- -- if (custom_conf->no_healthcheck) { -- ret = pack_custom_no_health_check(container_spec, have_health_settings, health_config); -- if (ret != 0) { -- goto out; -- } -- } else if (have_health_settings) { -- ret = pack_custom_with_health_check(container_spec, custom_conf, have_health_settings, health_config); -- if (ret != 0) { -- goto out; -- } -- } else { -- goto out; -+ if (hostconfig == NULL) { -+ return; - } - -- return ret; -+ util_free_array_by_len(hostconfig->cap_add, hostconfig->cap_add_len); -+ hostconfig->cap_add = NULL; -+ hostconfig->cap_add_len = 0; - --out: -- free_defs_health_check(health_config); -- return ret; --} -+ util_free_array_by_len(hostconfig->cap_drop, hostconfig->cap_drop_len); -+ hostconfig->cap_drop = NULL; -+ hostconfig->cap_drop_len = 0; - --static int pack_container_custom_config_annotation(container_config *container_spec, -- const isula_container_config_t *custom_conf) --{ -- int ret = 0; -- size_t j; -+ free_json_map_string_string(hostconfig->storage_opts); -+ hostconfig->storage_opts = NULL; - -- container_spec->annotations = util_common_calloc_s(sizeof(json_map_string_string)); -- if (container_spec->annotations == NULL) { -- ERROR("Out of memory"); -- ret = -1; -- goto out; -- } -- if (custom_conf->annotations != NULL) { -- for (j = 0; j < custom_conf->annotations->len; j++) { -- if (append_json_map_string_string(container_spec->annotations, custom_conf->annotations->keys[j], -- custom_conf->annotations->values[j])) { -- ERROR("Append map failed"); -- ret = -1; -- goto out; -- } -- } -- } --out: -- return ret; --} -+ free_json_map_string_string(hostconfig->sysctls); -+ hostconfig->sysctls = NULL; - --static int pack_container_custom_config_pre(container_config *container_spec, -- const isula_container_config_t *custom_conf) --{ -- int ret = 0; -+ util_free_array_by_len(hostconfig->devices, hostconfig->devices_len); -+ hostconfig->devices = NULL; -+ hostconfig->devices_len = 0; - -- ret = pack_container_custom_config_args(container_spec, custom_conf); -- if (ret != 0) { -- goto out; -- } -+ util_free_array_by_len(hostconfig->ns_change_files, hostconfig->ns_change_files_len); -+ hostconfig->ns_change_files = NULL; -+ hostconfig->ns_change_files_len = 0; - -- ret = pack_container_custom_config_mounts(container_spec, custom_conf); -- if (ret != 0) { -- goto out; -- } -+ util_free_array_by_len(hostconfig->hugetlbs, hostconfig->hugetlbs_len); -+ hostconfig->hugetlbs = NULL; -+ hostconfig->hugetlbs_len = 0; - -- ret = pack_container_custom_config_array(container_spec, custom_conf); -- if (ret != 0) { -- goto out; -- } -+ free(hostconfig->network_mode); -+ hostconfig->network_mode = NULL; - -- ret = pack_container_custom_config_labels(container_spec, custom_conf); -- if (ret != 0) { -- goto out; -- } -+ free(hostconfig->ipc_mode); -+ hostconfig->ipc_mode = NULL; - -- ret = pack_container_custom_config_health(container_spec, custom_conf); -- if (ret != 0) { -- goto out; -- } --out: -- return ret; --} -+ free(hostconfig->pid_mode); -+ hostconfig->pid_mode = NULL; - --/* translate create_custom_config to container_config */ --static int pack_container_custom_config(container_config *container_spec, -- const isula_container_config_t *custom_conf) --{ -- int ret = -1; -+ free(hostconfig->uts_mode); -+ hostconfig->uts_mode = NULL; - -- if (container_spec == NULL || custom_conf == NULL) { -- return ret; -- } -+ free(hostconfig->userns_mode); -+ hostconfig->userns_mode = NULL; - -- ret = pack_container_custom_config_pre(container_spec, custom_conf); -- if (ret != 0) { -- goto out; -- } -+ free(hostconfig->user_remap); -+ hostconfig->user_remap = NULL; - -- if (custom_conf->hostname != NULL) { -- container_spec->hostname = util_strdup_s(custom_conf->hostname); -- } -- container_spec->log_driver = util_strdup_s(custom_conf->log_driver); -+ util_free_array_by_len(hostconfig->ulimits, hostconfig->ulimits_len); -+ hostconfig->ulimits = NULL; -+ hostconfig->ulimits_len = 0; - -- /* console config */ -- container_spec->tty = custom_conf->tty; -- container_spec->open_stdin = custom_conf->open_stdin; -- container_spec->attach_stdin = custom_conf->attach_stdin; -- container_spec->attach_stdout = custom_conf->attach_stdout; -- container_spec->attach_stderr = custom_conf->attach_stderr; -+ free(hostconfig->restart_policy); -+ hostconfig->restart_policy = NULL; - -- /* user and group */ -- if (custom_conf->user != NULL) { -- container_spec->user = util_strdup_s(custom_conf->user); -- } -+ free(hostconfig->host_channel); -+ hostconfig->host_channel = NULL; - -- /* settings for system container */ -- if (custom_conf->system_container) { -- container_spec->system_container = custom_conf->system_container; -- } -+ free(hostconfig->hook_spec); -+ hostconfig->hook_spec = NULL; - -- if (custom_conf->ns_change_opt != NULL) { -- container_spec->ns_change_opt = util_strdup_s(custom_conf->ns_change_opt); -- } -+ free(hostconfig->env_target_file); -+ hostconfig->env_target_file = NULL; - -- ret = pack_container_custom_config_annotation(container_spec, custom_conf); -- if (ret != 0) { -- goto out; -- } -+ free(hostconfig->cgroup_parent); -+ hostconfig->cgroup_parent = NULL; - -- if (custom_conf->workdir != NULL) { -- container_spec->working_dir = util_strdup_s(custom_conf->workdir); -- } -+ util_free_array_by_len(hostconfig->binds, hostconfig->binds_len); -+ hostconfig->binds = NULL; -+ hostconfig->binds_len = 0; - --out: -- return ret; --} -+ util_free_array_by_len(hostconfig->blkio_weight_device, hostconfig->blkio_weight_device_len); -+ hostconfig->blkio_weight_device = NULL; -+ hostconfig->blkio_weight_device_len = 0; - --int generate_container_config(const isula_container_config_t *custom_conf, char **container_config_str) --{ -- int ret = 0; -- container_config *container_spec = NULL; -- struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 }; -- parser_error err = NULL; -+ util_free_array_by_len(hostconfig->blkio_throttle_read_bps_device, hostconfig->blkio_throttle_read_bps_device_len); -+ hostconfig->blkio_throttle_read_bps_device = NULL; -+ hostconfig->blkio_throttle_read_bps_device_len = 0; - -- /* step 1: malloc the container config */ -- container_spec = util_common_calloc_s(sizeof(container_config)); -- if (container_spec == NULL) { -- ERROR("Memory out"); -- ret = -1; -- goto out; -- } -+ util_free_array_by_len(hostconfig->blkio_throttle_write_bps_device, -+ hostconfig->blkio_throttle_write_bps_device_len); -+ hostconfig->blkio_throttle_write_bps_device = NULL; -+ hostconfig->blkio_throttle_write_bps_device_len = 0; - -- /* step 2: pack the container custom config */ -- ret = pack_container_custom_config(container_spec, custom_conf); -- if (ret != 0) { -- ERROR("Failed to pack the container custom config"); -- ret = -1; -- goto out; -- } -+ util_free_array_by_len(hostconfig->blkio_throttle_read_iops_device, -+ hostconfig->blkio_throttle_read_iops_device_len); -+ hostconfig->blkio_throttle_read_iops_device = NULL; -+ hostconfig->blkio_throttle_read_iops_device_len = 0; - -- /* step 3: generate the config string */ -- *container_config_str = container_config_generate_json(container_spec, &ctx, &err); -- if (*container_config_str == NULL) { -- ERROR("Failed to generate OCI specification json string"); -- ret = -1; -- goto out; -- } -+ util_free_array_by_len(hostconfig->blkio_throttle_write_iops_device, -+ hostconfig->blkio_throttle_write_iops_device_len); -+ hostconfig->blkio_throttle_write_iops_device = NULL; -+ hostconfig->blkio_throttle_write_iops_device_len = 0; - --out: -- free_container_config(container_spec); -- free(err); -+ util_free_array_by_len(hostconfig->device_cgroup_rules, hostconfig->device_cgroup_rules_len); -+ hostconfig->device_cgroup_rules = NULL; -+ hostconfig->device_cgroup_rules_len = 0; - -- return ret; --} -+ container_cgroup_resources_free(hostconfig->cr); -+ hostconfig->cr = NULL; - -+ free(hostconfig); -+} -\ No newline at end of file -diff --git a/src/cmd/isula/isula_host_spec.h b/src/cmd/isula/isula_host_spec.h -new file mode 100644 -index 0000000..d464494 ---- /dev/null -+++ b/src/cmd/isula/isula_host_spec.h -@@ -0,0 +1,156 @@ -+/****************************************************************************** -+ * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. 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: lifeng -+ * Create: 2020-09-28 -+ * Description: provide generate host spec in client -+ ******************************************************************************/ -+#ifndef CMD_ISULA_GENERATE_HOST_SPEC_H -+#define CMD_ISULA_GENERATE_HOST_SPEC_H -+ -+#include -+#include -+#include -+#include "isula_libutils/json_common.h" -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+typedef struct container_cgroup_resources { -+ uint16_t blkio_weight; -+ int64_t cpu_shares; -+ int64_t cpu_period; -+ int64_t cpu_quota; -+ int64_t cpu_realtime_period; -+ int64_t cpu_realtime_runtime; -+ char *cpuset_cpus; -+ char *cpuset_mems; -+ int64_t memory; -+ int64_t memory_swap; -+ int64_t memory_reservation; -+ int64_t kernel_memory; -+ int64_t pids_limit; -+ int64_t files_limit; -+ int64_t oom_score_adj; -+ int64_t swappiness; -+ int64_t nano_cpus; -+} container_cgroup_resources_t; -+ -+typedef struct isula_host_config { -+ char **devices; -+ size_t devices_len; -+ -+ char **hugetlbs; -+ size_t hugetlbs_len; -+ -+ char **group_add; -+ size_t group_add_len; -+ -+ char *network_mode; -+ -+ char *ipc_mode; -+ -+ char *pid_mode; -+ -+ char *uts_mode; -+ -+ char *userns_mode; -+ -+ char *user_remap; -+ -+ char **ulimits; -+ size_t ulimits_len; -+ -+ char *restart_policy; -+ -+ char *host_channel; -+ -+ char **cap_add; -+ size_t cap_add_len; -+ -+ char **cap_drop; -+ size_t cap_drop_len; -+ -+ json_map_string_string *storage_opts; -+ -+ json_map_string_string *sysctls; -+ -+ char **dns; -+ size_t dns_len; -+ -+ char **dns_options; -+ size_t dns_options_len; -+ -+ char **dns_search; -+ size_t dns_search_len; -+ -+ char **extra_hosts; -+ size_t extra_hosts_len; -+ -+ char *hook_spec; -+ -+ char **binds; -+ size_t binds_len; -+ -+ char **blkio_weight_device; -+ size_t blkio_weight_device_len; -+ -+ char **blkio_throttle_read_bps_device; -+ size_t blkio_throttle_read_bps_device_len; -+ -+ char **blkio_throttle_write_bps_device; -+ size_t blkio_throttle_write_bps_device_len; -+ -+ char **blkio_throttle_read_iops_device; -+ size_t blkio_throttle_read_iops_device_len; -+ -+ char **blkio_throttle_write_iops_device; -+ size_t blkio_throttle_write_iops_device_len; -+ -+ char **device_cgroup_rules; -+ size_t device_cgroup_rules_len; -+ -+ bool privileged; -+ bool system_container; -+ char **ns_change_files; -+ size_t ns_change_files_len; -+ bool auto_remove; -+ -+ bool oom_kill_disable; -+ -+ int64_t shm_size; -+ -+ bool readonly_rootfs; -+ -+ char *env_target_file; -+ -+ char *cgroup_parent; -+ -+ container_cgroup_resources_t *cr; -+ -+ char **security; -+ size_t security_len; -+} isula_host_config_t; -+ -+int generate_hostconfig(const isula_host_config_t *srcconfig, char **hostconfigstr); -+void isula_host_config_free(isula_host_config_t *hostconfig); -+ -+void isula_ns_change_files_free(isula_host_config_t *hostconfig); -+ -+void isula_host_config_storage_opts_free(isula_host_config_t *hostconfig); -+ -+void isula_host_config_sysctl_free(isula_host_config_t *hostconfig); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif -diff --git a/src/cmd/isula/stream/attach.c b/src/cmd/isula/stream/attach.c -index 669bb70..eadd0e9 100644 ---- a/src/cmd/isula/stream/attach.c -+++ b/src/cmd/isula/stream/attach.c -@@ -36,7 +36,6 @@ - #include "command_parser.h" - #include "connect.h" - #include "constants.h" --#include "libisula.h" - - const char g_cmd_attach_desc[] = "Attach to a running container"; - const char g_cmd_attach_usage[] = "attach [OPTIONS] CONTAINER"; -diff --git a/src/cmd/isula/stream/cp.c b/src/cmd/isula/stream/cp.c -index b894b37..37107fb 100644 ---- a/src/cmd/isula/stream/cp.c -+++ b/src/cmd/isula/stream/cp.c -@@ -30,7 +30,7 @@ - #include "command_parser.h" - #include "connect.h" - #include "io_wrapper.h" --#include "libisula.h" -+ - #include "utils.h" - - #define FromContainer 0x01u -@@ -48,12 +48,12 @@ static char *resolve_local_path(const char *path) - { - char abs_path[PATH_MAX] = { 0 }; - -- if (cleanpath(path, abs_path, sizeof(abs_path)) == NULL) { -+ if (util_clean_path(path, abs_path, sizeof(abs_path)) == NULL) { - ERROR("Failed to clean path"); - return NULL; - } - -- return preserve_trailing_dot_or_separator(abs_path, path); -+ return util_preserve_trailing_dot_or_separator(abs_path, path); - } - - static void print_copy_from_container_error(const char *ops_err, const char *archive_err, int ret, -diff --git a/src/cmd/isula/stream/exec.c b/src/cmd/isula/stream/exec.c -index 6ac1a7a..761c4c0 100644 ---- a/src/cmd/isula/stream/exec.c -+++ b/src/cmd/isula/stream/exec.c -@@ -12,11 +12,10 @@ - * Create: 2018-11-08 - * Description: provide container exec functions - ******************************************************************************/ -+#include "exec.h" - #include - #include - #include --#include --#include - #include - #include - #include -@@ -24,7 +23,7 @@ - #include - - #include "client_arguments.h" --#include "exec.h" -+#include "client_console.h" - #include "isula_libutils/log.h" - #include "isula_connect.h" - #include "console.h" -@@ -33,7 +32,7 @@ - #include "isula_libutils/container_inspect.h" - #include "connect.h" - #include "constants.h" --#include "libisula.h" -+ - #include "utils_array.h" - #include "utils_string.h" - -@@ -67,8 +66,8 @@ static int fill_exec_request(const struct client_arguments *args, const struct c - - request->user = util_strdup_s(args->custom_conf.user); - -- if (dup_array_of_strings((const char **)args->argv, args->argc, &(request->argv), (size_t *) & (request->argc)) != -- 0) { -+ if (util_dup_array_of_strings((const char **)args->argv, args->argc, &(request->argv), -+ (size_t *) & (request->argc)) != 0) { - ERROR("Failed to dup args"); - ret = -1; - goto out; -@@ -76,7 +75,7 @@ static int fill_exec_request(const struct client_arguments *args, const struct c - - /* environment variables */ - for (i = 0; i < util_array_len((const char **)(args->extra_env)); i++) { -- if (util_validate_env(args->extra_env[i], &new_env) != 0) { -+ if (util_valid_env(args->extra_env[i], &new_env) != 0) { - ERROR("Invalid environment %s", args->extra_env[i]); - ret = -1; - goto out; -@@ -151,6 +150,45 @@ out: - return ret; - } - -+static int do_resize_exec_console(const struct client_arguments *args, unsigned int height, unsigned int width) -+{ -+ int ret = 0; -+ isula_connect_ops *ops = NULL; -+ struct isula_resize_request request = { 0 }; -+ struct isula_resize_response *response = NULL; -+ client_connect_config_t config = { 0 }; -+ -+ ops = get_connect_client_ops(); -+ if (ops == NULL || ops->container.resize == NULL) { -+ ERROR("Unimplemented ops"); -+ ret = -1; -+ goto out; -+ } -+ -+ request.id = args->name; -+ request.suffix = args->exec_suffix; -+ request.height = height; -+ request.width = width; -+ -+ response = util_common_calloc_s(sizeof(struct isula_resize_response)); -+ if (response == NULL) { -+ ERROR("Out of memory"); -+ ret = -1; -+ goto out; -+ } -+ -+ config = get_connect_config(args); -+ ret = ops->container.resize(&request, response, &config); -+ if (ret != 0) { -+ ERROR("Failed to call resize"); -+ goto out; -+ } -+ -+out: -+ isula_resize_response_free(response); -+ return ret; -+} -+ - static int exec_cmd_init(int argc, const char **argv) - { - command_t cmd; -@@ -197,6 +235,8 @@ static int exec_cmd_init(int argc, const char **argv) - return ECOMMON; - } - -+ g_cmd_exec_args.resize_cb = do_resize_exec_console; -+ - return 0; - } - -@@ -367,98 +407,6 @@ out: - return exec_suffix; - } - --static int do_resize_exec_console(const struct client_arguments *args, unsigned int height, unsigned int width) --{ -- int ret = 0; -- isula_connect_ops *ops = NULL; -- struct isula_resize_request request = { 0 }; -- struct isula_resize_response *response = NULL; -- client_connect_config_t config = { 0 }; -- -- ops = get_connect_client_ops(); -- if (ops == NULL || ops->container.resize == NULL) { -- ERROR("Unimplemented ops"); -- ret = -1; -- goto out; -- } -- -- request.id = args->name; -- request.suffix = args->exec_suffix; -- request.height = height; -- request.width = width; -- -- response = util_common_calloc_s(sizeof(struct isula_resize_response)); -- if (response == NULL) { -- ERROR("Out of memory"); -- ret = -1; -- goto out; -- } -- -- config = get_connect_config(args); -- ret = ops->container.resize(&request, response, &config); -- if (ret != 0) { -- ERROR("Failed to call resize"); -- goto out; -- } -- --out: -- isula_resize_response_free(response); -- return ret; --} -- --static void *exec_console_resize_thread(void *arg) --{ -- int ret = 0; -- const struct client_arguments *args = arg; -- static struct winsize s_pre_wsz; -- struct winsize wsz; -- -- if (!isatty(STDIN_FILENO)) { -- goto out; -- } -- -- ret = pthread_detach(pthread_self()); -- if (ret != 0) { -- CRIT("Start: set thread detach fail"); -- goto out; -- } -- -- while (true) { -- sleep(1); // check the windows size per 1s -- ret = ioctl(STDIN_FILENO, TIOCGWINSZ, &wsz); -- if (ret < 0) { -- WARN("Failed to get window size"); -- continue; -- } -- if (wsz.ws_row == s_pre_wsz.ws_row && wsz.ws_col == s_pre_wsz.ws_col) { -- continue; -- } -- ret = do_resize_exec_console(args, wsz.ws_row, wsz.ws_col); -- if (ret != 0) { -- continue; -- } -- s_pre_wsz.ws_row = wsz.ws_row; -- s_pre_wsz.ws_col = wsz.ws_col; -- } -- --out: -- return NULL; --} -- --int exec_client_console_resize_thread(struct client_arguments *args) --{ -- int res = 0; -- pthread_t a_thread; -- -- res = pthread_create(&a_thread, NULL, exec_console_resize_thread, (void *)(args)); -- if (res != 0) { -- CRIT("Thread creation failed"); -- return -1; -- } -- -- return 0; --} -- - int cmd_exec_main(int argc, const char **argv) - { - int ret = 0; -@@ -503,7 +451,7 @@ int cmd_exec_main(int argc, const char **argv) - - if (custom_cfg->tty && isatty(STDIN_FILENO) && - (custom_cfg->attach_stdin || custom_cfg->attach_stdout || custom_cfg->attach_stderr)) { -- (void)exec_client_console_resize_thread(&g_cmd_exec_args); -+ (void)start_client_console_resize_thread(&g_cmd_exec_args); - } - - if (strncmp(g_cmd_exec_args.socket, "tcp://", strlen("tcp://")) == 0) { -diff --git a/src/cmd/isulad-shim/main.c b/src/cmd/isulad-shim/main.c -index 50b864d..3ab22d8 100644 ---- a/src/cmd/isulad-shim/main.c -+++ b/src/cmd/isulad-shim/main.c -@@ -71,7 +71,7 @@ static int parse_args(int argc, char **argv, char **cid, char **bundle, char **r - *cid = strdup(argv[1]); - *bundle = strdup(argv[2]); - *rt_name = strdup(argv[3]); -- if (*cid == NULL || *bundle == NULL || rt_name == NULL) { -+ if (*cid == NULL || *bundle == NULL || *rt_name == NULL) { - return SHIM_ERR; - } - -@@ -85,7 +85,10 @@ static int parse_args(int argc, char **argv, char **cid, char **bundle, char **r - return SHIM_OK; - } - -- -+/* -+ * Note: -+ * All files created in the working directory are cleared by the parent process isulad -+ */ - int main(int argc, char **argv) - { - char *container_id = NULL; -@@ -101,6 +104,10 @@ int main(int argc, char **argv) - _exit(EXIT_FAILURE); - } - -+ /* -+ * The default value of DEFAULT_TIME is 120 seconds, -+ * which is the same as the default value of containerd -+ */ - set_timeout_exit(DEFAULT_TIMEOUT); - - ret = set_subreaper(); -@@ -121,7 +128,11 @@ int main(int argc, char **argv) - exit(EXIT_FAILURE); - } - -- // open exit pipe -+ /* -+ * Open exit pipe -+ * The exit pipe exists only when the container is started, -+ * and the exec operation does not contain the exit pipe. -+ */ - if (!p->state->exec) { - if (p->state->exit_fifo != NULL) { - efd = open_no_inherit("exit_fifo", O_WRONLY, -1); -@@ -133,7 +144,7 @@ int main(int argc, char **argv) - } - } - -- // create main loop and start epoll -+ /* create main loop and start epoll for io copy */ - ret = process_io_init(p); - if (ret != SHIM_OK) { - write_message(g_log_fd, ERR_MSG, "process io init failed:%d", ret); -@@ -147,6 +158,9 @@ int main(int argc, char **argv) - - ret = create_process(p); - if (ret != SHIM_OK) { -+ if (p->console_sock_path != NULL) { -+ (void)unlink(p->console_sock_path); -+ } - exit(EXIT_FAILURE); - } - -diff --git a/src/cmd/isulad-shim/process.c b/src/cmd/isulad-shim/process.c -index 0baa615..c693cb8 100644 ---- a/src/cmd/isulad-shim/process.c -+++ b/src/cmd/isulad-shim/process.c -@@ -57,14 +57,13 @@ 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"); - } -- -- if (err != NULL) { -- free(err); -- } -+ /* "err" will definitely be allocated memory in the function above */ -+ free(err); - - return p_state; - } -@@ -73,7 +72,7 @@ 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 -+ /* 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)); -@@ -99,6 +98,7 @@ static int receive_fd(int sock) - iov[0].iov_len = sizeof(buf); - - struct msghdr msg; -+ (void)memset(&msg, 0, sizeof(struct msghdr)); - msg.msg_iov = iov; - msg.msg_iovlen = 1; - msg.msg_name = NULL; -@@ -106,10 +106,16 @@ static int receive_fd(int sock) - msg.msg_control = cmptr; - msg.msg_controllen = cmsgsize; - -+ /* -+ * return value: -+ * 0: the peer has performed an orderly shutdown -+ * -1: an error occurred -+ * >0: the number of bytes received -+ */ - int ret = recvmsg(sock, &msg, 0); -- if (ret == -1) { -- free(cmptr); -+ if (ret <= 0) { - write_message(g_log_fd, ERR_MSG, "get console fd failed:%d", SHIM_SYS_ERR(errno)); -+ free(cmptr); - return -1; - } - -@@ -140,19 +146,11 @@ static int add_io_dispatch(int epfd, io_thread_t *io_thd, int from, int to) - } - - io_copy_t *ioc = io_thd->ioc; -- fd_node_t *fn = (fd_node_t *)calloc(1, sizeof(fd_node_t)); -- if (fn == NULL) { -+ -+ if (pthread_mutex_lock(&(ioc->mutex)) != 0) { - return SHIM_ERR; - } -- fn->fd = to; -- fn->is_log = false; -- if (io_thd->terminal != NULL && to == io_thd->terminal->fd) { -- fn->is_log = true; -- } -- fn->next = NULL; -- -- pthread_mutex_lock(&(ioc->mutex)); -- // add src fd -+ /* add src fd */ - if (from != -1 && ioc->fd_from == -1) { - ioc->fd_from = from; - struct epoll_event ev; -@@ -161,15 +159,27 @@ static int add_io_dispatch(int epfd, io_thread_t *io_thd, int from, int to) - - ret = epoll_ctl(epfd, EPOLL_CTL_ADD, from, &ev); - if (ret != SHIM_OK) { -- free(fn); - 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 -+ /* add dest fd */ - if (to != -1) { -+ /* new fd_node_t for dest fd */ -+ fd_node_t *fn = (fd_node_t *)calloc(1, sizeof(fd_node_t)); -+ if (fn == NULL) { -+ pthread_mutex_unlock(&(ioc->mutex)); -+ return SHIM_ERR; -+ } -+ fn->fd = to; -+ fn->is_log = false; -+ if (io_thd->terminal != NULL && to == io_thd->terminal->fd) { -+ fn->is_log = true; -+ } -+ fn->next = NULL; -+ - if (ioc->fd_to == NULL) { - ioc->fd_to = fn; - } else { -@@ -192,10 +202,13 @@ static void remove_io_dispatch(io_thread_t *io_thd, int from, int to) - } - io_copy_t *ioc = io_thd->ioc; - -- pthread_mutex_lock(&(ioc->mutex)); -+ if (pthread_mutex_lock(&(ioc->mutex))) { -+ return; -+ } -+ - fd_node_t *tmp = NULL; - do { -- // remove src fd -+ /* remove src fd */ - if (from != -1 && from == ioc->fd_from) { - struct epoll_event ev; - ev.events = EPOLLIN; -@@ -203,12 +216,12 @@ static void remove_io_dispatch(io_thread_t *io_thd, int from, int to) - (void)epoll_ctl(io_thd->epfd, EPOLL_CTL_DEL, ioc->fd_from, &ev); - } - -- // remove dest fd -+ /* remove dest fd */ - if (ioc->fd_to == NULL) { - break; - } - if (ioc->fd_to->fd == to) { -- // remove the first fd node -+ /* remove the first fd node */ - tmp = ioc->fd_to; - ioc->fd_to = ioc->fd_to->next; - break; -@@ -225,6 +238,7 @@ static void remove_io_dispatch(io_thread_t *io_thd, int from, int to) - } while (0); - if (tmp != NULL) { - free(tmp); -+ tmp = NULL; - } - pthread_mutex_unlock(&(ioc->mutex)); - } -@@ -238,7 +252,7 @@ static void *task_io_copy(void *data) - io_copy_t *ioc = io_thd->ioc; - char *buf = calloc(1, DEFAULT_IO_COPY_BUF + 1); - if (buf == NULL) { -- _exit(EXIT_FAILURE); -+ return NULL; - } - - for (;;) { -@@ -250,13 +264,12 @@ static void *task_io_copy(void *data) - - 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. -+ /* End of file. The remote has closed the connection */ - break; - } else { - fd_node_t *fn = ioc->fd_to; -@@ -265,10 +278,9 @@ static void *task_io_copy(void *data) - shim_write_container_log_file(io_thd->terminal, ioc->id == stdid_out ? "stdout" : "stderr", buf, - r_count); - } else { -- int w_count = 0; -- w_count = write_nointr(fn->fd, buf, r_count); -+ int w_count = write_nointr(fn->fd, buf, r_count); - if (w_count < 0) { -- // remove the write fd -+ /* When any error occurs, remove the write fd */ - remove_io_dispatch(io_thd, -1, fn->fd); - } - } -@@ -366,6 +378,7 @@ static int start_io_copy_threads(process_t *p) - int ret = SHIM_ERR; - int i; - -+ /* 3 threads for stdin, stdout and stderr */ - for (i = 0; i < 3; i++) { - ret = process_io_start(p, i); - if (ret != SHIM_OK) { -@@ -423,7 +436,7 @@ static int connect_to_isulad(process_t *p, int std_id, const char *isulad_stdio, - 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 -+ /* if no I/O source is available, the I/O thread nead to be destroyed */ - destroy_io_thread(p, std_id); - - return SHIM_OK; -@@ -448,36 +461,43 @@ static void *task_console_accept(void *data) - goto out; - } - -- // do console io copy -- // -- // p.state.stdin---->runtime.console -+ /* 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) { - goto out; - } - -- // p.state.stdout<------runtime.console -+ /* p.state.stdout<------runtime.console */ - ret = connect_to_isulad(ac->p, stdid_out, ac->p->state->isulad_stdout, recv_fd); - if (ret != SHIM_OK) { - goto out; - } - -- // if the terminal is used, we do not need to active the io copy of stderr pipe -+ /* -+ * if the terminal is used, we do not need to active the io copy of stderr pipe, -+ * for stderr and stdout are mixed together -+ */ - destroy_io_thread(ac->p, stdid_err); - - out: -- // release listen socket -+ /* release listen socket at the first time */ - close_fd(&ac->listen_fd); - if (ac->p->console_sock_path != NULL) { -- unlink(ac->p->console_sock_path); -+ (void)unlink(ac->p->console_sock_path); - free(ac->p->console_sock_path); - ac->p->console_sock_path = NULL; - } - free(ac); - if (ret != SHIM_OK) { -+ /* -+ * When an error occurs during the receiving of the fd , the process -+ * exits directly. The files created in the working directory will be -+ * deleted by its parent process isulad -+ */ - exit(EXIT_FAILURE); - } -- - return NULL; - } - -@@ -495,8 +515,7 @@ static void *task_io_loop(void *data) - } - (void)sem_post(&p->sem_mainloop); - -- // begin wait -- while (1) { -+ for (;;) { - wait_fds = epoll_wait(p->io_loop_fd, evs, MAX_EVENTS, -1); - if (wait_fds < 0) { - if (errno == EINTR) { -@@ -526,7 +545,12 @@ static int new_temp_console_path(process_t *p) - if (p->console_sock_path == NULL) { - return SHIM_ERR; - } -- snprintf(p->console_sock_path, MAX_CONSOLE_SOCK_LEN, "/run/isulad%s-pty.sock", str_rand); -+ int nret = snprintf(p->console_sock_path, MAX_CONSOLE_SOCK_LEN, "/run/isulad%s-pty.sock", str_rand); -+ if (nret < 0 || nret >= MAX_CONSOLE_SOCK_LEN) { -+ free(p->console_sock_path); -+ p->console_sock_path = NULL; -+ return SHIM_ERR; -+ } - - return SHIM_OK; - } -@@ -548,14 +572,12 @@ static int console_init(process_t *p) - 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)); -@@ -584,17 +606,44 @@ failure: - close_fd(&fd); - if (ac != NULL) { - free(ac); -+ ac = NULL; - } -- unlink(p->console_sock_path); -+ (void)unlink(p->console_sock_path); - - return SHIM_ERR; - } - -+static int stdio_chown(int (*stdio_fd)[2], int uid, int gid) -+{ -+ int i, j; -+ -+ for (i = 0; i < 3; i++) { -+ for (j = 0; j < 2; j++) { -+ int ret = fchown(stdio_fd[i][j], uid, gid); -+ if (ret != SHIM_OK) { -+ return SHIM_ERR; -+ } -+ } -+ } -+ return SHIM_OK; -+} -+ -+static void stdio_release(int (*stdio_fd)[2]) -+{ -+ int i, j; -+ -+ for (i = 0; i < 3; i++) { -+ for (j = 0; j < 2; j++) { -+ if (stdio_fd[i][j] > 0) { -+ close(stdio_fd[i][j]); -+ } -+ } -+ } -+} -+ - 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)); -@@ -615,13 +664,8 @@ static stdio_t *initialize_io(process_t *p) - 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; -- } -- } -+ if (stdio_chown(stdio_fd, p->state->root_uid, p->state->root_gid) != SHIM_OK) { -+ goto failure; - } - - return stdio; -@@ -635,13 +679,7 @@ failure: - 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]); -- } -- } -- } -+ stdio_release(stdio_fd); - - return NULL; - } -@@ -656,7 +694,7 @@ static int open_terminal_io(process_t *p) - return SHIM_ERR; - } - -- // begin listen and accept fd from p->console_sock_path -+ /* begin listen and accept fd from p->console_sock_path */ - return console_init(p); - } - -@@ -669,17 +707,17 @@ static int open_generic_io(process_t *p) - return SHIM_ERR; - } - p->shim_io = io; -- // stdin -+ /* stdin */ - ret = connect_to_isulad(p, stdid_in, p->state->isulad_stdin, io->in); - if (ret != SHIM_OK) { - return SHIM_ERR; - } -- // stdout -+ /* stdout */ - ret = connect_to_isulad(p, stdid_out, p->state->isulad_stdout, io->out); - if (ret != SHIM_OK) { - return SHIM_ERR; - } -- // stderr -+ /* stderr */ - ret = connect_to_isulad(p, stdid_err, p->state->isulad_stderr, io->err); - if (ret != SHIM_OK) { - return SHIM_ERR; -@@ -690,7 +728,7 @@ static int open_generic_io(process_t *p) - - 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 -+ /* 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); -@@ -931,7 +969,11 @@ static void process_delete(process_t *p) - write_message(g_log_fd, ERR_MSG, "get cwd failed when do process delete"); - return; - } -- snprintf(log_path, PATH_MAX, "%s/log.json", cwd); -+ int nret = snprintf(log_path, PATH_MAX, "%s/log.json", cwd); -+ if (nret < 0 || nret >= PATH_MAX) { -+ free(cwd); -+ return; -+ } - - params[i++] = p->runtime; - for (j = 0; j < p->state->runtime_args_len; j++) { -@@ -952,9 +994,66 @@ static void process_delete(process_t *p) - return; - } - -+static void exec_runtime_process(process_t *p, int exec_fd) -+{ -+ 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, "memory error: %s", strerror(errno)); -+ _exit(EXIT_FAILURE); -+ } -+ -+ int nret = snprintf(log_path, PATH_MAX, "%s/log.json", cwd); -+ if (nret < 0 || nret >= PATH_MAX) { -+ _exit(EXIT_FAILURE); -+ } -+ nret = snprintf(pid_path, PATH_MAX, "%s/pid", cwd); -+ if (nret < 0 || nret >= PATH_MAX) { -+ _exit(EXIT_FAILURE); -+ } -+ -+ char *process_desc = NULL; -+ if (p->state->exec) { -+ process_desc = (char *)calloc(1, PATH_MAX); -+ if (process_desc == NULL) { -+ (void)dprintf(exec_fd, "memory error: %s", strerror(errno)); -+ _exit(EXIT_FAILURE); -+ } -+ nret = snprintf(process_desc, PATH_MAX, "%s/process.json", cwd); -+ if (nret < 0 || nret >= PATH_MAX) { -+ _exit(EXIT_FAILURE); -+ } -+ } -+ -+ 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, "fork/exec error: %s", strerror(errno)); -+ _exit(EXIT_FAILURE); -+} -+ - int create_process(process_t *p) - { -- int ret = -1; -+ int ret = SHIM_ERR; - char *data = NULL; - int exec_fd[2] = { -1, -1 }; - char exec_buff[BUFSIZ + 1] = { 0 }; -@@ -971,56 +1070,13 @@ int create_process(process_t *p) - return SHIM_ERR; - } - -- // child:runtime -+ /* child:runtime process */ - 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); -+ exec_runtime_process(p, exec_fd[1]); - } - -- // parent -+ /* parent:isulad-shim process */ - close_fd(&exec_fd[1]); - if (p->stdio != NULL) { - close_fd(&p->stdio->in); -@@ -1034,7 +1090,7 @@ int create_process(process_t *p) - goto out; - } - -- // block to wait pid exit -+ /* block to wait runtime 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)); -@@ -1042,7 +1098,7 @@ int create_process(process_t *p) - goto out; - } - -- // save pid -+ /* save runtime pid */ - data = read_text_file("pid"); - if (data == NULL) { - write_message(g_log_fd, ERR_MSG, "read pid of runtime failed"); -@@ -1061,6 +1117,7 @@ out: - close_fd(&exec_fd[0]); - if (data != NULL) { - free(data); -+ data = NULL; - } - - return ret; -@@ -1089,7 +1146,7 @@ int process_signal_handle_routine(process_t *p) - } - } - } else if (ret == SHIM_ERR_WAIT) { -- // avoid thread entering the infinite loop -+ /* avoid thread entering the infinite loop */ - usleep(1000); - continue; - } -diff --git a/src/cmd/isulad-shim/terminal.c b/src/cmd/isulad-shim/terminal.c -index 0be4b4d..657c187 100644 ---- a/src/cmd/isulad-shim/terminal.c -+++ b/src/cmd/isulad-shim/terminal.c -@@ -170,7 +170,7 @@ static int shim_json_data_write(log_terminal *terminal, const char *buf, int rea - return (read_count - ret); - } - --static bool get_time_buffer(struct timespec *timestamp, char *timebuffer, size_t maxsize) -+static bool util_get_time_buffer(struct timespec *timestamp, char *timebuffer, size_t maxsize) - { - struct tm tm_utc = { 0 }; - int32_t nanos = 0; -@@ -196,7 +196,7 @@ static bool get_time_buffer(struct timespec *timestamp, char *timebuffer, size_t - return true; - } - --static bool get_now_time_buffer(char *timebuffer, size_t maxsize) -+static bool util_get_now_time_buffer(char *timebuffer, size_t maxsize) - { - int err = 0; - struct timespec ts; -@@ -206,7 +206,7 @@ static bool get_now_time_buffer(char *timebuffer, size_t maxsize) - return false; - } - -- return get_time_buffer(&ts, timebuffer, maxsize); -+ return util_get_time_buffer(&ts, timebuffer, maxsize); - } - - static ssize_t shim_logger_write(log_terminal *terminal, const char *type, const char *buf, int read_count) -@@ -236,7 +236,7 @@ static ssize_t shim_logger_write(log_terminal *terminal, const char *type, const - msg->log_len = read_count; - msg->stream = type ? safe_strdup(type) : safe_strdup("stdout"); - -- get_now_time_buffer(timebuffer, sizeof(timebuffer)); -+ util_get_now_time_buffer(timebuffer, sizeof(timebuffer)); - msg->time = safe_strdup(timebuffer); - json = logger_json_file_generate_json(msg, &ctx, &err); - if (!json) { -diff --git a/src/cmd/isulad/isulad_commands.c b/src/cmd/isulad/isulad_commands.c -index 4b1ace0..2826aae 100644 ---- a/src/cmd/isulad/isulad_commands.c -+++ b/src/cmd/isulad/isulad_commands.c -@@ -17,7 +17,6 @@ - #include - #include - #include --#include - #include - - #include "isulad_commands.h" -@@ -30,9 +29,9 @@ - #include "constants.h" - #include "isula_libutils/isulad_daemon_configs.h" - #include "utils_array.h" --#include "utils_convert.h" - #include "utils_string.h" - #include "utils_verify.h" -+#include "opt_ulimit.h" - - const char isulad_desc[] = "GLOBAL OPTIONS:"; - const char isulad_usage[] = "[global options]"; -@@ -42,171 +41,6 @@ void print_version() - printf("Version %s, commit %s\n", VERSION, ISULAD_GIT_COMMIT); - } - --static int check_default_ulimit_input(const char *val) --{ -- int ret = 0; -- if (val == NULL || strcmp(val, "") == 0) { -- COMMAND_ERROR("ulimit argument can't be empty"); -- ret = -1; -- goto out; -- } -- -- if (val[0] == '=' || val[strlen(val) - 1] == '=') { -- COMMAND_ERROR("Invalid ulimit argument: \"%s\", delimiter '=' can't" -- " be the first or the last character", -- val); -- ret = -1; -- } -- --out: -- return ret; --} -- --static void get_default_ulimit_split_parts(const char *val, char ***parts, size_t *parts_len, char deli) --{ -- *parts = util_string_split_multi(val, deli); -- if (*parts == NULL) { -- ERROR("Out of memory"); -- return; -- } -- *parts_len = util_array_len((const char **)(*parts)); --} -- --static int parse_soft_hard_default_ulimit(const char *val, char **limitvals, size_t limitvals_len, int64_t *soft, -- int64_t *hard) --{ -- int ret = 0; -- // parse soft -- ret = util_safe_llong(limitvals[0], (long long *)soft); -- if (ret < 0) { -- COMMAND_ERROR("Invalid ulimit soft value: \"%s\", parse int64 failed: %s", val, strerror(-ret)); -- ret = -1; -- goto out; -- } -- -- // parse hard if exists -- if (limitvals_len > 1) { -- ret = util_safe_llong(limitvals[1], (long long *)hard); -- if (ret < 0) { -- COMMAND_ERROR("Invalid ulimit hard value: \"%s\", parse int64 failed: %s", val, strerror(-ret)); -- ret = -1; -- goto out; -- } -- -- if (*soft > *hard) { -- COMMAND_ERROR("Ulimit soft limit must be less than or equal to hard limit: %lld > %lld", -- (long long int)(*soft), (long long int)(*hard)); -- ret = -1; -- goto out; -- } -- } else { -- *hard = *soft; // default to soft in case no hard was set -- } --out: -- return ret; --} -- --int check_default_ulimit_type(const char *type) --{ -- int ret = 0; -- char **tmptype = NULL; -- char *ulimit_valid_type[] = { -- // "as", // Disabled since this doesn't seem usable with the way Docker inits a container. -- "core", "cpu", "data", "fsize", "locks", "memlock", "msgqueue", "nice", -- "nofile", "nproc", "rss", "rtprio", "rttime", "sigpending", "stack", NULL -- }; -- -- for (tmptype = ulimit_valid_type; *tmptype != NULL; tmptype++) { -- if (strcmp(type, *tmptype) == 0) { -- break; -- } -- } -- -- if (*tmptype == NULL) { -- COMMAND_ERROR("Invalid ulimit type: %s", type); -- ret = -1; -- } -- return ret; --} -- --static host_config_ulimits_element *parse_default_ulimit(const char *val) --{ -- int ret = 0; -- int64_t soft = 0; -- int64_t hard = 0; -- size_t parts_len = 0; -- size_t limitvals_len = 0; -- char **parts = NULL; -- char **limitvals = NULL; -- host_config_ulimits_element *ulimit = NULL; -- -- ret = check_default_ulimit_input(val); -- if (ret != 0) { -- return NULL; -- } -- -- get_default_ulimit_split_parts(val, &parts, &parts_len, '='); -- if (parts == NULL) { -- ERROR("Out of memory"); -- return NULL; -- } else if (parts_len != 2) { -- COMMAND_ERROR("Invalid ulimit argument: %s", val); -- ret = -1; -- goto out; -- } -- -- ret = check_default_ulimit_type(parts[0]); -- if (ret != 0) { -- ret = -1; -- goto out; -- } -- -- if (parts[1][0] == ':' || parts[1][strlen(parts[1]) - 1] == ':') { -- COMMAND_ERROR("Invalid ulimit value: \"%s\", delimiter ':' can't be the first" -- " or the last character", -- val); -- ret = -1; -- goto out; -- } -- -- // parse value -- get_default_ulimit_split_parts(parts[1], &limitvals, &limitvals_len, ':'); -- if (limitvals == NULL) { -- ret = -1; -- goto out; -- } -- -- if (limitvals_len > 2) { -- COMMAND_ERROR("Too many limit value arguments - %s, can only have up to two, `soft[:hard]`", parts[1]); -- ret = -1; -- goto out; -- } -- -- ret = parse_soft_hard_default_ulimit(val, limitvals, limitvals_len, &soft, &hard); -- if (ret < 0) { -- goto out; -- } -- -- ulimit = util_common_calloc_s(sizeof(host_config_ulimits_element)); -- if (ulimit == NULL) { -- ret = -1; -- goto out; -- } -- ulimit->name = util_strdup_s(parts[0]); -- ulimit->hard = hard; -- ulimit->soft = soft; -- --out: -- util_free_array(parts); -- util_free_array(limitvals); -- if (ret != 0) { -- free_host_config_ulimits_element(ulimit); -- ulimit = NULL; -- } -- -- return ulimit; --} -- - int command_default_ulimit_append(command_option_t *option, const char *arg) - { - int ret = 0; -@@ -219,7 +53,7 @@ int command_default_ulimit_append(command_option_t *option, const char *arg) - goto out; - } - -- tmp = parse_default_ulimit(arg); -+ tmp = parse_opt_ulimit(arg); - if (tmp == NULL) { - ERROR("parse default ulimit from arg failed"); - ret = -1; -@@ -368,7 +202,7 @@ static int check_args_graph_path(struct service_arguments *args) - ret = -1; - goto out; - } -- if (cleanpath(args->json_confs->graph, dstpath, sizeof(dstpath)) == NULL) { -+ if (util_clean_path(args->json_confs->graph, dstpath, sizeof(dstpath)) == NULL) { - ERROR("failed to get clean path"); - ret = -1; - goto out; -@@ -391,7 +225,7 @@ static int check_args_state_path(struct service_arguments *args) - ret = -1; - goto out; - } -- if (cleanpath(args->json_confs->state, dstpath, sizeof(dstpath)) == NULL) { -+ if (util_clean_path(args->json_confs->state, dstpath, sizeof(dstpath)) == NULL) { - ERROR("failed to get clean path"); - ret = -1; - goto out; -@@ -722,7 +556,7 @@ static int check_conf_default_ulimit(const struct service_arguments *args) - goto out; - } - -- ret = check_default_ulimit_type(type); -+ ret = check_opt_ulimit_type(type); - if (ret != 0) { - goto out; - } -diff --git a/src/cmd/isulad/isulad_commands.h b/src/cmd/isulad/isulad_commands.h -index 68dca4e..78ec584 100644 ---- a/src/cmd/isulad/isulad_commands.h -+++ b/src/cmd/isulad/isulad_commands.h -@@ -29,7 +29,7 @@ void print_common_help(); - void print_version(); - - // Default help command if implementation doesn't prvide one --int commmand_default_help(const char * const program_name, int argc, char **argv); -+int command_default_help(const char * const program_name, int argc, char **argv); - int command_isulad_valid_socket(command_option_t *option, const char *arg); - int parse_args(struct service_arguments *args, int argc, const char **argv); - int check_args(struct service_arguments *args); -@@ -105,7 +105,7 @@ int command_default_ulimit_append(command_option_t *option, const char *arg); - "group", \ - 'G', \ - &(cmdargs)->json_confs->group, \ -- "Group for the unix socket(default is isulad)", \ -+ "Group for the unix socket(default is isula)", \ - NULL }, \ - { CMD_OPT_TYPE_STRING_DUP, \ - false, \ -diff --git a/src/cmd/isulad/main.c b/src/cmd/isulad/main.c -index b019ac0..7a932b6 100644 ---- a/src/cmd/isulad/main.c -+++ b/src/cmd/isulad/main.c -@@ -58,7 +58,9 @@ - #include "log_gather_api.h" - #include "container_api.h" - #include "plugin_api.h" -+#ifdef ENABLE_SELINUX - #include "selinux_label.h" -+#endif - #include "http.h" - #include "runtime_api.h" - #include "daemon_arguments.h" -@@ -747,6 +749,7 @@ out: - return ret; - } - -+#ifdef ENABLE_SELINUX - static int overlay_supports_selinux(bool *supported) - { - #define KALLSYMS_ITEM_MAX_LEN 100 -@@ -820,6 +823,7 @@ static int configure_kernel_security_support(const struct service_arguments *arg - } - return 0; - } -+#endif - - static int update_server_args(struct service_arguments *args) - { -@@ -868,12 +872,14 @@ static int update_server_args(struct service_arguments *args) - goto out; - } - -+#ifdef ENABLE_SELINUX - // Configure and validate the kernels security support. Note this is a Linux/FreeBSD - // operation only, so it is safe to pass *just* the runtime OS graphdriver. - if (configure_kernel_security_support(args)) { - ret = -1; - goto out; - } -+#endif - - out: - return ret; -@@ -949,7 +955,7 @@ static int init_log_gather_thread(const char *log_full_path, struct isula_libuti - return -1; - } - while (1) { -- usleep_nointerupt(1000); -+ util_usleep_nointerupt(1000); - if (log_gather_exitcode >= 0) { - break; - } -@@ -1398,11 +1404,6 @@ int main(int argc, char **argv) - goto failure; - } - -- if (init_cgroups_path("/lxc", 0)) { -- msg = g_isulad_errmsg ? g_isulad_errmsg : "Failed to init cgroups path"; -- goto failure; -- } -- - if (add_sighandler()) { - msg = "Failed to add sig handlers"; - goto failure; -diff --git a/src/cmd/options/CMakeLists.txt b/src/cmd/options/CMakeLists.txt -new file mode 100644 -index 0000000..358634b ---- /dev/null -+++ b/src/cmd/options/CMakeLists.txt -@@ -0,0 +1,5 @@ -+# get current directory sources files -+aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} top_srcs) -+ -+set(OPT_SRCS ${top_srcs} PARENT_SCOPE) -+set(OPT_INCS ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE) -diff --git a/src/cmd/options/opt_ulimit.c b/src/cmd/options/opt_ulimit.c -new file mode 100644 -index 0000000..1a9c616 ---- /dev/null -+++ b/src/cmd/options/opt_ulimit.c -@@ -0,0 +1,190 @@ -+/****************************************************************************** -+ * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. 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: lifeng -+ * Create: 2020-09-28 -+ * Description: provide ulimit options parse function -+ ******************************************************************************/ -+#include "opt_ulimit.h" -+ -+#include -+#include -+#include -+#include -+ -+#include "isula_libutils/log.h" -+#include "utils.h" -+#include "utils_array.h" -+#include "utils_convert.h" -+#include "utils_string.h" -+ -+static int check_ulimit_input(const char *val) -+{ -+ int ret = 0; -+ if (val == NULL || strcmp(val, "") == 0) { -+ COMMAND_ERROR("ulimit argument can't be empty"); -+ ret = -1; -+ goto out; -+ } -+ -+ if (val[0] == '=' || val[strlen(val) - 1] == '=') { -+ COMMAND_ERROR("Invalid ulimit argument: \"%s\", delimiter '=' can't" -+ " be the first or the last character", -+ val); -+ ret = -1; -+ } -+ -+out: -+ return ret; -+} -+ -+static void get_ulimit_split_parts(const char *val, char ***parts, size_t *parts_len, char deli) -+{ -+ *parts = util_string_split_multi(val, deli); -+ if (*parts == NULL) { -+ COMMAND_ERROR("Out of memory"); -+ return; -+ } -+ *parts_len = util_array_len((const char **)(*parts)); -+} -+ -+static int parse_soft_hard_ulimit(const char *val, char **limitvals, size_t limitvals_len, int64_t *soft, int64_t *hard) -+{ -+ int ret = 0; -+ // parse soft -+ ret = util_safe_llong(limitvals[0], (long long *)soft); -+ if (ret < 0) { -+ COMMAND_ERROR("Invalid ulimit soft value: \"%s\", parse int64 failed: %s", val, strerror(-ret)); -+ ret = -1; -+ goto out; -+ } -+ -+ // parse hard if exists -+ if (limitvals_len > 1) { -+ ret = util_safe_llong(limitvals[1], (long long *)hard); -+ if (ret < 0) { -+ COMMAND_ERROR("Invalid ulimit hard value: \"%s\", parse int64 failed: %s", val, strerror(-ret)); -+ ret = -1; -+ goto out; -+ } -+ -+ if (*soft > *hard) { -+ COMMAND_ERROR("Ulimit soft limit must be less than or equal to hard limit: %lld > %lld", -+ (long long int)(*soft), (long long int)(*hard)); -+ ret = -1; -+ goto out; -+ } -+ } else { -+ *hard = *soft; // default to soft in case no hard was set -+ } -+out: -+ return ret; -+} -+ -+int check_opt_ulimit_type(const char *type) -+{ -+ int ret = 0; -+ char **tmptype = NULL; -+ char *ulimit_valid_type[] = { -+ // "as", // Disabled since this doesn't seem usable with the way Docker inits a container. -+ "core", "cpu", "data", "fsize", "locks", "memlock", "msgqueue", "nice", -+ "nofile", "nproc", "rss", "rtprio", "rttime", "sigpending", "stack", NULL -+ }; -+ -+ for (tmptype = ulimit_valid_type; *tmptype != NULL; tmptype++) { -+ if (strcmp(type, *tmptype) == 0) { -+ break; -+ } -+ } -+ -+ if (*tmptype == NULL) { -+ COMMAND_ERROR("Invalid ulimit type: %s", type); -+ ret = -1; -+ } -+ return ret; -+} -+ -+host_config_ulimits_element *parse_opt_ulimit(const char *val) -+{ -+ int ret = 0; -+ int64_t soft = 0; -+ int64_t hard = 0; -+ size_t parts_len = 0; -+ size_t limitvals_len = 0; -+ char **parts = NULL; -+ char **limitvals = NULL; -+ host_config_ulimits_element *ulimit = NULL; -+ -+ ret = check_ulimit_input(val); -+ if (ret != 0) { -+ return NULL; -+ } -+ -+ get_ulimit_split_parts(val, &parts, &parts_len, '='); -+ if (parts == NULL) { -+ ERROR("Out of memory"); -+ return NULL; -+ } else if (parts_len != 2) { -+ COMMAND_ERROR("Invalid ulimit argument: %s", val); -+ ret = -1; -+ goto out; -+ } -+ -+ ret = check_opt_ulimit_type(parts[0]); -+ if (ret != 0) { -+ ret = -1; -+ goto out; -+ } -+ -+ if (parts[1][0] == ':' || parts[1][strlen(parts[1]) - 1] == ':') { -+ COMMAND_ERROR("Invalid ulimit value: \"%s\", delimiter ':' can't be the first" -+ " or the last character", -+ val); -+ ret = -1; -+ goto out; -+ } -+ -+ // parse value -+ get_ulimit_split_parts(parts[1], &limitvals, &limitvals_len, ':'); -+ if (limitvals == NULL) { -+ ret = -1; -+ goto out; -+ } -+ -+ if (limitvals_len > 2) { -+ COMMAND_ERROR("Too many limit value arguments - %s, can only have up to two, `soft[:hard]`", parts[1]); -+ ret = -1; -+ goto out; -+ } -+ -+ ret = parse_soft_hard_ulimit(val, limitvals, limitvals_len, &soft, &hard); -+ if (ret < 0) { -+ goto out; -+ } -+ -+ ulimit = util_common_calloc_s(sizeof(host_config_ulimits_element)); -+ if (ulimit == NULL) { -+ ret = -1; -+ goto out; -+ } -+ ulimit->name = util_strdup_s(parts[0]); -+ ulimit->hard = hard; -+ ulimit->soft = soft; -+ -+out: -+ util_free_array(parts); -+ util_free_array(limitvals); -+ if (ret != 0) { -+ free_host_config_ulimits_element(ulimit); -+ ulimit = NULL; -+ } -+ -+ return ulimit; -+} -\ No newline at end of file -diff --git a/src/client/connect/pack_config.h b/src/cmd/options/opt_ulimit.h -similarity index 65% -rename from src/client/connect/pack_config.h -rename to src/cmd/options/opt_ulimit.h -index c1062fa..657955d 100644 ---- a/src/client/connect/pack_config.h -+++ b/src/cmd/options/opt_ulimit.h -@@ -8,27 +8,28 @@ - * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR - * PURPOSE. - * See the Mulan PSL v2 for more details. -- * Author: tanyifeng -- * Create: 2018-11-08 -- * Description: provide container package configure definition -+ * Author: lifeng -+ * Create: 2020-09-28 -+ * Description: provide ulimit options parse function - ******************************************************************************/ --#ifndef CLIENT_CONNECT_PACK_CONFIG_H --#define CLIENT_CONNECT_PACK_CONFIG_H -+#ifndef CMD_OPTIONS_ULIMIT_H -+#define CMD_OPTIONS_ULIMIT_H - --#include "libisula.h" -+#include -+#include -+#include -+ -+#include "isula_libutils/host_config.h" - - #ifdef __cplusplus - extern "C" { - #endif - --int generate_hostconfig(const isula_host_config_t *srcconfig, char **hostconfigstr); -- --int generate_container_config(const isula_container_config_t *custom_conf, -- char **container_config_str); -+int check_opt_ulimit_type(const char *type); -+host_config_ulimits_element *parse_opt_ulimit(const char *val); - - #ifdef __cplusplus - } - #endif - - #endif -- -diff --git a/src/common/constants.h b/src/common/constants.h -index 5aca48e..420ac92 100644 ---- a/src/common/constants.h -+++ b/src/common/constants.h -@@ -113,9 +113,6 @@ extern "C" { - - #define AUTH_PLUGIN "authz-broker" - --#define ISULAD_ISULA_ADAPTER "isula-adapter" --#define ISULAD_ISULA_ACCEL_ARGS "isulad.accel.args" --#define ISULAD_ISULA_ACCEL_ARGS_SEPERATOR ";" - #define ISULAD_ENABLE_PLUGINS "ISULAD_ENABLE_PLUGINS" - #define ISULAD_ENABLE_PLUGINS_SEPERATOR "," - #define ISULAD_ENABLE_PLUGINS_SEPERATOR_CHAR ',' -diff --git a/src/contrib/config/config.json b/src/contrib/config/config.json -index e87420d..b14c4a9 100644 ---- a/src/contrib/config/config.json -+++ b/src/contrib/config/config.json -@@ -49,7 +49,6 @@ - "path": "rootfs", - "readonly": false - }, -- "hostname": "ubuntu", - "mounts": [ - { - "destination": "/proc", -diff --git a/src/contrib/config/daemon.json b/src/contrib/config/daemon.json -index 2eac55e..9ffb08e 100644 ---- a/src/contrib/config/daemon.json -+++ b/src/contrib/config/daemon.json -@@ -1,5 +1,5 @@ - { -- "group": "isulad", -+ "group": "isula", - "default-runtime": "lcr", - "graph": "/var/lib/isulad", - "state": "/var/run/isulad", -diff --git a/src/contrib/config/systemcontainer_config.json b/src/contrib/config/systemcontainer_config.json -index b9e6e8c..c7e2ebd 100644 ---- a/src/contrib/config/systemcontainer_config.json -+++ b/src/contrib/config/systemcontainer_config.json -@@ -49,7 +49,6 @@ - "path": "rootfs", - "readonly": false - }, -- "hostname": "ubuntu", - "mounts": [ - { - "destination": "/proc", -diff --git a/src/daemon/common/CMakeLists.txt b/src/daemon/common/CMakeLists.txt -index f84830a..bd1badc 100644 ---- a/src/daemon/common/CMakeLists.txt -+++ b/src/daemon/common/CMakeLists.txt -@@ -1,13 +1,18 @@ - # get current directory sources files --aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/ daemon_common_top_srcs) -+aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} daemon_common_top_srcs) -+ -+if (NOT ENABLE_SELINUX) -+ list(REMOVE_ITEM daemon_common_top_srcs "${CMAKE_CURRENT_SOURCE_DIR}/selinux_label.c") -+endif() -+ - set(local_daemon_common_srcs ${daemon_common_top_srcs}) --set(local_daemon_common_incs ${CMAKE_CURRENT_SOURCE_DIR}) - - set(DAEMON_COMMON_SRCS - ${local_daemon_common_srcs} - PARENT_SCOPE - ) -+ - set(DAEMON_COMMON_INCS -- ${local_daemon_common_incs} -+ ${CMAKE_CURRENT_SOURCE_DIR} - PARENT_SCOPE - ) -diff --git a/src/daemon/common/selinux_label.c b/src/daemon/common/selinux_label.c -index b97e07f..33c06a8 100644 ---- a/src/daemon/common/selinux_label.c -+++ b/src/daemon/common/selinux_label.c -@@ -219,7 +219,7 @@ static int read_con(const char *fpath, char **content) - return -1; - } - -- tmp = isula_utils_read_file(fpath); -+ tmp = util_read_content_from_file(fpath); - if (tmp == NULL) { - ERROR("Failed to read file: %s", fpath); - ret = -1; -diff --git a/src/daemon/common/sysinfo.c b/src/daemon/common/sysinfo.c -index f147aee..e5de393 100644 ---- a/src/daemon/common/sysinfo.c -+++ b/src/daemon/common/sysinfo.c -@@ -18,6 +18,7 @@ - #include - #include - #include -+#include - - #include "err_msg.h" - #include "sysinfo.h" -@@ -106,7 +107,7 @@ static int add_null_to_list(void ***list) - } - newsize = (index + 2) * sizeof(void **); - oldsize = index * sizeof(void **); -- ret = mem_realloc((void **)&newlist, newsize, (*list), oldsize); -+ ret = util_mem_realloc((void **)&newlist, newsize, (*list), oldsize); - if (ret < 0) { - ERROR("Out of memory"); - return -1; -@@ -798,7 +799,7 @@ static void check_cgroup_cpuset_info(struct layer **layers, bool quiet, cgroup_c - goto error; - } - -- cpusetinfo->cpus = isula_utils_read_file(cpuset_cpus_path); -+ cpusetinfo->cpus = util_read_content_from_file(cpuset_cpus_path); - if (cpusetinfo->cpus == NULL) { - ERROR("Failed to read the file: %s", cpuset_cpus_path); - goto error; -@@ -810,7 +811,7 @@ static void check_cgroup_cpuset_info(struct layer **layers, bool quiet, cgroup_c - goto error; - } - -- cpusetinfo->mems = isula_utils_read_file(cpuset_mems_path); -+ cpusetinfo->mems = util_read_content_from_file(cpuset_mems_path); - if (cpusetinfo->mems == NULL) { - ERROR("Failed to read the file: %s", cpuset_mems_path); - goto error; -@@ -1170,6 +1171,8 @@ sysinfo_t *get_sys_info(bool quiet) - goto out; - } - -+ sysinfo->ncpus = get_nprocs(); -+ - check_cgroup_mem(layers, quiet, &sysinfo->cgmeminfo); - check_cgroup_cpu(layers, quiet, &sysinfo->cgcpuinfo); - check_cgroup_hugetlb(layers, quiet, &sysinfo->hugetlbinfo); -diff --git a/src/daemon/common/sysinfo.h b/src/daemon/common/sysinfo.h -index 7089c4e..8468e00 100644 ---- a/src/daemon/common/sysinfo.h -+++ b/src/daemon/common/sysinfo.h -@@ -71,6 +71,7 @@ typedef struct { - } cgroup_files_info_t; - - typedef struct { -+ int ncpus; - cgroup_mem_info_t cgmeminfo; - cgroup_cpu_info_t cgcpuinfo; - cgroup_hugetlb_info_t hugetlbinfo; -@@ -143,4 +144,3 @@ void free_mounts_info(mountinfo_t **minfos); - #endif - - #endif // DAEMON_COMMON_SYSINFO_H -- -diff --git a/src/daemon/config/daemon_arguments.c b/src/daemon/config/daemon_arguments.c -index 63e525b..ef28764 100644 ---- a/src/daemon/config/daemon_arguments.c -+++ b/src/daemon/config/daemon_arguments.c -@@ -109,7 +109,7 @@ int service_arguments_init(struct service_arguments *args) - goto free_out; - } - args->json_confs->engine = util_strdup_s("lcr"); -- args->json_confs->group = util_strdup_s("isulad"); -+ args->json_confs->group = util_strdup_s("isula"); - args->json_confs->graph = util_strdup_s(ISULAD_ROOT_PATH); - args->json_confs->state = util_strdup_s(ISULAD_STATE_PATH); - args->json_confs->log_level = util_strdup_s("INFO"); -@@ -279,7 +279,7 @@ int ulimit_array_append(host_config_ulimits_element ***ulimit_array, const host_ - new_size = (len + 2) * sizeof(host_config_ulimits_element *); - old_size = len * sizeof(host_config_ulimits_element *); - -- ret = mem_realloc((void **)(&new_ulimit_array), new_size, (void *)*ulimit_array, old_size); -+ ret = util_mem_realloc((void **)(&new_ulimit_array), new_size, (void *)*ulimit_array, old_size); - if (ret != 0) { - ERROR("Failed to realloc memory for append ulimit"); - return -1; -diff --git a/src/daemon/config/isulad_config.c b/src/daemon/config/isulad_config.c -index dac0332..c79c6a1 100644 ---- a/src/daemon/config/isulad_config.c -+++ b/src/daemon/config/isulad_config.c -@@ -223,6 +223,30 @@ free_out: - return epath; - } - -+int conf_get_cgroup_cpu_rt(int64_t *cpu_rt_period, int64_t *cpu_rt_runtime) -+{ -+ struct service_arguments *conf = NULL; -+ -+ if (isulad_server_conf_rdlock() != 0) { -+ return -1; -+ } -+ -+ conf = conf_get_server_conf(); -+ if (conf == NULL) { -+ (void)isulad_server_conf_unlock(); -+ return -1; -+ } -+ -+ *cpu_rt_period = conf->json_confs->cpu_rt_period; -+ *cpu_rt_runtime = conf->json_confs->cpu_rt_runtime; -+ -+ if (isulad_server_conf_unlock() != 0) { -+ return -1; -+ } -+ -+ return 0; -+} -+ - /* conf get graph checked flag file path */ - char *conf_get_graph_check_flag_file() - { -@@ -857,16 +881,16 @@ out: - return check_flag; - } - --#define OCI_STR_ARRAY_DUP(src, dest, srclen, destlen, ret) \ -- do { \ -- if ((src) != NULL) { \ -- (dest) = str_array_dup((const char **)(src), (srclen)); \ -- if ((dest) == NULL) { \ -- (ret) = -1; \ -- goto out; \ -- } \ -- (destlen) = (srclen); \ -- } \ -+#define OCI_STR_ARRAY_DUP(src, dest, srclen, destlen, ret) \ -+ do { \ -+ if ((src) != NULL) { \ -+ (dest) = util_str_array_dup((const char **)(src), (srclen)); \ -+ if ((dest) == NULL) { \ -+ (ret) = -1; \ -+ goto out; \ -+ } \ -+ (destlen) = (srclen); \ -+ } \ - } while (0) - - #define HOOKS_ELEM_DUP_DEF(item) \ -@@ -1049,7 +1073,7 @@ char *conf_get_default_runtime() - goto out; - } - -- result = strings_to_lower(conf->json_confs->default_runtime); -+ result = util_strings_to_lower(conf->json_confs->default_runtime); - - out: - (void)isulad_server_conf_unlock(); -@@ -1149,7 +1173,7 @@ static int set_path_group(const char *rpath, const char *group) - return -1; - } - } else { -- if (strcmp(group, "docker") == 0 || strcmp(group, "isulad") == 0) { -+ if (strcmp(group, "docker") == 0 || strcmp(group, "isula") == 0) { - DEBUG("Warning: could not change group %s to %s", rpath, group); - } else { - ERROR("Group %s not found", group); -@@ -1202,172 +1226,6 @@ out: - return ret; - } - --/* maybe create cpu realtime file */ --static int maybe_create_cpu_realtime_file(bool present, int64_t value, const char *file, const char *path) --{ -- int ret; -- int fd = 0; -- ssize_t nwrite; -- char fpath[PATH_MAX] = { 0 }; -- char buf[ISULAD_NUMSTRLEN64] = { 0 }; -- -- if (!present || value == 0) { -- return 0; -- } -- -- ret = util_mkdir_p(path, CONFIG_DIRECTORY_MODE); -- if (ret != 0) { -- ERROR("Failed to mkdir: %s", path); -- return -1; -- } -- -- int nret = snprintf(fpath, sizeof(fpath), "%s/%s", path, file); -- if (nret < 0 || nret >= sizeof(fpath)) { -- ERROR("Failed to print string"); -- return -1; -- } -- nret = snprintf(buf, sizeof(buf), "%lld", (long long int)value); -- if (nret < 0 || (size_t)nret >= sizeof(buf)) { -- ERROR("Failed to print string"); -- return -1; -- } -- -- fd = util_open(fpath, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0700); -- if (fd < 0) { -- ERROR("Failed to open file: %s: %s", fpath, strerror(errno)); -- isulad_set_error_message("Failed to open file: %s: %s", fpath, strerror(errno)); -- return -1; -- } -- nwrite = util_write_nointr(fd, buf, strlen(buf)); -- if (nwrite < 0) { -- ERROR("Failed to write %s to %s: %s", buf, fpath, strerror(errno)); -- isulad_set_error_message("Failed to write '%s' to '%s': %s", buf, fpath, strerror(errno)); -- close(fd); -- return -1; -- } -- close(fd); -- -- return 0; --} -- --static int get_cgroup_cpu_rt(int64_t *cpu_rt_period, int64_t *cpu_rt_runtime) --{ -- struct service_arguments *conf = NULL; -- -- if (isulad_server_conf_rdlock() != 0) { -- return -1; -- } -- -- conf = conf_get_server_conf(); -- if (conf == NULL) { -- (void)isulad_server_conf_unlock(); -- return -1; -- } -- -- *cpu_rt_period = conf->json_confs->cpu_rt_period; -- *cpu_rt_runtime = conf->json_confs->cpu_rt_runtime; -- -- if (isulad_server_conf_unlock() != 0) { -- return -1; -- } -- -- return 0; --} -- --static int recursively_create_cgroup(const char *path, int recursive_depth, int64_t cpu_rt_period, -- int64_t cpu_rt_runtime) --{ -- int ret = 0; -- sysinfo_t *sysinfo = NULL; -- char *dup = NULL; -- char *dirpath = NULL; -- char *mnt = NULL; -- char *root = NULL; -- char fpath[PATH_MAX] = { 0 }; -- -- dup = util_strdup_s(path); -- dirpath = dirname(dup); -- ret = init_cgroups_path(dirpath, (recursive_depth + 1)); -- free(dup); -- if (ret != 0) { -- return ret; -- } -- -- ret = find_cgroup_mountpoint_and_root("cpu", &mnt, &root); -- if (ret != 0 || mnt == NULL || root == NULL) { -- ERROR("Can not find cgroup mnt and root path for subsystem 'cpu'"); -- isulad_set_error_message("Can not find cgroup mnt and root path for subsystem 'cpu'"); -- ret = -1; -- goto out; -- } -- -- // When iSulad is run inside iSulad/docker, the root is based of the host cgroup. -- // Replace root to "/" -- if (strncmp(root, "/lxc/", strlen("/lxc/")) != 0) { -- root[1] = '\0'; -- } -- -- int nret = snprintf(fpath, sizeof(fpath), "%s/%s/%s", mnt, root, path); -- if (nret < 0 || (size_t)nret >= sizeof(fpath)) { -- ERROR("Failed to print string"); -- ret = -1; -- goto out; -- } -- -- sysinfo = get_sys_info(true); -- if (sysinfo == NULL) { -- ERROR("Can not get system info"); -- ret = -1; -- goto out; -- } -- -- ret = maybe_create_cpu_realtime_file(sysinfo->cgcpuinfo.cpu_rt_period, cpu_rt_period, "cpu.rt_period_us", fpath); -- if (ret != 0) { -- goto out; -- } -- ret = maybe_create_cpu_realtime_file(sysinfo->cgcpuinfo.cpu_rt_runtime, cpu_rt_runtime, "cpu.rt_runtime_us", fpath); -- if (ret != 0) { -- goto out; -- } --out: -- free(mnt); -- free(root); -- free_sysinfo(sysinfo); -- return ret; --} -- --/* init cgroups path */ --int init_cgroups_path(const char *path, int recursive_depth) --{ -- int64_t cpu_rt_period = 0; -- int64_t cpu_rt_runtime = 0; -- -- if ((recursive_depth + 1) > MAX_PATH_DEPTH) { -- ERROR("Reach the max cgroup depth:%s", path); -- return -1; -- } -- -- if (path == NULL || strcmp(path, "/") == 0 || strcmp(path, ".") == 0) { -- return 0; -- } -- -- if (get_cgroup_cpu_rt(&cpu_rt_period, &cpu_rt_runtime)) { -- return -1; -- } -- -- if (cpu_rt_period == 0 && cpu_rt_runtime == 0) { -- return 0; -- } -- -- // Recursively create cgroup to ensure that the system and all parent cgroups have values set -- // for the period and runtime as this limits what the children can be set to. -- if (recursively_create_cgroup(path, recursive_depth, cpu_rt_period, cpu_rt_runtime)) { -- return -1; -- } -- -- return 0; --} -- - #define OVERRIDE_STRING_VALUE(dst, src) \ - do { \ - if ((src) != NULL && strlen((src)) != 0) { \ -@@ -1658,7 +1516,9 @@ int merge_json_confs_into_global(struct service_arguments *args) - goto out; - } - -+#ifdef ENABLE_SELINUX - args->json_confs->selinux_enabled = tmp_json_confs->selinux_enabled; -+#endif - - out: - free(err); -diff --git a/src/daemon/config/isulad_config.h b/src/daemon/config/isulad_config.h -index c4dd8c1..b5c64c5 100644 ---- a/src/daemon/config/isulad_config.h -+++ b/src/daemon/config/isulad_config.h -@@ -49,6 +49,8 @@ char *conf_get_isulad_logdriver(); - int conf_get_daemon_log_config(char **loglevel, char **logdriver, char **engine_log_path); - char *conf_get_isulad_log_gather_fifo_path(); - -+int conf_get_cgroup_cpu_rt(int64_t *cpu_rt_period, int64_t *cpu_rt_runtime); -+ - char *conf_get_isulad_log_file(); - char *conf_get_engine_log_file(); - char *conf_get_enable_plugins(); -@@ -74,8 +76,6 @@ int conf_get_isulad_default_ulimit(host_config_ulimits_element ***ulimit); - - unsigned int conf_get_start_timeout(); - --int init_cgroups_path(const char *path, int recursive_depth); -- - char **conf_get_insecure_registry_list(); - - char **conf_get_registry_list(); -diff --git a/src/daemon/entry/connect/grpc/grpc_server_tls_auth.cc b/src/daemon/entry/connect/grpc/grpc_server_tls_auth.cc -index 18f2719..1bb1b92 100644 ---- a/src/daemon/entry/connect/grpc/grpc_server_tls_auth.cc -+++ b/src/daemon/entry/connect/grpc/grpc_server_tls_auth.cc -@@ -28,7 +28,7 @@ Status auth(ServerContext *context, std::string action) - const std::multimap init_metadata = context->client_metadata(); - auto tls_mode_kv = init_metadata.find("tls_mode"); - if (tls_mode_kv == init_metadata.end()) { -- return Status(StatusCode::UNKNOWN, "unkown error"); -+ return Status(StatusCode::UNKNOWN, "unknown error"); - } - std::string tls_mode = std::string(tls_mode_kv->second.data(), tls_mode_kv->second.length()); - if (tls_mode == "0") { -@@ -39,7 +39,7 @@ Status auth(ServerContext *context, std::string action) - } else if (AuthorizationPluginConfig::auth_plugin == "authz-broker") { - auto username_kv = init_metadata.find("username"); - if (username_kv == init_metadata.end()) { -- return Status(StatusCode::UNKNOWN, "unkown error"); -+ return Status(StatusCode::UNKNOWN, "unknown error"); - } - std::string username = std::string(username_kv->second.data(), username_kv->second.length()); - char *errmsg = nullptr; -diff --git a/src/daemon/entry/cri/cni_network_plugin.cc b/src/daemon/entry/cri/cni_network_plugin.cc -index 3442560..c1a4e1e 100644 ---- a/src/daemon/entry/cri/cni_network_plugin.cc -+++ b/src/daemon/entry/cri/cni_network_plugin.cc -@@ -42,7 +42,7 @@ static auto GetLoNetwork(std::vector binDirs) -> std::unique_ptr lo) - } - } - --void CniNetworkPlugin::SetDefaultNetwork(std::unique_ptr network, -- std::vector &binDirs, Errors &err) -+void CniNetworkPlugin::SetDefaultNetwork(std::unique_ptr network, std::vector &binDirs, -+ Errors &err) - { - if (network == nullptr) { - return; -@@ -154,8 +154,8 @@ void CniNetworkPlugin::PlatformInit(Errors &error) - free(tpath); - } - --auto CniNetworkPlugin::GetCNIConfFiles(const std::string &pluginDir, std::vector &vect_files, -- Errors &err) -> int -+auto CniNetworkPlugin::GetCNIConfFiles(const std::string &pluginDir, std::vector &vect_files, Errors &err) -+-> int - { - int ret { 0 }; - std::string usePluginDir { pluginDir }; -@@ -280,7 +280,8 @@ void CniNetworkPlugin::GetDefaultCNINetwork(const std::string &confDir, std::vec - continue; - } - -- SetDefaultNetwork(std::unique_ptr(new (std::nothrow) CNINetwork(n_list->name, n_list)), binDirs, err); -+ SetDefaultNetwork(std::unique_ptr(new (std::nothrow) CNINetwork(n_list->name, n_list)), binDirs, -+ err); - found = true; - break; - } -@@ -349,9 +350,8 @@ void CniNetworkPlugin::Status(Errors &err) - CheckInitialized(err); - } - --void CniNetworkPlugin::SetUpPod(const std::string &ns, const std::string &name, -- const std::string &interfaceName, const std::string &id, -- const std::map &annotations, -+void CniNetworkPlugin::SetUpPod(const std::string &ns, const std::string &name, const std::string &interfaceName, -+ const std::string &id, const std::map &annotations, - const std::map &options, Errors &err) - { - CheckInitialized(err); -@@ -393,8 +393,8 @@ void CniNetworkPlugin::SetUpPod(const std::string &ns, const std::string &name, - } - - void CniNetworkPlugin::TearDownPod(const std::string &ns, const std::string &name, const std::string &interfaceName, -- const std::string &id, -- const std::map &annotations, Errors &err) -+ const std::string &id, const std::map &annotations, -+ Errors &err) - { - CheckInitialized(err); - if (err.NotEmpty()) { -@@ -493,12 +493,12 @@ out: - INFO("get_pod_network_status: %s", podSandboxID.c_str()); - } - --void CniNetworkPlugin::AddToNetwork(CNINetwork *snetwork, const std::string &podName, -- const std::string &podNamespace, const std::string &interfaceName, -- const std::string &podSandboxID, const std::string &podNetnsPath, -+void CniNetworkPlugin::AddToNetwork(CNINetwork *snetwork, const std::string &podName, const std::string &podNamespace, -+ const std::string &interfaceName, const std::string &podSandboxID, -+ const std::string &podNetnsPath, - const std::map &annotations, -- const std::map &options, -- struct result **presult, Errors &err) -+ const std::map &options, struct result **presult, -+ Errors &err) - { - struct runtime_conf *rc { - nullptr -@@ -510,7 +510,8 @@ void CniNetworkPlugin::AddToNetwork(CNINetwork *snetwork, const std::string &pod - return; - } - -- BuildCNIRuntimeConf(podName, podNamespace, interfaceName, podSandboxID, podNetnsPath, annotations, options, &rc, err); -+ BuildCNIRuntimeConf(podName, podNamespace, interfaceName, podSandboxID, podNetnsPath, annotations, options, &rc, -+ err); - if (err.NotEmpty()) { - ERROR("Error adding network when building cni runtime conf: %s", err.GetCMessage()); - return; -@@ -536,12 +537,10 @@ void CniNetworkPlugin::AddToNetwork(CNINetwork *snetwork, const std::string &pod - free(serr); - } - --void CniNetworkPlugin::DeleteFromNetwork(CNINetwork *network, -- const std::string &podName, const std::string &podNamespace, -- const std::string &interfaceName, const std::string &podSandboxID, -- const std::string &podNetnsPath, -- const std::map &annotations, -- Errors &err) -+void CniNetworkPlugin::DeleteFromNetwork(CNINetwork *network, const std::string &podName, -+ const std::string &podNamespace, const std::string &interfaceName, -+ const std::string &podSandboxID, const std::string &podNetnsPath, -+ const std::map &annotations, Errors &err) - { - struct runtime_conf *rc { - nullptr -@@ -553,7 +552,8 @@ void CniNetworkPlugin::DeleteFromNetwork(CNINetwork *network, - return; - } - std::map options; -- BuildCNIRuntimeConf(podName, podNamespace, interfaceName, podSandboxID, podNetnsPath, annotations, options, &rc, err); -+ BuildCNIRuntimeConf(podName, podNamespace, interfaceName, podSandboxID, podNetnsPath, annotations, options, &rc, -+ err); - if (err.NotEmpty()) { - ERROR("Error deleting network when building cni runtime conf: %s", err.GetCMessage()); - return; -@@ -579,11 +579,10 @@ void CniNetworkPlugin::DeleteFromNetwork(CNINetwork *network, - free(serr); - } - --static void PrepareRuntimeConf(const std::string &podName, -- const std::string &podNs, const std::string &interfaceName, -+static void PrepareRuntimeConf(const std::string &podName, const std::string &podNs, const std::string &interfaceName, - const std::string &podSandboxID, const std::string &podNetnsPath, -- const std::map &options, -- struct runtime_conf **cni_rc, Errors &err) -+ const std::map &options, struct runtime_conf **cni_rc, -+ Errors &err) - { - const size_t defaultLen = 5; - if (cni_rc == nullptr) { -@@ -633,9 +632,9 @@ free_out: - free_runtime_conf(rt); - } - --void CniNetworkPlugin::BuildCNIRuntimeConf(const std::string &podName, -- const std::string &podNs, const std::string &interfaceName, -- const std::string &podSandboxID, const std::string &podNetnsPath, -+void CniNetworkPlugin::BuildCNIRuntimeConf(const std::string &podName, const std::string &podNs, -+ const std::string &interfaceName, const std::string &podSandboxID, -+ const std::string &podNetnsPath, - const std::map &annotations, - const std::map &options, - struct runtime_conf **cni_rc, Errors &err) -@@ -697,7 +696,7 @@ void CniNetworkPlugin::BuildCNIRuntimeConf(const std::string &podName, - rt->p_mapping[rt->p_mapping_len]->container_port = *(portMapping.GetContainerPort()); - } - if (portMapping.GetProtocol() != nullptr) { -- rt->p_mapping[rt->p_mapping_len]->protocol = strings_to_lower(portMapping.GetProtocol()->c_str()); -+ rt->p_mapping[rt->p_mapping_len]->protocol = util_strings_to_lower(portMapping.GetProtocol()->c_str()); - } - // ignore hostip, because GetPodPortMappings() don't set - (rt->p_mapping_len)++; -diff --git a/src/daemon/entry/cri/cri_container.cc b/src/daemon/entry/cri/cri_container.cc -index f6a2558..c6d9599 100644 ---- a/src/daemon/entry/cri/cri_container.cc -+++ b/src/daemon/entry/cri/cri_container.cc -@@ -37,8 +37,7 @@ - #include "url.h" - #include "ws_server.h" - --auto CRIRuntimeServiceImpl::GetRealContainerOrSandboxID(const std::string &id, bool isSandbox, -- Errors &error) -> std::string -+std::string CRIRuntimeServiceImpl::GetRealContainerOrSandboxID(const std::string &id, bool isSandbox, Errors &error) - { - std::string realID; - -@@ -121,20 +120,20 @@ void CRIRuntimeServiceImpl::GetContainerTimeStamps(container_inspect *inspect, i - return; - } - if (createdAt != nullptr) { -- if (to_unix_nanos_from_str(inspect->created, createdAt) != 0) { -+ if (util_to_unix_nanos_from_str(inspect->created, createdAt) != 0) { - err.Errorf("Parse createdAt failed: %s", inspect->created); - return; - } - } - if (inspect->state != nullptr) { - if (startedAt != nullptr) { -- if (to_unix_nanos_from_str(inspect->state->started_at, startedAt) != 0) { -+ if (util_to_unix_nanos_from_str(inspect->state->started_at, startedAt) != 0) { - err.Errorf("Parse startedAt failed: %s", inspect->state->started_at); - return; - } - } - if (finishedAt != nullptr) { -- if (to_unix_nanos_from_str(inspect->state->finished_at, finishedAt) != 0) { -+ if (util_to_unix_nanos_from_str(inspect->state->finished_at, finishedAt) != 0) { - err.Errorf("Parse finishedAt failed: %s", inspect->state->finished_at); - return; - } -@@ -169,14 +168,15 @@ auto CRIRuntimeServiceImpl::GenerateCreateContainerCustomConfig( - if (!podSandboxConfig.log_directory().empty() || !containerConfig.log_path().empty()) { - std::string logpath = podSandboxConfig.log_directory() + "/" + containerConfig.log_path(); - char real_logpath[PATH_MAX] { 0 }; -- if (cleanpath(logpath.c_str(), real_logpath, sizeof(real_logpath)) == nullptr) { -+ if (util_clean_path(logpath.c_str(), real_logpath, sizeof(real_logpath)) == nullptr) { - ERROR("Failed to clean path: %s", logpath.c_str()); - error.Errorf("Failed to clean path: %s", logpath.c_str()); - goto cleanup; - } - - if (append_json_map_string_string(custom_config->labels, -- CRIHelpers::Constants::CONTAINER_LOGPATH_LABEL_KEY.c_str(), real_logpath) != 0) { -+ CRIHelpers::Constants::CONTAINER_LOGPATH_LABEL_KEY.c_str(), -+ real_logpath) != 0) { - error.SetError("Append map string string failed"); - goto cleanup; - } -@@ -269,7 +269,7 @@ auto CRIRuntimeServiceImpl::PackCreateContainerHostConfigSecurityContext( - } - size_t newSize = (hostconfig->security_opt_len + securityOpts.size()) * sizeof(char *); - size_t oldSize = hostconfig->security_opt_len * sizeof(char *); -- int ret = mem_realloc((void **)(&tmp_security_opt), newSize, (void *)hostconfig->security_opt, oldSize); -+ int ret = util_mem_realloc((void **)(&tmp_security_opt), newSize, (void *)hostconfig->security_opt, oldSize); - if (ret != 0) { - error.Errorf("Out of memory"); - return -1; -@@ -322,10 +322,11 @@ cleanup: - return nullptr; - } - --auto CRIRuntimeServiceImpl::GenerateCreateContainerRequest(const std::string &realPodSandboxID, -- const runtime::v1alpha2::ContainerConfig &containerConfig, -- const runtime::v1alpha2::PodSandboxConfig &podSandboxConfig, -- const std::string &podSandboxRuntime, Errors &error) -> container_create_request * -+container_create_request * -+CRIRuntimeServiceImpl::GenerateCreateContainerRequest(const std::string &realPodSandboxID, -+ const runtime::v1alpha2::ContainerConfig &containerConfig, -+ const runtime::v1alpha2::PodSandboxConfig &podSandboxConfig, -+ const std::string &podSandboxRuntime, Errors &error) - { - struct parser_context ctx { - OPT_GEN_SIMPLIFY, 0 -@@ -393,10 +394,10 @@ cleanup: - return request; - } - --auto CRIRuntimeServiceImpl::CreateContainer(const std::string &podSandboxID, -- const runtime::v1alpha2::ContainerConfig &containerConfig, -- const runtime::v1alpha2::PodSandboxConfig &podSandboxConfig, -- Errors &error) -> std::string -+std::string CRIRuntimeServiceImpl::CreateContainer(const std::string &podSandboxID, -+ const runtime::v1alpha2::ContainerConfig &containerConfig, -+ const runtime::v1alpha2::PodSandboxConfig &podSandboxConfig, -+ Errors &error) - { - std::string response_id; - std::string podSandboxRuntime; -@@ -1186,8 +1187,8 @@ void CRIRuntimeServiceImpl::ContainerStatusToGRPC(container_inspect *inspect, - ConvertMountsToStatus(inspect, contStatus); - } - --auto CRIRuntimeServiceImpl::ContainerStatus(const std::string &containerID, -- Errors &error) -> std::unique_ptr -+std::unique_ptr -+CRIRuntimeServiceImpl::ContainerStatus(const std::string &containerID, Errors &error) - { - if (containerID.empty()) { - error.SetError("Empty pod sandbox id"); -diff --git a/src/daemon/entry/cri/cri_helpers.cc b/src/daemon/entry/cri/cri_helpers.cc -index bfb1d4a..8aa939c 100644 ---- a/src/daemon/entry/cri/cri_helpers.cc -+++ b/src/daemon/entry/cri/cri_helpers.cc -@@ -52,18 +52,18 @@ const std::string Constants::SANDBOX_ID_ANNOTATION_KEY { "io.kubernetes.cri.sand - const std::string Constants::NET_PLUGIN_EVENT_POD_CIDR_CHANGE { "pod-cidr-change" }; - const std::string Constants::NET_PLUGIN_EVENT_POD_CIDR_CHANGE_DETAIL_CIDR { "pod-cidr" }; - --const char *InternalLabelKeys[] = { -- CRIHelpers::Constants::CONTAINER_TYPE_LABEL_KEY.c_str(), -- CRIHelpers::Constants::CONTAINER_LOGPATH_LABEL_KEY.c_str(), -- CRIHelpers::Constants::SANDBOX_ID_LABEL_KEY.c_str(), nullptr --}; -+const char *InternalLabelKeys[] = { CRIHelpers::Constants::CONTAINER_TYPE_LABEL_KEY.c_str(), -+ CRIHelpers::Constants::CONTAINER_LOGPATH_LABEL_KEY.c_str(), -+ CRIHelpers::Constants::SANDBOX_ID_LABEL_KEY.c_str(), nullptr -+ }; - - auto GetDefaultSandboxImage(Errors &err) -> std::string - { - const std::string defaultPodSandboxImageName { "pause" }; - const std::string defaultPodSandboxImageVersion { "3.0" }; - std::string machine; -- struct utsname uts {}; -+ struct utsname uts { -+ }; - - if (uname(&uts) < 0) { - err.SetError("Failed to read host arch."); -@@ -85,8 +85,8 @@ auto GetDefaultSandboxImage(Errors &err) -> std::string - return defaultPodSandboxImageName + "-" + machine + ":" + defaultPodSandboxImageVersion; - } - --auto MakeLabels(const google::protobuf::Map &mapLabels, -- Errors &error) -> json_map_string_string * -+auto MakeLabels(const google::protobuf::Map &mapLabels, Errors &error) -+-> json_map_string_string * - { - json_map_string_string *labels = (json_map_string_string *)util_common_calloc_s(sizeof(json_map_string_string)); - if (labels == nullptr) { -@@ -112,8 +112,8 @@ cleanup: - return nullptr; - } - --auto MakeAnnotations(const google::protobuf::Map &mapAnnotations, -- Errors &error) -> json_map_string_string * -+auto MakeAnnotations(const google::protobuf::Map &mapAnnotations, Errors &error) -+-> json_map_string_string * - { - json_map_string_string *annotations = - (json_map_string_string *)util_common_calloc_s(sizeof(json_map_string_string)); -@@ -386,8 +386,8 @@ auto sha256(const char *val) -> std::string - return outputBuffer; - } - --auto GetNetworkPlaneFromPodAnno(const google::protobuf::Map &annotations, -- size_t *len, Errors &error) -> cri_pod_network_element ** -+auto GetNetworkPlaneFromPodAnno(const google::protobuf::Map &annotations, size_t *len, -+ Errors &error) -> cri_pod_network_element ** - { - auto iter = annotations.find(CRIHelpers::Constants::POD_NETWORK_ANNOTATION_KEY); - -@@ -404,8 +404,8 @@ auto GetNetworkPlaneFromPodAnno(const google::protobuf::Map std::unique_ptr -+auto CheckpointToSandbox(const std::string &id, const cri::PodSandboxCheckpoint &checkpoint) -+-> std::unique_ptr - { - std::unique_ptr result(new (std::nothrow) runtime::v1alpha2::PodSandbox); - if (result == nullptr) { -@@ -507,8 +507,8 @@ void GenerateMountBindings(const google::protobuf::RepeatedPtrField &envs) -> std::vector -+auto GenerateEnvList(const ::google::protobuf::RepeatedPtrField<::runtime::v1alpha2::KeyValue> &envs) -+-> std::vector - { - std::vector vect; - std::for_each(envs.begin(), envs.end(), [&vect](const ::runtime::v1alpha2::KeyValue & elem) { -@@ -568,7 +568,8 @@ auto GetSeccompiSuladOpts(const std::string &seccompProfile, Errors &error) -> s - if (seccompProfile.empty() || seccompProfile == "unconfined") { - return std::vector { { "seccomp", "unconfined", "" } }; - } -- if (seccompProfile == "iSulad/default" || seccompProfile == "docker/default" || seccompProfile == "runtime/default") { -+ if (seccompProfile == "iSulad/default" || seccompProfile == "docker/default" || -+ seccompProfile == "runtime/default") { - // return nil so docker will load the default seccomp profile - return std::vector {}; - } -@@ -578,7 +579,7 @@ auto GetSeccompiSuladOpts(const std::string &seccompProfile, Errors &error) -> s - } - std::string fname = seccompProfile.substr(std::string("localhost/").length(), seccompProfile.length()); - char dstpath[PATH_MAX] { 0 }; -- if (cleanpath(fname.c_str(), dstpath, sizeof(dstpath)) == nullptr) { -+ if (util_clean_path(fname.c_str(), dstpath, sizeof(dstpath)) == nullptr) { - error.Errorf("failed to get clean path"); - return std::vector {}; - } -@@ -609,8 +610,8 @@ auto GetSeccompiSuladOpts(const std::string &seccompProfile, Errors &error) -> s - return ret; - } - --auto GetSeccompSecurityOpts(const std::string &seccompProfile, const char &separator, -- Errors &error) -> std::vector -+auto GetSeccompSecurityOpts(const std::string &seccompProfile, const char &separator, Errors &error) -+-> std::vector - { - std::vector seccompOpts = GetSeccompiSuladOpts(seccompProfile, error); - if (error.NotEmpty()) { -@@ -620,8 +621,8 @@ auto GetSeccompSecurityOpts(const std::string &seccompProfile, const char &separ - return fmtiSuladOpts(seccompOpts, separator); - } - --auto GetSecurityOpts(const std::string &seccompProfile, const char &separator, -- Errors &error) -> std::vector -+auto GetSecurityOpts(const std::string &seccompProfile, const char &separator, Errors &error) -+-> std::vector - { - std::vector seccompSecurityOpts = GetSeccompSecurityOpts(seccompProfile, separator, error); - if (error.NotEmpty()) { -diff --git a/src/daemon/entry/cri/cri_sandbox.cc b/src/daemon/entry/cri/cri_sandbox.cc -index 540e8b3..6db9616 100644 ---- a/src/daemon/entry/cri/cri_sandbox.cc -+++ b/src/daemon/entry/cri/cri_sandbox.cc -@@ -116,16 +116,14 @@ void CRIRuntimeServiceImpl::ConstructPodSandboxCheckpoint(const runtime::v1alpha - } - - void CRIRuntimeServiceImpl::ApplySandboxResources(const runtime::v1alpha2::LinuxPodSandboxConfig * /*lc*/, -- host_config *hc, -- Errors & /*error*/) -+ host_config *hc, Errors & /*error*/) - { - hc->memory_swap = CRIRuntimeService::Constants::DefaultMemorySwap; - hc->cpu_shares = CRIRuntimeService::Constants::DefaultSandboxCPUshares; - } - - void CRIRuntimeServiceImpl::ApplySandboxLinuxOptions(const runtime::v1alpha2::LinuxPodSandboxConfig &lc, -- host_config *hc, container_config *custom_config, -- Errors &error) -+ host_config *hc, container_config *custom_config, Errors &error) - { - CRISecurity::ApplySandboxSecurityContext(lc, custom_config, hc, error); - if (error.NotEmpty()) { -@@ -184,7 +182,7 @@ void CRIRuntimeServiceImpl::MergeSecurityContextToHostConfig(const runtime::v1al - } - size_t newSize = (hc->security_opt_len + securityOpts.size()) * sizeof(char *); - size_t oldSize = hc->security_opt_len * sizeof(char *); -- int ret = mem_realloc((void **)(&tmp_security_opt), newSize, (void *)hc->security_opt, oldSize); -+ int ret = util_mem_realloc((void **)(&tmp_security_opt), newSize, (void *)hc->security_opt, oldSize); - if (ret != 0) { - error.Errorf("Out of memory"); - return; -@@ -258,7 +256,7 @@ void CRIRuntimeServiceImpl::MakeSandboxIsuladConfig(const runtime::v1alpha2::Pod - } - size_t newSize = (hc->security_opt_len + securityOpts.size()) * sizeof(char *); - size_t oldSize = hc->security_opt_len * sizeof(char *); -- int ret = mem_realloc((void **)(&tmp_security_opt), newSize, (void *)hc->security_opt, oldSize); -+ int ret = util_mem_realloc((void **)(&tmp_security_opt), newSize, (void *)hc->security_opt, oldSize); - if (ret != 0) { - error.Errorf("Out of memory"); - return; -@@ -292,9 +290,9 @@ void CRIRuntimeServiceImpl::SetupSandboxFiles(const std::string &resolvPath, - resolvContentStrs.push_back("nameserver " + CXXUtils::StringsJoin(servers, "\nnameserver ")); - } - -- std::vector searchs(config.dns_config().searches().begin(), config.dns_config().searches().end()); -- if (!searchs.empty()) { -- resolvContentStrs.push_back("search " + CXXUtils::StringsJoin(searchs, " ")); -+ std::vector searches(config.dns_config().searches().begin(), config.dns_config().searches().end()); -+ if (!searches.empty()) { -+ resolvContentStrs.push_back("search " + CXXUtils::StringsJoin(searches, " ")); - } - - std::vector options(config.dns_config().options().begin(), config.dns_config().options().end()); -@@ -304,17 +302,16 @@ void CRIRuntimeServiceImpl::SetupSandboxFiles(const std::string &resolvPath, - - if (!resolvContentStrs.empty()) { - std::string resolvContent = CXXUtils::StringsJoin(resolvContentStrs, "\n") + "\n"; -- if (util_write_file(resolvPath.c_str(), resolvContent.c_str(), resolvContent.size(), DEFAULT_SECURE_FILE_MODE) != 0) { -+ if (util_write_file(resolvPath.c_str(), resolvContent.c_str(), resolvContent.size(), -+ DEFAULT_SECURE_FILE_MODE) != 0) { - error.SetError("Failed to write resolv content"); - } - } - } - --auto CRIRuntimeServiceImpl::PackCreateContainerRequest( -- const runtime::v1alpha2::PodSandboxConfig &config, -- const std::string &image, host_config *hostconfig, -- container_config *custom_config, -- const std::string &runtimeHandler, Errors &error) -> container_create_request * -+container_create_request *CRIRuntimeServiceImpl::PackCreateContainerRequest( -+ const runtime::v1alpha2::PodSandboxConfig &config, const std::string &image, host_config *hostconfig, -+ container_config *custom_config, const std::string &runtimeHandler, Errors &error) - { - struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 }; - parser_error perror = nullptr; -@@ -353,11 +350,10 @@ error_out: - return nullptr; - } - --auto CRIRuntimeServiceImpl::GenerateSandboxCreateContainerRequest( -- const runtime::v1alpha2::PodSandboxConfig &config, -- const std::string &image, std::string &jsonCheckpoint, -- const std::string &runtimeHandler, -- Errors &error) -> container_create_request * -+container_create_request * -+CRIRuntimeServiceImpl::GenerateSandboxCreateContainerRequest(const runtime::v1alpha2::PodSandboxConfig &config, -+ const std::string &image, std::string &jsonCheckpoint, -+ const std::string &runtimeHandler, Errors &error) - { - container_create_request *create_request = nullptr; - host_config *hostconfig = nullptr; -@@ -415,8 +411,7 @@ cleanup: - - auto CRIRuntimeServiceImpl::CreateSandboxContainer(const runtime::v1alpha2::PodSandboxConfig &config, - const std::string &image, std::string &jsonCheckpoint, -- const std::string &runtimeHandler, -- Errors &error) -> std::string -+ const std::string &runtimeHandler, Errors &error) -> std::string - { - std::string response_id; - container_create_request *create_request = -@@ -483,8 +478,8 @@ void CRIRuntimeServiceImpl::SetupUserDefinedNetworkPlane(const runtime::v1alpha2 - if ((networks[i] != nullptr) && (networks[i]->name != nullptr) && (networks[i]->interface != nullptr) && - strcmp(networks[i]->name, Network::DEFAULT_NETWORK_PLANE_NAME.c_str()) != 0) { - INFO("SetupPod net: %s", networks[i]->name); -- m_pluginManager->SetUpPod(config.metadata().namespace_(), config.metadata().name(), networks[i]->interface, response_id, -- stdAnnos, options, error); -+ m_pluginManager->SetUpPod(config.metadata().namespace_(), config.metadata().name(), networks[i]->interface, -+ response_id, stdAnnos, options, error); - if (error.Empty()) { - continue; - } -@@ -545,8 +540,7 @@ cleanup: - } - - auto CRIRuntimeServiceImpl::RunPodSandbox(const runtime::v1alpha2::PodSandboxConfig &config, -- const std::string &runtimeHandler, -- Errors &error) -> std::string -+ const std::string &runtimeHandler, Errors &error) -> std::string - { - std::string response_id; - std::string jsonCheckpoint; -@@ -597,8 +591,7 @@ cleanup: - } - - auto CRIRuntimeServiceImpl::GetRealSandboxIDToStop(const std::string &podSandboxID, bool &hostNetwork, -- std::string &name, -- std::string &ns, std::string &realSandboxID, -+ std::string &name, std::string &ns, std::string &realSandboxID, - std::map &stdAnnos, Errors &error) -> int - { - Errors statusErr; -@@ -733,14 +726,16 @@ cleanup: - - auto CRIRuntimeServiceImpl::ClearCniNetwork(const std::string &realSandboxID, bool hostNetwork, const std::string &ns, - const std::string &name, std::vector &errlist, -- std::map &stdAnnos, Errors & /*error*/) -> int -+ std::map &stdAnnos, Errors & -+ /*error*/) -> int - { - Errors networkErr; - - bool ready = GetNetworkReady(realSandboxID, networkErr); - if (!hostNetwork && (ready || networkErr.NotEmpty())) { - Errors pluginErr; -- m_pluginManager->TearDownPod(ns, name, Network::DEFAULT_NETWORK_INTERFACE_NAME, realSandboxID, stdAnnos, pluginErr); -+ m_pluginManager->TearDownPod(ns, name, Network::DEFAULT_NETWORK_INTERFACE_NAME, realSandboxID, stdAnnos, -+ pluginErr); - if (pluginErr.NotEmpty()) { - WARN("TearDownPod cni network failed: %s", pluginErr.GetCMessage()); - errlist.push_back(pluginErr.GetMessage()); -@@ -828,8 +823,7 @@ cleanup: - free_container_stop_response(response); - } - --auto CRIRuntimeServiceImpl::DoRemovePodSandbox(const std::string &realSandboxID, -- std::vector &errors) -> int -+int CRIRuntimeServiceImpl::DoRemovePodSandbox(const std::string &realSandboxID, std::vector &errors) - { - int ret = 0; - container_delete_request *remove_request { nullptr }; -@@ -1087,8 +1081,8 @@ auto CRIRuntimeServiceImpl::GetIP(const std::string &podSandboxID, container_ins - return ""; - } - --auto CRIRuntimeServiceImpl::PodSandboxStatus( -- const std::string &podSandboxID, Errors &error) -> std::unique_ptr -+std::unique_ptr -+CRIRuntimeServiceImpl::PodSandboxStatus(const std::string &podSandboxID, Errors &error) - { - container_inspect *inspect { nullptr }; - std::unique_ptr podStatus(new runtime::v1alpha2::PodSandboxStatus); -diff --git a/src/daemon/entry/cri/cri_security_context.cc b/src/daemon/entry/cri/cri_security_context.cc -index 3b05e2c..634e53a 100644 ---- a/src/daemon/entry/cri/cri_security_context.cc -+++ b/src/daemon/entry/cri/cri_security_context.cc -@@ -19,8 +19,7 @@ - #include - - namespace CRISecurity { --static void ModifyContainerConfig(const runtime::v1alpha2::LinuxContainerSecurityContext &sc, -- container_config *config) -+static void ModifyContainerConfig(const runtime::v1alpha2::LinuxContainerSecurityContext &sc, container_config *config) - { - if (sc.has_run_as_user()) { - free(config->user); -@@ -89,7 +88,7 @@ static void ModifyHostConfigNoNewPrivs(const runtime::v1alpha2::LinuxContainerSe - - size_t oldSize = hostConfig->security_opt_len * sizeof(char *); - size_t newSize = oldSize + sizeof(char *); -- int ret = mem_realloc((void **)(&tmp_security_opt), newSize, (void *)hostConfig->security_opt, oldSize); -+ int ret = util_mem_realloc((void **)(&tmp_security_opt), newSize, (void *)hostConfig->security_opt, oldSize); - if (ret != 0) { - error.Errorf("Out of memory"); - return; -diff --git a/src/daemon/executor/container_cb/execution.c b/src/daemon/executor/container_cb/execution.c -index 44ae32e..a41bd83 100644 ---- a/src/daemon/executor/container_cb/execution.c -+++ b/src/daemon/executor/container_cb/execution.c -@@ -403,7 +403,7 @@ static int restart_container(container_t *cont) - goto out; - } - -- (void)get_now_time_buffer(timebuffer, sizeof(timebuffer)); -+ (void)util_get_now_time_buffer(timebuffer, sizeof(timebuffer)); - - params.rootpath = rootpath; - -@@ -706,7 +706,7 @@ static int container_kill_cb(const container_kill_request *request, container_ki - goto pack_response; - } - -- if (!util_check_signal_valid((int)signal)) { -+ if (!util_valid_signal((int)signal)) { - isulad_set_error_message("Not supported signal %d", signal); - ERROR("Not supported signal %d", signal); - cc = ISULAD_ERR_EXEC; -diff --git a/src/daemon/executor/container_cb/execution_create.c b/src/daemon/executor/container_cb/execution_create.c -index 91c9692..761f0af 100644 ---- a/src/daemon/executor/container_cb/execution_create.c -+++ b/src/daemon/executor/container_cb/execution_create.c -@@ -33,6 +33,7 @@ - #include - #include - #include -+#include - - #include "isula_libutils/log.h" - #include "isulad_config.h" -@@ -57,6 +58,9 @@ - #include "utils_verify.h" - #include "selinux_label.h" - -+static int do_init_cpurt_cgroups_path(const char *path, int recursive_depth, const char *mnt_root, -+ int64_t cpu_rt_period, int64_t cpu_rt_runtime); -+ - static int runtime_check(const char *name, bool *runtime_res) - { - int ret = 0; -@@ -479,7 +483,7 @@ static int register_new_container(const char *id, const char *runtime, host_conf - container_config_v2_common_config **v2_spec) - { - int ret = -1; -- bool registed = false; -+ bool registered = false; - char *runtime_root = NULL; - char *runtime_stat = NULL; - char *image_id = NULL; -@@ -511,8 +515,8 @@ static int register_new_container(const char *id, const char *runtime, host_conf - goto out; - } - -- registed = containers_store_add(id, cont); -- if (!registed) { -+ registered = containers_store_add(id, cont); -+ if (!registered) { - ERROR("Failed to register container '%s'", id); - goto out; - } -@@ -576,7 +580,7 @@ out: - - static char *get_runtime_from_request(const container_create_request *request) - { -- return strings_to_lower(request->runtime); -+ return util_strings_to_lower(request->runtime); - } - - static void pack_create_response(container_create_response *response, const char *id, uint32_t cc) -@@ -916,12 +920,13 @@ static int pack_security_config_to_v2_spec(const host_config *host_spec, contain - v2_spec->seccomp_profile = seccomp_profile; - seccomp_profile = NULL; - v2_spec->no_new_privileges = no_new_privileges; -- -+#ifdef ENABLE_SELINUX - if (init_label((const char **)label_opts, label_opts_len, &process_label, &mount_label) != 0) { - ERROR("Failed to append label"); - ret = -1; - goto out; - } -+#endif - - v2_spec->mount_label = mount_label; - mount_label = NULL; -@@ -944,7 +949,7 @@ static void v2_spec_fill_basic_info(const char *id, const char *name, const char - v2_spec->name = name ? util_strdup_s(name) : NULL; - v2_spec->image = image_name ? util_strdup_s(image_name) : util_strdup_s("none"); - v2_spec->image_type = image_type ? util_strdup_s(image_type) : NULL; -- (void)get_now_time_buffer(timebuffer, sizeof(timebuffer)); -+ (void)util_get_now_time_buffer(timebuffer, sizeof(timebuffer)); - free(v2_spec->created); - v2_spec->created = util_strdup_s(timebuffer); - v2_spec->config = container_spec; -@@ -1022,6 +1027,204 @@ static int save_container_config_before_create(const char *id, const char *runti - return 0; - } - -+/* maybe create cpu realtime file */ -+static int maybe_create_cpu_realtime_file(int64_t value, const char *file, const char *path) -+{ -+ int ret; -+ int fd = 0; -+ ssize_t nwrite; -+ char fpath[PATH_MAX] = { 0 }; -+ char buf[ISULAD_NUMSTRLEN64] = { 0 }; -+ -+ if (value == 0) { -+ return 0; -+ } -+ -+ ret = util_mkdir_p(path, CONFIG_DIRECTORY_MODE); -+ if (ret != 0) { -+ ERROR("Failed to mkdir: %s", path); -+ return -1; -+ } -+ -+ int nret = snprintf(fpath, sizeof(fpath), "%s/%s", path, file); -+ if (nret < 0 || nret >= sizeof(fpath)) { -+ ERROR("Failed to print string"); -+ return -1; -+ } -+ nret = snprintf(buf, sizeof(buf), "%lld", (long long int)value); -+ if (nret < 0 || (size_t)nret >= sizeof(buf)) { -+ ERROR("Failed to print string"); -+ return -1; -+ } -+ -+ fd = util_open(fpath, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0700); -+ if (fd < 0) { -+ ERROR("Failed to open file: %s: %s", fpath, strerror(errno)); -+ isulad_set_error_message("Failed to open file: %s: %s", fpath, strerror(errno)); -+ return -1; -+ } -+ nwrite = util_write_nointr(fd, buf, strlen(buf)); -+ if (nwrite < 0) { -+ ERROR("Failed to write %s to %s: %s", buf, fpath, strerror(errno)); -+ isulad_set_error_message("Failed to write '%s' to '%s': %s", buf, fpath, strerror(errno)); -+ close(fd); -+ return -1; -+ } -+ close(fd); -+ -+ return 0; -+} -+ -+static int recursively_create_cgroup(const char *path, const char *mnt_root, int recursive_depth, int64_t cpu_rt_period, -+ int64_t cpu_rt_runtime) -+{ -+ int ret = 0; -+ char *dup = NULL; -+ char *dirpath = NULL; -+ char fpath[PATH_MAX] = { 0 }; -+ -+ dup = util_strdup_s(path); -+ dirpath = dirname(dup); -+ ret = do_init_cpurt_cgroups_path(dirpath, (recursive_depth + 1), mnt_root, cpu_rt_period, cpu_rt_runtime); -+ free(dup); -+ if (ret != 0) { -+ return ret; -+ } -+ -+ int nret = snprintf(fpath, sizeof(fpath), "%s/%s", mnt_root, path); -+ if (nret < 0 || (size_t)nret >= sizeof(fpath)) { -+ ERROR("Failed to print string"); -+ ret = -1; -+ goto out; -+ } -+ -+ ret = maybe_create_cpu_realtime_file(cpu_rt_period, "cpu.rt_period_us", fpath); -+ if (ret != 0) { -+ goto out; -+ } -+ -+ ret = maybe_create_cpu_realtime_file(cpu_rt_runtime, "cpu.rt_runtime_us", fpath); -+ if (ret != 0) { -+ goto out; -+ } -+ -+out: -+ return ret; -+} -+ -+/* init cgroups path */ -+static int do_init_cpurt_cgroups_path(const char *path, int recursive_depth, const char *mnt_root, -+ int64_t cpu_rt_period, int64_t cpu_rt_runtime) -+{ -+ if ((recursive_depth + 1) > MAX_PATH_DEPTH) { -+ ERROR("Reach the max cgroup depth:%s", path); -+ return -1; -+ } -+ -+ if (path == NULL || strcmp(path, "/") == 0 || strcmp(path, ".") == 0) { -+ return 0; -+ } -+ -+ // Recursively create cgroup to ensure that the system and all parent cgroups have values set -+ // for the period and runtime as this limits what the children can be set to. -+ if (recursively_create_cgroup(path, mnt_root, recursive_depth, cpu_rt_period, cpu_rt_runtime)) { -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static char *get_cpurt_controller_mnt_path() -+{ -+ char *res = NULL; -+ int nret = 0; -+ char *mnt = NULL; -+ char *root = NULL; -+ char fpath[PATH_MAX] = { 0 }; -+ -+ nret = find_cgroup_mountpoint_and_root("cpu", &mnt, &root); -+ if (nret != 0 || mnt == NULL || root == NULL) { -+ ERROR("Can not find cgroup mnt and root path for subsystem 'cpu'"); -+ isulad_set_error_message("Can not find cgroup mnt and root path for subsystem 'cpu'"); -+ goto out; -+ } -+ -+ // When iSulad is run inside docker, the root is based of the host cgroup. -+ // Replace root to "/" -+ if (strncmp(root, "/docker/", strlen("/docker/")) == 0) { -+ root[1] = '\0'; -+ } -+ -+ nret = snprintf(fpath, sizeof(fpath), "%s/%s", mnt, root); -+ if (nret < 0 || (size_t)nret >= sizeof(fpath)) { -+ ERROR("Failed to print string"); -+ goto out; -+ } -+ -+ res = util_strdup_s(fpath); -+ -+out: -+ free(mnt); -+ free(root); -+ return res; -+} -+ -+static int cpurt_controller_init(const char *cgroups_path) -+{ -+ int ret = 0; -+ char *dup = NULL; -+ char *dirpath = NULL; -+ int64_t cpu_rt_period = 0; -+ int64_t cpu_rt_runtime = 0; -+ sysinfo_t *sysinfo = NULL; -+ char *mnt_root = NULL; -+ -+ if (cgroups_path == NULL || strcmp(cgroups_path, "/") == 0 || strcmp(cgroups_path, ".") == 0) { -+ return 0; -+ } -+ -+ if (conf_get_cgroup_cpu_rt(&cpu_rt_period, &cpu_rt_runtime)) { -+ return -1; -+ } -+ -+ if (cpu_rt_period == 0 && cpu_rt_runtime == 0) { -+ return 0; -+ } -+ -+ sysinfo = get_sys_info(true); -+ if (sysinfo == NULL) { -+ ERROR("Can not get system info"); -+ ret = -1; -+ goto out; -+ } -+ -+ if (!(sysinfo->cgcpuinfo.cpu_rt_period)) { -+ ERROR("Daemon-scoped cpu-rt-period and cpu-rt-runtime are not supported by kernel"); -+ isulad_set_error_message("Daemon-scoped cpu-rt-period and cpu-rt-runtime are not supported by kernel"); -+ ret = -1; -+ goto out; -+ } -+ -+ mnt_root = get_cpurt_controller_mnt_path(); -+ if (mnt_root == NULL) { -+ ERROR("Failed to get cpu rt controller mnt root path"); -+ isulad_set_error_message("Failed to get cpu rt controller mnt root path"); -+ ret = -1; -+ goto out; -+ } -+ -+ dup = util_strdup_s(cgroups_path); -+ dirpath = dirname(dup); -+ -+ ret = do_init_cpurt_cgroups_path(dirpath, 0, mnt_root, cpu_rt_period, cpu_rt_runtime); -+ -+out: -+ free_sysinfo(sysinfo); -+ free(mnt_root); -+ free(dup); -+ return ret; -+} -+ - /* - * request -> host_spec + container_spec - * container_spec + image config -@@ -1127,11 +1330,6 @@ int container_create_cb(const container_create_request *request, container_creat - goto umount_shm; - } - -- ret = merge_oci_cgroups_path(id, oci_spec, host_spec); -- if (ret < 0) { -- goto umount_shm; -- } -- - if (merge_config_for_syscontainer(request, host_spec, v2_spec->config, oci_spec) != 0) { - ERROR("Failed to merge config for syscontainer"); - cc = ISULAD_ERR_EXEC; -@@ -1165,6 +1363,13 @@ int container_create_cb(const container_create_request *request, container_creat - goto umount_channel; - } - -+ // init cgroup path for cpu_rt_runtime and cpu_rt_period -+ if (cpurt_controller_init(oci_spec->linux->cgroups_path) != 0) { -+ ERROR("Unable to init CPU RT controller %s", oci_spec->linux->cgroups_path); -+ cc = ISULAD_ERR_EXEC; -+ goto umount_channel; -+ } -+ - if (container_v2_spec_merge_contaner_spec(v2_spec) != 0) { - ERROR("Failed to merge container settings"); - cc = ISULAD_ERR_EXEC; -diff --git a/src/daemon/executor/container_cb/execution_extend.c b/src/daemon/executor/container_cb/execution_extend.c -index df4655d..e63ec54 100644 ---- a/src/daemon/executor/container_cb/execution_extend.c -+++ b/src/daemon/executor/container_cb/execution_extend.c -@@ -834,8 +834,41 @@ static void host_config_restore_unlocking(container_t *cont, host_config *backup - } - } - --static void update_container_cpu(const host_config *hostconfig, host_config *chostconfig) -+static int update_container_cpu(const host_config *hostconfig, host_config *chostconfig) - { -+ int ret = 0; -+ -+ if (hostconfig->nano_cpus > 0 && chostconfig->cpu_period > 0) { -+ ERROR("Conflicting options: Nano CPUs cannot be updated as CPU Period has already been set"); -+ isulad_set_error_message("Conflicting options: Nano CPUs cannot be updated as CPU Period has already been set"); -+ ret = -1; -+ goto out; -+ } -+ -+ if (hostconfig->nano_cpus > 0 && chostconfig->cpu_quota > 0) { -+ ERROR("Conflicting options: Nano CPUs cannot be updated as CPU Quota has already been set"); -+ isulad_set_error_message("Conflicting options: Nano CPUs cannot be updated as CPU Quota has already been set"); -+ ret = -1; -+ goto out; -+ } -+ -+ if (hostconfig->cpu_period > 0 && chostconfig->nano_cpus > 0) { -+ ERROR("Conflicting options: CPU Period cannot be updated as NanoCPUs has already been set"); -+ isulad_set_error_message("Conflicting options: CPU Period cannot be updated as NanoCPUs has already been set"); -+ ret = -1; -+ goto out; -+ } -+ -+ if (hostconfig->cpu_quota > 0 && chostconfig->nano_cpus > 0) { -+ ERROR("Conflicting options: CPU Quota cannot be updated as NanoCPUs has already been set"); -+ isulad_set_error_message("Conflicting options: CPU Quota cannot be updated as NanoCPUs has already been set"); -+ ret = -1; -+ goto out; -+ } -+ -+ if (hostconfig->nano_cpus != 0) { -+ chostconfig->nano_cpus = hostconfig->nano_cpus; -+ } - if (hostconfig->cpu_shares != 0) { - chostconfig->cpu_shares = hostconfig->cpu_shares; - } -@@ -853,6 +886,15 @@ static void update_container_cpu(const host_config *hostconfig, host_config *cho - free(chostconfig->cpuset_mems); - chostconfig->cpuset_mems = util_strdup_s(hostconfig->cpuset_mems); - } -+ if (hostconfig->cpu_realtime_period != 0) { -+ chostconfig->cpu_realtime_period = hostconfig->cpu_realtime_period; -+ } -+ if (hostconfig->cpu_realtime_runtime != 0) { -+ chostconfig->cpu_realtime_runtime = hostconfig->cpu_realtime_runtime; -+ } -+ -+out: -+ return ret; - } - - static int update_container_memory(const char *id, const host_config *hostconfig, host_config *chostconfig) -@@ -926,7 +968,11 @@ static int update_container(const container_t *cont, const host_config *hostconf - chostconfig->blkio_weight = hostconfig->blkio_weight; - } - -- update_container_cpu(hostconfig, chostconfig); -+ ret = update_container_cpu(hostconfig, chostconfig); -+ if (ret != 0) { -+ ret = -1; -+ goto out; -+ } - - ret = update_container_memory(id, hostconfig, chostconfig); - if (ret != 0) { -diff --git a/src/daemon/executor/container_cb/execution_information.c b/src/daemon/executor/container_cb/execution_information.c -index 4dd8166..720cd52 100644 ---- a/src/daemon/executor/container_cb/execution_information.c -+++ b/src/daemon/executor/container_cb/execution_information.c -@@ -183,7 +183,7 @@ static int get_proxy_env(char **proxy, const char *type) - - *proxy = getenv(type); - if (*proxy == NULL) { -- tmp = strings_to_upper(type); -+ tmp = util_strings_to_upper(type); - if (tmp == NULL) { - ERROR("Failed to upper string!"); - ret = -1; -@@ -1007,13 +1007,13 @@ static int dup_container_config_cmd_and_entrypoint(const container_config *src, - return 0; - } - -- ret = dup_array_of_strings((const char **)(src->cmd), src->cmd_len, &(dest->cmd), &(dest->cmd_len)); -+ ret = util_dup_array_of_strings((const char **)(src->cmd), src->cmd_len, &(dest->cmd), &(dest->cmd_len)); - if (ret != 0) { - goto out; - } - -- ret = dup_array_of_strings((const char **)(src->entrypoint), src->entrypoint_len, &(dest->entrypoint), -- &(dest->entrypoint_len)); -+ ret = util_dup_array_of_strings((const char **)(src->entrypoint), src->entrypoint_len, &(dest->entrypoint), -+ &(dest->entrypoint_len)); - out: - return ret; - } -diff --git a/src/daemon/executor/container_cb/execution_network.c b/src/daemon/executor/container_cb/execution_network.c -index 7bb0c36..f15707e 100644 ---- a/src/daemon/executor/container_cb/execution_network.c -+++ b/src/daemon/executor/container_cb/execution_network.c -@@ -46,7 +46,7 @@ static int write_hostname_to_file(const char *rootfs, const char *hostname) - goto out; - } - -- if (realpath_in_scope(rootfs, "/etc/hostname", &file_path) < 0) { -+ if (util_realpath_in_scope(rootfs, "/etc/hostname", &file_path) < 0) { - SYSERROR("Failed to get real path '/etc/hostname' under rootfs '%s'", rootfs); - isulad_set_error_message("Failed to get real path '/etc/hostname' under rootfs '%s'", rootfs); - goto out; -@@ -76,7 +76,7 @@ out: - - static int fopen_network(FILE **fp, char **file_path, const char *rootfs, const char *filename) - { -- if (realpath_in_scope(rootfs, filename, file_path) < 0) { -+ if (util_realpath_in_scope(rootfs, filename, file_path) < 0) { - SYSERROR("Failed to get real path '%s' under rootfs '%s'", filename, rootfs); - isulad_set_error_message("Failed to get real path '%s' under rootfs '%s'", filename, rootfs); - return -1; -@@ -674,7 +674,7 @@ static int chown_network(const char *user_remap, const char *rootfs, const char - ret = -1; - goto out; - } -- if (realpath_in_scope(rootfs, filename, &file_path) < 0) { -+ if (util_realpath_in_scope(rootfs, filename, &file_path) < 0) { - SYSERROR("Failed to get real path '%s' under rootfs '%s'", filename, rootfs); - isulad_set_error_message("Failed to get real path '%s' under rootfs '%s'", filename, rootfs); - ret = -1; -@@ -1004,10 +1004,10 @@ int init_container_network_confs(const char *id, const char *rootpath, const hos - container_config_v2_common_config *v2_spec) - { - int ret = 0; -- bool share_host = is_host(hc->network_mode); -+ bool share_host = namespace_is_host(hc->network_mode); - - // is container mode -- if (is_container(hc->network_mode)) { -+ if (namespace_is_container(hc->network_mode)) { - return init_container_network_confs_container(id, hc, v2_spec); - } - -diff --git a/src/daemon/executor/container_cb/execution_stream.c b/src/daemon/executor/container_cb/execution_stream.c -index c897624..7e2ac38 100644 ---- a/src/daemon/executor/container_cb/execution_stream.c -+++ b/src/daemon/executor/container_cb/execution_stream.c -@@ -381,18 +381,18 @@ static int archive_and_send_copy_data(const stream_func_wrapper *stream, - return -1; - } - -- if (cleanpath(resolvedpath, cleaned, sizeof(cleaned)) == NULL) { -+ if (util_clean_path(resolvedpath, cleaned, sizeof(cleaned)) == NULL) { - ERROR("Can not clean path: %s", resolvedpath); - goto cleanup; - } - -- nret = split_dir_and_base_name(cleaned, &srcdir, &srcbase); -+ nret = util_split_dir_and_base_name(cleaned, &srcdir, &srcbase); - if (nret != 0) { - ERROR("split %s failed", cleaned); - goto cleanup; - } - -- nret = split_dir_and_base_name(abspath, NULL, &absbase); -+ nret = util_split_dir_and_base_name(abspath, NULL, &absbase); - if (nret != 0) { - ERROR("split %s failed", abspath); - goto cleanup; -@@ -453,7 +453,7 @@ static container_path_stat *do_container_stat_path(const char *rootpath, const c - - if (S_ISLNK(st.st_mode)) { - char *p = NULL; -- hostpath = get_resource_path(rootpath, abspath); -+ hostpath = util_get_resource_path(rootpath, abspath); - if (hostpath == NULL) { - ERROR("Failed to get resource path"); - goto cleanup; -@@ -481,7 +481,7 @@ static container_path_stat *do_container_stat_path(const char *rootpath, const c - ERROR("Out of memory"); - goto cleanup; - } -- nret = split_dir_and_base_name(abspath, NULL, &stat->name); -+ nret = util_split_dir_and_base_name(abspath, NULL, &stat->name); - if (nret != 0) { - ERROR("split %s failed", abspath); - goto cleanup; -@@ -538,7 +538,7 @@ static container_path_stat *resolve_and_stat_path(const char *rootpath, const ch - char *abs = NULL; - container_path_stat *stat = NULL; - -- nret = resolve_path(rootpath, srcpath, &resolved, &abs); -+ nret = util_resolve_path(rootpath, srcpath, &resolved, &abs); - if (nret < 0) { - ERROR("Can not resolve path: %s", srcpath); - return NULL; -@@ -844,17 +844,17 @@ static int copy_to_container_resolve_path(const container_t *cont, const char *d - ERROR("Can not join path"); - return -1; - } -- if (cleanpath(joined, cleaned, sizeof(cleaned)) == NULL) { -+ if (util_clean_path(joined, cleaned, sizeof(cleaned)) == NULL) { - ERROR("Can not clean path: %s", dstdir); - goto cleanup; - } -- *abspath = preserve_trailing_dot_or_separator(cleaned, dstdir); -+ *abspath = util_preserve_trailing_dot_or_separator(cleaned, dstdir); - if (*abspath == NULL) { - ERROR("Can not preserve path"); - goto cleanup; - } - -- *resolvedpath = get_resource_path(cont->common_config->base_fs, *abspath); -+ *resolvedpath = util_get_resource_path(cont->common_config->base_fs, *abspath); - if (*resolvedpath == NULL) { - ERROR("Can not get resource path"); - goto cleanup; -@@ -1062,7 +1062,7 @@ static int64_t do_read_log_file(const char *path, int64_t require_line, long pos - break; - } - /* fopen is too fast, need wait rename operator finish */ -- usleep_nointerupt(1000); -+ util_usleep_nointerupt(1000); - } - if (fp == NULL) { - ERROR("open file: %s failed: %s", path, strerror(errno)); -@@ -1079,7 +1079,7 @@ static int64_t do_read_log_file(const char *path, int64_t require_line, long pos - (*last_pos) += (long)strlen(buffer); - - if (do_decode_write_log_entry(buffer, stream) != 0) { -- /* read a incomplete json object, try agin */ -+ /* read a incomplete json object, try again */ - decode_retries++; - if (decode_retries < MAX_JSON_DECODE_RETRY) { - continue; -@@ -1341,7 +1341,7 @@ static int handle_rotate(int fd, int wd, const char *path) - if (watch_fd >= 0) { - break; - } -- usleep_nointerupt(1000); -+ util_usleep_nointerupt(1000); - } - if (watch_fd < 0) { - SYSERROR("Add watch %s failed", path); -@@ -1509,7 +1509,7 @@ static int do_follow_log_file(const char *cid, stream_func_wrapper *stream, stru - ret = -1; - break; - } -- usleep_nointerupt(10000); -+ util_usleep_nointerupt(10000); - } - - out: -diff --git a/src/daemon/executor/container_cb/list.c b/src/daemon/executor/container_cb/list.c -index feccebe..9010337 100644 ---- a/src/daemon/executor/container_cb/list.c -+++ b/src/daemon/executor/container_cb/list.c -@@ -341,7 +341,7 @@ static int convert_common_config_info(const map_t *map_labels, const container_c - - dup_id_name(common_config, isuladinfo); - args_err = (common_config->created != NULL && -- to_unix_nanos_from_str(common_config->created, &isuladinfo->created) != 0); -+ util_to_unix_nanos_from_str(common_config->created, &isuladinfo->created) != 0); - if (args_err) { - ret = -1; - goto out; -@@ -439,7 +439,7 @@ static int fill_isuladinfo(container_container *isuladinfo, const container_conf - - isuladinfo->health_state = container_get_health_state(cont_state); - if (cont->common_config->created != NULL) { -- ret = to_unix_nanos_from_str(cont->common_config->created, &created_nanos); -+ ret = util_to_unix_nanos_from_str(cont->common_config->created, &created_nanos); - if (ret != 0) { - goto out; - } -diff --git a/src/daemon/executor/image_cb/image_cb.c b/src/daemon/executor/image_cb/image_cb.c -index 63a780b..57b1a6a 100644 ---- a/src/daemon/executor/image_cb/image_cb.c -+++ b/src/daemon/executor/image_cb/image_cb.c -@@ -596,7 +596,7 @@ static int trans_one_image(image_list_images_response *response, size_t image_in - int64_t created_nanos = 0; - types_timestamp_t timestamp; - -- if (to_unix_nanos_from_str(im_image->created, &created_nanos) != 0) { -+ if (util_to_unix_nanos_from_str(im_image->created, &created_nanos) != 0) { - ERROR("Failed to translate created time to nanos"); - ret = -1; - goto out; -@@ -930,7 +930,7 @@ out: - return ret; - } - --/* When inspect none image, we respone following string according hasen's request. */ -+/* When inspect none image, we respond following string according hasen's request. */ - #define INSPECT_NONE_IMAGE_RESP \ - "{ \ - \"ContainerConfig\": { \ -diff --git a/src/daemon/modules/container/container_events_handler.c b/src/daemon/modules/container/container_events_handler.c -index b227541..447097b 100644 ---- a/src/daemon/modules/container/container_events_handler.c -+++ b/src/daemon/modules/container/container_events_handler.c -@@ -141,7 +141,7 @@ static int container_state_changed(container_t *cont, const struct isulad_events - - should_restart = restart_manager_should_restart(id, events->exit_status, - cont->common_config->has_been_manually_stopped, -- time_seconds_since(started_at), &timeout); -+ util_time_seconds_since(started_at), &timeout); - free(started_at); - started_at = NULL; - -diff --git a/src/daemon/modules/container/container_gc/containers_gc.c b/src/daemon/modules/container/container_gc/containers_gc.c -index dbf2077..89c4e31 100644 ---- a/src/daemon/modules/container/container_gc/containers_gc.c -+++ b/src/daemon/modules/container/container_gc/containers_gc.c -@@ -130,7 +130,7 @@ out: - return ret; - } - --/* notes: this funciton must be called with gc_containers_lock */ -+/* notes: this function must be called with gc_containers_lock */ - static int gc_containers_to_disk() - { - int ret = 0; -@@ -356,7 +356,7 @@ static void apply_restart_policy_after_gc(const char *id) - exit_code = container_state_get_exitcode(cont->state); - - should_restart = restart_manager_should_restart(id, exit_code, cont->common_config->has_been_manually_stopped, -- time_seconds_since(started_at), &timeout); -+ util_time_seconds_since(started_at), &timeout); - free(started_at); - - if (should_restart) { -@@ -535,7 +535,7 @@ static void *gchandler(void *arg) - do_gc_container(it); - - wait_continue: -- usleep_nointerupt(100 * 1000); /* wait 100 millisecond to check next gc container */ -+ util_usleep_nointerupt(100 * 1000); /* wait 100 millisecond to check next gc container */ - } - error: - return NULL; -diff --git a/src/daemon/modules/container/container_state.c b/src/daemon/modules/container/container_state.c -index 47f12ac..d4a448a 100644 ---- a/src/daemon/modules/container/container_state.c -+++ b/src/daemon/modules/container/container_state.c -@@ -167,7 +167,7 @@ void container_state_set_running(container_state_t *s, const pid_ppid_info_t *pi - state->p_start_time = 0; - } - -- (void)get_now_time_buffer(timebuffer, sizeof(timebuffer)); -+ (void)util_get_now_time_buffer(timebuffer, sizeof(timebuffer)); - free(state->started_at); - state->started_at = util_strdup_s(timebuffer); - -@@ -198,7 +198,7 @@ void container_state_set_stopped(container_state_t *s, int exit_code) - state->p_pid = 0; - state->p_start_time = 0; - -- (void)get_now_time_buffer(timebuffer, sizeof(timebuffer)); -+ (void)util_get_now_time_buffer(timebuffer, sizeof(timebuffer)); - free(state->finished_at); - state->finished_at = util_strdup_s(timebuffer); - -@@ -259,7 +259,7 @@ void container_restart_update_start_and_finish_time(container_state_t *s, const - state->paused = false; - state->exit_code = 0; - -- (void)get_now_time_buffer(timebuffer, sizeof(timebuffer)); -+ (void)util_get_now_time_buffer(timebuffer, sizeof(timebuffer)); - free(state->finished_at); - state->finished_at = util_strdup_s(finish_at); - free(state->started_at); -@@ -294,7 +294,7 @@ void container_state_set_restarting(container_state_t *s, int exit_code) - state->p_start_time = 0; - state->exit_code = exit_code; - -- (void)get_now_time_buffer(timebuffer, sizeof(timebuffer)); -+ (void)util_get_now_time_buffer(timebuffer, sizeof(timebuffer)); - free(state->finished_at); - state->finished_at = util_strdup_s(timebuffer); - -diff --git a/src/daemon/modules/container/health_check/health_check.c b/src/daemon/modules/container/health_check/health_check.c -index 8905f90..75c3f3d 100644 ---- a/src/daemon/modules/container/health_check/health_check.c -+++ b/src/daemon/modules/container/health_check/health_check.c -@@ -297,8 +297,8 @@ static int append_last_log_result(defs_health *health, const defs_health_log_ele - return -1; - } - -- ret = mem_realloc((void **)(&tmp_log), (health->log_len + 1) * sizeof(defs_health_log_element *), health->log, -- health->log_len * sizeof(defs_health_log_element *)); -+ ret = util_mem_realloc((void **)(&tmp_log), (health->log_len + 1) * sizeof(defs_health_log_element *), health->log, -+ health->log_len * sizeof(defs_health_log_element *)); - if (ret != 0) { - ERROR("failed to realloc memory"); - return -1; -@@ -356,12 +356,12 @@ static int handle_unhealthy_case(container_t *cont, const defs_health_log_elemen - DEFAULT_START_PERIOD : - cont->common_config->config->healthcheck->start_period; - int64_t first, last; -- if (to_unix_nanos_from_str(cont->state->state->started_at, &first)) { -+ if (util_to_unix_nanos_from_str(cont->state->state->started_at, &first)) { - ERROR("Parse container started time failed: %s", cont->state->state->started_at); - ret = -1; - goto out; - } -- if (to_unix_nanos_from_str(result->start, &last)) { -+ if (util_to_unix_nanos_from_str(result->start, &last)) { - ERROR("Parse last health check start time failed: %s", result->start); - ret = -1; - goto out; -@@ -560,7 +560,7 @@ void *health_check_run(void *arg) - cmd_slice = NULL; - EVENT("EVENT: {Object: %s, Type: Health checking}", cont->common_config->id); - -- (void)get_now_time_buffer(timebuffer, sizeof(timebuffer)); -+ (void)util_get_now_time_buffer(timebuffer, sizeof(timebuffer)); - result = util_common_calloc_s(sizeof(defs_health_log_element)); - if (result == NULL) { - ERROR("Out of memory"); -@@ -581,7 +581,7 @@ void *health_check_run(void *arg) - health_check_exec_success_handle(container_res, result, output); - } - -- (void)get_now_time_buffer(timebuffer, sizeof(timebuffer)); -+ (void)util_get_now_time_buffer(timebuffer, sizeof(timebuffer)); - result->end = util_strdup_s(timebuffer); - - if (handle_probe_result(cont->common_config->id, result) != 0) { -@@ -644,7 +644,7 @@ static int do_monitor_interval(const char *container_id, health_check_manager_t - goto out; - } - set_monitor_idle_status(health_check); -- if (get_now_time_stamp(start_timestamp) == false) { -+ if (util_get_now_time_stamp(start_timestamp) == false) { - ERROR("Failed to get time stamp"); - ret = -1; - goto out; -@@ -658,12 +658,12 @@ static int do_monitor_default(int64_t probe_interval, health_check_manager_t *he - { - int64_t time_interval = 0; - -- if (get_now_time_stamp(last_timestamp) == false) { -+ if (util_get_now_time_stamp(last_timestamp) == false) { - ERROR("Failed to get time stamp"); - return -1; - } - -- if (get_time_interval(*start_timestamp, *last_timestamp, &time_interval)) { -+ if (util_get_time_interval(*start_timestamp, *last_timestamp, &time_interval)) { - ERROR("Failed to get time interval"); - return -1; - } -@@ -671,7 +671,7 @@ static int do_monitor_default(int64_t probe_interval, health_check_manager_t *he - if (time_interval >= probe_interval) { - set_monitor_interval_timeout_status(health_check); - } -- usleep_nointerupt(500); -+ util_usleep_nointerupt(500); - - return 0; - } -@@ -697,7 +697,7 @@ static void *health_check_monitor(void *arg) - goto out; - } - -- if (get_now_time_stamp(&start_timestamp) == false) { -+ if (util_get_now_time_stamp(&start_timestamp) == false) { - ERROR("Failed to monitor start time stamp"); - goto out; - } -diff --git a/src/daemon/modules/container/restore/restore.c b/src/daemon/modules/container/restore/restore.c -index 372d4bd..02f4127 100644 ---- a/src/daemon/modules/container/restore/restore.c -+++ b/src/daemon/modules/container/restore/restore.c -@@ -348,7 +348,7 @@ static void restored_restart_container(container_t *cont) - - started_at = container_state_get_started_at(cont->state); - if (restart_manager_should_restart(id, container_state_get_exitcode(cont->state), -- cont->common_config->has_been_manually_stopped, time_seconds_since(started_at), -+ cont->common_config->has_been_manually_stopped, util_time_seconds_since(started_at), - &timeout)) { - cont->common_config->restart_count++; - INFO("Restart container %s after 5 second", id); -diff --git a/src/daemon/modules/container/supervisor/supervisor.c b/src/daemon/modules/container/supervisor/supervisor.c -index ac49f6a..6267a25 100644 ---- a/src/daemon/modules/container/supervisor/supervisor.c -+++ b/src/daemon/modules/container/supervisor/supervisor.c -@@ -189,7 +189,7 @@ retry: - } - - if (retry_count < max_retry) { -- usleep_nointerupt(100 * 1000); /* 100 millisecond */ -+ util_usleep_nointerupt(100 * 1000); /* 100 millisecond */ - retry_count++; - goto retry; - } -diff --git a/src/daemon/modules/events/collector.c b/src/daemon/modules/events/collector.c -index 1165972..3e587ae 100644 ---- a/src/daemon/modules/events/collector.c -+++ b/src/daemon/modules/events/collector.c -@@ -598,7 +598,7 @@ out: - static int check_since_time(const types_timestamp_t *since, const struct isulad_events_format *event) - { - if (since != NULL && (since->has_seconds || since->has_nanos)) { -- if (types_timestamp_cmp(&event->timestamp, since) < 0) { -+ if (util_types_timestamp_cmp(&event->timestamp, since) < 0) { - return -1; - } - } -@@ -608,7 +608,7 @@ static int check_since_time(const types_timestamp_t *since, const struct isulad_ - static int check_util_time(const types_timestamp_t *until, const struct isulad_events_format *event) - { - if (until != NULL && (until->has_seconds || until->has_nanos)) { -- if (types_timestamp_cmp(&event->timestamp, until) > 0) { -+ if (util_types_timestamp_cmp(&event->timestamp, until) > 0) { - return -1; - } - } -@@ -684,7 +684,7 @@ int events_subscribe(const char *name, const types_timestamp_t *since, const typ - - if (since != NULL && (since->has_seconds || since->has_nanos) && until != NULL && - (until->has_seconds || until->has_nanos)) { -- if (types_timestamp_cmp(since, until) > 0) { -+ if (util_types_timestamp_cmp(since, until) > 0) { - ERROR("'since' time cannot be after 'until' time"); - return -1; - } -@@ -717,7 +717,7 @@ static void events_forward(struct isulad_events_format *r) - name = context_info->name; - - if (context_info->since != NULL) { -- if (types_timestamp_cmp(&r->timestamp, context_info->since) < 0) { -+ if (util_types_timestamp_cmp(&r->timestamp, context_info->since) < 0) { - continue; - } - } -@@ -806,7 +806,7 @@ static void *event_should_exit(void *arg) - t_now.has_nanos = true; - t_now.nanos = (int32_t)ts_now.tv_nsec; - -- if (types_timestamp_cmp(&t_now, context_info->until) > 0) { -+ if (util_types_timestamp_cmp(&t_now, context_info->until) > 0) { - INFO("Finish response for RPC, client should exit"); - linked_list_del(it); - sem_post(&context_info->context_sem); -@@ -988,15 +988,15 @@ out: - return ret; - } - --static int start_monitord() -+static int start_monitored() - { - int ret = 0; -- int monitord_exitcode = 0; -+ int monitored_exitcode = 0; - sem_t monitord_sem; - struct monitord_sync_data msync = { 0 }; - - msync.monitord_sem = &monitord_sem; -- msync.exit_code = &monitord_exitcode; -+ msync.exit_code = &monitored_exitcode; - if (sem_init(msync.monitord_sem, 0, 0)) { - isulad_set_error_message("Failed to init monitor sem"); - ret = -1; -@@ -1004,7 +1004,7 @@ static int start_monitord() - } - - if (new_monitord(&msync)) { -- isulad_set_error_message("Create monitord thread failed"); -+ isulad_set_error_message("Create monitored thread failed"); - ret = -1; - sem_destroy(msync.monitord_sem); - goto out; -@@ -1012,8 +1012,8 @@ static int start_monitord() - - sem_wait(msync.monitord_sem); - sem_destroy(msync.monitord_sem); -- if (monitord_exitcode) { -- isulad_set_error_message("Monitord start failed"); -+ if (monitored_exitcode) { -+ isulad_set_error_message("Monitored start failed"); - ret = -1; - goto out; - } -@@ -1032,7 +1032,7 @@ int events_module_init(char **msg) - goto out; - } - -- if (start_monitord()) { -+ if (start_monitored()) { - *msg = g_isulad_errmsg ? g_isulad_errmsg : "Failed to init cgroups path"; - ret = -1; - goto out; -diff --git a/src/daemon/modules/events/monitord.c b/src/daemon/modules/events/monitord.c -index 70ab4eb..3cf0744 100644 ---- a/src/daemon/modules/events/monitord.c -+++ b/src/daemon/modules/events/monitord.c -@@ -10,7 +10,7 @@ - * See the Mulan PSL v2 for more details. - * Author: tanyifeng - * Create: 2017-11-22 -- * Description: provide container monitord functions -+ * Description: provide container monitored functions - ******************************************************************************/ - #define _GNU_SOURCE - -@@ -33,7 +33,7 @@ - #include "event_type.h" - #include "utils_file.h" - --struct monitord_handler { -+struct monitored_handler { - struct epoll_descr *pdescr; - int fifo_fd; - char *fifo_path; -@@ -61,8 +61,8 @@ out: - return 0; - } - --/* free monitord */ --static void free_monitord(struct monitord_handler *mhandler) -+/* free monitored */ -+static void free_monitored(struct monitored_handler *mhandler) - { - if (mhandler->fifo_fd != -1) { - epoll_loop_del_handler(mhandler->pdescr, mhandler->fifo_fd); -@@ -76,16 +76,16 @@ static void free_monitord(struct monitord_handler *mhandler) - mhandler->fifo_path = NULL; - } - -- DEBUG("Clean monitord data..."); -+ DEBUG("Clean monitored data..."); - } - - #define EVENTS_FIFO_SIZE (1024 * 1024) --/* monitord */ --static void *monitord(void *arg) -+/* monitored */ -+static void *monitored(void *arg) - { - int ret = 0; - char *fifo_file_path = NULL; -- struct monitord_handler mhandler = { 0 }; -+ struct monitored_handler mhandler = { 0 }; - struct flock mlock; - struct monitord_sync_data *msync = arg; - struct epoll_descr descr; -@@ -97,7 +97,7 @@ static void *monitord(void *arg) - goto pexit; - } - -- prctl(PR_SET_NAME, "Monitord"); -+ prctl(PR_SET_NAME, "Monitored"); - - ret = epoll_loop_open(&descr); - if (ret != 0) { -@@ -114,13 +114,13 @@ static void *monitord(void *arg) - mhandler.fifo_path = fifo_file_path; - - if (mknod(fifo_file_path, S_IFIFO | S_IRUSR | S_IWUSR, (dev_t)0) && errno != EEXIST) { -- ERROR("Create monitord fifo file failed: %s", strerror(errno)); -+ ERROR("Create monitored fifo file failed: %s", strerror(errno)); - goto err; - } - - mhandler.fifo_fd = util_open(fifo_file_path, O_RDWR | O_NONBLOCK | O_CLOEXEC, 0); - if (mhandler.fifo_fd == -1) { -- ERROR("Open monitord fifo file failed: %s", strerror(errno)); -+ ERROR("Open monitored fifo file failed: %s", strerror(errno)); - goto err; - } - -@@ -134,7 +134,7 @@ static void *monitord(void *arg) - mlock.l_start = 0; - mlock.l_len = 0; - if (fcntl(mhandler.fifo_fd, F_SETLK, &mlock)) { -- INFO("Monitord already running on path: %s", fifo_file_path); -+ INFO("Monitored already running on path: %s", fifo_file_path); - goto err; - } - -@@ -146,7 +146,7 @@ static void *monitord(void *arg) - - sem_post(msync->monitord_sem); - -- /* loop forever except error occured */ -+ /* loop forever except error occurred */ - do { - ret = epoll_loop(&descr, -1); - } while (ret == 0); -@@ -158,22 +158,22 @@ err: - *(msync->exit_code) = -1; - sem_post(msync->monitord_sem); - err2: -- free_monitord(&mhandler); -+ free_monitored(&mhandler); - epoll_loop_close(&descr); - - pexit: - return NULL; - } - --/* new monitord */ -+/* new monitored */ - int new_monitord(struct monitord_sync_data *msync) - { - int ret = 0; - char *statedir = NULL; -- pthread_t monitord_thread; -+ pthread_t monitored_thread; - - if (msync == NULL || msync->monitord_sem == NULL) { -- ERROR("Monitord sem is NULL"); -+ ERROR("Monitored sem is NULL"); - ret = -1; - goto out; - } -@@ -185,15 +185,15 @@ int new_monitord(struct monitord_sync_data *msync) - goto out; - } - -- if (setenv("ISULAD_MONITORD_PATH", statedir, 1)) { -- ERROR("Setenv monitord path failed"); -+ if (setenv("ISULAD_MONITORED_PATH", statedir, 1)) { -+ ERROR("Setenv monitored path failed"); - ret = -1; - goto out; - } - -- INFO("Starting monitord..."); -- if (pthread_create(&monitord_thread, NULL, monitord, msync) != 0) { -- ERROR("Create monitord thread failed"); -+ INFO("Starting monitored..."); -+ if (pthread_create(&monitored_thread, NULL, monitored, msync) != 0) { -+ ERROR("Create monitored thread failed"); - ret = -1; - } - -diff --git a/src/daemon/modules/events/monitord.h b/src/daemon/modules/events/monitord.h -index 00a09ca..beace80 100644 ---- a/src/daemon/modules/events/monitord.h -+++ b/src/daemon/modules/events/monitord.h -@@ -10,10 +10,10 @@ - * See the Mulan PSL v2 for more details. - * Author: maoweiyong - * Create: 2017-11-22 -- * Description: provide monitord definition -+ * Description: provide monitored definition - ******************************************************************************/ --#ifndef DAEMON_MODULES_EVENTS_MONITORD_H --#define DAEMON_MODULES_EVENTS_MONITORD_H -+#ifndef DAEMON_MODULES_EVENTS_MONITORED_H -+#define DAEMON_MODULES_EVENTS_MONITORED_H - #include - #include - #include -diff --git a/src/daemon/modules/events_sender/event_sender.c b/src/daemon/modules/events_sender/event_sender.c -index 63c8c26..03dcbbf 100644 ---- a/src/daemon/modules/events_sender/event_sender.c -+++ b/src/daemon/modules/events_sender/event_sender.c -@@ -59,7 +59,7 @@ static void isulad_monitor_fifo_send(const struct monitord_msg *msg) - do { - ret = util_write_nointr(fd, msg, sizeof(struct monitord_msg)); - if (ret != sizeof(struct monitord_msg)) { -- usleep_nointerupt(1000); -+ util_usleep_nointerupt(1000); - } - } while (ret != sizeof(struct monitord_msg)); - -diff --git a/src/daemon/modules/image/CMakeLists.txt b/src/daemon/modules/image/CMakeLists.txt -index a4d569e..a92799a 100644 ---- a/src/daemon/modules/image/CMakeLists.txt -+++ b/src/daemon/modules/image/CMakeLists.txt -@@ -100,5 +100,7 @@ target_link_libraries(${LIB_ISULAD_IMG} - ${SELINUX_LIBRARY} - -lpthread -lcrypto -larchive -lz libhttpclient) - -+target_compile_definitions(${LIB_ISULAD_IMG} PRIVATE LIB_ISULAD_IMG_SO) -+ - install(TARGETS ${LIB_ISULAD_IMG} - LIBRARY DESTINATION ${LIB_INSTALL_DIR_DEFAULT} PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE) -diff --git a/src/daemon/modules/image/embedded/db/db_all.c b/src/daemon/modules/image/embedded/db/db_all.c -index 185eb75..6d6670d 100644 ---- a/src/daemon/modules/image/embedded/db/db_all.c -+++ b/src/daemon/modules/image/embedded/db/db_all.c -@@ -299,7 +299,7 @@ static int db_save_image_info_sql(struct db_image *image) - sqlite3_bind_text(stmt, 12, image->config_digest, -1, SQLITE_STATIC); - sqlite3_bind_text(stmt, 13, image->config_path, -1, SQLITE_STATIC); - if (sqlite3_step(stmt) != SQLITE_DONE) { -- ERROR("Insert image info into the image infomation table failed!"); -+ ERROR("Insert image info into the image information table failed!"); - ret = DB_FAIL; - } - -@@ -373,7 +373,7 @@ int db_save_image(struct db_image *image) - ret = db_add_image_name_sql(image->image_name, - image->config_digest, image->config_path); - if (ret) { -- /* Should not error when add image name. If error occured, -+ /* Should not error when add image name. If error occurred, - * database is abnormal, so do not rollback. */ - goto out; - } -@@ -699,8 +699,8 @@ static int read_all_images_info(sqlite3_stmt *stmt, void **data) - } - oldsize = (*imagesinfo)->imagesnum * sizeof(struct db_image *); - newsize = ((*imagesinfo)->imagesnum + 1) * sizeof(struct db_image *); -- ret = mem_realloc((void **)(&(*imagesinfo)->images_info), newsize, -- (*imagesinfo)->images_info, oldsize); -+ ret = util_mem_realloc((void **)(&(*imagesinfo)->images_info), newsize, -+ (*imagesinfo)->images_info, oldsize); - if (ret < 0) { - ERROR("Out of memory!"); - goto cleanup; -diff --git a/src/daemon/modules/image/embedded/db/sqlite_common.c b/src/daemon/modules/image/embedded/db/sqlite_common.c -index f8c7c2a..42fdf6d 100644 ---- a/src/daemon/modules/image/embedded/db/sqlite_common.c -+++ b/src/daemon/modules/image/embedded/db/sqlite_common.c -@@ -25,10 +25,10 @@ - - // Waiting at most (10 * 1000ms) when database is busy - // to avoid concurrent write or read. --#define SQLITE_BUSY_TIMEOUT 120000 -+#define ISULA_SQLITE_BUSY_TIMEOUT 120000 - --#define SQLITE_PAGECACHE_SIZE 4096 --#define SQLITE_PAGECACHE_NUM 8 -+#define ISULA_SQLITE_PAGECACHE_SIZE 4096 -+#define ISULA_SQLITE_PAGECACHE_NUM 8 - - sqlite3 *g_db = NULL; - -@@ -74,7 +74,7 @@ int db_sqlite_request(const char *stmt) - char *errmsg = NULL; - int ret; - -- ret = sqlite3_busy_timeout(g_db, SQLITE_BUSY_TIMEOUT); -+ ret = sqlite3_busy_timeout(g_db, ISULA_SQLITE_BUSY_TIMEOUT); - if (ret != SQLITE_OK) { - ERROR("Falied to set sqlite busy timeout"); - return ret; -@@ -94,7 +94,7 @@ int db_sqlite_request_callback(const char *stmt, - char *errmsg = NULL; - int ret; - -- ret = sqlite3_busy_timeout(g_db, SQLITE_BUSY_TIMEOUT); -+ ret = sqlite3_busy_timeout(g_db, ISULA_SQLITE_BUSY_TIMEOUT); - if (ret != SQLITE_OK) { - ERROR("Falied to set sqlite busy timeout"); - return ret; -@@ -163,8 +163,8 @@ int db_common_init(const char *rootpath) - ERROR("Failed to print string"); - return -1; - } -- ret = sqlite3_config(SQLITE_CONFIG_PAGECACHE, NULL, SQLITE_PAGECACHE_SIZE, -- SQLITE_PAGECACHE_NUM); -+ ret = sqlite3_config(SQLITE_CONFIG_PAGECACHE, NULL, ISULA_SQLITE_PAGECACHE_SIZE, -+ ISULA_SQLITE_PAGECACHE_NUM); - if (ret != SQLITE_OK) { - goto open_new_db; - } -diff --git a/src/daemon/modules/image/embedded/embedded_config_merge.c b/src/daemon/modules/image/embedded/embedded_config_merge.c -index c60bbcc..29878a4 100644 ---- a/src/daemon/modules/image/embedded/embedded_config_merge.c -+++ b/src/daemon/modules/image/embedded/embedded_config_merge.c -@@ -13,6 +13,7 @@ - * Description: provide embedded image merge config - ******************************************************************************/ - #define _GNU_SOURCE /* See feature_test_macros(7) */ -+#include "embedded_config_merge.h" - #include /* Obtain O_* constant definitions */ - #include - #include -@@ -28,13 +29,13 @@ - #include "specs_mount.h" - #include "lim.h" - #include "mediatype.h" --#include "embedded_config_merge.h" -+#include "image_spec_merge.h" - - static int embedded_merge_entrypoint(embedded_config *config, container_config *container_spec) - { - if (config->entrypoint && container_spec->entrypoint_len == 0) { -- int ret = dup_array_of_strings((const char **)config->entrypoint, config->entrypoint_len, -- &(container_spec->entrypoint), &(container_spec->entrypoint_len)); -+ int ret = util_dup_array_of_strings((const char **)config->entrypoint, config->entrypoint_len, -+ &(container_spec->entrypoint), &(container_spec->entrypoint_len)); - if (ret != 0) { - ERROR("Failed to duplicate entrypoint from manifest"); - return -1; -@@ -47,64 +48,16 @@ static int embedded_merge_entrypoint(embedded_config *config, container_config * - static int embedded_merge_env(const embedded_config *config, container_config *container_spec) - { - int ret = 0; -- size_t new_size = 0; -- size_t old_size = 0; -- size_t i = 0; -- size_t j = 0; -- char **temp = NULL; -- char **im_kv = NULL; -- char **custom_kv = NULL; - - if (config->env == NULL || config->env_len == 0) { - return 0; - } - -- if (config->env_len > LIST_ENV_SIZE_MAX - container_spec->env_len) { -- ERROR("The length of envionment variables is too long, the limit is %lld", LIST_ENV_SIZE_MAX); -- isulad_set_error_message("The length of envionment variables is too long, the limit is %lld", -- LIST_ENV_SIZE_MAX); -+ if (image_spec_merge_env((const char **)config->env, config->env_len, container_spec) != 0) { - ret = -1; - goto out; - } -- new_size = (container_spec->env_len + config->env_len) * sizeof(char *); -- old_size = container_spec->env_len * sizeof(char *); -- ret = mem_realloc((void **)&temp, new_size, container_spec->env, old_size); -- if (ret != 0) { -- ERROR("Failed to realloc memory for envionment variables"); -- ret = -1; -- goto out; -- } -- -- container_spec->env = temp; -- for (i = 0; i < config->env_len; i++) { -- bool found = false; -- im_kv = util_string_split(config->env[i], '='); -- if (im_kv == NULL) { -- continue; -- } - -- for (j = 0; j < container_spec->env_len; j++) { -- custom_kv = util_string_split(container_spec->env[j], '='); -- if (custom_kv == NULL) { -- continue; -- } -- if (strcmp(im_kv[0], custom_kv[0]) == 0) { -- found = true; -- } -- util_free_array(custom_kv); -- custom_kv = NULL; -- if (found) { -- break; -- } -- } -- -- if (!found) { -- container_spec->env[container_spec->env_len] = util_strdup_s(config->env[i]); -- container_spec->env_len++; -- } -- util_free_array(im_kv); -- im_kv = NULL; -- } - out: - return ret; - } -diff --git a/src/daemon/modules/image/embedded/embedded_config_merge.h b/src/daemon/modules/image/embedded/embedded_config_merge.h -index db0a15e..d2fd734 100644 ---- a/src/daemon/modules/image/embedded/embedded_config_merge.h -+++ b/src/daemon/modules/image/embedded/embedded_config_merge.h -@@ -15,7 +15,7 @@ - #ifndef __EMBEDDED_IMAGE_MERGE_CONFIG_H_ - #define __EMBEDDED_IMAGE_MERGE_CONFIG_H_ - --#include "isula_libutils/oci_image_spec.h" -+#include "isula_libutils/container_config.h" - - #ifdef __cplusplus - extern "C" { -@@ -28,4 +28,3 @@ int embedded_image_merge_config(const char *image_config, container_config *cont - #endif - - #endif -- -diff --git a/src/daemon/modules/image/embedded/lim.c b/src/daemon/modules/image/embedded/lim.c -index 8de60d9..f986b6c 100644 ---- a/src/daemon/modules/image/embedded/lim.c -+++ b/src/daemon/modules/image/embedded/lim.c -@@ -249,7 +249,7 @@ static bool validate_layer_path_in_host(size_t layer_index, const char *location - UTIL_FREE_AND_SET_NULL(tmp_path); - return false; - } -- tmp_path = follow_symlink_in_scope(abs_path, parent_location); -+ tmp_path = util_follow_symlink_in_scope(abs_path, parent_location); - if (tmp_path == NULL || !strncmp(tmp_path, "..", 2)) { - ERROR("invalid layer path %s", path_in_host); - isulad_try_set_error_message("Invalid content in manifest: layer not exists"); -@@ -312,7 +312,7 @@ static bool validate_layer_digest(size_t layer_index, char *path, uint32_t fmod, - /* If layer is a directory, digest must be empty */ - if ((int)fmod == S_IFDIR) { - ERROR("Invalid digest %s, digest must be empty if media type is %s", digest, MediaTypeEmbeddedLayerDir); -- isulad_try_set_error_message("Invalid content in mainfest: layer digest must be empty if mediaType is %s", -+ isulad_try_set_error_message("Invalid content in manifest: layer digest must be empty if mediaType is %s", - MediaTypeEmbeddedLayerDir); - return false; - } -@@ -320,13 +320,13 @@ static bool validate_layer_digest(size_t layer_index, char *path, uint32_t fmod, - /* check if digest format is valid */ - if (!util_valid_digest(digest)) { - ERROR("invalid digest %s for layer", digest); -- isulad_try_set_error_message("Invalid content in mainfest: layer(except first layer) has invalid digest"); -+ isulad_try_set_error_message("Invalid content in manifest: layer(except first layer) has invalid digest"); - return false; - } - - /* calc and check digest */ - if (!sha256_valid_digest_file(path, digest)) { -- isulad_try_set_error_message("Invalid content in mainfest: layer(except first layer) has invalid digest"); -+ isulad_try_set_error_message("Invalid content in manifest: layer(except first layer) has invalid digest"); - return false; - } - -@@ -386,7 +386,7 @@ static bool validate_image_name(char *image_name) - { - if (image_name == NULL) { - ERROR("image name not exist"); -- isulad_try_set_error_message("Invalid content in manfiest: image name not exist"); -+ isulad_try_set_error_message("Invalid content in manifest: image name not exist"); - return false; - } - -@@ -399,7 +399,7 @@ static bool validate_image_name(char *image_name) - - if (!util_valid_embedded_image_name(image_name)) { - ERROR("invalid image name %s", image_name); -- isulad_try_set_error_message("Invalid content in manfiest: invalid image name"); -+ isulad_try_set_error_message("Invalid content in manifest: invalid image name"); - return false; - } - return true; -@@ -410,7 +410,7 @@ static bool validate_image_layers_number(size_t layers_len) - { - if (layers_len > LAYER_NUM_MAX || layers_len < 1) { - ERROR("invalid layers number %ld maxium is %d", layers_len, LAYER_NUM_MAX); -- isulad_try_set_error_message("Invalid content in mainfest: layer empty or max depth exceeded"); -+ isulad_try_set_error_message("Invalid content in manifest: layer empty or max depth exceeded"); - return false; - } - return true; -diff --git a/src/daemon/modules/image/embedded/lim.h b/src/daemon/modules/image/embedded/lim.h -index 7a0f7b8..cb21884 100644 ---- a/src/daemon/modules/image/embedded/lim.h -+++ b/src/daemon/modules/image/embedded/lim.h -@@ -33,7 +33,7 @@ struct image_creator { - struct image_info { - char *image_name; /* image name */ - char *image_type; /* image type. docker or embedded */ -- int64_t size; /* image sieze */ -+ int64_t size; /* image size */ - char *chain_id; /* chain id of image's top layer */ - char *config_digest; /* sha256 digest of image's config */ - }; -diff --git a/src/daemon/modules/image/image.c b/src/daemon/modules/image/image.c -index 87025ad..551c630 100644 ---- a/src/daemon/modules/image/image.c -+++ b/src/daemon/modules/image/image.c -@@ -245,7 +245,7 @@ static const struct bim_type *bim_query(const char *image_name) - } - temp = g_bims[i].ops->resolve_image_name(image_name); - if (temp == NULL) { -- isulad_append_error_message("Failed to resovle image name%s", image_name); -+ isulad_append_error_message("Failed to resolve image name%s", image_name); - return NULL; - } - int r = g_bims[i].ops->detect(temp); -@@ -325,7 +325,7 @@ static struct bim *bim_get(const char *image_type, const char *image_name, const - if (image_name != NULL) { - bim->image_name = bim->ops->resolve_image_name(image_name); - if (bim->image_name == NULL) { -- isulad_append_error_message("Failed to resovle image name%s", image_name); -+ isulad_append_error_message("Failed to resolve image name%s", image_name); - bim_put(bim); - return NULL; - } -@@ -808,7 +808,7 @@ static int append_images_to_response(im_list_response *response, imagetool_image - - new_size = (old_num + images_num) * sizeof(imagetool_image *); - old_size = old_num * sizeof(imagetool_image *); -- ret = mem_realloc((void **)(&tmp), new_size, response->images->images, old_size); -+ ret = util_mem_realloc((void **)(&tmp), new_size, response->images->images, old_size); - if (ret != 0) { - ERROR("Failed to realloc memory for append images"); - ret = -1; -@@ -962,17 +962,17 @@ void free_im_pull_request(im_pull_request *req) - req->type = NULL; - free(req->image); - req->image = NULL; -- free_sensitive_string(req->username); -+ util_free_sensitive_string(req->username); - req->username = NULL; -- free_sensitive_string(req->password); -+ util_free_sensitive_string(req->password); - req->password = NULL; -- free_sensitive_string(req->auth); -+ util_free_sensitive_string(req->auth); - req->auth = NULL; -- free_sensitive_string(req->server_address); -+ util_free_sensitive_string(req->server_address); - req->server_address = NULL; -- free_sensitive_string(req->registry_token); -+ util_free_sensitive_string(req->registry_token); - req->registry_token = NULL; -- free_sensitive_string(req->identity_token); -+ util_free_sensitive_string(req->identity_token); - req->identity_token = NULL; - free(req); - } -@@ -1235,16 +1235,16 @@ void free_im_login_request(im_login_request *ptr) - return; - } - -- free_sensitive_string(ptr->username); -+ util_free_sensitive_string(ptr->username); - ptr->username = NULL; - -- free_sensitive_string(ptr->password); -+ util_free_sensitive_string(ptr->password); - ptr->password = NULL; - - free(ptr->type); - ptr->type = NULL; - -- free_sensitive_string(ptr->server); -+ util_free_sensitive_string(ptr->server); - ptr->server = NULL; - - free(ptr); -diff --git a/src/daemon/modules/image/image_rootfs_handler.c b/src/daemon/modules/image/image_rootfs_handler.c -index dd30535..19735f6 100644 ---- a/src/daemon/modules/image/image_rootfs_handler.c -+++ b/src/daemon/modules/image/image_rootfs_handler.c -@@ -41,43 +41,6 @@ - #define UnixPasswdPath "/etc/passwd" - #define UnixGroupPath "/etc/group" - --static void parse_user_group(const char *username, char **user, char **group, char **tmp_dup) --{ -- char *tmp = NULL; -- char *pdot = NULL; -- -- if (user == NULL || group == NULL || tmp_dup == NULL) { -- return; -- } -- -- if (username != NULL) { -- tmp = util_strdup_s(username); -- -- // for free tmp in caller -- *tmp_dup = tmp; -- -- pdot = strstr(tmp, ":"); -- if (pdot != NULL) { -- *pdot = '\0'; -- if (pdot != tmp) { -- // User found -- *user = tmp; -- } -- if (*(pdot + 1) != '\0') { -- // group found -- *group = pdot + 1; -- } -- } else { -- // No : found -- if (*tmp != '\0') { -- *user = tmp; -- } -- } -- } -- -- return; --} -- - static void uids_gids_range_err_log() - { - ERROR("uids and gids must be in range 0-%lld", MAXUID); -@@ -189,7 +152,7 @@ static int append_additional_gids(gid_t gid, gid_t **additional_gids, size_t *le - } - } - -- ret = mem_realloc((void **)&new_gids, new_len * sizeof(gid_t), *additional_gids, (*len) * sizeof(gid_t)); -+ ret = util_mem_realloc((void **)&new_gids, new_len * sizeof(gid_t), *additional_gids, (*len) * sizeof(gid_t)); - if (ret != 0) { - ERROR("Out of memory"); - return -1; -@@ -310,7 +273,7 @@ static int append_additional_groups(const struct group *grp, struct group **grou - struct group *new_groups = NULL; - size_t new_len = *len + 1; - -- ret = mem_realloc((void **)&new_groups, new_len * sizeof(struct group), *groups, (*len) * sizeof(struct group)); -+ ret = util_mem_realloc((void **)&new_groups, new_len * sizeof(struct group), *groups, (*len) * sizeof(struct group)); - if (ret != 0) { - ERROR("Out of memory"); - return -1; -@@ -432,7 +395,7 @@ static int read_user_file(const char *basefs, const char *user_path, FILE **stre - int64_t filesize = 0; - char *real_path = NULL; - -- if (realpath_in_scope(basefs, user_path, &real_path) < 0) { -+ if (util_realpath_in_scope(basefs, user_path, &real_path) < 0) { - ERROR("user target file '%s' real path must be under '%s'", user_path, basefs); - isulad_set_error_message("user target file '%s' real path must be under '%s'", user_path, basefs); - ret = -1; -@@ -492,7 +455,7 @@ static int get_exec_user(const char *username, FILE *f_passwd, FILE *f_group, de - char *matched_username = NULL; - - // parse user and group by username -- parse_user_group(username, &user, &group, &tmp); -+ util_parse_user_group(username, &user, &group, &tmp); - - // proc by f_passwd - ret = proc_by_fpasswd(f_passwd, user, puser, &matched_username); -diff --git a/src/daemon/modules/image/image_spec_merge.c b/src/daemon/modules/image/image_spec_merge.c -new file mode 100644 -index 0000000..a5d7501 ---- /dev/null -+++ b/src/daemon/modules/image/image_spec_merge.c -@@ -0,0 +1,84 @@ -+/****************************************************************************** -+* 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: lifeng -+* Create: 2020-10-10 -+* Description: provide oci image operator definition -+*******************************************************************************/ -+#include "image_spec_merge.h" -+ -+#include "utils.h" -+#include "isula_libutils/log.h" -+#include "err_msg.h" -+ -+int image_spec_merge_env(const char **env, size_t env_len, container_config *container_spec) -+{ -+ int ret = 0; -+ size_t new_size = 0; -+ size_t old_size = 0; -+ size_t i = 0; -+ size_t j = 0; -+ char **temp = NULL; -+ char **im_kv = NULL; -+ char **custom_kv = NULL; -+ -+ if (env == NULL || env_len == 0) { -+ return 0; -+ } -+ -+ if (env_len > LIST_ENV_SIZE_MAX - container_spec->env_len) { -+ ERROR("The length of envionment variables is too long, the limit is %lld", LIST_ENV_SIZE_MAX); -+ isulad_set_error_message("The length of envionment variables is too long, the limit is %lld", -+ LIST_ENV_SIZE_MAX); -+ ret = -1; -+ goto out; -+ } -+ new_size = (container_spec->env_len + env_len) * sizeof(char *); -+ old_size = container_spec->env_len * sizeof(char *); -+ ret = util_mem_realloc((void **)&temp, new_size, container_spec->env, old_size); -+ if (ret != 0) { -+ ERROR("Failed to realloc memory for envionment variables"); -+ ret = -1; -+ goto out; -+ } -+ -+ container_spec->env = temp; -+ for (i = 0; i < env_len; i++) { -+ bool found = false; -+ im_kv = util_string_split(env[i], '='); -+ if (im_kv == NULL) { -+ continue; -+ } -+ -+ for (j = 0; j < container_spec->env_len; j++) { -+ custom_kv = util_string_split(container_spec->env[j], '='); -+ if (custom_kv == NULL) { -+ continue; -+ } -+ if (strcmp(im_kv[0], custom_kv[0]) == 0) { -+ found = true; -+ } -+ util_free_array(custom_kv); -+ custom_kv = NULL; -+ if (found) { -+ break; -+ } -+ } -+ -+ if (!found) { -+ container_spec->env[container_spec->env_len] = util_strdup_s(env[i]); -+ container_spec->env_len++; -+ } -+ util_free_array(im_kv); -+ im_kv = NULL; -+ } -+out: -+ return ret; -+} -\ No newline at end of file -diff --git a/src/daemon/modules/image/image_spec_merge.h b/src/daemon/modules/image/image_spec_merge.h -new file mode 100644 -index 0000000..3cc91b0 ---- /dev/null -+++ b/src/daemon/modules/image/image_spec_merge.h -@@ -0,0 +1,30 @@ -+/****************************************************************************** -+* 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: lifeng -+* Create: 2020-10-10 -+* Description: provide isula image rootfs handler definition -+*******************************************************************************/ -+#ifndef DAEMON_MODULES_IMAGE_SPEC_MERGE_H -+#define DAEMON_MODULES_IMAGE_SPEC_MERGE_H -+ -+#include "isula_libutils/container_config.h" -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+int image_spec_merge_env(const char **env, size_t env_len, container_config *container_spec); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif // DAEMON_MODULES_IMAGE_SPEC_MERGE_H -diff --git a/src/daemon/modules/image/oci/oci_common_operators.c b/src/daemon/modules/image/oci/oci_common_operators.c -index 6b95e86..967894b 100644 ---- a/src/daemon/modules/image/oci/oci_common_operators.c -+++ b/src/daemon/modules/image/oci/oci_common_operators.c -@@ -125,7 +125,7 @@ static int do_image_time_filter(map_itor *itor, bool is_before_filter, int64_t * - goto out; - } - -- if (to_unix_nanos_from_str(image_info->created, &tmp_nanos) != 0) { -+ if (util_to_unix_nanos_from_str(image_info->created, &tmp_nanos) != 0) { - ERROR("Failed to get unix nano from string"); - ret = -1; - goto out; -@@ -176,7 +176,7 @@ static bool image_time_filter(const imagetool_image *src, const struct filters_a - } - } - -- if (to_unix_nanos_from_str(src->created, &tmp_nanos) != 0) { -+ if (util_to_unix_nanos_from_str(src->created, &tmp_nanos) != 0) { - ERROR("Failed to get unix nano from string"); - goto out; - } -@@ -316,7 +316,7 @@ static int dup_oci_image_info_by_filters(const imagetool_image *src, const struc - new_size = (images_list->images_len + 1) * sizeof(imagetool_image *); - old_size = images_list->images_len * sizeof(imagetool_image *); - -- ret = mem_realloc((void **)(&tmp_images), new_size, images_list->images, old_size); -+ ret = util_mem_realloc((void **)(&tmp_images), new_size, images_list->images, old_size); - if (ret != 0) { - ERROR("Failed to realloc memory for append images"); - ret = -1; -@@ -434,8 +434,8 @@ int oci_status_image(im_status_request *request, im_status_response **response) - - resolved_name = oci_resolve_image_name(image_ref); - if (resolved_name == NULL) { -- ERROR("Failed to reslove image name %s", image_ref); -- isulad_set_error_message("Failed to reslove image name %s", image_ref); -+ ERROR("Failed to resolve image name %s", image_ref); -+ isulad_set_error_message("Failed to resolve image name %s", image_ref); - ret = -1; - goto pack_response; - } -diff --git a/src/daemon/modules/image/oci/oci_config_merge.c b/src/daemon/modules/image/oci/oci_config_merge.c -index 9b5050f..5fdacd3 100644 ---- a/src/daemon/modules/image/oci/oci_config_merge.c -+++ b/src/daemon/modules/image/oci/oci_config_merge.c -@@ -31,6 +31,7 @@ - #include "err_msg.h" - #include "utils_array.h" - #include "utils_string.h" -+#include "image_spec_merge.h" - - static void oci_image_merge_working_dir(const char *working_dir, container_config *container_spec) - { -@@ -44,63 +45,16 @@ static void oci_image_merge_working_dir(const char *working_dir, container_confi - static int oci_image_merge_env(const oci_image_spec_config *config, container_config *container_spec) - { - int ret = 0; -- size_t new_size = 0; -- size_t old_size = 0; -- size_t i = 0; -- size_t j = 0; -- char **temp = NULL; -- char **im_kv = NULL; -- char **custom_kv = NULL; - - if (config->env == NULL || config->env_len == 0) { - return 0; - } - -- if (config->env_len > LIST_ENV_SIZE_MAX - container_spec->env_len) { -- ERROR("The length of envionment variables is too long, the limit is %lld", LIST_ENV_SIZE_MAX); -- isulad_set_error_message("The length of envionment variables is too long, the limit is %d", LIST_ENV_SIZE_MAX); -+ if (image_spec_merge_env((const char **)config->env, config->env_len, container_spec) != 0) { - ret = -1; - goto out; - } -- new_size = (container_spec->env_len + config->env_len) * sizeof(char *); -- old_size = container_spec->env_len * sizeof(char *); -- ret = mem_realloc((void **)&temp, new_size, container_spec->env, old_size); -- if (ret != 0) { -- ERROR("Failed to realloc memory for envionment variables"); -- ret = -1; -- goto out; -- } -- -- container_spec->env = temp; -- for (i = 0; i < config->env_len; i++) { -- bool found = false; -- im_kv = util_string_split(config->env[i], '='); -- if (im_kv == NULL) { -- continue; -- } - -- for (j = 0; j < container_spec->env_len; j++) { -- custom_kv = util_string_split(container_spec->env[j], '='); -- if (custom_kv == NULL) { -- continue; -- } -- if (strcmp(im_kv[0], custom_kv[0]) == 0) { -- found = true; -- } -- util_free_array(custom_kv); -- custom_kv = NULL; -- if (found) { -- break; -- } -- } -- -- if (!found) { -- container_spec->env[container_spec->env_len] = util_strdup_s(config->env[i]); -- container_spec->env_len++; -- } -- util_free_array(im_kv); -- im_kv = NULL; -- } - out: - return ret; - } -diff --git a/src/daemon/modules/image/oci/oci_image.c b/src/daemon/modules/image/oci/oci_image.c -index b9331c3..f544019 100644 ---- a/src/daemon/modules/image/oci/oci_image.c -+++ b/src/daemon/modules/image/oci/oci_image.c -@@ -53,6 +53,7 @@ static char *format_driver_name(const char *driver) - } - } - -+#ifndef LIB_ISULAD_IMG_SO - static int do_integration_of_images_check(bool image_layer_check, struct storage_module_init_options *opts) - { - char *check_file = NULL; -@@ -89,6 +90,7 @@ out: - free(check_file); - return ret; - } -+#endif // LIB_ISULAD_IMG_SO - - static int storage_module_init_helper(const isulad_daemon_configs *args) - { -@@ -123,17 +125,19 @@ static int storage_module_init_helper(const isulad_daemon_configs *args) - goto out; - } - -- if (dup_array_of_strings((const char **)args->storage_opts, args->storage_opts_len, &storage_opts->driver_opts, -- &storage_opts->driver_opts_len) != 0) { -+ if (util_dup_array_of_strings((const char **)args->storage_opts, args->storage_opts_len, &storage_opts->driver_opts, -+ &storage_opts->driver_opts_len) != 0) { - ERROR("Failed to get storage storage opts"); - ret = -1; - goto out; - } - -+#ifndef LIB_ISULAD_IMG_SO - if (do_integration_of_images_check(args->image_layer_check, storage_opts) != 0) { - ret = -1; - goto out; - } -+#endif // LIB_ISULAD_IMG_SO - - if (storage_module_init(storage_opts) != 0) { - ERROR("Failed to init storage module"); -diff --git a/src/daemon/modules/image/oci/oci_import.c b/src/daemon/modules/image/oci/oci_import.c -index 0386372..99181cd 100644 ---- a/src/daemon/modules/image/oci/oci_import.c -+++ b/src/daemon/modules/image/oci/oci_import.c -@@ -54,7 +54,7 @@ typedef struct { - types_timestamp_t now_time; - char *tag; - char *layer_file; -- char *layer_of_hold_flag; -+ char *layer_of_hold_refs; - } import_desc; - - static void free_import_desc(import_desc *desc) -@@ -81,8 +81,8 @@ static void free_import_desc(import_desc *desc) - desc->uncompressed_digest = NULL; - free(desc->layer_file); - desc->layer_file = NULL; -- free(desc->layer_of_hold_flag); -- desc->layer_of_hold_flag = NULL; -+ free(desc->layer_of_hold_refs); -+ desc->layer_of_hold_refs = NULL; - - free(desc); - -@@ -98,7 +98,7 @@ static int register_layer(import_desc *desc) - return -1; - } - -- id = without_sha256_prefix(desc->uncompressed_digest); -+ id = util_without_sha256_prefix(desc->uncompressed_digest); - if (id == NULL) { - ERROR("Invalid NULL param"); - return -1; -@@ -114,7 +114,7 @@ static int register_layer(import_desc *desc) - if (storage_layer_create(id, &copts) != 0) { - return -1; - } -- desc->layer_of_hold_flag = util_strdup_s(id); -+ desc->layer_of_hold_refs = util_strdup_s(id); - - return 0; - } -@@ -140,7 +140,7 @@ static int create_config(import_desc *desc) - return -1; - } - -- ret = normalized_host_os_arch(&host_os, &host_arch, &host_variant); -+ ret = util_normalized_host_os_arch(&host_os, &host_arch, &host_variant); - if (ret != 0) { - ERROR("get host os and arch for import failed"); - isulad_try_set_error_message("get host os and arch for import failed"); -@@ -178,7 +178,7 @@ static int create_config(import_desc *desc) - goto out; - } - -- if (!get_time_buffer(&desc->now_time, time_str, TIME_BUF_MAX_LEN)) { -+ if (!util_get_time_buffer(&desc->now_time, time_str, TIME_BUF_MAX_LEN)) { - ERROR("get time string from timestamp failed"); - isulad_try_set_error_message("get time string from timestamp failed"); - ret = -1; -@@ -319,8 +319,8 @@ static int register_image(import_desc *desc) - opts.create_time = &desc->now_time; - opts.digest = desc->manifest_digest; - -- image_id = without_sha256_prefix(desc->config_digest); -- top_layer_id = without_sha256_prefix(desc->uncompressed_digest); -+ image_id = util_without_sha256_prefix(desc->config_digest); -+ top_layer_id = util_without_sha256_prefix(desc->uncompressed_digest); - ret = storage_img_create(image_id, top_layer_id, NULL, &opts); - if (ret != 0) { - pre_top_layer = storage_get_img_top_layer(image_id); -@@ -374,12 +374,11 @@ static int register_image(import_desc *desc) - } - - out: -- if (desc->layer_of_hold_flag != NULL && -- storage_set_hold_flag(desc->layer_of_hold_flag, false) != 0) { -- ERROR("clear hold flag failed for layer %s", desc->layer_of_hold_flag); -+ if (desc->layer_of_hold_refs != NULL && storage_dec_hold_refs(desc->layer_of_hold_refs) != 0) { -+ ERROR("decrease hold refs failed for layer %s", desc->layer_of_hold_refs); - } else { -- free(desc->layer_of_hold_flag); -- desc->layer_of_hold_flag = NULL; -+ free(desc->layer_of_hold_refs); -+ desc->layer_of_hold_refs = NULL; - } - - if (ret != 0 && image_created) { -@@ -420,7 +419,7 @@ static import_desc *prepre_import(char *file, char *tag) - goto out; - } - -- if (!get_now_time_stamp(&desc->now_time)) { -+ if (!util_get_now_time_stamp(&desc->now_time)) { - ERROR("get time stamp for import failed"); - isulad_try_set_error_message("get time stamp for import failed"); - ret = -1; -@@ -494,9 +493,8 @@ static int do_import(char *file, char *tag) - } - - out: -- if (desc->layer_of_hold_flag != NULL && -- storage_set_hold_flag(desc->layer_of_hold_flag, false) != 0) { -- ERROR("clear hold flag failed for layer %s", desc->layer_of_hold_flag); -+ if (desc->layer_of_hold_refs != NULL && storage_dec_hold_refs(desc->layer_of_hold_refs) != 0) { -+ ERROR("decrease hold refs failed for layer %s", desc->layer_of_hold_refs); - } - - free_import_desc(desc); -diff --git a/src/daemon/modules/image/oci/oci_load.c b/src/daemon/modules/image/oci/oci_load.c -index f7908b6..5511c04 100644 ---- a/src/daemon/modules/image/oci/oci_load.c -+++ b/src/daemon/modules/image/oci/oci_load.c -@@ -200,12 +200,25 @@ static void oci_load_free_image(load_image_t *im) - - free_oci_image_manifest(im->manifest); - -- free(im->layer_of_hold_flag); -- im->layer_of_hold_flag = NULL; -+ free(im->layer_of_hold_refs); -+ im->layer_of_hold_refs = NULL; - - free(im); - } - -+inline static void do_free_load_image(load_image_t *im) -+{ -+ if (im == NULL) { -+ return; -+ } -+ -+ if (im->layer_of_hold_refs != NULL && storage_dec_hold_refs(im->layer_of_hold_refs) != 0) { -+ ERROR("decrease hold refs failed for layer %s", im->layer_of_hold_refs); -+ } -+ -+ oci_load_free_image(im); -+} -+ - static char **str_array_copy(char **arr, size_t len) - { - char **str_arr = NULL; -@@ -224,25 +237,6 @@ static char **str_array_copy(char **arr, size_t len) - return str_arr; - } - --static types_timestamp_t oci_load_get_timestamp(char *created) --{ -- int64_t nanos = 0; -- types_timestamp_t timestamp = { 0 }; -- -- if (to_unix_nanos_from_str(created, &nanos) != 0) { -- ERROR("Failed to get created time from image config"); -- goto out; -- } -- -- timestamp.has_seconds = true; -- timestamp.seconds = nanos / Time_Second; -- timestamp.has_nanos = true; -- timestamp.nanos = nanos % Time_Second; -- --out: -- return timestamp; --} -- - static char *oci_load_calc_chain_id(char *parent_chain_id, char *diff_id) - { - int sret = 0; -@@ -299,21 +293,31 @@ static char *oci_load_without_sha256_prefix(char *digest) - return digest + strlen(SHA256_PREFIX); - } - --static int oci_load_set_chain_id(load_image_t *image) -+static int registry_layer_from_tarball(const load_layer_blob_t *layer, const char *id, const char *parent) - { -- char *parent_chain_id = ""; -- size_t i = 0; -+ int ret = 0; - -- for (; i < image->layers_len; i++) { -- image->layers[i]->chain_id = oci_load_calc_chain_id(parent_chain_id, image->layers[i]->diff_id); -- if (image->layers[i]->chain_id == NULL) { -- ERROR("calc chain id failed, diff id %s, parent chain id %s", image->layers[i]->diff_id, parent_chain_id); -- return -1; -- } -- parent_chain_id = image->layers[i]->chain_id; -+ if (layer == NULL || id == NULL) { -+ ERROR("Invalid input params"); -+ return -1; - } - -- return 0; -+ storage_layer_create_opts_t copts = { -+ .parent = parent, -+ .uncompress_digest = layer->diff_id, -+ .compressed_digest = layer->compressed_digest, -+ .writable = false, -+ .layer_data_path = layer->fpath, -+ }; -+ -+ if (storage_layer_create(id, &copts) != 0) { -+ ERROR("create layer %s failed, parent %s, file %s", id, parent, layer->fpath); -+ ret = -1; -+ goto out; -+ } -+ -+out: -+ return ret; - } - - static int oci_load_register_layers(load_image_t *desc) -@@ -341,22 +345,22 @@ static int oci_load_register_layers(load_image_t *desc) - goto out; - } - -- storage_layer_create_opts_t copts = { -- .parent = parent, -- .uncompress_digest = desc->layers[i]->diff_id, -- .compressed_digest = desc->layers[i]->compressed_digest, -- .writable = false, -- .layer_data_path = desc->layers[i]->fpath, -- }; -- ret = storage_layer_create(id, &copts); -- if (ret != 0) { -- ERROR("create layer %s failed, parent %s, file %s", id, parent, desc->layers[i]->fpath); -+ if (desc->layers[i]->alread_exist) { -+ DEBUG("Layer:%s is already exist in storage, no need to registry", desc->layers[i]->fpath); -+ parent = id; -+ continue; -+ } -+ -+ if (registry_layer_from_tarball(desc->layers[i], id, parent) != 0) { -+ ERROR("Registry layer:%s from local tarball failed", desc->layers[i]->fpath); -+ ret = -1; - goto out; - } -- free(desc->layer_of_hold_flag); -- desc->layer_of_hold_flag = util_strdup_s(id); -- if (parent != NULL && storage_set_hold_flag(parent, false) != 0) { -- ERROR("clear hold flag failed for layer %s", parent); -+ -+ free(desc->layer_of_hold_refs); -+ desc->layer_of_hold_refs = util_strdup_s(id); -+ if (parent != NULL && storage_dec_hold_refs(parent) != 0) { -+ ERROR("decrease hold refs failed for layer %s", parent); - ret = -1; - goto out; - } -@@ -442,7 +446,7 @@ static int oci_load_create_image(load_image_t *desc, const char *dst_tag) - goto out; - } - -- timestamp = oci_load_get_timestamp(conf->created); -+ timestamp = util_to_timestamp_from_str(conf->created); - top_layer_index = desc->layers_len - 1; - opts.create_time = ×tamp; - opts.digest = desc->manifest_digest; -@@ -553,7 +557,7 @@ static int oci_load_set_loaded_time(char *image_id) - int ret = 0; - types_timestamp_t now = { 0 }; - -- if (!get_now_time_stamp(&now)) { -+ if (!util_get_now_time_stamp(&now)) { - ret = -1; - ERROR("get now time stamp failed"); - goto out; -@@ -623,12 +627,62 @@ out: - return ret; - } - -+static int check_and_set_digest_from_tarball(load_layer_blob_t *layer, const char *conf_diff_id) -+{ -+ int ret = 0; -+ bool gzip = false; -+ -+ if (layer == NULL || conf_diff_id == NULL) { -+ ERROR("Invalid input param"); -+ return -1; -+ } -+ -+ if (!util_file_exists(layer->fpath)) { -+ ERROR("Layer data file:%s is not exist", layer->fpath); -+ isulad_try_set_error_message("%s no such file", layer->fpath); -+ ret = -1; -+ goto out; -+ } -+ -+ layer->alread_exist = false; -+ layer->diff_id = oci_calc_diffid(layer->fpath); -+ if (layer->diff_id == NULL) { -+ ERROR("Calc layer:%s diff id failed", layer->fpath); -+ ret = -1; -+ goto out; -+ } -+ -+ if (util_gzip_compressed(layer->fpath, &gzip) != 0) { -+ ERROR("Judge layer file gzip attr err"); -+ ret = -1; -+ goto out; -+ } -+ -+ layer->compressed_digest = gzip ? sha256_full_file_digest(layer->fpath) : util_strdup_s(layer->diff_id); -+ if (layer->compressed_digest == NULL) { -+ ERROR("Calc layer %s compressed digest failed", layer->fpath); -+ ret = -1; -+ goto out; -+ } -+ -+ if (strcmp(layer->diff_id, conf_diff_id) != 0) { -+ ERROR("invalid diff id for layer:%s: expected %s, got %s", layer->chain_id, conf_diff_id, layer->diff_id); -+ ret = -1; -+ goto out; -+ } -+ -+out: -+ return ret; -+} -+ - static int oci_load_set_layers_info(load_image_t *im, const image_manifest_items_element *manifest, const char *dstdir) - { - int ret = 0; - size_t i = 0; -- bool gzip = false; -- char *layer_fpath = NULL; -+ oci_image_spec *conf = NULL; -+ char *parent_chain_id_sha256 = ""; -+ char *id = NULL; -+ char *parent_chain_id = NULL; - - if (im == NULL || manifest == NULL || dstdir == NULL) { - ERROR("Invalid input params image or manifest is null"); -@@ -638,12 +692,25 @@ static int oci_load_set_layers_info(load_image_t *im, const image_manifest_items - im->layers_len = manifest->layers_len; - im->layers = util_common_calloc_s(sizeof(load_layer_blob_t *) * manifest->layers_len); - if (im->layers == NULL) { -- ret = -1; - ERROR("Calloc memory failed"); -+ ret = -1; - goto out; - } - -- for (; i < im->layers_len; i++) { -+ conf = load_image_config(im->config_fpath); -+ if (conf == NULL || conf->rootfs == NULL) { -+ ERROR("Load image config file %s failed", im->config_fpath); -+ ret = -1; -+ goto out; -+ } -+ -+ if (conf->rootfs->diff_ids_len != im->layers_len) { -+ ERROR("Invalid manifest, layers length mismatch: expected %zu, got %zu", im->layers_len, conf->rootfs->diff_ids_len); -+ ret = -1; -+ goto out; -+ } -+ -+ for (; i < conf->rootfs->diff_ids_len; i++) { - im->layers[i] = util_common_calloc_s(sizeof(load_layer_blob_t)); - if (im->layers[i] == NULL) { - ERROR("Out of memory"); -@@ -651,47 +718,57 @@ static int oci_load_set_layers_info(load_image_t *im, const image_manifest_items - goto out; - } - -- layer_fpath = util_path_join(dstdir, manifest->layers[i]); -- if (layer_fpath == NULL) { -+ im->layers[i]->fpath = util_path_join(dstdir, manifest->layers[i]); -+ if (im->layers[i]->fpath == NULL) { - ERROR("Path join failed"); - ret = -1; - goto out; - } -- -- if (util_gzip_compressed(layer_fpath, &gzip) != 0) { -- ERROR("Judge layer file gzip attribute err"); -+ // The format is sha256:xxx -+ im->layers[i]->chain_id = oci_load_calc_chain_id(parent_chain_id_sha256, conf->rootfs->diff_ids[i]); -+ if (im->layers[i]->chain_id == NULL) { -+ ERROR("calc chain id failed, diff id %s, parent chain id %s", conf->rootfs->diff_ids[i], parent_chain_id_sha256); - ret = -1; - goto out; - } -+ parent_chain_id_sha256 = im->layers[i]->chain_id; - -- im->layers[i]->diff_id = oci_calc_diffid(layer_fpath); -- if (im->layers[i]->diff_id == NULL) { -+ id = oci_load_without_sha256_prefix(im->layers[i]->chain_id); -+ if (id == NULL) { -+ ERROR("Wipe out sha256 prefix failed from layer with chain id : %s", im->layers[i]->chain_id); - ret = -1; -- ERROR("Calc layer %s uncompressed digest failed", manifest->layers[i]); - goto out; - } - -- im->layers[i]->compressed_digest = gzip ? sha256_full_file_digest(layer_fpath) : -- util_strdup_s(im->layers[i]->diff_id); -- if (im->layers[i]->compressed_digest == NULL) { -- ret = -1; -- ERROR("Calc layer %s compressed digest failed", manifest->layers[i]); -- goto out; -+ if (storage_inc_hold_refs(id) == 0) { -+ free(im->layer_of_hold_refs); -+ im->layer_of_hold_refs = util_strdup_s(id); -+ if (parent_chain_id != NULL && storage_dec_hold_refs(parent_chain_id) != 0) { -+ ERROR("Decrease hold refs failed for layer with chain id:%s", parent_chain_id); -+ ret = -1; -+ goto out; -+ } -+ -+ im->layers[i]->diff_id = util_strdup_s(conf->rootfs->diff_ids[i]); -+ if (im->layers[i]->diff_id == NULL) { -+ ERROR("Dup layer diff id:%s from conf failed", conf->rootfs->diff_ids[i]); -+ ret = -1; -+ goto out; -+ } -+ im->layers[i]->alread_exist = true; -+ parent_chain_id = id; -+ continue; - } - -- im->layers[i]->fpath = util_strdup_s(layer_fpath); -- if (im->layers[i]->fpath == NULL) { -+ if (check_and_set_digest_from_tarball(im->layers[i], conf->rootfs->diff_ids[i]) != 0) { -+ ERROR("Check layer digest failed"); - ret = -1; -- ERROR("Image layer data file path is NULL"); - goto out; - } -- UTIL_FREE_AND_SET_NULL(layer_fpath); - } - - out: -- if (layer_fpath != NULL) { -- free(layer_fpath); -- } -+ free_oci_image_spec(conf); - return ret; - } - -@@ -743,11 +820,6 @@ static load_image_t *oci_load_process_manifest(const image_manifest_items_elemen - goto out; - } - -- if (oci_load_set_chain_id(im) != 0) { -- ret = -1; -- ERROR("Calc image chain id failed"); -- } -- - out: - free(config_fpath); - free(image_digest); -@@ -758,6 +830,38 @@ out: - return im; - } - -+static int64_t get_layer_size_from_storage(char *chain_id_pre) -+{ -+ char *id = NULL; -+ struct layer *l = NULL; -+ int64_t size = 0; -+ -+ if (chain_id_pre == NULL) { -+ ERROR("Invalid input param"); -+ return -1; -+ } -+ -+ id = oci_load_without_sha256_prefix(chain_id_pre); -+ if (id == NULL) { -+ ERROR("Get chain id failed from value:%s", chain_id_pre); -+ size = -1; -+ goto out; -+ } -+ -+ l = storage_layer_get(id); -+ if (l == NULL) { -+ ERROR("Layer with chain id:%s is not exist in store", id); -+ size = -1; -+ goto out; -+ } -+ -+ size = l->compress_size; -+ -+out: -+ free_layer(l); -+ return size; -+} -+ - static int oci_load_set_manifest_info(load_image_t *im) - { - int ret = 0; -@@ -811,14 +915,24 @@ static int oci_load_set_manifest_info(load_image_t *im) - ERROR("Out of memory"); - goto out; - } -+ - im->manifest->layers[i]->media_type = util_strdup_s(MediaTypeDockerSchema2LayerGzip); - im->manifest->layers[i]->digest = util_strdup_s(im->layers[i]->diff_id); - -- size = util_file_size(im->layers[i]->fpath); -- if (size < 0) { -- ERROR("Calc image layer %s size error", im->layers[i]->fpath); -- ret = -1; -- goto out; -+ if (im->layers[i]->alread_exist) { -+ size = get_layer_size_from_storage(im->layers[i]->chain_id); -+ if (size < 0) { -+ ERROR("Get image layer:%s size error from local store", im->layers[i]->chain_id); -+ ret = -1; -+ goto out; -+ } -+ } else { -+ size = util_file_size(im->layers[i]->fpath); -+ if (size < 0) { -+ ERROR("Calc image layer %s size error", im->layers[i]->fpath); -+ ret = -1; -+ goto out; -+ } - } - im->manifest->layers[i]->size = size; - } -@@ -831,38 +945,6 @@ out: - return ret; - } - --static int oci_load_check_image_layers(load_image_t *im) --{ -- int ret = 0; -- size_t i = 0; -- oci_image_spec *conf = NULL; -- -- conf = load_image_config(im->config_fpath); -- if (conf == NULL || conf->rootfs == NULL) { -- ERROR("Load image config file %s failed", im->config_fpath); -- ret = -1; -- goto out; -- } -- -- if (conf->rootfs->diff_ids_len != im->layers_len) { -- ret = -1; -- ERROR("Config file layer numbers are not equal to with image layer numbers"); -- goto out; -- } -- -- for (; i < im->layers_len; i++) { -- if (strcmp(im->layers[i]->diff_id, conf->rootfs->diff_ids[i]) != 0) { -- ERROR("Layer diff id %s check err", im->layers[i]->diff_id); -- ret = -1; -- goto out; -- } -- } -- --out: -- free_oci_image_spec(conf); -- return ret; --} -- - static size_t oci_tag_count(image_manifest_items_element **manifest, size_t manifest_len) - { - size_t cnt_tags = 0; -@@ -1014,14 +1096,6 @@ int oci_do_load(const im_load_request *request) - - if (oci_load_set_manifest_info(im) != 0) { - ERROR("Image %s set manifest info err", im->im_id); -- isulad_try_set_error_message("Image %s set manifest info err", im->im_id); -- ret = -1; -- goto out; -- } -- -- if (oci_load_check_image_layers(im) != 0) { -- ERROR("Image %s check err", im->im_id); -- isulad_try_set_error_message("Image %s check err", im->im_id); - ret = -1; - goto out; - } -@@ -1033,7 +1107,8 @@ int oci_do_load(const im_load_request *request) - ret = -1; - goto out; - } -- oci_load_free_image(im); -+ -+ do_free_load_image(im); - im = NULL; - } - -@@ -1048,13 +1123,7 @@ out: - } - free(manifest); - -- if (im != NULL) { -- if (im->layer_of_hold_flag != NULL && storage_set_hold_flag(im->layer_of_hold_flag, false) != 0) { -- ERROR("clear hold flag failed for layer %s", im->layer_of_hold_flag); -- } -- -- oci_load_free_image(im); -- } -+ do_free_load_image(im); - - if (reader.close != NULL) { - reader.close(reader.context, NULL); -diff --git a/src/daemon/modules/image/oci/oci_load.h b/src/daemon/modules/image/oci/oci_load.h -index 5fdeb4c..e1e0906 100644 ---- a/src/daemon/modules/image/oci/oci_load.h -+++ b/src/daemon/modules/image/oci/oci_load.h -@@ -33,8 +33,11 @@ typedef struct { - char *diff_id; - // compressed digest - char *compressed_digest; -+ // with "sha256:" prefix - char *chain_id; - char *fpath; -+ // layer already exist in storage -+ bool alread_exist; - } load_layer_blob_t; - - typedef struct { -@@ -49,7 +52,7 @@ typedef struct { - char *manifest_digest; - types_timestamp_t create_time; - oci_image_manifest *manifest; -- char *layer_of_hold_flag; -+ char *layer_of_hold_refs; - } load_image_t; - - int oci_do_load(const im_load_request *request); -diff --git a/src/daemon/modules/image/oci/oci_pull.c b/src/daemon/modules/image/oci/oci_pull.c -index 21efd34..9d94b66 100644 ---- a/src/daemon/modules/image/oci/oci_pull.c -+++ b/src/daemon/modules/image/oci/oci_pull.c -@@ -63,7 +63,7 @@ static int decode_auth(const char *auth, char **username, char **password) - (void)memset(auth_parts[1], 0, strlen(auth_parts[1])); - - out: -- free_sensitive_string((char *)decoded); -+ util_free_sensitive_string((char *)decoded); - decoded = NULL; - util_free_array(auth_parts); - auth_parts = NULL; -@@ -194,8 +194,7 @@ int oci_do_pull_image(const im_pull_request *request, im_pull_response *response - image2 = storage_img_get(request->image); - if (image == NULL || image2 == NULL) { - ERROR("get image %s failed after pulling", request->image); -- isulad_set_error_message("Failed to pull image %s with error: image not found after pulling", -- request->image); -+ isulad_set_error_message("Failed to pull image %s with error: image not found after pulling", request->image); - ret = -1; - goto out; - } -diff --git a/src/daemon/modules/image/oci/registry/auths.c b/src/daemon/modules/image/oci/registry/auths.c -index a6c549c..a7da0c6 100644 ---- a/src/daemon/modules/image/oci/registry/auths.c -+++ b/src/daemon/modules/image/oci/registry/auths.c -@@ -35,12 +35,12 @@ - #include "utils_file.h" - #include "utils_string.h" - --static char *g_auth_path = DEFAULT_AUTH_DIR"/"AUTH_FILE_NAME ; -+static char *g_auth_path = DEFAULT_AUTH_DIR "/" AUTH_FILE_NAME; - - void auths_set_dir(char *auth_dir) - { - int sret = 0; -- char path[PATH_MAX] = {0}; -+ char path[PATH_MAX] = { 0 }; - - if (auth_dir == NULL) { - return; -@@ -109,9 +109,9 @@ static int decode_auth_aes(char *encoded, char **username, char **password) - (void)memset(auth_parts[1], 0, strlen(auth_parts[1])); - - out: -- free_sensitive_string((char *)auth); -+ util_free_sensitive_string((char *)auth); - auth = NULL; -- free_sensitive_string((char *)decoded); -+ util_free_sensitive_string((char *)decoded); - decoded = NULL; - util_free_array(auth_parts); - auth_parts = NULL; -@@ -164,12 +164,12 @@ static char *encode_auth_aes(char *username, char *password) - - out: - (void)memset(plain_text, 0, strlen(plain_text)); -- free_sensitive_string((char*)aes); -+ util_free_sensitive_string((char *)aes); - aes = NULL; -- free_sensitive_string(plain_text_base64); -+ util_free_sensitive_string(plain_text_base64); - plain_text_base64 = NULL; - if (ret != 0) { -- free_sensitive_string(aes_base64); -+ util_free_sensitive_string(aes_base64); - aes_base64 = NULL; - } - return aes_base64; -@@ -307,7 +307,7 @@ out: - return ret; - } - --static int write_auth_file(char *content) -+static int ensure_auth_dir_exist() - { - int ret = 0; - char *auths_dir = NULL; -@@ -319,17 +319,10 @@ static int write_auth_file(char *content) - goto out; - } - -- ret = util_mkdir_p(auths_dir, 0700); -+ ret = util_mkdir_p(auths_dir, DEFAULT_AUTH_DIR_MODE); - if (ret != 0) { -- ERROR("mkdir for aeskey failed"); -- isulad_try_set_error_message("create direcotry for auths failed"); -- goto out; -- } -- -- ret = util_atomic_write_file(g_auth_path, content, strlen(content), AUTH_FILE_MODE); -- if (ret != 0) { -- ERROR("failed to write auths json to file"); -- isulad_try_set_error_message("failed to write auths json to file"); -+ ERROR("mkdir for auths failed"); -+ isulad_try_set_error_message("create directory for auths failed"); - goto out; - } - -@@ -354,6 +347,11 @@ int auths_save(char *host, char *username, char *password) - return -1; - } - -+ ret = ensure_auth_dir_exist(); -+ if (ret != 0) { -+ goto out; -+ } -+ - auths = registry_auths_parse_file(g_auth_path, NULL, &err); - if (auths == NULL) { - auths = util_common_calloc_s(sizeof(registry_auths)); -@@ -392,7 +390,7 @@ int auths_save(char *host, char *username, char *password) - goto out; - } - -- ret = write_auth_file(json); -+ ret = util_atomic_write_file(g_auth_path, json, strlen(json), AUTH_FILE_MODE); - if (ret != 0) { - ERROR("failed to write auths json to file"); - goto out; -diff --git a/src/daemon/modules/image/oci/registry/auths.h b/src/daemon/modules/image/oci/registry/auths.h -index 263b80f..63969ed 100644 ---- a/src/daemon/modules/image/oci/registry/auths.h -+++ b/src/daemon/modules/image/oci/registry/auths.h -@@ -20,6 +20,7 @@ extern "C" { - #endif - - #define DEFAULT_AUTH_DIR "/root/.isulad" -+#define DEFAULT_AUTH_DIR_MODE 0700 - #define AUTH_FILE_NAME "auths.json" - #define AUTH_FILE_MODE 0600 - #define MAX_AUTHS_LEN 65536 -@@ -37,4 +38,3 @@ int auths_delete(char *host); - #endif - - #endif -- -diff --git a/src/daemon/modules/image/oci/registry/certs.c b/src/daemon/modules/image/oci/registry/certs.c -index 68ad549..9deb8f1 100644 ---- a/src/daemon/modules/image/oci/registry/certs.c -+++ b/src/daemon/modules/image/oci/registry/certs.c -@@ -79,7 +79,7 @@ static int load_certs(const char *path, const char *name, bool use_decrypted_key - return -1; - } - -- if (ca_file != NULL && util_has_suffix(name, CA_SUFFIX)) { -+ if (*ca_file == NULL && util_has_suffix(name, CA_SUFFIX)) { - *ca_file = util_path_join(path, name); - if (*ca_file == NULL) { - ret = -1; -@@ -87,7 +87,7 @@ static int load_certs(const char *path, const char *name, bool use_decrypted_key - goto out; - } - goto out; -- } else if (cert_file != NULL && *cert_file == NULL && util_has_suffix(name, CLIENT_CERT_SUFFIX)) { -+ } else if (*cert_file == NULL && *key_file == NULL && util_has_suffix(name, CLIENT_CERT_SUFFIX)) { - key_name = corresponding_key_name(name); - if (key_name == NULL) { - ERROR("find corresponding key name for cert failed"); -diff --git a/src/daemon/modules/image/oci/registry/http_request.c b/src/daemon/modules/image/oci/registry/http_request.c -index 3fcb9de..b5fcf74 100644 ---- a/src/daemon/modules/image/oci/registry/http_request.c -+++ b/src/daemon/modules/image/oci/registry/http_request.c -@@ -431,7 +431,7 @@ static int setup_common_options(pull_descriptor *desc, struct http_get_options * - } - - if (custom_headers != NULL) { -- options->custom_headers = str_array_dup(custom_headers, util_array_len(custom_headers)); -+ options->custom_headers = util_str_array_dup(custom_headers, util_array_len(custom_headers)); - if (options->custom_headers == NULL) { - ERROR("dup headers failed"); - ret = -1; -diff --git a/src/daemon/modules/image/oci/registry/registry.c b/src/daemon/modules/image/oci/registry/registry.c -index 77b4d02..2d38ea5 100644 ---- a/src/daemon/modules/image/oci/registry/registry.c -+++ b/src/daemon/modules/image/oci/registry/registry.c -@@ -73,13 +73,15 @@ typedef struct { - size_t file_list_len; - } cached_layer; - --// Share infomation of downloading layers to avoid downloading the same layer. -+// Share information of downloading layers to avoid downloading the same layer. - typedef struct { - pthread_mutex_t mutex; - bool mutex_inited; - pthread_cond_t cond; - bool cond_inited; - map_t *cached_layers; -+ pthread_mutex_t image_mutex; -+ bool image_mutex_inited; - } registry_global; - - static registry_global *g_shared; -@@ -133,7 +135,7 @@ static int parse_manifest_schema1(pull_descriptor *desc) - desc->layers[index].empty_layer = v1config->throwaway; - free_image_manifest_v1_compatibility(v1config); - v1config = NULL; -- // Cann't download an empty layer, skip related infomation. -+ // Cann't download an empty layer, skip related information. - if (desc->layers[index].empty_layer) { - continue; - } -@@ -564,7 +566,7 @@ static int register_layers(pull_descriptor *desc) - continue; - } - -- id = without_sha256_prefix(desc->layers[i].chain_id); -+ id = util_without_sha256_prefix(desc->layers[i].chain_id); - if (id == NULL) { - ERROR("layer %zu have NULL digest for image %s", i, desc->image_name); - ret = -1; -@@ -609,9 +611,9 @@ static int register_layers(pull_descriptor *desc) - ERROR("create layer %s failed, parent %s, file %s", id, parent, desc->layers[i].file); - goto out; - } -- free(desc->layer_of_hold_flag); -- desc->layer_of_hold_flag = util_strdup_s(id); -- if (parent != NULL && storage_set_hold_flag(parent, false) != 0) { -+ free(desc->layer_of_hold_refs); -+ desc->layer_of_hold_refs = util_strdup_s(id); -+ if (parent != NULL && storage_dec_hold_refs(parent) != 0) { - ERROR("clear hold flag failed for layer %s", parent); - ret = -1; - goto out; -@@ -632,7 +634,7 @@ out: - - static int get_top_layer_index(pull_descriptor *desc, size_t *top_layer_index) - { -- size_t i = 0; -+ int i = 0; - - if (desc == NULL || top_layer_index == NULL) { - ERROR("Invalid NULL pointer"); -@@ -672,7 +674,7 @@ static int create_image(pull_descriptor *desc, char *image_id, bool *reuse) - - opts.create_time = &desc->config.create_time; - opts.digest = desc->manifest.digest; -- top_layer_id = without_sha256_prefix(desc->layers[top_layer_index].chain_id); -+ top_layer_id = util_without_sha256_prefix(desc->layers[top_layer_index].chain_id); - if (top_layer_id == NULL) { - ERROR("NULL top layer id found for image %s", desc->image_name); - ret = -1; -@@ -785,7 +787,7 @@ static int set_loaded_time(pull_descriptor *desc, char *image_id) - int ret = 0; - types_timestamp_t now = { 0 }; - -- if (!get_now_time_stamp(&now)) { -+ if (!util_get_now_time_stamp(&now)) { - ret = -1; - ERROR("get now time stamp failed"); - goto out; -@@ -863,7 +865,9 @@ static int register_image(pull_descriptor *desc) - goto out; - } - -- image_id = without_sha256_prefix(desc->config.digest); -+ // lock when create image to make sure image content all exist -+ mutex_lock(&g_shared->image_mutex); -+ image_id = util_without_sha256_prefix(desc->config.digest); - ret = create_image(desc, image_id, &reuse); - if (ret != 0) { - ERROR("create image %s failed", desc->image_name); -@@ -907,6 +911,7 @@ static int register_image(pull_descriptor *desc) - } - - out: -+ mutex_unlock(&g_shared->image_mutex); - - if (ret != 0 && image_created) { - if (storage_img_delete(image_id, true)) { -@@ -956,7 +961,7 @@ static int parse_docker_config(pull_descriptor *desc) - parent_chain_id = desc->layers[i].chain_id; - } - -- desc->config.create_time = created_to_timestamp(config->created); -+ desc->config.create_time = util_to_timestamp_from_str(config->created); - - out: - -@@ -1007,7 +1012,7 @@ static int parse_oci_config(pull_descriptor *desc) - parent_chain_id = desc->layers[i].chain_id; - } - -- desc->config.create_time = created_to_timestamp(config->created); -+ desc->config.create_time = util_to_timestamp_from_str(config->created); - - out: - free_oci_image_spec(config); -@@ -1212,6 +1217,8 @@ static int add_fetch_task(thread_fetch_info *info) - goto out; - } - } -+ // retry get cached layer after some time of unlock -+ cache = get_cached_layer(info->blob_digest); - } - - ret = add_cached_layer(info->blob_digest, info->file); -@@ -1395,15 +1402,15 @@ static int fetch_all(pull_descriptor *desc) - for (j = 0; j < list->layers_len; j++) { - if ((list->layers[j]->parent == NULL && i == 0) || - (parent_chain_id != NULL && list->layers[j]->parent != NULL && -- !strcmp(list->layers[j]->parent, without_sha256_prefix(parent_chain_id)) && -+ !strcmp(list->layers[j]->parent, util_without_sha256_prefix(parent_chain_id)) && - strcmp(list->layers[j]->uncompressed_digest, list->layers[j]->compressed_digest))) { -- // If can't set hold flag, it means it not exist anymore. -- if (storage_set_hold_flag(list->layers[j]->id, true) != 0) { -+ // If can't set hold refs, it means it not exist anymore. -+ if (storage_inc_hold_refs(list->layers[j]->id) != 0) { - continue; - } -- free(desc->layer_of_hold_flag); -- desc->layer_of_hold_flag = util_strdup_s(list->layers[j]->id); -- if (parent_chain_id != NULL && storage_set_hold_flag(parent_chain_id, false) != 0) { -+ free(desc->layer_of_hold_refs); -+ desc->layer_of_hold_refs = util_strdup_s(list->layers[j]->id); -+ if (parent_chain_id != NULL && storage_dec_hold_refs(parent_chain_id) != 0) { - continue; - } - desc->layers[i].already_exist = true; -@@ -1541,7 +1548,7 @@ static int create_config_from_v1config(pull_descriptor *desc) - goto out; - } - -- desc->config.create_time = created_to_timestamp(config->created); -+ desc->config.create_time = util_to_timestamp_from_str(config->created); - - free(err); - err = NULL; -@@ -1592,7 +1599,7 @@ static bool reuse_image(pull_descriptor *desc) - goto out; - } - -- id = without_sha256_prefix(desc->config.digest); -+ id = util_without_sha256_prefix(desc->config.digest); - if (id == NULL) { - goto out; - } -@@ -1795,9 +1802,8 @@ int registry_pull(registry_pull_options *options) - INFO("Pull images %s success", options->image_name); - - out: -- if (desc->layer_of_hold_flag != NULL && -- storage_set_hold_flag(desc->layer_of_hold_flag, false) != 0) { -- ERROR("clear hold flag failed for layer %s", desc->layer_of_hold_flag); -+ if (desc->layer_of_hold_refs != NULL && storage_dec_hold_refs(desc->layer_of_hold_refs) != 0) { -+ ERROR("decrease hold refs failed for layer %s", desc->layer_of_hold_refs); - } - - if (desc->blobpath != NULL) { -@@ -1859,6 +1865,13 @@ int registry_init(char *auths_dir, char *certs_dir) - } - g_shared->mutex_inited = true; - -+ ret = pthread_mutex_init(&g_shared->image_mutex, NULL); -+ if (ret != 0) { -+ ERROR("Failed to init image mutex for create image"); -+ goto out; -+ } -+ g_shared->image_mutex_inited = true; -+ - ret = pthread_cond_init(&g_shared->cond, NULL); - if (ret != 0) { - ERROR("Failed to init cond for download info"); -@@ -1882,6 +1895,9 @@ out: - if (g_shared->mutex_inited) { - pthread_mutex_destroy(&g_shared->mutex); - } -+ if (g_shared->image_mutex_inited) { -+ pthread_mutex_destroy(&g_shared->image_mutex); -+ } - map_free(g_shared->cached_layers); - g_shared->cached_layers = NULL; - free(g_shared); -@@ -1941,9 +1957,9 @@ static void free_registry_auth(registry_auth *auth) - if (auth == NULL) { - return; - } -- free_sensitive_string(auth->username); -+ util_free_sensitive_string(auth->username); - auth->username = NULL; -- free_sensitive_string(auth->password); -+ util_free_sensitive_string(auth->password); - auth->password = NULL; - return; - } -diff --git a/src/daemon/modules/image/oci/registry/registry_apiv2.c b/src/daemon/modules/image/oci/registry/registry_apiv2.c -index 7abca9f..6bc3cd4 100644 ---- a/src/daemon/modules/image/oci/registry/registry_apiv2.c -+++ b/src/daemon/modules/image/oci/registry/registry_apiv2.c -@@ -285,7 +285,7 @@ static int parse_ping_header(pull_descriptor *desc, char *http_head) - } - } - -- if (!strings_contains_word(version, "registry/2.0")) { -+ if (!util_strings_contains_word(version, "registry/2.0")) { - ERROR("Docker-Distribution-Api-Version does not contain registry/2.0, it's value is %s." - "Registry can not support registry API V2", - version); -@@ -339,7 +339,7 @@ int registry_pingv2(pull_descriptor *desc, char *protocol) - // Sending url - // https://registry.isula.org/v2/ - INFO("sending ping url: %s", url); -- ret = http_request_buf(desc, url, (const char **)headers, &output, HEAD_ONLY); -+ ret = http_request_buf(desc, url, (const char **)headers, &output, HEAD_BODY); - if (ret != 0) { - ERROR("http request failed"); - goto out; -@@ -425,7 +425,7 @@ static int registry_request(pull_descriptor *desc, char *path, char **custom_hea - goto out; - } - -- headers = str_array_dup((const char **)custom_headers, util_array_len((const char **)custom_headers)); -+ headers = util_str_array_dup((const char **)custom_headers, util_array_len((const char **)custom_headers)); - if (ret != 0) { - ERROR("duplicate custom headers failed"); - ret = -1; -@@ -717,6 +717,7 @@ static void try_log_resp_body(char *path, char *file) - if (size < LXC_LOG_BUFFER_SIZE) { // Max length not exactly, just avoid too long. - ERROR("Get %s response message body: %s", path, body); - } -+ free(body); - return; - } - -@@ -797,7 +798,7 @@ out: - - static bool is_variant_same(char *variant1, char *variant2) - { -- // Compatiable with manifests which didn't have variant -+ // Compatible with manifests which didn't have variant - if (variant1 == NULL || variant2 == NULL) { - return true; - } -@@ -819,7 +820,7 @@ static int select_oci_manifest(oci_image_index *index, char **content_type, char - return -1; - } - -- ret = normalized_host_os_arch(&host_os, &host_arch, &host_variant); -+ ret = util_normalized_host_os_arch(&host_os, &host_arch, &host_variant); - if (ret != 0) { - ret = -1; - goto out; -@@ -876,7 +877,7 @@ static int select_docker_manifest(registry_manifest_list *manifests, char **cont - return -1; - } - -- ret = normalized_host_os_arch(&host_os, &host_arch, &host_variant); -+ ret = util_normalized_host_os_arch(&host_os, &host_arch, &host_variant); - if (ret != 0) { - ret = -1; - goto out; -@@ -1201,7 +1202,7 @@ int login_to_registry(pull_descriptor *desc) - goto out; - } - -- ret = registry_request(desc, path, NULL, NULL, &resp_buffer, HEAD_ONLY, &errcode); -+ ret = registry_request(desc, path, NULL, NULL, &resp_buffer, HEAD_BODY, &errcode); - if (ret != 0) { - ERROR("registry: Get %s failed, resp: %s", path, resp_buffer); - isulad_try_set_error_message("login to registry for %s failed", desc->host); -diff --git a/src/daemon/modules/image/oci/registry_type.c b/src/daemon/modules/image/oci/registry_type.c -index cf7360b..c2b6bba 100644 ---- a/src/daemon/modules/image/oci/registry_type.c -+++ b/src/daemon/modules/image/oci/registry_type.c -@@ -78,9 +78,9 @@ void free_pull_desc(pull_descriptor *desc) - free(desc->tag); - desc->tag = NULL; - -- free_sensitive_string(desc->username); -+ util_free_sensitive_string(desc->username); - desc->username = NULL; -- free_sensitive_string(desc->password); -+ util_free_sensitive_string(desc->password); - desc->password = NULL; - free(desc->auths_dir); - desc->auths_dir = NULL; -@@ -140,8 +140,8 @@ void free_pull_desc(pull_descriptor *desc) - desc->layers = NULL; - desc->layers_len = 0; - -- free(desc->layer_of_hold_flag); -- desc->layer_of_hold_flag = NULL; -+ free(desc->layer_of_hold_refs); -+ desc->layer_of_hold_refs = NULL; - - free(desc); - -diff --git a/src/daemon/modules/image/oci/registry_type.h b/src/daemon/modules/image/oci/registry_type.h -index 349ddfc..9592587 100644 ---- a/src/daemon/modules/image/oci/registry_type.h -+++ b/src/daemon/modules/image/oci/registry_type.h -@@ -105,7 +105,7 @@ typedef struct { - // This is temporary field. Once http request is performed, it is cleared - char **headers; - -- char *layer_of_hold_flag; -+ char *layer_of_hold_refs; - - // Image blobs downloaded - manifest_blob manifest; -diff --git a/src/daemon/modules/image/oci/storage/image_store/image_store.c b/src/daemon/modules/image/oci/storage/image_store/image_store.c -index 1d4add9..8b9eea0 100644 ---- a/src/daemon/modules/image/oci/storage/image_store/image_store.c -+++ b/src/daemon/modules/image/oci/storage/image_store/image_store.c -@@ -765,7 +765,7 @@ static int get_layers_from_manifest(const registry_manifest_schema1 *manifest, l - layers[index].empty_layer = v1config->throwaway; - free_image_manifest_v1_compatibility(v1config); - v1config = NULL; -- // Cann't download an empty layer, skip related infomation. -+ // Cann't download an empty layer, skip related information. - if (layers[index].empty_layer) { - continue; - } -@@ -777,7 +777,7 @@ static int get_layers_from_manifest(const registry_manifest_schema1 *manifest, l - for (j = 0; j < list->layers_len; j++) { - if ((list->layers[j]->parent == NULL && index == 0) || - (parent_chain_id != NULL && list->layers[j]->parent != NULL && -- !strcmp(list->layers[j]->parent, without_sha256_prefix(parent_chain_id)))) { -+ !strcmp(list->layers[j]->parent, util_without_sha256_prefix(parent_chain_id)))) { - layers[index].diff_id = util_strdup_s(list->layers[j]->uncompressed_digest); - layers[i].chain_id = util_string_append(list->layers[j]->id, SHA256_PREFIX); - parent_chain_id = layers[i].chain_id; -@@ -830,11 +830,11 @@ static int update_image_info(types_timestamp_t *created, const char *config_dige - free(img->id); - img->id = util_strdup_s(config_digest); - -- (void)get_now_time_buffer(timebuffer, sizeof(timebuffer)); -+ (void)util_get_now_time_buffer(timebuffer, sizeof(timebuffer)); - img->loaded = util_strdup_s(timebuffer); - - if (created != NULL && (created->has_seconds || created->has_nanos) && -- !get_time_buffer(created, timebuffer, sizeof(timebuffer))) { -+ !util_get_time_buffer(created, timebuffer, sizeof(timebuffer))) { - ERROR("Failed to get time buffer"); - return -1; - } -@@ -988,7 +988,7 @@ static int convert_to_v2_image_and_load(const char *path) - goto out; - } - -- created = created_to_timestamp(config->created); -+ created = util_to_timestamp_from_str(config->created); - if (update_image_info(&created, config_digest, img) != 0) { - ERROR("Failed to update image info"); - ret = -1; -@@ -1320,10 +1320,10 @@ static storage_image *new_storage_image(const char *id, const char *searchable_d - im->layer = util_strdup_s(layer); - im->metadata = util_strdup_s(metadata); - -- (void)get_now_time_buffer(timebuffer, sizeof(timebuffer)); -+ (void)util_get_now_time_buffer(timebuffer, sizeof(timebuffer)); - im->loaded = util_strdup_s(timebuffer); - if (time != NULL && (time->has_seconds || time->has_nanos) && -- !get_time_buffer(time, timebuffer, sizeof(timebuffer))) { -+ !util_get_time_buffer(time, timebuffer, sizeof(timebuffer))) { - ERROR("Failed to get time buffer"); - ret = -1; - goto out; -@@ -1338,91 +1338,6 @@ out: - return im; - } - --char *image_store_create(const char *id, const char **names, size_t names_len, const char *layer, const char *metadata, -- const types_timestamp_t *time, const char *searchable_digest) --{ -- int ret = 0; -- char *dst_id = NULL; -- char **unique_names = NULL; -- size_t unique_names_len = 0; -- image_t *img = NULL; -- storage_image *im = NULL; -- -- if (g_image_store == NULL) { -- ERROR("Image store is not ready"); -- return NULL; -- } -- -- if (!image_store_lock(EXCLUSIVE)) { -- ERROR("Failed to lock image store with exclusive lock, not allowed to create new images"); -- return NULL; -- } -- -- if (id == NULL) { -- dst_id = generate_random_image_id(); -- } else { -- dst_id = util_strdup_s(id); -- } -- -- if (dst_id == NULL) { -- ERROR("Out of memory or generate random image id failed"); -- ret = -1; -- goto out; -- } -- -- if (map_search(g_image_store->byid, (void *)dst_id) != NULL) { -- ERROR("ID is already in use: %s", dst_id); -- ret = -1; -- goto out; -- } -- -- if (util_string_array_unique(names, names_len, &unique_names, &unique_names_len) != 0) { -- ERROR("Failed to unique names"); -- ret = -1; -- goto out; -- } -- -- im = new_storage_image(dst_id, searchable_digest, &unique_names, &unique_names_len, time, layer, metadata); -- if (im == NULL) { -- ERROR("Failed to generate new storage image"); -- ret = -1; -- goto out; -- } -- -- img = new_image(im); -- if (img == NULL) { -- ERROR("Out of memory"); -- ret = -1; -- goto out; -- } -- im = NULL; -- -- if (image_store_append_image(dst_id, searchable_digest, img) != 0) { -- ERROR("Failed to append image to image store"); -- ret = -1; -- goto out; -- } -- -- if (save_image(img->simage) != 0) { -- ERROR("Failed to save image"); -- ret = -1; -- goto out; -- } -- --out: -- if (ret != 0) { -- free(dst_id); -- dst_id = NULL; -- free_storage_image(im); -- im = NULL; -- free_image_t(img); -- img = NULL; -- } -- util_free_array_by_len(unique_names, unique_names_len); -- image_store_unlock(); -- return dst_id; --} -- - static image_t *get_image_for_store_by_prefix(const char *id) - { - bool ret = true; -@@ -1494,40 +1409,6 @@ found: - return value; - } - --char *image_store_lookup(const char *id) --{ -- char *image_id = NULL; -- image_t *img = NULL; -- -- if (id == NULL) { -- ERROR("Invalid input parameter, id is NULL"); -- return NULL; -- } -- -- if (g_image_store == NULL) { -- ERROR("Image store is not ready"); -- return NULL; -- } -- -- if (!image_store_lock(SHARED)) { -- ERROR("Failed to lock image store with shared lock, not allowed to get image id assignments"); -- return NULL; -- } -- -- img = lookup(id); -- if (img == NULL) { -- ERROR("Image not known"); -- goto out; -- } -- -- image_id = util_strdup_s(img->simage->id); -- --out: -- image_ref_dec(img); -- image_store_unlock(); -- return image_id; --} -- - static char *get_value_from_json_map_string_string(json_map_string_string *map, const char *key) - { - size_t i; -@@ -1701,6 +1582,130 @@ out: - return ret; - } - -+char *image_store_create(const char *id, const char **names, size_t names_len, const char *layer, const char *metadata, -+ const types_timestamp_t *time, const char *searchable_digest) -+{ -+ int ret = 0; -+ char *dst_id = NULL; -+ char **unique_names = NULL; -+ size_t unique_names_len = 0; -+ image_t *img = NULL; -+ storage_image *im = NULL; -+ -+ if (g_image_store == NULL) { -+ ERROR("Image store is not ready"); -+ return NULL; -+ } -+ -+ if (!image_store_lock(EXCLUSIVE)) { -+ ERROR("Failed to lock image store with exclusive lock, not allowed to create new images"); -+ return NULL; -+ } -+ -+ if (id == NULL) { -+ dst_id = generate_random_image_id(); -+ } else { -+ dst_id = util_strdup_s(id); -+ } -+ -+ if (dst_id == NULL) { -+ ERROR("Out of memory or generate random image id failed"); -+ ret = -1; -+ goto out; -+ } -+ -+ if (map_search(g_image_store->byid, (void *)dst_id) != NULL) { -+ ERROR("ID is already in use: %s", dst_id); -+ ret = -1; -+ goto out; -+ } -+ -+ if (util_string_array_unique(names, names_len, &unique_names, &unique_names_len) != 0) { -+ ERROR("Failed to unique names"); -+ ret = -1; -+ goto out; -+ } -+ -+ im = new_storage_image(dst_id, searchable_digest, &unique_names, &unique_names_len, time, layer, metadata); -+ if (im == NULL) { -+ ERROR("Failed to generate new storage image"); -+ ret = -1; -+ goto out; -+ } -+ -+ img = new_image(im); -+ if (img == NULL) { -+ ERROR("Out of memory"); -+ ret = -1; -+ goto out; -+ } -+ im = NULL; -+ -+ if (image_store_append_image(dst_id, searchable_digest, img) != 0) { -+ ERROR("Failed to append image to image store"); -+ ret = -1; -+ goto out; -+ } -+ -+ if (save_image(img->simage) != 0) { -+ ERROR("Failed to save image"); -+ if (do_delete_image_info(dst_id) != 0) { -+ ERROR("Failed to delete image info"); -+ } -+ im = NULL; -+ img = NULL; -+ ret = -1; -+ goto out; -+ } -+ -+out: -+ if (ret != 0) { -+ free(dst_id); -+ dst_id = NULL; -+ free_storage_image(im); -+ im = NULL; -+ free_image_t(img); -+ img = NULL; -+ } -+ util_free_array_by_len(unique_names, unique_names_len); -+ image_store_unlock(); -+ return dst_id; -+} -+ -+char *image_store_lookup(const char *id) -+{ -+ char *image_id = NULL; -+ image_t *img = NULL; -+ -+ if (id == NULL) { -+ ERROR("Invalid input parameter, id is NULL"); -+ return NULL; -+ } -+ -+ if (g_image_store == NULL) { -+ ERROR("Image store is not ready"); -+ return NULL; -+ } -+ -+ if (!image_store_lock(SHARED)) { -+ ERROR("Failed to lock image store with shared lock, not allowed to get image id assignments"); -+ return NULL; -+ } -+ -+ img = lookup(id); -+ if (img == NULL) { -+ ERROR("Image not known"); -+ goto out; -+ } -+ -+ image_id = util_strdup_s(img->simage->id); -+ -+out: -+ image_ref_dec(img); -+ image_store_unlock(); -+ return image_id; -+} -+ - int image_store_delete(const char *id) - { - int ret = 0; -@@ -1812,7 +1817,7 @@ static int append_big_data_name(storage_image *im, const char *name) - old_size = im->big_data_names_len * sizeof(char *); - new_size = old_size + sizeof(char *); - -- if (mem_realloc((void **)&tmp_names, new_size, (void *)im->big_data_names, old_size) != 0) { -+ if (util_mem_realloc((void **)&tmp_names, new_size, (void *)im->big_data_names, old_size) != 0) { - ERROR("Failed to realloc memory"); - return -1; - } -@@ -2007,7 +2012,7 @@ static int append_name(char ***names, size_t *names_len, const char *name) - old_size = *names_len * sizeof(char *); - new_size = old_size + sizeof(char *); - -- if (mem_realloc((void **)&tmp_names, new_size, (void *)*names, old_size) != 0) { -+ if (util_mem_realloc((void **)&tmp_names, new_size, (void *)*names, old_size) != 0) { - ERROR("Failed to realloc memory"); - return -1; - } -@@ -2052,7 +2057,7 @@ int image_store_add_name(const char *id, const char *name) - goto out; - } - -- if (dup_array_of_strings((const char **)img->simage->names, img->simage->names_len, &names, &names_len) != 0) { -+ if (util_dup_array_of_strings((const char **)img->simage->names, img->simage->names_len, &names, &names_len) != 0) { - ERROR("Out of memory"); - ret = -1; - goto out; -@@ -2234,7 +2239,8 @@ int image_store_get_names(const char *id, char ***names, size_t *names_len) - goto out; - } - -- ret = dup_array_of_strings((const char **)img->simage->names, img->simage->names_len, &tmp_names, &tmp_names_len); -+ ret = util_dup_array_of_strings((const char **)img->simage->names, img->simage->names_len, &tmp_names, -+ &tmp_names_len); - if (ret != 0) { - ERROR("Out of memory"); - goto out; -@@ -2322,7 +2328,7 @@ int image_store_set_load_time(const char *id, const types_timestamp_t *time) - goto out; - } - -- if (!get_time_buffer(time, timebuffer, sizeof(timebuffer))) { -+ if (!util_get_time_buffer(time, timebuffer, sizeof(timebuffer))) { - ERROR("Failed to get time buffer"); - ret = -1; - goto out; -@@ -2414,7 +2420,7 @@ char *image_store_big_data(const char *id, const char *key) - goto out; - } - -- content = isula_utils_read_file(filename); -+ content = util_read_content_from_file(filename); - - out: - image_ref_dec(img); -@@ -2620,8 +2626,8 @@ int image_store_big_data_names(const char *id, char ***names, size_t *names_len) - goto out; - } - -- if (dup_array_of_strings((const char **)img->simage->big_data_names, img->simage->big_data_names_len, names, -- names_len) != 0) { -+ if (util_dup_array_of_strings((const char **)img->simage->big_data_names, img->simage->big_data_names_len, names, -+ names_len) != 0) { - ERROR("Failed to dup image's names"); - ret = -1; - goto out; -@@ -3014,43 +3020,6 @@ out: - return ret; - } - --static void parse_user_group(const char *username, char **user, char **group, char **tmp_dup) --{ -- char *tmp = NULL; -- char *pdot = NULL; -- -- if (user == NULL || group == NULL || tmp_dup == NULL) { -- return; -- } -- -- if (username != NULL) { -- tmp = util_strdup_s(username); -- -- // for free tmp in caller -- *tmp_dup = tmp; -- -- pdot = strstr(tmp, ":"); -- if (pdot != NULL) { -- *pdot = '\0'; -- if (pdot != tmp) { -- // User found -- *user = tmp; -- } -- if (*(pdot + 1) != '\0') { -- // group found -- *group = pdot + 1; -- } -- } else { -- // No : found -- if (*tmp != '\0') { -- *user = tmp; -- } -- } -- } -- -- return; --} -- - static int pack_health_check_from_image(const docker_image_config_v2 *config_v2, imagetool_image *info) - { - int ret = 0; -@@ -3106,7 +3075,7 @@ static int pack_user_info_from_image(const docker_image_config_v2 *config_v2, im - } - - // parse user and group by username -- parse_user_group(config_v2->config->user, &user, &group, &tmp); -+ util_parse_user_group(config_v2->config->user, &user, &group, &tmp); - - if (user == NULL) { - ERROR("Failed to parse user"); -@@ -3114,6 +3083,14 @@ static int pack_user_info_from_image(const docker_image_config_v2 *config_v2, im - goto out; - } - if (util_safe_llong(user, &converted) == 0) { -+ if (info->uid == NULL) { -+ info->uid = (imagetool_image_uid *)util_common_calloc_s(sizeof(imagetool_image_uid)); -+ if (info->uid == NULL) { -+ ERROR("Out of memory"); -+ ret = -1; -+ goto out; -+ } -+ } - info->uid->value = (int64_t)converted; - } else { - info->username = util_strdup_s(user); -@@ -3366,7 +3343,7 @@ int image_store_get_fs_info(imagetool_fs_info *fs_info) - goto out; - } - -- fs_usage_tmp->timestamp = get_now_time_nanos(); -+ fs_usage_tmp->timestamp = util_get_now_time_nanos(); - - fs_usage_tmp->fs_id = util_common_calloc_s(sizeof(imagetool_fs_info_image_filesystems_fs_id)); - if (fs_usage_tmp->fs_id == NULL) { -diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.c -index 11523a3..fb2f502 100644 ---- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.c -+++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.c -@@ -2842,10 +2842,12 @@ free_out: - static char *generate_mount_options(const struct driver_mount_opts *moptions, const char *dev_options) - { - char *res_str = NULL; -- char *tmp = NULL; - - append_mount_options(&res_str, dev_options); -+#ifdef ENABLE_SELINX - if (moptions != NULL && moptions->mount_label != NULL) { -+ char *tmp = NULL; -+ - tmp = selinux_format_mountlabel(res_str, moptions->mount_label); - if (tmp == NULL) { - goto error_out; -@@ -2854,7 +2856,6 @@ static char *generate_mount_options(const struct driver_mount_opts *moptions, co - res_str = tmp; - tmp = NULL; - } -- - goto out; - - error_out: -@@ -2862,6 +2863,7 @@ error_out: - res_str = NULL; - - out: -+#endif - return res_str; - } - -@@ -3306,4 +3308,4 @@ void free_device_set(struct device_set *devset) - UTIL_FREE_AND_SET_NULL(devset->base_device_filesystem); - - free(devset); --} -\ No newline at end of file -+} -diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.c -index 5fb8b90..f2df4f8 100644 ---- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.c -+++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.c -@@ -8,8 +8,8 @@ - * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR - * PURPOSE. - * See the Mulan PSL v2 for more details. -- * Author: tanyifeng -- * Create: 2017-11-22 -+ * Author: lifeng -+ * Create: 2020-04-22 - * Description: provide image functions - ******************************************************************************/ - -diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.h b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.h -index 58eae32..7faf70c 100644 ---- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.h -+++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.h -@@ -8,8 +8,8 @@ - * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR - * PURPOSE. - * See the Mulan PSL v2 for more details. -- * Author: tanyifeng -- * Create: 2019-04-02 -+ * Author: lifeng -+ * Create: 2020-04-22 - * Description: provide graphdriver function definition - ******************************************************************************/ - #ifndef DAEMON_MODULES_IMAGE_OCI_STORAGE_LAYER_STORE_GRAPHDRIVER_DRIVER_H -@@ -98,7 +98,8 @@ struct graphdriver { - // options for device mapper - struct device_set *devset; - -- pthread_rwlock_t rwlock; // lock to protect graphdriver between cleanup and other operations -+ // lock to protect graphdriver between cleanup and other operations -+ pthread_rwlock_t rwlock; - }; - - int graphdriver_init(const struct storage_module_init_options *opts); -diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c -index c81c4bc..95909a8 100644 ---- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c -+++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c -@@ -8,8 +8,8 @@ - * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR - * PURPOSE. - * See the Mulan PSL v2 for more details. -- * Author: tanyifeng -- * Create: 2019-04-02 -+ * Author: lifeng -+ * Create: 2020-04-02 - * Description: provide overlay2 function definition - ******************************************************************************/ - #include "driver_overlay2.h" -@@ -275,6 +275,7 @@ int overlay2_init(struct graphdriver *driver, const char *drvier_home, const cha - char *root_dir = NULL; - - if (driver == NULL || drvier_home == NULL) { -+ ERROR("Invalid input arguments"); - return -1; - } - -@@ -427,7 +428,7 @@ static int do_diff_symlink(const char *id, char *link_id, const char *driver_hom - goto out; - } - -- if (cleanpath(link_path, clean_path, sizeof(clean_path)) == NULL) { -+ if (util_clean_path(link_path, clean_path, sizeof(clean_path)) == NULL) { - ERROR("failed to get clean path %s", link_path); - ret = -1; - goto out; -@@ -682,7 +683,7 @@ out: - return ret; - } - --static int mk_sub_directorys(const char *id, const char *parent, const char *layer_dir, const char *driver_home) -+static int mk_sub_directories(const char *id, const char *parent, const char *layer_dir, const char *driver_home) - { - int ret = 0; - char *lowers = NULL; -@@ -802,11 +803,11 @@ static int do_create(const char *id, const char *parent, const struct graphdrive - if (set_layer_quota(layer_dir, create_opts->storage_opt, driver) != 0) { - ERROR("Unable to set layer quota %s", layer_dir); - ret = -1; -- goto out; -+ goto err_out; - } - } - -- if (mk_sub_directorys(id, parent, layer_dir, driver->home) != 0) { -+ if (mk_sub_directories(id, parent, layer_dir, driver->home) != 0) { - ret = -1; - goto err_out; - } -@@ -874,6 +875,7 @@ int overlay2_create_rw(const char *id, const char *parent, const struct graphdri - int ret = 0; - - if (id == NULL || driver == NULL || create_opts == NULL) { -+ ERROR("Invalid input arguments"); - return -1; - } - -@@ -899,22 +901,17 @@ out: - int overlay2_create_ro(const char *id, const char *parent, const struct graphdriver *driver, - const struct driver_create_opts *create_opts) - { -- int ret = 0; -- - if (id == NULL || driver == NULL || create_opts == NULL) { -+ ERROR("Invalid input arguments"); - return -1; - } - - if (create_opts->storage_opt != NULL && create_opts->storage_opt->len != 0) { - ERROR("--storage-opt size is only supported for ReadWrite Layers"); -- ret = -1; -- goto out; -+ return -1; - } - -- ret = do_create(id, parent, driver, create_opts); -- --out: -- return ret; -+ return do_create(id, parent, driver, create_opts); - } - - static char *read_layer_link_file(const char *layer_dir) -@@ -961,6 +958,7 @@ int overlay2_rm_layer(const char *id, const struct graphdriver *driver) - char clean_path[PATH_MAX] = { 0 }; - - if (id == NULL || driver == NULL) { -+ ERROR("Invalid input arguments"); - return -1; - } - -@@ -979,7 +977,7 @@ int overlay2_rm_layer(const char *id, const struct graphdriver *driver) - ret = -1; - goto out; - } -- if (cleanpath(link_path, clean_path, sizeof(clean_path)) == NULL) { -+ if (util_clean_path(link_path, clean_path, sizeof(clean_path)) == NULL) { - ERROR("failed to get clean path %s", link_path); - ret = -1; - goto out; -@@ -1262,6 +1260,7 @@ static char *get_abs_mount_opt_data(const char *layer_dir, const char *abs_lower - tmp = NULL; - } - -+#ifdef ENABLE_SELINUX - if (mount_opts != NULL && mount_opts->mount_label != NULL) { - tmp = selinux_format_mountlabel(mount_data, mount_opts->mount_label); - if (tmp == NULL) { -@@ -1271,6 +1270,7 @@ static char *get_abs_mount_opt_data(const char *layer_dir, const char *abs_lower - mount_data = tmp; - tmp = NULL; - } -+#endif - - goto out; - -@@ -1344,6 +1344,7 @@ static char *get_rel_mount_opt_data(const char *id, const char *rel_lower_dir, c - tmp = NULL; - } - -+#ifdef ENABLE_SELINUX - if (mount_opts != NULL && mount_opts->mount_label != NULL) { - tmp = selinux_format_mountlabel(mount_data, mount_opts->mount_label); - if (tmp == NULL) { -@@ -1353,6 +1354,7 @@ static char *get_rel_mount_opt_data(const char *id, const char *rel_lower_dir, c - mount_data = tmp; - tmp = NULL; - } -+#endif - - goto out; - -@@ -1494,6 +1496,7 @@ char *overlay2_mount_layer(const char *id, const struct graphdriver *driver, con - char *layer_dir = NULL; - - if (id == NULL || driver == NULL) { -+ ERROR("Invalid input arguments"); - return NULL; - } - -@@ -1526,6 +1529,7 @@ int overlay2_umount_layer(const char *id, const struct graphdriver *driver) - char *layer_dir = NULL; - - if (id == NULL || driver == NULL) { -+ ERROR("Invalid input arguments"); - return -1; - } - -@@ -1815,6 +1819,7 @@ int overlay2_get_driver_status(const struct graphdriver *driver, struct graphdri - char tmp[MAX_INFO_LENGTH] = { 0 }; - - if (driver == NULL || status == NULL) { -+ ERROR("Invalid input arguments"); - return -1; - } - -@@ -1856,6 +1861,7 @@ int overlay2_clean_up(struct graphdriver *driver) - int ret = 0; - - if (driver == NULL) { -+ ERROR("Invalid input arguments"); - ret = -1; - goto out; - } -@@ -1901,6 +1907,7 @@ int overlay2_repair_lowers(const char *id, const char *parent, const struct grap - size_t lowers_size = 0; - - if (id == NULL || driver == NULL) { -+ ERROR("Invalid input arguments"); - return -1; - } - -@@ -1966,7 +1973,7 @@ static int do_cal_layer_fs_info(const char *layer_diff, imagetool_fs_info *fs_in - goto out; - } - -- fs_usage_tmp->timestamp = get_now_time_nanos(); -+ fs_usage_tmp->timestamp = util_get_now_time_nanos(); - - fs_usage_tmp->fs_id = util_common_calloc_s(sizeof(imagetool_fs_info_image_filesystems_fs_id)); - if (fs_usage_tmp->fs_id == NULL) { -@@ -2016,6 +2023,7 @@ int overlay2_get_layer_fs_info(const char *id, const struct graphdriver *driver, - char *layer_diff = NULL; - - if (id == NULL || fs_info == NULL) { -+ ERROR("Invalid input arguments"); - return -1; - } - -diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.h b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.h -index 8e2c30b..5f3228f 100644 ---- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.h -+++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.h -@@ -8,7 +8,7 @@ - * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR - * PURPOSE. - * See the Mulan PSL v2 for more details. -- * Author: tanyifeng -+ * Author: lifeng - * Create: 2019-04-02 - * Description: provide overlay2 function definition - ******************************************************************************/ -diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/quota/project_quota.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/quota/project_quota.c -index 8efe709..2bcfb0e 100644 ---- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/quota/project_quota.c -+++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/quota/project_quota.c -@@ -321,7 +321,7 @@ void free_pquota_control(struct pquota_control *ctrl) - ctrl->backing_fs_device = NULL; - - if (pthread_rwlock_destroy(&(ctrl->rwlock)) != 0) { -- SYSERROR("destory pquota_control rwlock failed"); -+ SYSERROR("destroy pquota_control rwlock failed"); - } - free(ctrl); - } -@@ -334,7 +334,7 @@ static int get_quota_stat(const char *backing_fs_blockdev) - - ret = quotactl(QCMD(Q_XGETQSTAT, FS_PROJ_QUOTA), backing_fs_blockdev, 0, (caddr_t)&fs_quota_stat_info); - if (ret != 0) { -- SYSERROR("Failed to get quota stat on %s", backing_fs_blockdev); -+ SYSWARN("Failed to get quota stat on %s", backing_fs_blockdev); - return ret; - } - -diff --git a/src/daemon/modules/image/oci/storage/layer_store/layer.h b/src/daemon/modules/image/oci/storage/layer_store/layer.h -index d86e02e..f2dad64 100644 ---- a/src/daemon/modules/image/oci/storage/layer_store/layer.h -+++ b/src/daemon/modules/image/oci/storage/layer_store/layer.h -@@ -38,7 +38,7 @@ typedef struct _layer_t_ { - char *mount_point_json_path; - storage_mount_point *smount_point; - -- bool hold; -+ int hold_refs_num; - - uint64_t refcnt; - } layer_t; -diff --git a/src/daemon/modules/image/oci/storage/layer_store/layer_store.c b/src/daemon/modules/image/oci/storage/layer_store/layer_store.c -index 934ec35..704dbd6 100644 ---- a/src/daemon/modules/image/oci/storage/layer_store/layer_store.c -+++ b/src/daemon/modules/image/oci/storage/layer_store/layer_store.c -@@ -556,7 +556,7 @@ static int update_layer_datas(const char *id, const struct layer_opts *opts, lay - if (opts->opts != NULL) { - slayer->mountlabel = util_strdup_s(opts->opts->mount_label); - } -- if (!get_now_local_utc_time_buffer(timebuffer, TIME_STR_SIZE)) { -+ if (!util_get_now_local_utc_time_buffer(timebuffer, TIME_STR_SIZE)) { - ERROR("Get create time failed"); - ret = -1; - goto free_out; -@@ -738,7 +738,7 @@ out: - static int insert_memory_stores(const char *id, const struct layer_opts *opts, layer_t *l) - { - int ret = 0; -- size_t i = 0; -+ int i = 0; - - if (!append_layer_into_list(l)) { - ret = -1; -@@ -863,7 +863,9 @@ static char *caculate_playload(struct archive *ar) - int nret = 0; - const isula_crc_table_t *ctab = NULL; - uint64_t crc = 0; -+ // max crc bits is 8 - unsigned char sum_data[8] = { 0 }; -+ // add \0 at crc bits last, so need a 9 bits array - unsigned char tmp_data[9] = { 0 }; - bool empty = true; - -@@ -893,6 +895,7 @@ static char *caculate_playload(struct archive *ar) - } - - isula_crc_sum(crc, sum_data); -+ // max crc bits is 8 - for (r = 0; r < 8; r++) { - tmp_data[r] = sum_data[r]; - } -@@ -1004,12 +1007,6 @@ out: - - static int make_tar_split_file(const char *lid, const struct io_read_wrapper *diff, int64_t *size) - { -- /* -- * step 1: read header; -- * step 2: build entry json; -- * step 3: write into tar split; -- * step 4: gzip tar split, and save file. -- * */ - int *pfd = (int *)diff->context; - char *save_fname = NULL; - char *save_fname_gz = NULL; -@@ -1024,6 +1021,7 @@ static int make_tar_split_file(const char *lid, const struct io_read_wrapper *di - if (save_fname_gz == NULL) { - goto out; - } -+ // step 1: read header; - tfd = util_open(save_fname, O_WRONLY | O_CREAT, SECURE_CONFIG_FILE_MODE); - if (tfd == -1) { - SYSERROR("touch file failed"); -@@ -1032,6 +1030,8 @@ static int make_tar_split_file(const char *lid, const struct io_read_wrapper *di - close(tfd); - tfd = -1; - -+ // step 2: build entry json; -+ // step 3: write into tar split; - ret = foreach_archive_entry(archive_entry_parse, *pfd, save_fname, size); - if (ret != 0) { - goto out; -@@ -1042,7 +1042,7 @@ static int make_tar_split_file(const char *lid, const struct io_read_wrapper *di - goto out; - } - -- // gzip tar split file -+ // step 4: gzip tar split, and save file. - ret = util_gzip_z(save_fname, save_fname_gz, SECURE_CONFIG_FILE_MODE); - - // always remove tmp tar split file, even though gzip failed. -@@ -1153,28 +1153,32 @@ static int layer_store_remove_layer(const char *id) - return ret; - } - --int layer_set_hold_flag(const char *layer_id, bool hold) -+int layer_set_hold_refs(const char *layer_id, bool increase) - { - layer_t *l = NULL; - int ret = 0; - - if (layer_id == NULL) { -- ERROR("Invalid NULL layer id when reset hold flag"); -+ ERROR("Invalid NULL layer id when set hold refs"); - return -1; - } - - if (!layer_store_lock(true)) { -- ERROR("Failed to lock layer store, reset hold flag for layer %s failed", layer_id); -+ ERROR("Failed to lock layer store, reset hold refs for layer %s failed", layer_id); - return -1; - } - - l = map_search(g_metadata.by_id, (void *)layer_id); - if (l == NULL) { -- ERROR("layer %s not found when reset hold flag", layer_id); -+ ERROR("layer %s not found when set hold refs", layer_id); - ret = -1; - goto out; - } -- l->hold = hold; -+ if (increase) { -+ l->hold_refs_num++; -+ } else { -+ l->hold_refs_num--; -+ } - - out: - layer_store_unlock(); -@@ -1182,28 +1186,38 @@ out: - return ret; - } - --int layer_get_hold_flag(const char *layer_id, bool *hold) -+int layer_inc_hold_refs(const char *layer_id) -+{ -+ return layer_set_hold_refs(layer_id, true); -+} -+ -+int layer_dec_hold_refs(const char *layer_id) -+{ -+ return layer_set_hold_refs(layer_id, false); -+} -+ -+int layer_get_hold_refs(const char *layer_id, int *refs_num) - { - int ret = 0; - layer_t *l = NULL; - -- if (layer_id == NULL || hold == NULL) { -- ERROR("Invalid NULL param when get hold flag"); -+ if (layer_id == NULL || refs_num == NULL) { -+ ERROR("Invalid NULL param when get hold refs"); - return -1; - } - - if (!layer_store_lock(true)) { -- ERROR("Failed to lock layer store, get hold flag of layer %s failed", layer_id); -+ ERROR("Failed to lock layer store, get hold refs of layer %s failed", layer_id); - return -1; - } - - l = map_search(g_metadata.by_id, (void *)layer_id); - if (l == NULL) { -- ERROR("layer %s not found when reset hold flag", layer_id); -+ ERROR("layer %s not found when get hold refs", layer_id); - ret = -1; - goto out; - } -- *hold = l->hold; -+ *refs_num = l->hold_refs_num; - - out: - layer_store_unlock(); -@@ -1214,7 +1228,7 @@ out: - int layer_store_create(const char *id, const struct layer_opts *opts, const struct io_read_wrapper *diff, char **new_id) - { - int ret = 0; -- char *lid = util_strdup_s(id); -+ char *lid = NULL; - layer_t *l = NULL; - - if (opts == NULL) { -@@ -1226,10 +1240,12 @@ int layer_store_create(const char *id, const struct layer_opts *opts, const stru - return -1; - } - -- // If the layer already exist, hold the layer is enough -+ lid = util_strdup_s(id); -+ -+ // If the layer already exist, increase refs number to hold the layer is enough - l = lookup(lid); - if (l != NULL) { -- l->hold = true; // mark it as hold, so others can't delete this layer -+ l->hold_refs_num++; // increase refs number, so others can't delete this layer - goto free_out; - } - -@@ -1246,12 +1262,12 @@ int layer_store_create(const char *id, const struct layer_opts *opts, const stru - l = lookup(lid); - if (l == NULL) { - ret = -1; -- goto driver_remove; -+ goto clear_memory; - } - l->slayer->incompelte = true; - if (save_layer(l) != 0) { - ret = -1; -- goto driver_remove; -+ goto clear_memory; - } - - ret = apply_diff(l, diff); -@@ -1272,7 +1288,7 @@ int layer_store_create(const char *id, const struct layer_opts *opts, const stru - *new_id = lid; - lid = NULL; - } -- l->hold = true; // mark it as hold, so others can't delete this layer -+ l->hold_refs_num++; // increase refs number, so others can't delete this layer - goto free_out; - } - ERROR("Save layer failed"); -@@ -1600,8 +1616,8 @@ int layer_store_umount(const char *id, bool force) - } - l = lookup_with_lock(id); - if (l == NULL) { -- ERROR("layer not known"); -- return -1; -+ ERROR("layer not known,skip umount"); -+ return 0; - } - layer_lock(l); - ret = umount_helper(l, force); -@@ -1724,7 +1740,7 @@ out: - return ret; - } - --static bool load_layer_json_cb(const char *path_name, const struct dirent *sub_dir) -+static bool load_layer_json_cb(const char *path_name, const struct dirent *sub_dir, void *context) - { - #define LAYER_NAME_LEN 64 - bool flag = false; -@@ -1814,7 +1830,7 @@ static int load_layers_from_json_files() - return -1; - } - -- ret = util_scan_subdirs(g_root_dir, load_layer_json_cb); -+ ret = util_scan_subdirs(g_root_dir, load_layer_json_cb, NULL); - if (ret != 0) { - goto unlock_out; - } -@@ -1968,7 +1984,7 @@ static uint64_t payload_to_crc(char *payload) - return crc; - } - --static int file_crc(char *file, uint64_t *crc, uint64_t policy) -+static int file_crc64(char *file, uint64_t *crc, uint64_t policy) - { - #define BLKSIZE 32768 - int ret = 0; -@@ -2023,7 +2039,7 @@ out: - return ret; - } - --static int valid_crc(storage_entry *entry, char *rootfs) -+static int valid_crc64(storage_entry *entry, char *rootfs) - { - int ret = 0; - int nret = 0; -@@ -2058,7 +2074,7 @@ static int valid_crc(storage_entry *entry, char *rootfs) - goto out; - } - -- ret = file_crc(file, &crc, ISO_POLY); -+ ret = file_crc64(file, &crc, ISO_POLY); - if (ret != 0) { - ERROR("calc crc of file %s failed", file); - ret = -1; -@@ -2204,7 +2220,7 @@ static int do_integration_check(layer_t *l, char *rootfs) - } - while (entry != NULL) { - if (entry->type == STORAGE_ENTRY_TYPE_CRC) { -- ret = valid_crc(entry, rootfs); -+ ret = valid_crc64(entry, rootfs); - if (ret != 0) { - ERROR("integration check failed, layer %s, file %s", l->slayer->id, entry->name); - goto out; -diff --git a/src/daemon/modules/image/oci/storage/layer_store/layer_store.h b/src/daemon/modules/image/oci/storage/layer_store/layer_store.h -index f025f0f..94d4bf0 100644 ---- a/src/daemon/modules/image/oci/storage/layer_store/layer_store.h -+++ b/src/daemon/modules/image/oci/storage/layer_store/layer_store.h -@@ -57,8 +57,9 @@ void layer_store_cleanup(); - void remove_layer_list_tail(); - int layer_store_create(const char *id, const struct layer_opts *opts, const struct io_read_wrapper *content, - char **new_id); --int layer_set_hold_flag(const char *layer_id, bool hold); --int layer_get_hold_flag(const char *layer_id, bool *hold); -+int layer_inc_hold_refs(const char *layer_id); -+int layer_dec_hold_refs(const char *layer_id); -+int layer_get_hold_refs(const char *layer_id, int *ref_num); - int layer_store_delete(const char *id); - bool layer_store_exists(const char *id); - int layer_store_list(struct layer_list *resp); -diff --git a/src/daemon/modules/image/oci/storage/rootfs_store/rootfs_store.c b/src/daemon/modules/image/oci/storage/rootfs_store/rootfs_store.c -index 22a194c..ed4b45c 100644 ---- a/src/daemon/modules/image/oci/storage/rootfs_store/rootfs_store.c -+++ b/src/daemon/modules/image/oci/storage/rootfs_store/rootfs_store.c -@@ -211,15 +211,15 @@ static int get_containers_from_json() - - ret = util_list_all_subdir(g_rootfs_store->dir, &container_dirs); - if (ret != 0) { -- ERROR("Failed to get container directorys"); -+ ERROR("Failed to get container directories"); - goto out; - } - container_dirs_num = util_array_len((const char **)container_dirs); - - for (i = 0; i < container_dirs_num; i++) { - if (util_reg_match(id_patten, container_dirs[i]) != 0) { -- DEBUG("Container's json is placed inside container's data directory, so skip any other file or directory: %s", -- container_dirs[i]); -+ WARN("Container's json is placed inside container's data directory, so skip any other file or directory: %s", -+ container_dirs[i]); - continue; - } - -@@ -227,14 +227,15 @@ static int get_containers_from_json() - nret = snprintf(container_path, sizeof(container_path), "%s/%s", g_rootfs_store->dir, container_dirs[i]); - if (nret < 0 || (size_t)nret >= sizeof(container_path)) { - ERROR("Failed to get container path"); -- ret = -1; -- goto out; -+ continue; - } - - if (append_container_by_directory(container_path) != 0) { -- ERROR("Found container path but load json failed: %s", container_dirs[i]); -- ret = -1; -- goto out; -+ ERROR("Found container path but load json failed: %s, deleting...", container_path); -+ if (util_recursive_rmdir(container_path, 0) != 0) { -+ ERROR("Failed to delete rootfs directory : %s", container_path); -+ } -+ continue; - } - } - -@@ -367,7 +368,7 @@ static int load_container_to_store_field(cntrootfs_t *cntr) - should_save = true; - } - if (!map_replace(g_rootfs_store->byname, (void *)cntr->srootfs->names[i], (void *)cntr)) { -- ERROR("Failed to insert containes to name index"); -+ ERROR("Failed to insert containers to name index"); - ret = -1; - goto out; - } -@@ -662,7 +663,7 @@ static storage_rootfs *new_storage_rootfs(const char *id, const char *image, cha - c->layer = util_strdup_s(layer); - c->metadata = util_strdup_s(metadata); - -- if (!get_now_time_buffer(timebuffer, sizeof(timebuffer))) { -+ if (!util_get_now_time_buffer(timebuffer, sizeof(timebuffer))) { - ERROR("Failed to get now time string"); - ret = -1; - goto out; -@@ -727,90 +728,6 @@ out: - return ret; - } - --char *rootfs_store_create(const char *id, const char **names, size_t names_len, const char *image, const char *layer, -- const char *metadata, struct storage_rootfs_options *rootfs_opts) --{ -- int ret = 0; -- char *dst_id = NULL; -- char **unique_names = NULL; -- size_t unique_names_len = 0; -- cntrootfs_t *cntr = NULL; -- storage_rootfs *c = NULL; -- -- if (g_rootfs_store == NULL) { -- ERROR("Container store is not ready"); -- return NULL; -- } -- -- if (!rootfs_store_lock(EXCLUSIVE)) { -- ERROR("Failed to lock container store, not allowed to create new containers"); -- return NULL; -- } -- -- if (id == NULL) { -- dst_id = generate_random_container_id(); -- } else { -- dst_id = util_strdup_s(id); -- } -- -- if (dst_id == NULL) { -- ERROR("Out of memory or generate random container id failed"); -- ret = -1; -- goto out; -- } -- -- if (map_search(g_rootfs_store->byid, (void *)dst_id) != NULL) { -- ERROR("ID is already in use: %s", dst_id); -- ret = -1; -- goto out; -- } -- -- if (util_string_array_unique(names, names_len, &unique_names, &unique_names_len) != 0) { -- ERROR("Failed to unique names"); -- ret = -1; -- goto out; -- } -- -- c = new_storage_rootfs(dst_id, image, unique_names, unique_names_len, layer, metadata, rootfs_opts); -- if (c == NULL) { -- ERROR("Failed to generate new storage container"); -- ret = -1; -- goto out; -- } -- -- cntr = new_rootfs(c); -- if (cntr == NULL) { -- ERROR("Out of memory"); -- ret = -1; -- goto out; -- } -- c = NULL; -- -- if (rootfs_store_append_container_rootfs(dst_id, layer, (const char **)unique_names, unique_names_len, cntr) != 0) { -- ERROR("Failed to append container to container store"); -- ret = -1; -- goto out; -- } -- -- if (save_rootfs(cntr) != 0) { -- ERROR("Failed to save container"); -- ret = -1; -- goto out; -- } -- --out: -- if (ret != 0) { -- free(dst_id); -- dst_id = NULL; -- free_storage_rootfs(c); -- c = NULL; -- free_rootfs_t(cntr); -- cntr = NULL; -- } -- rootfs_store_unlock(); -- return dst_id; --} -- - static cntrootfs_t *get_rootfs_for_store_by_prefix(const char *id) - { - bool ret = true; -@@ -882,39 +799,6 @@ found: - return value; - } - --char *rootfs_store_lookup(const char *id) --{ -- char *container_id = NULL; -- cntrootfs_t *cntr = NULL; -- -- if (id == NULL) { -- ERROR("Invalid input parameter, id is NULL"); -- return NULL; -- } -- -- if (g_rootfs_store == NULL) { -- ERROR("Container store is not ready"); -- return NULL; -- } -- -- if (!rootfs_store_lock(SHARED)) { -- ERROR("Failed to lock rootfs store, not allowed to lookup rootfs id assginments"); -- return NULL; -- } -- -- cntr = lookup(id); -- if (cntr == NULL) { -- ERROR("Container not known"); -- return NULL; -- } -- -- container_id = util_strdup_s(cntr->srootfs->id); -- rootfs_ref_dec(cntr); -- rootfs_store_unlock(); -- -- return container_id; --} -- - static int remove_rootfs_from_memory(const char *id) - { - struct linked_list *item = NULL; -@@ -984,13 +868,13 @@ static int remove_rootfs_dir(const char *id) - return 0; - } - --int rootfs_store_delete(const char *id) -+static int delete_rootfs_from_store_without_lock(const char *id) - { -- cntrootfs_t *cntr = NULL; - int ret = 0; -+ cntrootfs_t *cntr = NULL; - - if (id == NULL) { -- ERROR("Invalid input parameter, id is NULL"); -+ ERROR("Invalid input parameter: empty id"); - return -1; - } - -@@ -999,16 +883,10 @@ int rootfs_store_delete(const char *id) - return -1; - } - -- if (!rootfs_store_lock(EXCLUSIVE)) { -- ERROR("Failed to lock rootfs store"); -- return -1; -- } -- - cntr = lookup(id); - if (cntr == NULL) { -- WARN("rootfs %s not exists already, return success", id); -- ret = 0; -- goto out; -+ ERROR("Rootfs %s not known", id); -+ return -1; - } - - if (remove_rootfs_from_memory(cntr->srootfs->id) != 0) { -@@ -1025,17 +903,138 @@ int rootfs_store_delete(const char *id) - - out: - rootfs_ref_dec(cntr); -- rootfs_store_unlock(); - return ret; - } - --static int delete_rootfs_from_store_without_lock(const char *id) -+char *rootfs_store_create(const char *id, const char **names, size_t names_len, const char *image, const char *layer, -+ const char *metadata, struct storage_rootfs_options *rootfs_opts) - { - int ret = 0; -+ char *dst_id = NULL; -+ char **unique_names = NULL; -+ size_t unique_names_len = 0; - cntrootfs_t *cntr = NULL; -+ storage_rootfs *c = NULL; -+ -+ if (g_rootfs_store == NULL) { -+ ERROR("Container store is not ready"); -+ return NULL; -+ } -+ -+ if (!rootfs_store_lock(EXCLUSIVE)) { -+ ERROR("Failed to lock container store, not allowed to create new containers"); -+ return NULL; -+ } - - if (id == NULL) { -- ERROR("Invalid input parameter: empty id"); -+ dst_id = generate_random_container_id(); -+ } else { -+ dst_id = util_strdup_s(id); -+ } -+ -+ if (dst_id == NULL) { -+ ERROR("Out of memory or generate random container id failed"); -+ ret = -1; -+ goto out; -+ } -+ -+ if (map_search(g_rootfs_store->byid, (void *)dst_id) != NULL) { -+ ERROR("ID is already in use: %s", dst_id); -+ ret = -1; -+ goto out; -+ } -+ -+ if (util_string_array_unique(names, names_len, &unique_names, &unique_names_len) != 0) { -+ ERROR("Failed to unique names"); -+ ret = -1; -+ goto out; -+ } -+ -+ c = new_storage_rootfs(dst_id, image, unique_names, unique_names_len, layer, metadata, rootfs_opts); -+ if (c == NULL) { -+ ERROR("Failed to generate new storage container"); -+ ret = -1; -+ goto out; -+ } -+ -+ cntr = new_rootfs(c); -+ if (cntr == NULL) { -+ ERROR("Out of memory"); -+ ret = -1; -+ goto out; -+ } -+ c = NULL; -+ -+ if (rootfs_store_append_container_rootfs(dst_id, layer, (const char **)unique_names, unique_names_len, cntr) != 0) { -+ ERROR("Failed to append container to container store"); -+ ret = -1; -+ goto out; -+ } -+ -+ if (save_rootfs(cntr) != 0) { -+ ERROR("Failed to save container"); -+ if (delete_rootfs_from_store_without_lock(dst_id) != 0) { -+ ERROR("Failed to delete rootfs from store"); -+ } -+ c = NULL; -+ cntr = NULL; -+ ret = -1; -+ goto out; -+ } -+ -+out: -+ if (ret != 0) { -+ free(dst_id); -+ dst_id = NULL; -+ free_storage_rootfs(c); -+ c = NULL; -+ free_rootfs_t(cntr); -+ cntr = NULL; -+ } -+ rootfs_store_unlock(); -+ return dst_id; -+} -+ -+char *rootfs_store_lookup(const char *id) -+{ -+ char *container_id = NULL; -+ cntrootfs_t *cntr = NULL; -+ -+ if (id == NULL) { -+ ERROR("Invalid input parameter, id is NULL"); -+ return NULL; -+ } -+ -+ if (g_rootfs_store == NULL) { -+ ERROR("Container store is not ready"); -+ return NULL; -+ } -+ -+ if (!rootfs_store_lock(SHARED)) { -+ ERROR("Failed to lock rootfs store, not allowed to lookup rootfs id assginments"); -+ return NULL; -+ } -+ -+ cntr = lookup(id); -+ if (cntr == NULL) { -+ ERROR("Container not known"); -+ return NULL; -+ } -+ -+ container_id = util_strdup_s(cntr->srootfs->id); -+ rootfs_ref_dec(cntr); -+ rootfs_store_unlock(); -+ -+ return container_id; -+} -+ -+int rootfs_store_delete(const char *id) -+{ -+ cntrootfs_t *cntr = NULL; -+ int ret = 0; -+ -+ if (id == NULL) { -+ ERROR("Invalid input parameter, id is NULL"); - return -1; - } - -@@ -1044,10 +1043,16 @@ static int delete_rootfs_from_store_without_lock(const char *id) - return -1; - } - -+ if (!rootfs_store_lock(EXCLUSIVE)) { -+ ERROR("Failed to lock rootfs store"); -+ return -1; -+ } -+ - cntr = lookup(id); - if (cntr == NULL) { -- ERROR("Rootfs %s not known", id); -- return -1; -+ WARN("rootfs %s not exists already, return success", id); -+ ret = 0; -+ goto out; - } - - if (remove_rootfs_from_memory(cntr->srootfs->id) != 0) { -@@ -1064,6 +1069,7 @@ static int delete_rootfs_from_store_without_lock(const char *id) - - out: - rootfs_ref_dec(cntr); -+ rootfs_store_unlock(); - return ret; - } - -@@ -1262,40 +1268,6 @@ out: - return dup_rootfs; - } - --char *rootfs_store_metadata(const char *id) --{ -- cntrootfs_t *img = NULL; -- char *metadata = NULL; -- -- if (id == NULL) { -- ERROR("Invalid parameter, id is NULL"); -- return NULL; -- } -- -- if (g_rootfs_store == NULL) { -- ERROR("Rootfs store is not ready"); -- return NULL; -- } -- -- if (!rootfs_store_lock(SHARED)) { -- ERROR("Failed to lock rootfs store with shared lock, not allowed to get rootfs metadata assignments"); -- return NULL; -- } -- -- img = lookup(id); -- if (img == NULL) { -- ERROR("Rootfs not known"); -- goto out; -- } -- -- metadata = util_strdup_s(img->srootfs->metadata); -- --out: -- rootfs_ref_dec(img); -- rootfs_store_unlock(); -- return metadata; --} -- - int rootfs_store_get_all_rootfs(struct rootfs_list *all_rootfs) - { - int ret = 0; -diff --git a/src/daemon/modules/image/oci/storage/rootfs_store/rootfs_store.h b/src/daemon/modules/image/oci/storage/rootfs_store/rootfs_store.h -index 6cab97a..e13f97b 100644 ---- a/src/daemon/modules/image/oci/storage/rootfs_store/rootfs_store.h -+++ b/src/daemon/modules/image/oci/storage/rootfs_store/rootfs_store.h -@@ -62,9 +62,6 @@ bool rootfs_store_exists(const char *id); - // Retrieve information about a container given an ID or name. - storage_rootfs *rootfs_store_get_rootfs(const char *id); - --// Reads metadata associated with an item with the specified ID. --char *rootfs_store_metadata(const char *id); -- - // Return a slice enumerating the known containers. - int rootfs_store_get_all_rootfs(struct rootfs_list *all_rootfs); - -diff --git a/src/daemon/modules/image/oci/storage/storage.c b/src/daemon/modules/image/oci/storage/storage.c -index 8ad96d6..6e83665 100644 ---- a/src/daemon/modules/image/oci/storage/storage.c -+++ b/src/daemon/modules/image/oci/storage/storage.c -@@ -103,15 +103,14 @@ static int fill_read_wrapper(const char *layer_data_path, struct io_read_wrapper - reader_tmp = util_common_calloc_s(sizeof(struct io_read_wrapper)); - if (reader_tmp == NULL) { - ERROR("Memory out"); -- ret = -1; -- goto out; -+ return -1; - } - - fd_ptr = util_common_calloc_s(sizeof(int)); - if (fd_ptr == NULL) { - ERROR("Memory out"); - ret = -1; -- goto out; -+ goto err_out; - } - - *fd_ptr = util_open(layer_data_path, O_RDONLY, 0); -@@ -126,12 +125,13 @@ static int fill_read_wrapper(const char *layer_data_path, struct io_read_wrapper - reader_tmp->close = layer_archive_io_close; - *reader = reader_tmp; - -- goto out; -+ fd_ptr = NULL; -+ reader_tmp = NULL; - - err_out: - free(fd_ptr); - free(reader_tmp); --out: -+ - return ret; - } - -@@ -182,16 +182,32 @@ out: - return opts; - } - --int storage_set_hold_flag(const char *layer_id, bool hold) -+int storage_inc_hold_refs(const char *layer_id) -+{ -+ int ret = 0; -+ -+ if (!storage_lock(&g_storage_rwlock, true)) { -+ ERROR("Failed to lock image store when increase hold refs number for layer %s", layer_id); -+ return -1; -+ } -+ -+ ret = layer_inc_hold_refs(layer_id); -+ -+ storage_unlock(&g_storage_rwlock); -+ -+ return ret; -+} -+ -+int storage_dec_hold_refs(const char *layer_id) - { - int ret = 0; - - if (!storage_lock(&g_storage_rwlock, true)) { -- ERROR("Failed to lock image store when reset hold flag for layer %s", layer_id); -+ ERROR("Failed to lock image store when decrease hold refs number for layer %s", layer_id); - return -1; - } - -- ret = layer_set_hold_flag(layer_id, hold); -+ ret = layer_dec_hold_refs(layer_id); - - storage_unlock(&g_storage_rwlock); - -@@ -499,7 +515,7 @@ static int do_delete_related_layers(const char *img_id, const char *img_top_laye - char *layer_id = NULL; - char *last_deleted_layer_id = NULL; - struct layer *layer_info = NULL; -- bool hold = false; -+ int refs_num = 0; - - layer_id = util_strdup_s(img_top_layer_id); - if (layer_id == NULL) { -@@ -509,13 +525,13 @@ static int do_delete_related_layers(const char *img_id, const char *img_top_laye - } - - while (layer_id != NULL) { -- ret = layer_get_hold_flag(layer_id, &hold); -+ ret = layer_get_hold_refs(layer_id, &refs_num); - if (ret != 0) { - break; - } -- // if the layer is hold, it means it's pulling/importing/loading or other layer creating actions, -- // so do not delete it -- if (hold) { -+ // if the layer's hold refs number not 0, it means it's pulling/importing/loading or -+ // other layer creating actions, so do not delete it -+ if (refs_num > 0) { - break; - } - -@@ -1197,8 +1213,8 @@ int storage_rootfs_umount(const char *container_id, bool force) - - rootfs_info = rootfs_store_get_rootfs(container_id); - if (rootfs_info == NULL) { -- ERROR("Failed to get rootfs %s info", container_id); -- ret = -1; -+ ERROR("Failed to get rootfs %s info, skip umount", container_id); -+ ret = 0; - goto out; - } - -@@ -1313,7 +1329,7 @@ static int parse_checked_layer_file(const char *path, map_t *checked_layers) - return (errno == ENOENT ? 0 : -1); - } - -- ret = isula_utils_read_line(fp, parse_checked_layer_cb, (void *)checked_layers); -+ ret = util_proc_file_line_by_line(fp, parse_checked_layer_cb, (void *)checked_layers); - - fclose(fp); - return ret; -diff --git a/src/daemon/modules/image/oci/storage/storage.h b/src/daemon/modules/image/oci/storage/storage.h -index 4ba6470..d3c4420 100644 ---- a/src/daemon/modules/image/oci/storage/storage.h -+++ b/src/daemon/modules/image/oci/storage/storage.h -@@ -151,7 +151,9 @@ char *storage_img_get_image_id(const char *img_name); - /* layer operations */ - int storage_layer_create(const char *layer_id, storage_layer_create_opts_t *opts); - --int storage_set_hold_flag(const char *layer_id, bool hold); -+int storage_inc_hold_refs(const char *layer_id); -+ -+int storage_dec_hold_refs(const char *layer_id); - - struct layer_list *storage_layers_get_by_compress_digest(const char *digest); - -diff --git a/src/daemon/modules/image/oci/utils_images.c b/src/daemon/modules/image/oci/utils_images.c -index 9204d0d..42831cc 100644 ---- a/src/daemon/modules/image/oci/utils_images.c -+++ b/src/daemon/modules/image/oci/utils_images.c -@@ -63,7 +63,7 @@ char *oci_get_host(const char *name) - } - - parts = util_string_split(name, '/'); -- if ((parts != NULL && *parts != NULL && !strings_contains_any(*parts, ".:") && strcmp(*parts, "localhost")) || -+ if ((parts != NULL && *parts != NULL && !util_strings_contains_any(*parts, ".:") && strcmp(*parts, "localhost")) || - (strstr(name, "/") == NULL)) { - util_free_array(parts); - return NULL; -@@ -382,8 +382,8 @@ static char *convert_created_by(image_manifest_v1_compatibility *config) - return created_by; - } - --int add_rootfs_and_history(const layer_blob *layers, size_t layers_len, -- const registry_manifest_schema1 *manifest, docker_image_config_v2 *config) -+int add_rootfs_and_history(const layer_blob *layers, size_t layers_len, const registry_manifest_schema1 *manifest, -+ docker_image_config_v2 *config) - { - int i = 0; - int ret = 0; -@@ -464,26 +464,6 @@ out: - return ret; - } - --types_timestamp_t created_to_timestamp(char *created) --{ -- int64_t nanos = 0; -- types_timestamp_t timestamp = { 0 }; -- -- if (to_unix_nanos_from_str(created, &nanos) != 0) { -- ERROR("Failed to get created time from image config"); -- goto out; -- } -- -- timestamp.has_seconds = true; -- timestamp.seconds = nanos / Time_Second; -- timestamp.has_nanos = true; -- timestamp.nanos = nanos % Time_Second; -- --out: -- -- return timestamp; --} -- - bool oci_valid_time(char *time) - { - int64_t nanos = 0; -@@ -493,7 +473,7 @@ bool oci_valid_time(char *time) - return false; - } - -- if (to_unix_nanos_from_str(time, &nanos) != 0) { -+ if (util_to_unix_nanos_from_str(time, &nanos) != 0) { - ERROR("Failed to translate created time %s to nanos", time); - return false; - } -diff --git a/src/daemon/modules/image/oci/utils_images.h b/src/daemon/modules/image/oci/utils_images.h -index 9f85d1a..4ab4afc 100644 ---- a/src/daemon/modules/image/oci/utils_images.h -+++ b/src/daemon/modules/image/oci/utils_images.h -@@ -53,7 +53,6 @@ char *oci_calc_diffid(const char *file); - void free_items_not_inherit(docker_image_config_v2 *config); - int add_rootfs_and_history(const layer_blob *layers, size_t layers_len, const registry_manifest_schema1 *manifest, - docker_image_config_v2 *config); --types_timestamp_t created_to_timestamp(char *created); - bool oci_valid_time(char *time); - - #ifdef __cplusplus -@@ -61,4 +60,3 @@ bool oci_valid_time(char *time); - #endif - - #endif // DAEMON_MODULES_IMAGE_OCI_UTILS_IMAGES_H -- -diff --git a/src/daemon/modules/plugin/plugin.c b/src/daemon/modules/plugin/plugin.c -index bead032..2532656 100644 ---- a/src/daemon/modules/plugin/plugin.c -+++ b/src/daemon/modules/plugin/plugin.c -@@ -185,7 +185,7 @@ static char *get_uniq_enable_plugins(const oci_runtime_spec *oci) - UTIL_FREE_AND_SET_NULL(full); - - for (i = 0; i < util_array_len((const char **)raw); i++) { -- if (strings_in_slice((const char **)arr, util_array_len((const char **)arr), raw[i])) { -+ if (util_strings_in_slice((const char **)arr, util_array_len((const char **)arr), raw[i])) { - continue; - } - if (util_array_append(&arr, raw[i]) != 0) { -@@ -274,7 +274,7 @@ static char **get_enable_plugins(const char *plugins) - arr_len = util_array_len((const char **)arr); - - for (i = 0; i < arr_len; i++) { -- if (strings_in_slice((const char **)dst, dst_len, arr[i])) { -+ if (util_strings_in_slice((const char **)dst, dst_len, arr[i])) { - continue; - } - if (util_array_append(&dst, arr[i]) != 0) { -@@ -691,7 +691,7 @@ static void *plugin_manager_routine(void *arg) - // initilize inotify instance - inotify_fd = inotify_init(); - if (inotify_fd < 0) { -- ERROR("Failed to initalize inotify instance"); -+ ERROR("Failed to initialize inotify instance"); - return NULL; - } - // add plugin_dir to watch -@@ -1129,7 +1129,7 @@ static int pm_init_plugin(const plugin_t *plugin) - } - } - /* -- * add elem to reqs, if no containers availabe add no elem. -+ * add elem to reqs, if no containers available add no elem. - */ - for (i = 0; i < container_num; i++) { - ret = pm_prepare_init_reqs(plugin, &reqs, cnames[i]); -diff --git a/src/daemon/modules/runtime/engines/engine.h b/src/daemon/modules/runtime/engines/engine.h -index d9482cf..ced3cf2 100644 ---- a/src/daemon/modules/runtime/engines/engine.h -+++ b/src/daemon/modules/runtime/engines/engine.h -@@ -40,6 +40,8 @@ struct engine_cgroup_resources { - uint64_t memory_swap; - uint64_t memory_reservation; - uint64_t kernel_memory_limit; -+ int64_t cpurt_runtime; -+ int64_t cpurt_period; - }; - - typedef struct _engine_start_request_t { -diff --git a/src/daemon/modules/runtime/engines/lcr/lcr_engine.c b/src/daemon/modules/runtime/engines/lcr/lcr_engine.c -index 83a206a..691bfaa 100644 ---- a/src/daemon/modules/runtime/engines/lcr/lcr_engine.c -+++ b/src/daemon/modules/runtime/engines/lcr/lcr_engine.c -@@ -94,6 +94,8 @@ static bool lcr_update_container(const char *name, const char *lcrpath, const st - lcr_cr.memory_swap = cr->memory_swap; - lcr_cr.memory_reservation = cr->memory_reservation; - lcr_cr.kernel_memory_limit = cr->kernel_memory_limit; -+ lcr_cr.cpurt_period = cr->cpurt_period; -+ lcr_cr.cpurt_runtime = cr->cpurt_runtime; - - return g_lcr_update_op(name, lcrpath, &lcr_cr); - } -diff --git a/src/daemon/modules/runtime/engines/lcr/lcr_rt_ops.c b/src/daemon/modules/runtime/engines/lcr/lcr_rt_ops.c -index 77ca9a1..27c6a63 100644 ---- a/src/daemon/modules/runtime/engines/lcr/lcr_rt_ops.c -+++ b/src/daemon/modules/runtime/engines/lcr/lcr_rt_ops.c -@@ -504,6 +504,9 @@ out: - - static void to_engine_resources(const host_config *hostconfig, struct engine_cgroup_resources *cr) - { -+ uint64_t period = 0; -+ int64_t quota = 0; -+ - if (hostconfig == NULL || cr == NULL) { - return; - } -@@ -518,6 +521,15 @@ static void to_engine_resources(const host_config *hostconfig, struct engine_cgr - cr->memory_swap = (uint64_t)hostconfig->memory_swap; - cr->memory_reservation = (uint64_t)hostconfig->memory_reservation; - cr->kernel_memory_limit = (uint64_t)hostconfig->kernel_memory; -+ cr->cpurt_period = hostconfig->cpu_realtime_period; -+ cr->cpurt_runtime = hostconfig->cpu_realtime_runtime; -+ -+ if (hostconfig->nano_cpus > 0) { -+ period = (uint64_t)(100 * Time_Milli / Time_Micro); -+ quota = hostconfig->nano_cpus * (int64_t)period / 1e9; -+ cr->cpu_period = period; -+ cr->cpu_quota = (uint64_t)quota; -+ } - } - - int rt_lcr_update(const char *id, const char *runtime, const rt_update_params_t *params) -diff --git a/src/daemon/modules/runtime/isula/isula_rt_ops.c b/src/daemon/modules/runtime/isula/isula_rt_ops.c -index d056156..6e4512f 100644 ---- a/src/daemon/modules/runtime/isula/isula_rt_ops.c -+++ b/src/daemon/modules/runtime/isula/isula_rt_ops.c -@@ -155,7 +155,7 @@ static void get_err_message(char *buf, int buf_size, const char *workdir, const - if (pline == NULL) { - break; - } -- if (strings_contains_word(pline, "error")) { -+ if (util_strings_contains_word(pline, "error")) { - if (lines[0] == NULL) { - lines[0] = pline; - pline = NULL; -@@ -714,7 +714,7 @@ realexec: - goto out; - } - -- status = wait_for_pid_status(pid); -+ status = util_wait_for_pid_status(pid); - if (status < 0) { - ERROR("failed wait shim-parent %d exit %s", pid, strerror(errno)); - ret = -1; -@@ -763,7 +763,7 @@ static int get_container_process_pid(const char *workdir) - file_read_int(fname, &pid); - if (!pid) { - if (shim_alive(workdir)) { -- usleep_nointerupt(100000); -+ util_usleep_nointerupt(100000); - continue; - } - ERROR("failed read pid from dead shim %s", workdir); -diff --git a/src/daemon/modules/service/service_container.c b/src/daemon/modules/service/service_container.c -index 737cfea..4e830d3 100644 ---- a/src/daemon/modules/service/service_container.c -+++ b/src/daemon/modules/service/service_container.c -@@ -1323,7 +1323,7 @@ void umount_share_shm(container_t *cont) - if (cont->hostconfig->system_container) { - return; - } -- if (cont->hostconfig->ipc_mode == NULL || is_shareable(cont->hostconfig->ipc_mode)) { -+ if (cont->hostconfig->ipc_mode == NULL || namespace_is_shareable(cont->hostconfig->ipc_mode)) { - if (cont->common_config == NULL || cont->common_config->shm_path == NULL) { - return; - } -@@ -1375,7 +1375,7 @@ static int do_append_process_exec_env(const char **default_env, defs_process *sp - } - new_size = (spec->env_len + default_env_len) * sizeof(char *); - old_size = spec->env_len * sizeof(char *); -- ret = mem_realloc((void **)&temp, new_size, spec->env, old_size); -+ ret = util_mem_realloc((void **)&temp, new_size, spec->env, old_size); - if (ret != 0) { - ERROR("Failed to realloc memory for envionment variables"); - ret = -1; -@@ -1577,7 +1577,7 @@ static defs_process *make_exec_process_spec(const container_config *container_sp - } - } - -- ret = dup_array_of_strings((const char **)request->argv, request->argv_len, &(spec->args), &(spec->args_len)); -+ ret = util_dup_array_of_strings((const char **)request->argv, request->argv_len, &(spec->args), &(spec->args_len)); - if (ret != 0) { - ERROR("Failed to dup envs for exec process spec"); - goto err_out; -diff --git a/src/daemon/modules/spec/specs.c b/src/daemon/modules/spec/specs.c -index 030a1ba..5c52d63 100644 ---- a/src/daemon/modules/spec/specs.c -+++ b/src/daemon/modules/spec/specs.c -@@ -39,7 +39,9 @@ - #include "specs_namespace.h" - #include "path.h" - #include "constants.h" -+#ifdef ENABLE_SELINUX - #include "selinux_label.h" -+#endif - #include "err_msg.h" - #include "utils_array.h" - #include "utils_file.h" -@@ -179,7 +181,7 @@ static int make_annotations_cgroup_dir(const container_config *container_spec, c - if (path == NULL) { - path = "/isulad"; - } -- if (cleanpath(path, cleaned, sizeof(cleaned)) == NULL) { -+ if (util_clean_path(path, cleaned, sizeof(cleaned)) == NULL) { - ERROR("Failed to clean path: %s", path); - ret = -1; - goto out; -@@ -676,7 +678,8 @@ static int merge_hugetlbs(oci_runtime_spec *oci_spec, host_config_hugetlbs_eleme - old_size = oci_spec->linux->resources->hugepage_limits_len * sizeof(defs_resources_hugepage_limits_element *); - new_size = (oci_spec->linux->resources->hugepage_limits_len + hugetlbs_len) * - sizeof(defs_resources_hugepage_limits_element *); -- ret = mem_realloc((void **)&hugepage_limits_temp, new_size, oci_spec->linux->resources->hugepage_limits, old_size); -+ ret = util_mem_realloc((void **)&hugepage_limits_temp, new_size, oci_spec->linux->resources->hugepage_limits, -+ old_size); - if (ret != 0) { - ERROR("Failed to realloc memory for hugepage limits"); - ret = -1; -@@ -901,10 +904,39 @@ static int merge_hostname(oci_runtime_spec *oci_spec, const host_config *host_sp - return 0; - } - -+static int merge_nanocpus(oci_runtime_spec *oci_spec, int64_t nanocpus) -+{ -+ int ret = 0; -+ uint64_t period = 0; -+ int64_t quota = 0; -+ -+ ret = make_sure_oci_spec_linux_resources_cpu(oci_spec); -+ if (ret < 0) { -+ goto out; -+ } -+ -+ period = (uint64_t)(100 * Time_Milli / Time_Micro); -+ quota = nanocpus * (int64_t)period / 1e9; -+ -+ oci_spec->linux->resources->cpu->quota = quota; -+ oci_spec->linux->resources->cpu->period = period; -+ -+out: -+ return ret; -+} -+ - static int merge_conf_cgroup_cpu_int64(oci_runtime_spec *oci_spec, const host_config *host_spec) - { - int ret = 0; - -+ if (host_spec->nano_cpus > 0) { -+ ret = merge_nanocpus(oci_spec, host_spec->nano_cpus); -+ if (ret != 0) { -+ ERROR("Failed to merge cgroup nano cpus"); -+ goto out; -+ } -+ } -+ - /* cpu shares */ - if (host_spec->cpu_shares != 0) { - ret = merge_cpu_shares(oci_spec, host_spec->cpu_shares); -@@ -1291,8 +1323,8 @@ static int replace_entrypoint_cmds_from_spec(const oci_runtime_spec *oci_spec, c - isulad_set_error_message("No command specified"); - return -1; - } -- return dup_array_of_strings((const char **)(oci_spec->process->args), oci_spec->process->args_len, -- &(container_spec->cmd), &(container_spec->cmd_len)); -+ return util_dup_array_of_strings((const char **)(oci_spec->process->args), oci_spec->process->args_len, -+ &(container_spec->cmd), &(container_spec->cmd_len)); - } - - static int merge_conf_args(oci_runtime_spec *oci_spec, container_config *container_spec) -@@ -1381,8 +1413,8 @@ static int merge_share_namespace_helper(const oci_runtime_spec *oci_spec, const - goto out; - } - -- ret = mem_realloc((void **)&work_ns, (len + 1) * sizeof(defs_namespace_reference *), (void *)work_ns, -- len * sizeof(defs_namespace_reference *)); -+ ret = util_mem_realloc((void **)&work_ns, (len + 1) * sizeof(defs_namespace_reference *), (void *)work_ns, -+ len * sizeof(defs_namespace_reference *)); - if (ret != 0) { - ERROR("Out of memory"); - goto out; -@@ -1658,7 +1690,7 @@ static int split_security_opt(const char *security_opt, char ***items, size_t *i - { - int ret = 0; - -- if (strings_contains_any(security_opt, "=")) { -+ if (util_strings_contains_any(security_opt, "=")) { - *items = util_string_split_n(security_opt, '=', 2); - if (*items == NULL) { - ERROR("Out of memory"); -@@ -1666,7 +1698,7 @@ static int split_security_opt(const char *security_opt, char ***items, size_t *i - goto out; - } - *items_size = util_array_len((const char **)*items); -- } else if (strings_contains_any(security_opt, ":")) { -+ } else if (util_strings_contains_any(security_opt, ":")) { - *items = util_string_split_n(security_opt, ':', 2); - if (*items == NULL) { - ERROR("Out of memory"); -@@ -1751,6 +1783,7 @@ out: - return ret; - } - -+#ifdef ENABLE_SELINUX - static int to_host_config_selinux_labels(const char **labels, size_t len, char ***dst, size_t *dst_len) - { - int ret = 0; -@@ -1837,8 +1870,8 @@ static int handle_connected_container_mode(host_config *hc) - char **pid_label = NULL; - size_t pid_label_len = 0; - -- char *ipc_container = connected_container(hc->ipc_mode); -- char *pid_container = connected_container(hc->pid_mode); -+ char *ipc_container = namespace_get_connected_container(hc->ipc_mode); -+ char *pid_container = namespace_get_connected_container(hc->pid_mode); - if (ipc_container != NULL) { - char *ipc_process_label = get_container_process_label(ipc_container); - if (dup_security_opt(ipc_process_label, &ipc_label, &ipc_label_len) != 0) { -@@ -1908,23 +1941,26 @@ static int generate_security_opt(host_config *hc) - util_free_array(items); - } - -- if (is_host(hc->ipc_mode) || is_host(hc->pid_mode) || hc->privileged) { -+ if (namespace_is_host(hc->ipc_mode) || namespace_is_host(hc->pid_mode) || hc->privileged) { - return handle_host_or_privileged_mode(hc); - } - - return handle_connected_container_mode(hc); - } -+#endif - - static int merge_security_conf(oci_runtime_spec *oci_spec, host_config *host_spec, - container_config_v2_common_config *v2_spec) - { - int ret = 0; - -+#ifdef ENABLE_SELINUX - ret = generate_security_opt(host_spec); - if (ret != 0) { - ERROR("Failed to generate security opt"); - goto out; - } -+#endif - - ret = merge_caps(oci_spec, (const char **)host_spec->cap_add, host_spec->cap_add_len, - (const char **)host_spec->cap_drop, host_spec->cap_drop_len); -@@ -1952,13 +1988,53 @@ static int merge_security_conf(oci_runtime_spec *oci_spec, host_config *host_spe - goto out; - } - -+#ifdef ENABLE_SELINUX - ret = merge_selinux(oci_spec, v2_spec); - if (ret != 0) { - ERROR("Failed to merge selinux config"); - goto out; - } -+#endif -+ -+out: -+ return ret; -+} -+ -+int merge_oci_cgroups_path(const char *id, oci_runtime_spec *oci_spec, const host_config *host_spec) -+{ -+ int ret = 0; -+ char *default_cgroup_parent = NULL; -+ char *path = NULL; -+ -+ if (id == NULL || oci_spec == NULL || host_spec == NULL) { -+ ERROR("Invalid arguments"); -+ ret = -1; -+ goto out; -+ } -+ -+ if (make_sure_oci_spec_linux(oci_spec) != 0) { -+ ERROR("Failed to make oci spec linux"); -+ ret = -1; -+ goto out; -+ } -+ -+ default_cgroup_parent = conf_get_isulad_cgroup_parent(); -+ path = default_cgroup_parent; -+ if (host_spec->cgroup_parent != NULL) { -+ path = host_spec->cgroup_parent; -+ } -+ -+ if (path == NULL) { -+ free(oci_spec->linux->cgroups_path); -+ oci_spec->linux->cgroups_path = util_path_join("/isulad", id); -+ return 0; -+ } -+ -+ free(oci_spec->linux->cgroups_path); -+ oci_spec->linux->cgroups_path = util_path_join(path, id); - - out: -+ free(default_cgroup_parent); - return ret; - } - -@@ -2029,45 +2105,13 @@ int merge_all_specs(host_config *host_spec, const char *real_rootfs, container_c - goto out; - } - --out: -- return ret; --} -- --int merge_oci_cgroups_path(const char *id, oci_runtime_spec *oci_spec, const host_config *host_spec) --{ -- int ret = 0; -- char *default_cgroup_parent = NULL; -- char *path = NULL; -- -- if (id == NULL || oci_spec == NULL || host_spec == NULL) { -- ERROR("Invalid arguments"); -- ret = -1; -- goto out; -- } -- -- if (make_sure_oci_spec_linux(oci_spec) != 0) { -- ERROR("Failed to make oci spec linux"); -- ret = -1; -+ ret = merge_oci_cgroups_path(v2_spec->id, oci_spec, host_spec); -+ if (ret != 0) { -+ ERROR("Failed to make cgroup parent"); - goto out; - } - -- default_cgroup_parent = conf_get_isulad_cgroup_parent(); -- path = default_cgroup_parent; -- if (host_spec->cgroup_parent != NULL) { -- path = host_spec->cgroup_parent; -- } -- -- if (path == NULL) { -- free(oci_spec->linux->cgroups_path); -- oci_spec->linux->cgroups_path = util_path_join("/isulad", id); -- return 0; -- } -- -- free(oci_spec->linux->cgroups_path); -- oci_spec->linux->cgroups_path = util_path_join(path, id); -- - out: -- UTIL_FREE_AND_SET_NULL(default_cgroup_parent); - return ret; - } - -diff --git a/src/daemon/modules/spec/specs_extend.c b/src/daemon/modules/spec/specs_extend.c -index 13b597e..96be761 100644 ---- a/src/daemon/modules/spec/specs_extend.c -+++ b/src/daemon/modules/spec/specs_extend.c -@@ -50,7 +50,7 @@ - } \ - old_size = dest->item##_len * sizeof(defs_hook *); \ - new_size = (dest->item##_len + src->item##_len + 1) * sizeof(defs_hook *); \ -- ret = mem_realloc((void **)&(item), new_size, dest->item, old_size); \ -+ ret = util_mem_realloc((void **)&(item), new_size, dest->item, old_size); \ - if (ret != 0) { \ - ERROR("Failed to realloc memory for hooks_" #item " variables"); \ - ret = -1; \ -@@ -360,7 +360,7 @@ static char *get_env_abs_file_path(const oci_runtime_spec *oci_spec, const char - if (oci_spec->root == NULL || oci_spec->root->path == NULL) { - return NULL; - } -- if (realpath_in_scope(oci_spec->root->path, env_target_file, &env_path) < 0) { -+ if (util_realpath_in_scope(oci_spec->root->path, env_target_file, &env_path) < 0) { - ERROR("env target file '%s' real path must be under rootfs '%s'", env_target_file, oci_spec->root->path); - goto out; - } -@@ -437,7 +437,7 @@ int merge_env(oci_runtime_spec *oci_spec, const char **env, size_t env_len) - } - new_size = (oci_spec->process->env_len + env_len) * sizeof(char *); - old_size = oci_spec->process->env_len * sizeof(char *); -- ret = mem_realloc((void **)&temp, new_size, oci_spec->process->env, old_size); -+ ret = util_mem_realloc((void **)&temp, new_size, oci_spec->process->env, old_size); - if (ret != 0) { - ERROR("Failed to realloc memory for envionment variables"); - ret = -1; -@@ -547,7 +547,7 @@ int merge_ulimits_pre(oci_runtime_spec *oci_spec, size_t host_ulimits_len) - } - old_size = oci_spec->process->rlimits_len * sizeof(defs_process_rlimits_element *); - new_size = (oci_spec->process->rlimits_len + host_ulimits_len) * sizeof(defs_process_rlimits_element *); -- ret = mem_realloc((void **)&rlimits_temp, new_size, oci_spec->process->rlimits, old_size); -+ ret = util_mem_realloc((void **)&rlimits_temp, new_size, oci_spec->process->rlimits, old_size); - if (ret != 0) { - ERROR("Failed to realloc memory for rlimits"); - ret = -1; -@@ -603,47 +603,49 @@ out: - return ret; - } - --static int do_merge_one_ulimit(const oci_runtime_spec *oci_spec, defs_process_rlimits_element *rlimit) -+static bool rlimit_already_exists(const oci_runtime_spec *oci_spec, defs_process_rlimits_element *rlimit) - { - size_t j; - bool exists = false; - - for (j = 0; j < oci_spec->process->rlimits_len; j++) { - if (oci_spec->process->rlimits[j]->type == NULL) { -- ERROR("rlimit type is empty"); -- UTIL_FREE_AND_SET_NULL(rlimit->type); -- free(rlimit); -- return -1; -+ continue; - } - if (strcmp(oci_spec->process->rlimits[j]->type, rlimit->type) == 0) { - exists = true; - break; - } - } -- if (exists) { -- /* ulimit exist, discard default ulimit */ -- UTIL_FREE_AND_SET_NULL(rlimit->type); -- free(rlimit); -- } else { -- oci_spec->process->rlimits[oci_spec->process->rlimits_len] = rlimit; -- oci_spec->process->rlimits_len++; -- } - -- return 0; -+ return exists; - } - --static int merge_one_ulimit(const oci_runtime_spec *oci_spec, const host_config_ulimits_element *ulimit) -+static int append_one_ulimit(const oci_runtime_spec *oci_spec, const host_config_ulimits_element *ulimit) - { -+ int ret = 0; - defs_process_rlimits_element *rlimit = NULL; - - if (trans_ulimit_to_rlimit(&rlimit, ulimit) != 0) { -- return -1; -+ ret = -1; -+ goto out; -+ } -+ -+ if (rlimit_already_exists(oci_spec, rlimit)) { -+ ret = 0; -+ goto out; - } - -- return do_merge_one_ulimit(oci_spec, rlimit); -+ oci_spec->process->rlimits[oci_spec->process->rlimits_len] = rlimit; -+ oci_spec->process->rlimits_len++; -+ rlimit = NULL; -+ -+out: -+ free_defs_process_rlimits_element(rlimit); -+ return ret; - } - --static int merge_ulimits(oci_runtime_spec *oci_spec, host_config_ulimits_element **ulimits, size_t ulimits_len) -+static int append_global_ulimits(oci_runtime_spec *oci_spec, host_config_ulimits_element **ulimits, size_t ulimits_len) - { - int ret = 0; - size_t i = 0; -@@ -658,7 +660,7 @@ static int merge_ulimits(oci_runtime_spec *oci_spec, host_config_ulimits_element - } - - for (i = 0; i < ulimits_len; i++) { -- ret = merge_one_ulimit(oci_spec, ulimits[i]); -+ ret = append_one_ulimit(oci_spec, ulimits[i]); - if (ret != 0) { - ret = -1; - goto out; -@@ -682,7 +684,7 @@ int merge_global_ulimit(oci_runtime_spec *oci_spec) - - if (ulimits != NULL) { - ulimits_len = ulimit_array_len(ulimits); -- if (merge_ulimits(oci_spec, ulimits, ulimits_len)) { -+ if (append_global_ulimits(oci_spec, ulimits, ulimits_len)) { - ret = -1; - goto out; - } -diff --git a/src/daemon/modules/spec/specs_mount.c b/src/daemon/modules/spec/specs_mount.c -index 9c4b109..37bbd37 100644 ---- a/src/daemon/modules/spec/specs_mount.c -+++ b/src/daemon/modules/spec/specs_mount.c -@@ -40,7 +40,9 @@ - #include "specs_mount.h" - #include "specs_extend.h" - #include "container_api.h" -+#ifdef ENABLE_SELINUX - #include "selinux_label.h" -+#endif - #include "err_msg.h" - #include "utils_array.h" - #include "utils_file.h" -@@ -88,7 +90,7 @@ static int append_additional_mounts(oci_runtime_spec *oci_spec, const char *type - new_size = (oci_spec->mounts_len + files_len) * sizeof(defs_mount *); - old_size = oci_spec->mounts_len * sizeof(defs_mount *); - -- ret = mem_realloc((void **)&spec_mounts, new_size, oci_spec->mounts, old_size); -+ ret = util_mem_realloc((void **)&spec_mounts, new_size, oci_spec->mounts, old_size); - if (ret != 0) { - ERROR("Out of memory"); - ret = -1; -@@ -176,7 +178,7 @@ static bool valid_dirent_info(const char *dir, const struct dirent *info_archivo - return false; - } - -- // do not map device which name containes ":" -+ // do not map device which name contains ":" - pdot = strstr(info_archivo->d_name, ":"); - if (pdot != NULL) { - INFO("Skipping device %s include \":\"", info_archivo->d_name); -@@ -216,7 +218,7 @@ static int pack_devices(const char *fullpath, char ***devices, size_t *device_le - tmp_length += 1; - new_size = sizeof(char *) * tmp_length; - -- ret = mem_realloc((void **)&tmp_device, new_size, *devices, old_size); -+ ret = util_mem_realloc((void **)&tmp_device, new_size, *devices, old_size); - if (ret != 0) { - ERROR("get_devices: Failed to realloc memory"); - ret = -1; -@@ -561,19 +563,21 @@ defs_mount *parse_mount(const char *mount) - goto out; - } - -- if (!cleanpath(mount_element->destination, dstpath, sizeof(dstpath))) { -+ if (!util_clean_path(mount_element->source, dstpath, sizeof(dstpath))) { -+ ERROR("Failed to get clean path"); -+ ret = -1; -+ goto out; -+ } -+ free(mount_element->source); -+ mount_element->source = util_strdup_s(dstpath); -+ -+ if (!util_clean_path(mount_element->destination, dstpath, sizeof(dstpath))) { - ERROR("failed to get clean path"); - ret = EINVALIDARGS; - goto out; - } -- - free(mount_element->destination); - mount_element->destination = util_strdup_s(dstpath); -- if (mount_element->destination == NULL) { -- ERROR("out of memory"); -- ret = -1; -- goto out; -- } - - /* append default options if it's bind mount */ - ret = append_default_mount_options(mount_element, has_ro, has_pro); -@@ -723,16 +727,26 @@ defs_mount *parse_volume(const char *volume) - } - } - -- if (!cleanpath(mount_element->destination, dstpath, sizeof(dstpath))) { -+ if (!util_clean_path(mount_element->source, dstpath, sizeof(dstpath))) { -+ ERROR("Failed to get clean path"); -+ ret = -1; -+ goto free_out; -+ } -+ free(mount_element->source); -+ mount_element->source = util_strdup_s(dstpath); -+ -+ if (!util_clean_path(mount_element->destination, dstpath, sizeof(dstpath))) { - ERROR("Failed to get clean path"); - ret = -1; - goto free_out; - } - free(mount_element->destination); - mount_element->destination = util_strdup_s(dstpath); -+ - if (label != NULL) { - options_len++; - } -+ - mount_element->options = util_common_calloc_s(options_len * sizeof(char *)); - if (mount_element->options == NULL) { - ERROR("Out of memory"); -@@ -899,7 +913,7 @@ out: - return ret; - } - --static int get_weight_devices_from_path(const host_config_blkio_weight_device_element *weight_dev, -+static int get_weight_devices_from_path(const defs_blkio_weight_device *weight_dev, - defs_block_io_device_weight *spec_weight_dev) - { - int ret = 0; -@@ -929,7 +943,7 @@ static int get_weight_devices_from_path(const host_config_blkio_weight_device_el - } - - static int merge_host_config_blk_weight_device(defs_block_io_device_weight **out_spec_weight_dev, -- const host_config_blkio_weight_device_element *weight_dev) -+ const defs_blkio_weight_device *weight_dev) - { - int ret = 0; - defs_block_io_device_weight *spec_weight_dev = NULL; -@@ -958,112 +972,56 @@ out: - return ret; - } - --static int get_read_bps_devices_from_path(const host_config_blkio_device_read_bps_element *read_bps_dev, -- defs_block_io_device_throttle *spec_read_bps_dev) --{ -- int ret = 0; -- struct stat st; -- -- if (read_bps_dev == NULL || spec_read_bps_dev == NULL) { -- return -1; -- } -- -- ret = stat(read_bps_dev->path, &st); -- if (ret < 0) { -- ERROR("Failed to get state of device:%s", read_bps_dev->path); -- isulad_set_error_message("no such file or directory: %s", read_bps_dev->path); -- return -1; -- } -- -- /* fill spec throttle read bps dev */ -- spec_read_bps_dev->rate = read_bps_dev->rate; -- spec_read_bps_dev->major = (int64_t)major(st.st_rdev); -- spec_read_bps_dev->minor = (int64_t)minor(st.st_rdev); -- -- return 0; --} -- --static int merge_host_config_blk_read_bps_device(defs_block_io_device_throttle **out_spec_read_bps_dev, -- const host_config_blkio_device_read_bps_element *blkio_device_read_bps) --{ -- int ret = 0; -- defs_block_io_device_throttle *spec_read_bps_dev = NULL; -- -- spec_read_bps_dev = util_common_calloc_s(sizeof(defs_block_io_device_throttle)); -- if (spec_read_bps_dev == NULL) { -- ERROR("Memory out"); -- ret = -1; -- goto erro_out; -- } -- -- ret = get_read_bps_devices_from_path(blkio_device_read_bps, spec_read_bps_dev); -- if (ret != 0) { -- ERROR("Failed to get throttle read bps devices info"); -- ret = -1; -- goto erro_out; -- } -- -- *out_spec_read_bps_dev = spec_read_bps_dev; -- goto out; -- --erro_out: -- free_defs_block_io_device_throttle(spec_read_bps_dev); -- --out: -- return ret; --} -- --static int get_write_bps_devices_from_path(const host_config_blkio_device_write_bps_element *write_bps_dev, -- defs_block_io_device_throttle *spec_write_bps_dev) -+static int get_blkio_device_throttle_info(const defs_blkio_device *blkio_dev_info, -+ defs_block_io_device_throttle *blkio_dev_throttle) - { - int ret = 0; - struct stat st; - -- if (write_bps_dev == NULL || spec_write_bps_dev == NULL) { -+ if (blkio_dev_info == NULL || blkio_dev_throttle == NULL) { - return -1; - } - -- ret = stat(write_bps_dev->path, &st); -+ ret = stat(blkio_dev_info->path, &st); - if (ret < 0) { -- ERROR("no such file or directory :%s", write_bps_dev->path); -- isulad_set_error_message("no such file or directory: %s", write_bps_dev->path); -+ ERROR("no such file or directory :%s", blkio_dev_info->path); -+ isulad_set_error_message("no such file or directory: %s", blkio_dev_info->path); - return -1; - } - - /* fill spec throttle write bps dev */ -- spec_write_bps_dev->rate = write_bps_dev->rate; -- spec_write_bps_dev->major = (int64_t)major(st.st_rdev); -- spec_write_bps_dev->minor = (int64_t)minor(st.st_rdev); -+ blkio_dev_throttle->rate = blkio_dev_info->rate; -+ blkio_dev_throttle->major = (int64_t)major(st.st_rdev); -+ blkio_dev_throttle->minor = (int64_t)minor(st.st_rdev); - - return 0; - } - --static int --merge_host_config_blk_write_bps_device(defs_block_io_device_throttle **out_spec_write_bps_dev, -- const host_config_blkio_device_write_bps_element *blkio_device_write_bps) -+static int merge_host_config_blk_device(defs_block_io_device_throttle **blkio_dev_throttle, -+ const defs_blkio_device *blkio_dev) - { - int ret = 0; -- defs_block_io_device_throttle *spec_write_bps_dev = NULL; -+ defs_block_io_device_throttle *tmp_throttle = NULL; - -- spec_write_bps_dev = util_common_calloc_s(sizeof(defs_block_io_device_throttle)); -- if (spec_write_bps_dev == NULL) { -+ tmp_throttle = util_common_calloc_s(sizeof(defs_block_io_device_throttle)); -+ if (tmp_throttle == NULL) { - ERROR("Memory out"); - ret = -1; - goto erro_out; - } - -- ret = get_write_bps_devices_from_path(blkio_device_write_bps, spec_write_bps_dev); -+ ret = get_blkio_device_throttle_info(blkio_dev, tmp_throttle); - if (ret != 0) { -- ERROR("Failed to get throttle write bps devices info"); -+ ERROR("Failed to get throttle read bps devices info"); - ret = -1; - goto erro_out; - } - -- *out_spec_write_bps_dev = spec_write_bps_dev; -+ *blkio_dev_throttle = tmp_throttle; - goto out; - - erro_out: -- free_defs_block_io_device_throttle(spec_write_bps_dev); -+ free_defs_block_io_device_throttle(tmp_throttle); - - out: - return ret; -@@ -1091,7 +1049,7 @@ static int merge_all_devices(oci_runtime_spec *oci_spec, host_config_devices_ele - } - new_size = (oci_spec->linux->devices_len + devices_len) * sizeof(defs_device *); - old_size = oci_spec->linux->devices_len * sizeof(defs_device *); -- ret = mem_realloc((void **)&spec_dev, new_size, oci_spec->linux->devices, old_size); -+ ret = util_mem_realloc((void **)&spec_dev, new_size, oci_spec->linux->devices, old_size); - if (ret != 0) { - ERROR("Out of memory"); - ret = -1; -@@ -1108,7 +1066,7 @@ static int merge_all_devices(oci_runtime_spec *oci_spec, host_config_devices_ele - } - new_size = (oci_spec->linux->resources->devices_len + devices_len) * sizeof(defs_device_cgroup *); - old_size = oci_spec->linux->resources->devices_len * sizeof(defs_device_cgroup *); -- ret = mem_realloc((void **)&spec_cgroup_dev, new_size, oci_spec->linux->resources->devices, old_size); -+ ret = util_mem_realloc((void **)&spec_cgroup_dev, new_size, oci_spec->linux->resources->devices, old_size); - if (ret != 0) { - ERROR("Out of memory"); - ret = -1; -@@ -1416,7 +1374,7 @@ int merge_volumes(oci_runtime_spec *oci_spec, char **volumes, size_t volumes_len - } - new_size = (oci_spec->mounts_len + volumes_len) * sizeof(defs_mount *); - old_size = oci_spec->mounts_len * sizeof(defs_mount *); -- ret = mem_realloc((void **)&mounts_temp, new_size, oci_spec->mounts, old_size); -+ ret = util_mem_realloc((void **)&mounts_temp, new_size, oci_spec->mounts, old_size); - if (ret != 0) { - ERROR("Failed to realloc memory volumes"); - ret = -1; -@@ -1440,14 +1398,14 @@ int merge_volumes(oci_runtime_spec *oci_spec, char **volumes, size_t volumes_len - old_mp_val_size = - common_config->mount_points->len * sizeof(container_config_v2_common_config_mount_points_element *); - -- ret = mem_realloc((void **)&mp_key, new_mp_key_size, common_config->mount_points->keys, old_mp_key_size); -+ ret = util_mem_realloc((void **)&mp_key, new_mp_key_size, common_config->mount_points->keys, old_mp_key_size); - if (ret != 0) { - ERROR("Failed to realloc memory mount point"); - ret = -1; - goto out; - } - common_config->mount_points->keys = mp_key; -- ret = mem_realloc((void **)&mp_val, new_mp_val_size, common_config->mount_points->values, old_mp_val_size); -+ ret = util_mem_realloc((void **)&mp_val, new_mp_val_size, common_config->mount_points->values, old_mp_val_size); - if (ret != 0) { - ERROR("Failed to realloc memory mount point"); - ret = -1; -@@ -1502,7 +1460,7 @@ static int merge_custom_one_device(oci_runtime_spec *oci_spec, const host_config - } - new_size = (oci_spec->linux->devices_len + 1) * sizeof(defs_device *); - old_size = new_size - sizeof(defs_device *); -- ret = mem_realloc((void **)&spec_dev, new_size, oci_spec->linux->devices, old_size); -+ ret = util_mem_realloc((void **)&spec_dev, new_size, oci_spec->linux->devices, old_size); - if (ret != 0) { - ERROR("Failed to realloc memory for devices"); - ret = -1; -@@ -1520,7 +1478,7 @@ static int merge_custom_one_device(oci_runtime_spec *oci_spec, const host_config - } - new_size = (oci_spec->linux->resources->devices_len + 1) * sizeof(defs_device_cgroup *); - old_size = new_size - sizeof(defs_device_cgroup *); -- ret = mem_realloc((void **)&spec_cgroup_dev, new_size, oci_spec->linux->resources->devices, old_size); -+ ret = util_mem_realloc((void **)&spec_cgroup_dev, new_size, oci_spec->linux->resources->devices, old_size); - if (ret != 0) { - ERROR("Failed to realloc memory for cgroup devices"); - ret = -1; -@@ -1583,8 +1541,7 @@ out: - return ret; - } - --static int merge_blkio_weight_device(oci_runtime_spec *oci_spec, -- host_config_blkio_weight_device_element **blkio_weight_device, -+static int merge_blkio_weight_device(oci_runtime_spec *oci_spec, defs_blkio_weight_device **blkio_weight_device, - size_t blkio_weight_device_len) - { - int ret = 0; -@@ -1608,7 +1565,8 @@ static int merge_blkio_weight_device(oci_runtime_spec *oci_spec, - new_size = (oci_spec->linux->resources->block_io->weight_device_len + blkio_weight_device_len) * - sizeof(defs_block_io_device_weight *); - old_size = oci_spec->linux->resources->block_io->weight_device_len * sizeof(defs_block_io_device_weight *); -- ret = mem_realloc((void **)&weight_device, new_size, oci_spec->linux->resources->block_io->weight_device, old_size); -+ ret = util_mem_realloc((void **)&weight_device, new_size, oci_spec->linux->resources->block_io->weight_device, -+ old_size); - if (ret != 0) { - ERROR("Failed to realloc memory for weight devices"); - ret = -1; -@@ -1633,8 +1591,7 @@ out: - return ret; - } - --static int merge_blkio_read_bps_device(oci_runtime_spec *oci_spec, -- host_config_blkio_device_read_bps_element **blkio_read_bps_device, -+static int merge_blkio_read_bps_device(oci_runtime_spec *oci_spec, defs_blkio_device **blkio_read_bps_device, - size_t throttle_read_bps_device_len) - { - int ret = 0; -@@ -1661,8 +1618,8 @@ static int merge_blkio_read_bps_device(oci_runtime_spec *oci_spec, - sizeof(defs_block_io_device_throttle *); - old_size = oci_spec->linux->resources->block_io->throttle_read_bps_device_len * - sizeof(defs_block_io_device_throttle *); -- ret = mem_realloc((void **)&throttle_read_bps_device, new_size, -- oci_spec->linux->resources->block_io->throttle_read_bps_device, old_size); -+ ret = util_mem_realloc((void **)&throttle_read_bps_device, new_size, -+ oci_spec->linux->resources->block_io->throttle_read_bps_device, old_size); - if (ret != 0) { - ERROR("Failed to realloc memory for blkio throttle read bps devices"); - ret = -1; -@@ -1671,7 +1628,7 @@ static int merge_blkio_read_bps_device(oci_runtime_spec *oci_spec, - oci_spec->linux->resources->block_io->throttle_read_bps_device = throttle_read_bps_device; - - for (i = 0; i < throttle_read_bps_device_len; i++) { -- ret = merge_host_config_blk_read_bps_device( -+ ret = merge_host_config_blk_device( - &oci_spec->linux->resources->block_io - ->throttle_read_bps_device[oci_spec->linux->resources->block_io->throttle_read_bps_device_len], - blkio_read_bps_device[i]); -@@ -1687,8 +1644,7 @@ out: - return ret; - } - --static int merge_blkio_write_bps_device(oci_runtime_spec *oci_spec, -- host_config_blkio_device_write_bps_element **blkio_write_bps_device, -+static int merge_blkio_write_bps_device(oci_runtime_spec *oci_spec, defs_blkio_device **blkio_write_bps_device, - size_t throttle_write_bps_device_len) - { - int ret = 0; -@@ -1715,8 +1671,8 @@ static int merge_blkio_write_bps_device(oci_runtime_spec *oci_spec, - sizeof(defs_block_io_device_throttle *); - old_size = oci_spec->linux->resources->block_io->throttle_write_bps_device_len * - sizeof(defs_block_io_device_throttle *); -- ret = mem_realloc((void **)&throttle_write_bps_device, new_size, -- oci_spec->linux->resources->block_io->throttle_write_bps_device, old_size); -+ ret = util_mem_realloc((void **)&throttle_write_bps_device, new_size, -+ oci_spec->linux->resources->block_io->throttle_write_bps_device, old_size); - if (ret != 0) { - ERROR("Failed to realloc memory for throttle write bps devices"); - ret = -1; -@@ -1725,7 +1681,7 @@ static int merge_blkio_write_bps_device(oci_runtime_spec *oci_spec, - oci_spec->linux->resources->block_io->throttle_write_bps_device = throttle_write_bps_device; - - for (i = 0; i < throttle_write_bps_device_len; i++) { -- ret = merge_host_config_blk_write_bps_device( -+ ret = merge_host_config_blk_device( - &oci_spec->linux->resources->block_io - ->throttle_write_bps_device[oci_spec->linux->resources->block_io->throttle_write_bps_device_len], - blkio_write_bps_device[i]); -@@ -1741,6 +1697,300 @@ out: - return ret; - } - -+static int merge_blkio_read_iops_device(oci_runtime_spec *oci_spec, defs_blkio_device **blkio_read_iops_device, -+ size_t throttle_read_iops_device_len) -+{ -+ int ret = 0; -+ size_t new_size = 0; -+ size_t old_size = 0; -+ size_t i = 0; -+ defs_block_io_device_throttle **throttle_read_iops_device = NULL; -+ -+ ret = make_sure_oci_spec_linux_resources_blkio(oci_spec); -+ if (ret < 0) { -+ goto out; -+ } -+ -+ if (oci_spec->linux->resources->block_io->throttle_read_iops_device_len > -+ LIST_DEVICE_SIZE_MAX - throttle_read_iops_device_len) { -+ ERROR("Too many throttle read iops devices to merge, the limit is %lld", LIST_DEVICE_SIZE_MAX); -+ isulad_set_error_message("Too many throttle read iops devices devices to merge, the limit is %d", -+ LIST_DEVICE_SIZE_MAX); -+ ret = -1; -+ goto out; -+ } -+ -+ new_size = (oci_spec->linux->resources->block_io->throttle_read_iops_device_len + throttle_read_iops_device_len) * -+ sizeof(defs_block_io_device_throttle *); -+ old_size = oci_spec->linux->resources->block_io->throttle_read_iops_device_len * -+ sizeof(defs_block_io_device_throttle *); -+ ret = util_mem_realloc((void **)&throttle_read_iops_device, new_size, -+ oci_spec->linux->resources->block_io->throttle_read_iops_device, old_size); -+ if (ret != 0) { -+ ERROR("Failed to realloc memory for blkio throttle read iops devices"); -+ ret = -1; -+ goto out; -+ } -+ oci_spec->linux->resources->block_io->throttle_read_iops_device = throttle_read_iops_device; -+ -+ for (i = 0; i < throttle_read_iops_device_len; i++) { -+ ret = merge_host_config_blk_device( -+ &oci_spec->linux->resources->block_io -+ ->throttle_read_iops_device[oci_spec->linux->resources->block_io->throttle_read_iops_device_len], -+ blkio_read_iops_device[i]); -+ if (ret != 0) { -+ ERROR("Failed to merge blkio throttle read iops device"); -+ ret = -1; -+ goto out; -+ } -+ oci_spec->linux->resources->block_io->throttle_read_iops_device_len++; -+ } -+ -+out: -+ return ret; -+} -+ -+static int merge_blkio_write_iops_device(oci_runtime_spec *oci_spec, defs_blkio_device **blkio_write_iops_device, -+ size_t throttle_write_iops_device_len) -+{ -+ int ret = 0; -+ size_t new_size = 0; -+ size_t old_size = 0; -+ size_t i = 0; -+ defs_block_io_device_throttle **throttle_write_iops_device = NULL; -+ -+ ret = make_sure_oci_spec_linux_resources_blkio(oci_spec); -+ if (ret < 0) { -+ goto out; -+ } -+ -+ if (oci_spec->linux->resources->block_io->throttle_write_iops_device_len > -+ LIST_DEVICE_SIZE_MAX - throttle_write_iops_device_len) { -+ ERROR("Too many throttle write iops devices to merge, the limit is %lld", LIST_DEVICE_SIZE_MAX); -+ isulad_set_error_message("Too many throttle write iops devices devices to merge, the limit is %d", -+ LIST_DEVICE_SIZE_MAX); -+ ret = -1; -+ goto out; -+ } -+ -+ new_size = (oci_spec->linux->resources->block_io->throttle_write_iops_device_len + throttle_write_iops_device_len) * -+ sizeof(defs_block_io_device_throttle *); -+ old_size = oci_spec->linux->resources->block_io->throttle_write_iops_device_len * -+ sizeof(defs_block_io_device_throttle *); -+ ret = util_mem_realloc((void **)&throttle_write_iops_device, new_size, -+ oci_spec->linux->resources->block_io->throttle_write_iops_device, old_size); -+ if (ret != 0) { -+ ERROR("Failed to realloc memory for throttle write iops devices"); -+ ret = -1; -+ goto out; -+ } -+ oci_spec->linux->resources->block_io->throttle_write_iops_device = throttle_write_iops_device; -+ -+ for (i = 0; i < throttle_write_iops_device_len; i++) { -+ ret = merge_host_config_blk_device( -+ &oci_spec->linux->resources->block_io->throttle_write_iops_device -+ [oci_spec->linux->resources->block_io->throttle_write_iops_device_len], -+ blkio_write_iops_device[i]); -+ if (ret != 0) { -+ ERROR("Failed to merge blkio throttle write iops device"); -+ ret = -1; -+ goto out; -+ } -+ oci_spec->linux->resources->block_io->throttle_write_iops_device_len++; -+ } -+ -+out: -+ return ret; -+} -+ -+static int merge_conf_populate_device(oci_runtime_spec *oci_spec, host_config *host_spec) -+{ -+ int ret = 0; -+ -+ if (host_spec->privileged) { -+ INFO("Skipped \"--device\" due to conflict with \"--privileged\""); -+ return 0; -+ } -+ -+ if (host_spec->devices != NULL && host_spec->devices_len != 0) { -+ /* privileged containers will populate all devices in host */ -+ ret = merge_custom_devices(oci_spec, host_spec->devices, host_spec->devices_len); -+ if (ret != 0) { -+ ERROR("Failed to merge custom devices"); -+ goto out; -+ } -+ } -+out: -+ return ret; -+} -+ -+/* format example: b 7:* rmw */ -+static int parse_device_cgroup_rule(defs_device_cgroup *spec_dev_cgroup, const char *rule) -+{ -+ int ret = 0; -+ char **parts = NULL; -+ size_t parts_len = 0; -+ char **file_mode = NULL; -+ size_t file_mode_len = 0; -+ -+ if (rule == NULL || spec_dev_cgroup == NULL) { -+ return -1; -+ } -+ -+ parts = util_string_split(rule, ' '); -+ if (parts == NULL) { -+ ERROR("Failed to split rule %s", rule); -+ ret = -1; -+ goto free_out; -+ } -+ -+ parts_len = util_array_len((const char **)parts); -+ if (parts_len != 3) { -+ ERROR("Invalid rule %s", rule); -+ ret = -1; -+ goto free_out; -+ } -+ -+ /* fill spec cgroup dev */ -+ spec_dev_cgroup->allow = true; -+ spec_dev_cgroup->access = util_strdup_s(parts[2]); -+ spec_dev_cgroup->type = util_strdup_s(parts[0]); -+ -+ file_mode = util_string_split(parts[1], ':'); -+ if (file_mode == NULL) { -+ ERROR("Invalid rule mode %s", parts[1]); -+ ret = -1; -+ goto free_out; -+ } -+ -+ file_mode_len = util_array_len((const char **)file_mode); -+ if (file_mode_len != 2) { -+ ERROR("Invalid rule mode %s", parts[1]); -+ ret = -1; -+ goto free_out; -+ } -+ -+ if (strcmp(file_mode[0], "*") == 0) { -+ spec_dev_cgroup->major = -1; -+ } else { -+ if (util_safe_llong(file_mode[0], (long long *)&spec_dev_cgroup->major) != 0) { -+ ERROR("Invalid rule mode %s", file_mode[0]); -+ ret = -1; -+ goto free_out; -+ } -+ } -+ -+ if (strcmp(file_mode[1], "*") == 0) { -+ spec_dev_cgroup->minor = -1; -+ } else { -+ if (util_safe_llong(file_mode[1], (long long *)&spec_dev_cgroup->minor) != 0) { -+ ERROR("Invalid rule mode %s", file_mode[1]); -+ ret = -1; -+ goto free_out; -+ } -+ } -+ -+free_out: -+ util_free_array(parts); -+ util_free_array(file_mode); -+ -+ return ret; -+} -+ -+static int make_device_cgroup_rule(defs_device_cgroup **out_spec_dev_cgroup, const char *dev_cgroup_rule) -+{ -+ int ret = 0; -+ defs_device_cgroup *spec_dev_cgroup = NULL; -+ -+ spec_dev_cgroup = util_common_calloc_s(sizeof(defs_device_cgroup)); -+ if (spec_dev_cgroup == NULL) { -+ ERROR("Memory out"); -+ ret = -1; -+ goto erro_out; -+ } -+ -+ ret = parse_device_cgroup_rule(spec_dev_cgroup, dev_cgroup_rule); -+ if (ret != 0) { -+ ERROR("Failed to parse device cgroup rule %s", dev_cgroup_rule); -+ ret = -1; -+ goto erro_out; -+ } -+ -+ *out_spec_dev_cgroup = spec_dev_cgroup; -+ goto out; -+ -+erro_out: -+ free_defs_device_cgroup(spec_dev_cgroup); -+out: -+ return ret; -+} -+ -+static int do_merge_device_cgroup_rules(oci_runtime_spec *oci_spec, const char **dev_cgroup_rules, -+ size_t dev_cgroup_rules_len) -+{ -+ int ret = 0; -+ size_t new_size = 0, old_size = 0; -+ size_t i = 0; -+ -+ ret = make_sure_oci_spec_linux_resources(oci_spec); -+ if (ret < 0) { -+ goto out; -+ } -+ -+ /* malloc for cgroup->device */ -+ defs_device_cgroup **spec_cgroup_dev = NULL; -+ if (dev_cgroup_rules_len > SIZE_MAX / sizeof(defs_device_cgroup *) - oci_spec->linux->resources->devices_len) { -+ ERROR("Too many cgroup devices to merge!"); -+ ret = -1; -+ goto out; -+ } -+ new_size = (oci_spec->linux->resources->devices_len + dev_cgroup_rules_len) * sizeof(defs_device_cgroup *); -+ old_size = oci_spec->linux->resources->devices_len * sizeof(defs_device_cgroup *); -+ ret = util_mem_realloc((void **)&spec_cgroup_dev, new_size, oci_spec->linux->resources->devices, old_size); -+ if (ret != 0) { -+ ERROR("Out of memory"); -+ ret = -1; -+ goto out; -+ } -+ oci_spec->linux->resources->devices = spec_cgroup_dev; -+ -+ for (i = 0; i < dev_cgroup_rules_len; i++) { -+ ret = make_device_cgroup_rule(&oci_spec->linux->resources->devices[oci_spec->linux->resources->devices_len], -+ dev_cgroup_rules[i]); -+ if (ret != 0) { -+ ERROR("Failed to merge custom device"); -+ ret = -1; -+ goto out; -+ } -+ oci_spec->linux->resources->devices_len++; -+ } -+out: -+ return ret; -+} -+ -+static int merge_conf_device_cgroup_rule(oci_runtime_spec *oci_spec, host_config *host_spec) -+{ -+ int ret = 0; -+ -+ if (host_spec->privileged) { -+ INFO("Skipped \"--device-cgroup-rule\" due to conflict with \"--privileged\""); -+ return 0; -+ } -+ -+ if (host_spec->device_cgroup_rules == NULL || host_spec->device_cgroup_rules_len == 0) { -+ return 0; -+ } -+ -+ ret = do_merge_device_cgroup_rules(oci_spec, (const char **)host_spec->device_cgroup_rules, -+ host_spec->device_cgroup_rules_len); -+ if (ret != 0) { -+ ERROR("Failed to merge custom devices cgroup rules"); -+ goto out; -+ } -+out: -+ return ret; -+} -+ - int merge_conf_device(oci_runtime_spec *oci_spec, host_config *host_spec) - { - int ret = 0; -@@ -1774,20 +2024,38 @@ int merge_conf_device(oci_runtime_spec *oci_spec, host_config *host_spec) - } - } - -- /* devices which will be populated into container */ -- if (host_spec->devices != NULL && host_spec->devices_len != 0) { -- /* privileged containers will populate all devices in host */ -- if (!host_spec->privileged) { -- ret = merge_custom_devices(oci_spec, host_spec->devices, host_spec->devices_len); -- if (ret != 0) { -- ERROR("Failed to merge custom devices"); -- goto out; -- } -- } else { -- INFO("Skipped \"--device\" due to conflict with \"--privileged\""); -+ /* blkio throttle read iops devices */ -+ if (host_spec->blkio_device_read_iops != NULL && host_spec->blkio_device_read_iops_len != 0) { -+ ret = merge_blkio_read_iops_device(oci_spec, host_spec->blkio_device_read_iops, -+ host_spec->blkio_device_read_iops_len); -+ if (ret != 0) { -+ ERROR("Failed to merge blkio read iops devices"); -+ goto out; - } - } - -+ /* blkio throttle write iops devices */ -+ if (host_spec->blkio_device_write_iops != NULL && host_spec->blkio_device_write_iops_len != 0) { -+ ret = merge_blkio_write_iops_device(oci_spec, host_spec->blkio_device_write_iops, -+ host_spec->blkio_device_write_iops_len); -+ if (ret != 0) { -+ ERROR("Failed to merge blkio write iops devices"); -+ goto out; -+ } -+ } -+ -+ /* devices which will be populated into container */ -+ if (merge_conf_populate_device(oci_spec, host_spec)) { -+ ret = -1; -+ goto out; -+ } -+ -+ /* device cgroup rules which will be added into container */ -+ if (merge_conf_device_cgroup_rule(oci_spec, host_spec)) { -+ ret = -1; -+ goto out; -+ } -+ - out: - return ret; - } -@@ -1801,8 +2069,8 @@ static bool mounts_expand(oci_runtime_spec *container, size_t add_len) - ERROR("Too many mount elements!"); - return false; - } -- ret = mem_realloc((void **)&tmp_mount, (old_len + add_len) * sizeof(defs_mount *), container->mounts, -- old_len * sizeof(defs_mount *)); -+ ret = util_mem_realloc((void **)&tmp_mount, (old_len + add_len) * sizeof(defs_mount *), container->mounts, -+ old_len * sizeof(defs_mount *)); - if (ret < 0) { - ERROR("memory realloc failed for mount array expand"); - return false; -@@ -1920,7 +2188,7 @@ static int change_dev_shm_size(oci_runtime_spec *oci_spec, host_config *host_spe - char size_opt[MOUNT_PROPERTIES_SIZE] = { 0 }; - char *tmp = NULL; - -- if (is_none(host_spec->ipc_mode)) { -+ if (namespace_is_none(host_spec->ipc_mode)) { - return 0; - } - -@@ -1982,7 +2250,9 @@ static int append_network_files_mounts(oci_runtime_spec *oci_spec, host_config * - bool has_hosts_mount = false; - bool has_resolv_mount = false; - bool has_hostname_mount = false; -- bool share = is_container(host_spec->network_mode); -+#ifdef ENABLE_SELINUX -+ bool share = namespace_is_container(host_spec->network_mode); -+#endif - - for (i = 0; i < oci_spec->mounts_len; i++) { - if (is_mount_destination_hosts(oci_spec->mounts[i]->destination)) { -@@ -2007,11 +2277,13 @@ static int append_network_files_mounts(oci_runtime_spec *oci_spec, host_config * - } else { - /* add network config files */ - if (!has_hosts_mount) { -+#ifdef ENABLE_SELINUX - if (relabel(v2_spec->hosts_path, v2_spec->mount_label, share) != 0) { - ERROR("Error to relabel hosts path: %s", v2_spec->hosts_path); - ret = -1; - goto out; - } -+#endif - if (!mount_file(oci_spec, v2_spec->hosts_path, ETC_HOSTS)) { - ERROR("Merge hosts mount failed"); - ret = -1; -@@ -2023,11 +2295,13 @@ static int append_network_files_mounts(oci_runtime_spec *oci_spec, host_config * - WARN("ResolvConfPath set to %s, but can't stat this filename skipping", v2_spec->resolv_conf_path); - } else { - if (!has_resolv_mount) { -+#ifdef ENABLE_SELINUX - if (relabel(v2_spec->resolv_conf_path, v2_spec->mount_label, share) != 0) { - ERROR("Error to relabel resolv.conf path: %s", v2_spec->resolv_conf_path); - ret = -1; - goto out; - } -+#endif - if (!mount_file(oci_spec, v2_spec->resolv_conf_path, RESOLV_CONF_PATH)) { - ERROR("Merge resolv.conf mount failed"); - ret = -1; -@@ -2040,10 +2314,12 @@ static int append_network_files_mounts(oci_runtime_spec *oci_spec, host_config * - WARN("HostnamePath set to %s, but can't stat this filename; skipping", v2_spec->resolv_conf_path); - } else { - if (!has_hostname_mount) { -+#ifdef ENABLE_SELINUX - if (relabel(v2_spec->hostname_path, v2_spec->mount_label, share) != 0) { - ERROR("Error to relabel hostname path: %s", v2_spec->hostname_path); - return -1; - } -+#endif - if (!mount_file(oci_spec, v2_spec->hostname_path, ETC_HOSTNAME)) { - ERROR("Merge hostname mount failed"); - ret = -1; -@@ -2263,12 +2539,12 @@ static int setup_ipc_dirs(oci_runtime_spec *oci_spec, host_config *host_spec, - return 0; - } - // setup shareable dirs -- if (host_spec->ipc_mode == NULL || is_shareable(host_spec->ipc_mode)) { -+ if (host_spec->ipc_mode == NULL || namespace_is_shareable(host_spec->ipc_mode)) { - return prepare_share_shm(oci_spec, host_spec, v2_spec); - } - -- if (is_container(host_spec->ipc_mode)) { -- tmp_cid = connected_container(host_spec->ipc_mode); -+ if (namespace_is_container(host_spec->ipc_mode)) { -+ tmp_cid = namespace_get_connected_container(host_spec->ipc_mode); - cont = containers_store_get(tmp_cid); - if (cont == NULL) { - ERROR("Invalid share path: %s", host_spec->ipc_mode); -@@ -2277,7 +2553,7 @@ static int setup_ipc_dirs(oci_runtime_spec *oci_spec, host_config *host_spec, - } - right_path = util_strdup_s(cont->common_config->shm_path); - container_unref(cont); -- } else if (is_host(host_spec->ipc_mode)) { -+ } else if (namespace_is_host(host_spec->ipc_mode)) { - if (!util_file_exists(SHM_MOUNT_POINT)) { - ERROR("/dev/shm is not mounted, but must be for --ipc=host"); - ret = -1; -diff --git a/src/daemon/modules/spec/specs_namespace.c b/src/daemon/modules/spec/specs_namespace.c -index 7364617..e291f09 100644 ---- a/src/daemon/modules/spec/specs_namespace.c -+++ b/src/daemon/modules/spec/specs_namespace.c -@@ -37,7 +37,7 @@ static char *parse_share_namespace_with_prefix(const char *type, const char *pat - char ns_path[PATH_MAX] = { 0 }; - char *ns_type = NULL; - -- tmp_cid = connected_container(path); -+ tmp_cid = namespace_get_connected_container(path); - if (tmp_cid == NULL) { - goto out; - } -@@ -96,14 +96,14 @@ int get_share_namespace_path(const char *type, const char *src_path, char **dest - return -1; - } - -- if (is_none(src_path)) { -+ if (namespace_is_none(src_path)) { - *dest_path = NULL; -- } else if (is_host(src_path)) { -- *dest_path = get_host_namespace_path(type); -+ } else if (namespace_is_host(src_path)) { -+ *dest_path = namespace_get_host_namespace_path(type); - if (*dest_path == NULL) { - ret = -1; - } -- } else if (is_container(src_path)) { -+ } else if (namespace_is_container(src_path)) { - *dest_path = parse_share_namespace_with_prefix(type, src_path); - if (*dest_path == NULL) { - ret = -1; -diff --git a/src/daemon/modules/spec/specs_security.c b/src/daemon/modules/spec/specs_security.c -index 3273b31..c90d193 100644 ---- a/src/daemon/modules/spec/specs_security.c -+++ b/src/daemon/modules/spec/specs_security.c -@@ -58,7 +58,8 @@ static int append_capability(char ***dstcaps, size_t *dstcaps_len, const char *c - ret = -1; - goto out; - } -- ret = mem_realloc((void **)&tmp, sizeof(char *) * (*dstcaps_len + 1), *dstcaps, sizeof(char *) * (*dstcaps_len)); -+ ret = util_mem_realloc((void **)&tmp, sizeof(char *) * (*dstcaps_len + 1), *dstcaps, -+ sizeof(char *) * (*dstcaps_len)); - if (ret != 0) { - ERROR("Out of memory"); - ret = -1; -@@ -108,7 +109,7 @@ static int tweak_drops_capabilities(char ***new_caps, size_t *new_caps_len, char - size_t i = 0; - int ret = 0; - -- if (strings_in_slice((const char **)drops, drops_len, "all")) { -+ if (util_strings_in_slice((const char **)drops, drops_len, "all")) { - goto out; - } - -@@ -119,7 +120,7 @@ static int tweak_drops_capabilities(char ***new_caps, size_t *new_caps_len, char - } - - // if we don't drop `all`, add back all the non-dropped caps -- if (!strings_in_slice((const char **)drops, drops_len, basic_caps[i] + strlen("CAP_"))) { -+ if (!util_strings_in_slice((const char **)drops, drops_len, basic_caps[i] + strlen("CAP_"))) { - ret = append_capability(new_caps, new_caps_len, basic_caps[i]); - if (ret != 0) { - ERROR("Failed to append capabilities"); -@@ -155,14 +156,14 @@ static int tweak_adds_capabilities(char ***new_caps, size_t *new_caps_len, const - ret = -1; - goto out; - } -- if (!strings_in_slice(g_all_caps, all_caps_len, tmpcap)) { -+ if (!util_strings_in_slice(g_all_caps, all_caps_len, tmpcap)) { - ERROR("Unknown capability to add: '%s'", tmpcap); - ret = -1; - goto out; - } - - // add cap if not already in the list -- if (!strings_in_slice((const char **)*new_caps, *new_caps_len, tmpcap)) { -+ if (!util_strings_in_slice((const char **)*new_caps, *new_caps_len, tmpcap)) { - ret = append_capability(new_caps, new_caps_len, tmpcap); - if (ret != 0) { - ERROR("Failed to append capabilities"); -@@ -195,7 +196,7 @@ static bool valid_drops_cap(const char **drops, size_t drops_len) - ERROR("Failed to print string"); - return false; - } -- if (!strings_in_slice(g_all_caps, all_caps_len, tmpcap)) { -+ if (!util_strings_in_slice(g_all_caps, all_caps_len, tmpcap)) { - ERROR("Unknown capability to drop: '%s'", drops[i]); - return false; - } -@@ -222,7 +223,7 @@ static int tweak_capabilities(char ***caps, size_t *caps_len, const char **adds, - return -1; - } - -- if (strings_in_slice((const char **)adds, adds_len, "all")) { -+ if (util_strings_in_slice((const char **)adds, adds_len, "all")) { - ret = copy_capabilities(&basic_caps, &basic_caps_len, g_all_caps, all_caps_len); - } else { - ret = copy_capabilities(&basic_caps, &basic_caps_len, (const char **)*caps, *caps_len); -@@ -361,16 +362,16 @@ static bool is_arch_in_seccomp(const docker_seccomp *seccomp, const char *arch) - return false; - } - --static bool is_cap_in_seccomp(const defs_process_capabilities *capabilites, const char *cap) -+static bool is_cap_in_seccomp(const defs_process_capabilities *capabilities, const char *cap) - { - size_t i = 0; - -- if (capabilites == NULL) { -+ if (capabilities == NULL) { - return false; - } - -- for (i = 0; i < capabilites->bounding_len; i++) { -- if (strcasecmp(capabilites->bounding[i], cap) == 0) { -+ for (i = 0; i < capabilities->bounding_len; i++) { -+ if (strcasecmp(capabilities->bounding[i], cap) == 0) { - return true; - } - } -@@ -378,7 +379,7 @@ static bool is_cap_in_seccomp(const defs_process_capabilities *capabilites, cons - } - - static void meet_include(const docker_seccomp *seccomp, const docker_seccomp_syscalls_element *syscall, -- const defs_process_capabilities *capabilites, bool *meet_include_arch, bool *meet_include_cap) -+ const defs_process_capabilities *capabilities, bool *meet_include_arch, bool *meet_include_cap) - { - size_t i; - -@@ -401,7 +402,7 @@ static void meet_include(const docker_seccomp *seccomp, const docker_seccomp_sys - *meet_include_cap = true; - } else { - for (i = 0; i < syscall->includes->caps_len; i++) { -- if (is_cap_in_seccomp(capabilites, syscall->includes->caps[i])) { -+ if (is_cap_in_seccomp(capabilities, syscall->includes->caps[i])) { - *meet_include_cap = true; - break; - } -@@ -410,7 +411,7 @@ static void meet_include(const docker_seccomp *seccomp, const docker_seccomp_sys - } - - static void meet_exclude(const docker_seccomp *seccomp, const docker_seccomp_syscalls_element *syscall, -- const defs_process_capabilities *capabilites, bool *meet_exclude_arch, bool *meet_exclude_cap) -+ const defs_process_capabilities *capabilities, bool *meet_exclude_arch, bool *meet_exclude_cap) - { - size_t i; - -@@ -434,7 +435,7 @@ static void meet_exclude(const docker_seccomp *seccomp, const docker_seccomp_sys - *meet_exclude_cap = true; - } else { - for (i = 0; i < syscall->excludes->caps_len; i++) { -- if (is_cap_in_seccomp(capabilites, syscall->excludes->caps[i])) { -+ if (is_cap_in_seccomp(capabilities, syscall->excludes->caps[i])) { - *meet_exclude_cap = false; - break; - } -@@ -443,15 +444,15 @@ static void meet_exclude(const docker_seccomp *seccomp, const docker_seccomp_sys - } - - static bool meet_filtering_rules(const docker_seccomp *seccomp, const docker_seccomp_syscalls_element *syscall, -- const defs_process_capabilities *capabilites) -+ const defs_process_capabilities *capabilities) - { - bool meet_include_arch = false; - bool meet_include_cap = false; - bool meet_exclude_arch = true; - bool meet_exclude_cap = true; - -- meet_include(seccomp, syscall, capabilites, &meet_include_arch, &meet_include_cap); -- meet_exclude(seccomp, syscall, capabilites, &meet_exclude_arch, &meet_exclude_cap); -+ meet_include(seccomp, syscall, capabilities, &meet_include_arch, &meet_include_cap); -+ meet_exclude(seccomp, syscall, capabilities, &meet_exclude_arch, &meet_exclude_cap); - - return meet_include_arch && meet_include_cap && meet_exclude_arch && meet_exclude_cap; - } -@@ -530,7 +531,7 @@ static int dup_syscall_args_to_oci_spec(const docker_seccomp_syscalls_element *d - - static int dup_syscall_to_oci_spec(const docker_seccomp *docker_seccomp_spec, - oci_runtime_config_linux_seccomp *oci_seccomp_spec, -- const defs_process_capabilities *capabilites) -+ const defs_process_capabilities *capabilities) - { - int ret = 0; - size_t i, j, k; -@@ -550,7 +551,7 @@ static int dup_syscall_to_oci_spec(const docker_seccomp *docker_seccomp_spec, - return -1; - } - for (i = 0; i < docker_seccomp_spec->syscalls_len; i++) { -- if (!meet_filtering_rules(docker_seccomp_spec, docker_seccomp_spec->syscalls[i], capabilites)) { -+ if (!meet_filtering_rules(docker_seccomp_spec, docker_seccomp_spec->syscalls[i], capabilities)) { - continue; - } - k = oci_seccomp_spec->syscalls_len; -@@ -581,7 +582,7 @@ static int dup_syscall_to_oci_spec(const docker_seccomp *docker_seccomp_spec, - - new_size = sizeof(defs_syscall *) * oci_seccomp_spec->syscalls_len; - old_size = sizeof(defs_syscall *) * docker_seccomp_spec->syscalls_len; -- ret = mem_realloc((void **)&tmp_syscalls, new_size, oci_seccomp_spec->syscalls, old_size); -+ ret = util_mem_realloc((void **)&tmp_syscalls, new_size, oci_seccomp_spec->syscalls, old_size); - if (ret < 0) { - ERROR("Out of memory"); - return -1; -@@ -593,7 +594,7 @@ static int dup_syscall_to_oci_spec(const docker_seccomp *docker_seccomp_spec, - - static oci_runtime_config_linux_seccomp * - trans_docker_seccomp_to_oci_format(const docker_seccomp *docker_seccomp_spec, -- const defs_process_capabilities *capabilites) -+ const defs_process_capabilities *capabilities) - { - oci_runtime_config_linux_seccomp *oci_seccomp_spec = NULL; - -@@ -611,7 +612,7 @@ trans_docker_seccomp_to_oci_format(const docker_seccomp *docker_seccomp_spec, - } - - // syscalls -- if (dup_syscall_to_oci_spec(docker_seccomp_spec, oci_seccomp_spec, capabilites)) { -+ if (dup_syscall_to_oci_spec(docker_seccomp_spec, oci_seccomp_spec, capabilities)) { - goto out; - } - -@@ -626,7 +627,7 @@ done: - return oci_seccomp_spec; - } - --int merge_default_seccomp_spec(oci_runtime_spec *oci_spec, const defs_process_capabilities *capabilites) -+int merge_default_seccomp_spec(oci_runtime_spec *oci_spec, const defs_process_capabilities *capabilities) - { - oci_runtime_config_linux_seccomp *oci_seccomp_spec = NULL; - docker_seccomp *docker_seccomp_spec = NULL; -@@ -641,7 +642,7 @@ int merge_default_seccomp_spec(oci_runtime_spec *oci_spec, const defs_process_ca - isulad_set_error_message("failed to parse seccomp file: %s", SECCOMP_DEFAULT_PATH); - return -1; - } -- oci_seccomp_spec = trans_docker_seccomp_to_oci_format(docker_seccomp_spec, capabilites); -+ oci_seccomp_spec = trans_docker_seccomp_to_oci_format(docker_seccomp_spec, capabilities); - free_docker_seccomp(docker_seccomp_spec); - if (oci_seccomp_spec == NULL) { - ERROR("Failed to trans docker format seccomp profile to oci standard"); -@@ -669,7 +670,7 @@ static int append_systemcall_to_seccomp(oci_runtime_config_linux_seccomp *seccom - } - new_size = (seccomp->syscalls_len + 1) * sizeof(defs_syscall *); - old_size = new_size - sizeof(defs_syscall *); -- nret = mem_realloc((void **)&tmp_syscalls, new_size, seccomp->syscalls, old_size); -+ nret = util_mem_realloc((void **)&tmp_syscalls, new_size, seccomp->syscalls, old_size); - if (nret < 0) { - CRIT("Memory allocation error."); - return -1; -@@ -849,6 +850,7 @@ out: - return ret; - } - -+#ifdef ENABLE_SELINUX - int merge_selinux(oci_runtime_spec *oci_spec, container_config_v2_common_config *v2_spec) - { - if (make_sure_oci_spec_process(oci_spec) < 0) { -@@ -860,6 +862,7 @@ int merge_selinux(oci_runtime_spec *oci_spec, container_config_v2_common_config - - return 0; - } -+#endif - - static int get_adds_cap_for_system_container(const host_config *host_spec, char ***adds, size_t *adds_len) - { -@@ -880,7 +883,7 @@ static int get_adds_cap_for_system_container(const host_config *host_spec, char - - // if cap_drop in g_system_caps, move it from g_system_caps - for (i = 0; i < system_caps_len; i++) { -- if (!strings_in_slice((const char **)drops, drops_len, g_system_caps[i])) { -+ if (!util_strings_in_slice((const char **)drops, drops_len, g_system_caps[i])) { - ret = append_capability(adds, adds_len, g_system_caps[i]); - if (ret != 0) { - ERROR("Failed to append capabilities"); -diff --git a/src/daemon/modules/spec/specs_security.h b/src/daemon/modules/spec/specs_security.h -index 5131d7f..f33814d 100644 ---- a/src/daemon/modules/spec/specs_security.h -+++ b/src/daemon/modules/spec/specs_security.h -@@ -25,13 +25,15 @@ - #include "isula_libutils/container_config_v2.h" - #include "isula_libutils/oci_runtime_spec.h" - --int merge_default_seccomp_spec(oci_runtime_spec *oci_spec, const defs_process_capabilities *capabilites); -+int merge_default_seccomp_spec(oci_runtime_spec *oci_spec, const defs_process_capabilities *capabilities); - int merge_caps(oci_runtime_spec *oci_spec, const char **adds, size_t adds_len, const char **drops, size_t drops_len); - int refill_oci_process_capabilities(defs_process_capabilities **caps, const char **src_caps, size_t src_caps_len); - int merge_sysctls(oci_runtime_spec *oci_spec, const json_map_string_string *sysctls); - int merge_no_new_privileges(oci_runtime_spec *oci_spec, bool value); - int adapt_settings_for_system_container(oci_runtime_spec *oci_spec, const host_config *host_spec); - int merge_seccomp(oci_runtime_spec *oci_spec, const char *seccomp_profile); -+#ifdef ENABLE_SELINUX - int merge_selinux(oci_runtime_spec *oci_spec, container_config_v2_common_config *v2_spec); -+#endif - - #endif -diff --git a/src/daemon/modules/spec/verify.c b/src/daemon/modules/spec/verify.c -index b257def..ac7f277 100644 ---- a/src/daemon/modules/spec/verify.c -+++ b/src/daemon/modules/spec/verify.c -@@ -765,37 +765,12 @@ out: - return ret; - } - --static inline bool is_hostconfig_blkio_weight_invalid(uint16_t weight) --{ -- return weight > 0 && (weight < 10 || weight > 1000); --} -- --/* verify hostconfig blkio weight */ --static int verify_hostconfig_blkio_weight(const sysinfo_t *sysinfo, uint16_t weight) --{ -- int ret = 0; -- -- if (weight > 0 && !(sysinfo->blkioinfo.blkio_weight)) { -- ERROR("Your kernel does not support Block I/O weight. Weight in host config discarded."); -- isulad_set_error_message("Your kernel does not support Block I/O weight. Weight in host config discarded."); -- ret = -1; -- goto out; -- } -- if (is_hostconfig_blkio_weight_invalid(weight)) { -- ERROR("Range of blkio weight is from 10 to 1000."); -- isulad_set_error_message("Range of blkio weight is from 10 to 1000."); -- ret = -1; -- goto out; -- } -- --out: -- return ret; --} -- - /* verify blkio device */ --static int verify_blkio_device(const sysinfo_t *sysinfo, size_t weight_device_len) -+static int verify_blkio_device(const sysinfo_t *sysinfo, const defs_block_io_device_weight **weight_device, -+ size_t weight_device_len) - { - int ret = 0; -+ size_t i = 0; - - if (weight_device_len > 0 && !(sysinfo->blkioinfo.blkio_weight_device)) { - ERROR("Your kernel does not support Block I/O weight_device."); -@@ -803,6 +778,16 @@ static int verify_blkio_device(const sysinfo_t *sysinfo, size_t weight_device_le - ret = -1; - } - -+ for (i = 0; i < weight_device_len; i++) { -+ if (is_blkio_weight_invalid(weight_device[i]->weight)) { -+ ERROR("Range of blkio weight is from 10 to 1000."); -+ isulad_set_error_message("Range of blkio weight is from 10 to 1000."); -+ ret = -1; -+ goto out; -+ } -+ } -+ -+out: - return ret; - } - -@@ -929,7 +914,8 @@ static int verify_resources_blkio(const sysinfo_t *sysinfo, const defs_resources - goto out; - } - -- ret = verify_blkio_device(sysinfo, blkio->weight_device_len); -+ ret = verify_blkio_device(sysinfo, (const defs_block_io_device_weight **)blkio->weight_device, -+ blkio->weight_device_len); - if (ret != 0) { - goto out; - } -@@ -1028,7 +1014,7 @@ static int verify_resources_hugetlbs(const sysinfo_t *sysinfo, defs_resources_hu - } - newsize = sizeof(defs_resources_hugepage_limits_element *) * (newlen + 1); - oldsize = newsize - sizeof(defs_resources_hugepage_limits_element *); -- ret = mem_realloc((void **)&tmphugetlb, newsize, newhugetlb, oldsize); -+ ret = util_mem_realloc((void **)&tmphugetlb, newsize, newhugetlb, oldsize); - if (ret < 0) { - free(pagesize); - ERROR("Out of memory"); -@@ -1147,7 +1133,7 @@ static bool verify_oci_linux_sysctl(const oci_runtime_config_linux *l) - } - for (i = 0; i < l->sysctl->len; i++) { - if (strcmp("kernel.pid_max", l->sysctl->keys[i]) == 0) { -- if (!pid_max_kernel_namespaced()) { -+ if (!util_check_pid_max_kernel_namespaced()) { - isulad_set_error_message("Sysctl '%s' is not kernel namespaced, it cannot be changed", - l->sysctl->keys[i]); - return false; -@@ -1155,7 +1141,7 @@ static bool verify_oci_linux_sysctl(const oci_runtime_config_linux *l) - return true; - } - } -- if (!check_sysctl_valid(l->sysctl->keys[i])) { -+ if (!util_valid_sysctl(l->sysctl->keys[i])) { - isulad_set_error_message("Sysctl %s=%s is not whitelist", l->sysctl->keys[i], l->sysctl->values[i]); - return false; - } -@@ -1484,7 +1470,7 @@ static int verify_process_env(const defs_process *process) - char *new_env = NULL; - - for (i = 0; i < process->env_len; i++) { -- if (util_validate_env(process->env[i], &new_env) != 0) { -+ if (util_valid_env(process->env[i], &new_env) != 0) { - ERROR("Invalid environment %s", process->env[i]); - isulad_set_error_message("Invalid environment %s", process->env[i]); - ret = -1; -@@ -1619,7 +1605,7 @@ static int append_hugetlb_array(host_config_hugetlbs_element ***hugetlb, size_t - - newsize = sizeof(host_config_hugetlbs_element *) * (len + 1); - oldsize = newsize - sizeof(host_config_hugetlbs_element *); -- ret = mem_realloc((void **)&tmphugetlb, newsize, *hugetlb, oldsize); -+ ret = util_mem_realloc((void **)&tmphugetlb, newsize, *hugetlb, oldsize); - if (ret < 0) { - return -1; - } -@@ -1738,10 +1724,58 @@ out: - return ret; - } - -+static int verify_nano_cpus(const sysinfo_t *sysinfo, const host_config *hostconfig) -+{ -+ int ret = 0; -+ -+ if (hostconfig->nano_cpus == 0) { -+ return 0; -+ } -+ -+ if (hostconfig->nano_cpus > 0 && hostconfig->cpu_period > 0) { -+ ERROR("Conflicting options: Nano CPUs and CPU Period cannot both be set."); -+ isulad_set_error_message("Conflicting options: Nano CPUs and CPU Period cannot both be set."); -+ ret = -1; -+ goto out; -+ } -+ -+ if (hostconfig->nano_cpus > 0 && hostconfig->cpu_quota > 0) { -+ ERROR("Conflicting options: Nano CPUs and CPU Quota cannot both be set."); -+ isulad_set_error_message("Conflicting options: Nano CPUs and CPU Quota cannot both be set."); -+ ret = -1; -+ goto out; -+ } -+ -+ if (hostconfig->nano_cpus > 0 && (!(sysinfo->cgcpuinfo.cpu_cfs_quota) || !(sysinfo->cgcpuinfo.cpu_cfs_period))) { -+ ERROR("NanoCPUs can not be set, as your kernel does not support CPU cfs period/quota or the cgroup is not mounted."); -+ isulad_set_error_message( -+ "NanoCPUs can not be set, as your kernel does not support CPU cfs period/quota or the cgroup is not mounted."); -+ ret = -1; -+ goto out; -+ } -+ -+ if (hostconfig->nano_cpus < 0 || (hostconfig->nano_cpus > (sysinfo->ncpus * 1e9))) { -+ ERROR("Range of CPUs is from 0.01 to %d.00, as there are only %d CPUs available", sysinfo->ncpus, -+ sysinfo->ncpus); -+ isulad_set_error_message("Range of CPUs is from 0.01 to %d.00, as there are only %d CPUs available", -+ sysinfo->ncpus, sysinfo->ncpus); -+ ret = -1; -+ goto out; -+ } -+ -+out: -+ return ret; -+} -+ - static int host_config_settings_cpu(const sysinfo_t *sysinfo, const host_config *hostconfig) - { - int ret = 0; - -+ ret = verify_nano_cpus(sysinfo, hostconfig); -+ if (ret != 0) { -+ goto out; -+ } -+ - ret = verify_cpu_realtime(sysinfo, hostconfig->cpu_realtime_period, hostconfig->cpu_realtime_runtime); - if (ret != 0) { - goto out; -@@ -1771,12 +1805,25 @@ static int host_config_settings_blkio(const sysinfo_t *sysinfo, const host_confi - { - int ret = 0; - -- ret = verify_hostconfig_blkio_weight(sysinfo, hostconfig->blkio_weight); -+ ret = verify_blkio_weight(sysinfo, hostconfig->blkio_weight); - if (ret != 0) { - goto out; - } - -- ret = verify_blkio_device(sysinfo, hostconfig->blkio_weight_device_len); -+ ret = verify_blkio_device(sysinfo, (const defs_block_io_device_weight **)hostconfig->blkio_weight_device, -+ hostconfig->blkio_weight_device_len); -+ if (ret != 0) { -+ goto out; -+ } -+ -+ ret = verify_blkio_rw_bps_device(sysinfo, hostconfig->blkio_device_read_bps_len, -+ hostconfig->blkio_device_write_bps_len); -+ if (ret != 0) { -+ goto out; -+ } -+ -+ ret = verify_blkio_rw_iops_device(sysinfo, hostconfig->blkio_device_read_iops_len, -+ hostconfig->blkio_device_write_iops_len); - if (ret != 0) { - goto out; - } -@@ -1904,6 +1951,25 @@ out: - return ret; - } - -+/* verify device cgroup rule */ -+static int verify_host_config_device_cgroup_rules(const host_config *hostconfig) -+{ -+ int ret = 0; -+ size_t i = 0; -+ -+ for (i = 0; i < hostconfig->device_cgroup_rules_len; i++) { -+ if (!util_valid_device_cgroup_rule(hostconfig->device_cgroup_rules[i])) { -+ ERROR("Invalid device cgroup rule %s", hostconfig->device_cgroup_rules[i]); -+ isulad_set_error_message("Invalid device cgroup rule %s", hostconfig->device_cgroup_rules[i]); -+ ret = -1; -+ goto out; -+ } -+ } -+ -+out: -+ return ret; -+} -+ - /* verify host config settings */ - int verify_host_config_settings(host_config *hostconfig, bool update) - { -@@ -1930,6 +1996,11 @@ int verify_host_config_settings(host_config *hostconfig, bool update) - goto out; - } - -+ ret = verify_host_config_device_cgroup_rules(hostconfig); -+ if (ret != 0) { -+ goto out; -+ } -+ - #ifdef ENABLE_OCI_IMAGE - // storage options - ret = verify_storage_opts(hostconfig); -@@ -1942,6 +2013,7 @@ out: - return ret; - } - -+#ifdef ENABLE_SELINUX - static int relabel_mounts_if_needed(defs_mount **mounts, size_t len, const char *mount_label) - { - int ret = 0; -@@ -1976,6 +2048,7 @@ static int relabel_mounts_if_needed(defs_mount **mounts, size_t len, const char - out: - return ret; - } -+#endif - - /* verify container settings start */ - int verify_container_settings_start(const oci_runtime_spec *oci_spec) -@@ -1989,11 +2062,13 @@ int verify_container_settings_start(const oci_runtime_spec *oci_spec) - ret = -1; - goto out; - } -+#ifdef ENABLE_SELINUX - if (relabel_mounts_if_needed(oci_spec->mounts, oci_spec->mounts_len, oci_spec->linux->mount_label) != 0) { - ERROR("Failed to relabel mount"); - ret = -1; - goto out; - } -+#endif - } - - out: -diff --git a/src/utils/cutils/map/rb_tree.c b/src/utils/cutils/map/rb_tree.c -index 30f5330..ddae064 100644 ---- a/src/utils/cutils/map/rb_tree.c -+++ b/src/utils/cutils/map/rb_tree.c -@@ -106,16 +106,16 @@ rb_tree_t *rbtree_new(key_comparator comparator, key_value_freer kvfreer) - return tree; - } - --static void rbtree_destory_all(rb_tree_t *tree, rb_node_t *node) -+static void rbtree_destroy_all(rb_tree_t *tree, rb_node_t *node) - { - if (node == tree->nil) { - return; - } - if (node->left != tree->nil) { -- rbtree_destory_all(tree, node->left); -+ rbtree_destroy_all(tree, node->left); - } - if (node->right != tree->nil) { -- rbtree_destory_all(tree, node->right); -+ rbtree_destroy_all(tree, node->right); - } - if (tree->kvfreer != NULL) { - tree->kvfreer(node->key, node->value); -@@ -128,7 +128,7 @@ void rbtree_clear(rb_tree_t *tree) - if (tree == NULL) { - return; - } -- rbtree_destory_all(tree, tree->root); -+ rbtree_destroy_all(tree, tree->root); - } - - void rbtree_free(rb_tree_t *tree) -diff --git a/src/utils/cutils/namespace.c b/src/utils/cutils/namespace.c -index 202dc55..2916c8b 100644 ---- a/src/utils/cutils/namespace.c -+++ b/src/utils/cutils/namespace.c -@@ -18,18 +18,18 @@ - - #include "utils.h" - --char *connected_container(const char *mode) -+char *namespace_get_connected_container(const char *mode) - { - const char *p = mode != NULL ? (mode + strlen(SHARE_NAMESPACE_PREFIX)) : NULL; - -- if (is_container(mode)) { -+ if (namespace_is_container(mode)) { - return util_strdup_s(p); - } - - return NULL; - } - --char *get_host_namespace_path(const char *type) -+char *namespace_get_host_namespace_path(const char *type) - { - if (type == NULL) { - return NULL; -diff --git a/src/utils/cutils/namespace.h b/src/utils/cutils/namespace.h -index 8d7e41a..cf76805 100644 ---- a/src/utils/cutils/namespace.h -+++ b/src/utils/cutils/namespace.h -@@ -58,7 +58,7 @@ typedef enum { - #define ETC_HOSTNAME "/etc/hostname" - #define RESOLV_CONF_PATH "/etc/resolv.conf" - --static inline bool is_host(const char *mode) -+static inline bool namespace_is_host(const char *mode) - { - if (mode != NULL && strcmp(mode, SHARE_NAMESPACE_HOST) == 0) { - return true; -@@ -66,7 +66,7 @@ static inline bool is_host(const char *mode) - return false; - } - --static inline bool is_none(const char *mode) -+static inline bool namespace_is_none(const char *mode) - { - if (mode != NULL && strcmp(mode, SHARE_NAMESPACE_NONE) == 0) { - return true; -@@ -74,7 +74,7 @@ static inline bool is_none(const char *mode) - return false; - } - --static inline bool is_container(const char *mode) -+static inline bool namespace_is_container(const char *mode) - { - if (mode != NULL && strncmp(mode, SHARE_NAMESPACE_PREFIX, strlen(SHARE_NAMESPACE_PREFIX)) == 0) { - return true; -@@ -82,7 +82,7 @@ static inline bool is_container(const char *mode) - return false; - } - --static inline bool is_shareable(const char *mode) -+static inline bool namespace_is_shareable(const char *mode) - { - if (mode != NULL && strcmp(mode, SHARE_NAMESPACE_SHAREABLE) == 0) { - return true; -@@ -90,8 +90,8 @@ static inline bool is_shareable(const char *mode) - return false; - } - --char *connected_container(const char *mode); --char *get_host_namespace_path(const char *type); -+char *namespace_get_connected_container(const char *mode); -+char *namespace_get_host_namespace_path(const char *type); - - #ifdef __cplusplus - } -diff --git a/src/utils/cutils/path.c b/src/utils/cutils/path.c -index 8bf9b67..533480a 100644 ---- a/src/utils/cutils/path.c -+++ b/src/utils/cutils/path.c -@@ -90,7 +90,7 @@ static int do_clean_path(const char *respath, const char *limit_respath, const c - return 0; - } - --char *cleanpath(const char *path, char *realpath, size_t realpath_len) -+char *util_clean_path(const char *path, char *realpath, size_t realpath_len) - { - char *respath = NULL; - char *dest = NULL; -@@ -168,7 +168,7 @@ static int do_path_realloc(const char *start, const char *end, char **rpath, cha - } else { - new_size += PATH_MAX; - } -- nret = mem_realloc((void **)(&new_rpath), new_size, *rpath, PATH_MAX); -+ nret = util_mem_realloc((void **)(&new_rpath), new_size, *rpath, PATH_MAX); - if (nret) { - ERROR("Failed to realloc memory for files limit variables"); - return -1; -@@ -363,7 +363,7 @@ static char *eval_symlinks_in_scope(const char *fullpath, const char *rootpath) - return NULL; - } - -- root = cleanpath(rootpath, resroot, sizeof(resroot)); -+ root = util_clean_path(rootpath, resroot, sizeof(resroot)); - if (root == NULL) { - ERROR("Failed to get cleaned path"); - return NULL; -@@ -418,20 +418,20 @@ out: - return NULL; - } - --char *follow_symlink_in_scope(const char *fullpath, const char *rootpath) -+char *util_follow_symlink_in_scope(const char *fullpath, const char *rootpath) - { - char resfull[PATH_MAX] = { 0 }; - char *full = NULL; - char resroot[PATH_MAX] = { 0 }; - char *root = NULL; - -- full = cleanpath(fullpath, resfull, sizeof(resfull)); -+ full = util_clean_path(fullpath, resfull, sizeof(resfull)); - if (full == NULL) { - ERROR("Failed to get cleaned path"); - return NULL; - } - -- root = cleanpath(rootpath, resroot, sizeof(resroot)); -+ root = util_clean_path(rootpath, resroot, sizeof(resroot)); - if (root == NULL) { - ERROR("Failed to get cleaned path"); - return NULL; -@@ -440,7 +440,7 @@ char *follow_symlink_in_scope(const char *fullpath, const char *rootpath) - return eval_symlinks_in_scope(full, root); - } - --bool specify_current_dir(const char *path) -+bool util_specify_current_dir(const char *path) - { - char *dup = NULL; - char *base = NULL; -@@ -461,7 +461,7 @@ bool specify_current_dir(const char *path) - return res; - } - --bool has_trailing_path_separator(const char *path) -+bool util_has_trailing_path_separator(const char *path) - { - return path != NULL && strlen(path) > 0 && (path[strlen(path) - 1] == '/'); - } -@@ -471,7 +471,7 @@ static void set_char_to_separator(char *p) - *p = '/'; - } - --char *preserve_trailing_dot_or_separator(const char *cleanedpath, const char *originalpath) -+char *util_preserve_trailing_dot_or_separator(const char *cleanedpath, const char *originalpath) - { - int nret; - char respath[PATH_MAX + 3] = { 0 }; -@@ -490,21 +490,21 @@ char *preserve_trailing_dot_or_separator(const char *cleanedpath, const char *or - return NULL; - } - -- if (!specify_current_dir(cleanedpath) && specify_current_dir(originalpath)) { -- if (!has_trailing_path_separator(respath)) { -+ if (!util_specify_current_dir(cleanedpath) && util_specify_current_dir(originalpath)) { -+ if (!util_has_trailing_path_separator(respath)) { - set_char_to_separator(&respath[strlen(respath)]); - } - respath[strlen(respath)] = '.'; - } - -- if (!has_trailing_path_separator(respath) && has_trailing_path_separator(originalpath)) { -+ if (!util_has_trailing_path_separator(respath) && util_has_trailing_path_separator(originalpath)) { - set_char_to_separator(&respath[strlen(respath)]); - } - - return util_strdup_s(respath); - } - --int filepath_split(const char *path, char **dir, char **base) -+int util_filepath_split(const char *path, char **dir, char **base) - { - ssize_t i; - char *dup = NULL; -@@ -539,7 +539,7 @@ int filepath_split(const char *path, char **dir, char **base) - return 0; - } - --int split_dir_and_base_name(const char *path, char **dir, char **base) -+int util_split_dir_and_base_name(const char *path, char **dir, char **base) - { - char *dupdir = NULL; - char *dupbase = NULL; -@@ -561,7 +561,7 @@ int split_dir_and_base_name(const char *path, char **dir, char **base) - return 0; - } - --char *get_resource_path(const char *rootpath, const char *path) -+char *util_get_resource_path(const char *rootpath, const char *path) - { - int nret; - char tmppath[PATH_MAX] = { 0 }; -@@ -572,14 +572,14 @@ char *get_resource_path(const char *rootpath, const char *path) - return NULL; - } - -- if (cleanpath(tmppath, fullpath, sizeof(fullpath)) == NULL) { -+ if (util_clean_path(tmppath, fullpath, sizeof(fullpath)) == NULL) { - return NULL; - } - -- return follow_symlink_in_scope(fullpath, rootpath); -+ return util_follow_symlink_in_scope(fullpath, rootpath); - } - --int resolve_path(const char *rootpath, const char *path, char **resolvedpath, char **abspath) -+int util_resolve_path(const char *rootpath, const char *path, char **resolvedpath, char **abspath) - { - int ret = -1; - int nret; -@@ -599,24 +599,24 @@ int resolve_path(const char *rootpath, const char *path, char **resolvedpath, ch - return -1; - } - -- if (cleanpath(tmppath, cleanedpath, sizeof(cleanedpath)) == NULL) { -+ if (util_clean_path(tmppath, cleanedpath, sizeof(cleanedpath)) == NULL) { - ERROR("Failed to get cleaned path: %s", tmppath); - return -1; - } - -- *abspath = preserve_trailing_dot_or_separator(cleanedpath, tmppath); -+ *abspath = util_preserve_trailing_dot_or_separator(cleanedpath, tmppath); - if (*abspath == NULL) { - ERROR("Failed to preserve path"); - goto cleanup; - } - -- nret = filepath_split(*abspath, &dirpath, &basepath); -+ nret = util_filepath_split(*abspath, &dirpath, &basepath); - if (nret < 0) { - ERROR("Failed to split path"); - goto cleanup; - } - -- resolved_dir_path = get_resource_path(rootpath, dirpath); -+ resolved_dir_path = util_get_resource_path(rootpath, dirpath); - if (resolved_dir_path == NULL) { - ERROR("Failed to get resource path"); - goto cleanup; -@@ -648,17 +648,17 @@ cleanup: - return ret; - } - --int split_path_dir_entry(const char *path, char **dir, char **base) -+int util_split_path_dir_entry(const char *path, char **dir, char **base) - { - #define EXTRA_LEN 3 - char cleaned[PATH_MAX + EXTRA_LEN] = { 0 }; - char *dup = NULL; - -- if (cleanpath(path, cleaned, PATH_MAX) == NULL) { -+ if (util_clean_path(path, cleaned, PATH_MAX) == NULL) { - ERROR("Failed to clean path"); - return -1; - } -- if (specify_current_dir(path)) { -+ if (util_specify_current_dir(path)) { - set_char_to_separator(&cleaned[strlen(cleaned)]); - cleaned[strlen(cleaned)] = '.'; - } -@@ -694,7 +694,7 @@ static char *find_realpath(const char *path) - } - // is not absolutely path - if (target[0] != '\0' && target[0] != '/') { -- if (split_path_dir_entry(iter_path, &parent, NULL) < 0) { -+ if (util_split_path_dir_entry(iter_path, &parent, NULL) < 0) { - goto out; - } - free(iter_path); -@@ -721,7 +721,7 @@ out: - return NULL; - } - --int realpath_in_scope(const char *rootfs, const char *path, char **real_path) -+int util_realpath_in_scope(const char *rootfs, const char *path, char **real_path) - { - int ret = 0; - char full_path[PATH_MAX] = { 0 }; -@@ -734,7 +734,7 @@ int realpath_in_scope(const char *rootfs, const char *path, char **real_path) - ret = -1; - goto out; - } -- if (cleanpath(full_path, cleaned, PATH_MAX) == NULL) { -+ if (util_clean_path(full_path, cleaned, PATH_MAX) == NULL) { - ERROR("Failed to clean path: %s", full_path); - ret = -1; - goto out; -diff --git a/src/utils/cutils/path.h b/src/utils/cutils/path.h -index 21986ec..7f926b2 100644 ---- a/src/utils/cutils/path.h -+++ b/src/utils/cutils/path.h -@@ -22,34 +22,33 @@ extern "C" { - #endif - - /* -- * cleanpath is similar to realpath of glibc, but not expands symbolic links, -+ * util_clean_path is similar to realpath of glibc, but not expands symbolic links, - * and not check the existence of components of the path. - */ --char *cleanpath(const char *path, char *realpath, size_t realpath_len); -+char *util_clean_path(const char *path, char *realpath, size_t realpath_len); - --bool specify_current_dir(const char *path); -+bool util_specify_current_dir(const char *path); - --char *follow_symlink_in_scope(const char *fullpath, const char *rootpath); -+char *util_follow_symlink_in_scope(const char *fullpath, const char *rootpath); - --int split_dir_and_base_name(const char *path, char **dir, char **base); -+int util_split_dir_and_base_name(const char *path, char **dir, char **base); - --int filepath_split(const char *path, char **dir, char **base); -+int util_filepath_split(const char *path, char **dir, char **base); - --char *get_resource_path(const char *rootpath, const char *path); -+char *util_get_resource_path(const char *rootpath, const char *path); - --int resolve_path(const char *rootpath, const char *path, char **resolvedpath, char **abspath); -+int util_resolve_path(const char *rootpath, const char *path, char **resolvedpath, char **abspath); - --bool has_trailing_path_separator(const char *path); -+bool util_has_trailing_path_separator(const char *path); - --char *preserve_trailing_dot_or_separator(const char *cleanedpath, const char *originalpath); -+char *util_preserve_trailing_dot_or_separator(const char *cleanedpath, const char *originalpath); - --int split_path_dir_entry(const char *path, char **dir, char **base); -+int util_split_path_dir_entry(const char *path, char **dir, char **base); - --int realpath_in_scope(const char *rootfs, const char *path, char **real_path); -+int util_realpath_in_scope(const char *rootfs, const char *path, char **real_path); - - #ifdef __cplusplus - } - #endif - - #endif -- -diff --git a/src/utils/cutils/utils.c b/src/utils/cutils/utils.c -index e9ef33b..a7a4150 100644 ---- a/src/utils/cutils/utils.c -+++ b/src/utils/cutils/utils.c -@@ -45,9 +45,7 @@ - #include "utils_string.h" - #include "utils_verify.h" - --#define MAX_NUM_STR_LEN 21 -- --int mem_realloc(void **newptr, size_t newsize, void *oldptr, size_t oldsize) -+int util_mem_realloc(void **newptr, size_t newsize, void *oldptr, size_t oldsize) - { - void *tmp = NULL; - -@@ -105,7 +103,7 @@ static int util_read_pipe(int pipe_fd, char **out_buf, size_t *out_buf_size, siz - } - - new_size = old_size + PIPE_BUF + 1; -- ret = mem_realloc((void *)(&tmp), new_size, (void *)buffer, old_size); -+ ret = util_mem_realloc((void *)(&tmp), new_size, (void *)buffer, old_size); - if (ret != 0) { - ERROR("Memory out"); - ret = -1; -@@ -244,20 +242,6 @@ int util_sig_parse(const char *sig_name) - return -1; - } - --bool util_check_signal_valid(int sig) --{ -- size_t i; -- const struct signame signames[] = SIGNAL_MAP_DEFAULT; -- -- for (i = 0; i < sizeof(signames) / sizeof(signames[0]); i++) { -- if (signames[i].num == sig) { -- return true; -- } -- } -- -- return false; --} -- - void *util_smart_calloc_s(size_t unit_size, size_t count) - { - if (unit_size == 0) { -@@ -296,7 +280,7 @@ char *util_strdup_s(const char *src) - return dst; - } - --int wait_for_pid(pid_t pid) -+int util_wait_for_pid(pid_t pid) - { - int st; - int nret = 0; -@@ -318,7 +302,7 @@ rep: - return 0; - } - --int wait_for_pid_status(pid_t pid) -+int util_wait_for_pid_status(pid_t pid) - { - int st; - int nret = 0; -@@ -706,12 +690,12 @@ bool util_exec_top_cmd(exec_top_func_t cb_func, char **args, const char *pid_arg - if (stdout_close_flag != 0 && stderr_close_flag != 0) { - break; - } -- usleep_nointerupt(1000); -+ util_usleep_nointerupt(1000); - } - - marshal_stderr_msg(&stderr_buffer, &stderr_real_size); - -- status = wait_for_pid_status(pid); -+ status = util_wait_for_pid_status(pid); - - ret = deal_with_result_of_waitpid(status, &stderr_buffer, stderr_real_size); - -@@ -840,12 +824,12 @@ bool util_exec_cmd(exec_func_t cb_func, void *args, const char *stdin_msg, char - if (stdout_close_flag != 0 && stderr_close_flag != 0) { - break; - } -- usleep_nointerupt(1000); -+ util_usleep_nointerupt(1000); - } - - marshal_stderr_msg(&stderr_buffer, &stderr_real_size); - -- status = wait_for_pid_status(pid); -+ status = util_wait_for_pid_status(pid); - - ret = deal_with_result_of_waitpid(status, &stderr_buffer, stderr_real_size); - -@@ -857,7 +841,7 @@ out: - return ret; - } - --char **get_backtrace(void) -+char **util_get_backtrace(void) - { - #define BACKTRACE_SIZE 16 - int addr_cnts; -@@ -877,78 +861,6 @@ char **get_backtrace(void) - return syms; - } - --static long long get_time_unit(int unit) --{ -- long long u[255] = { 0 }; -- -- u['M'] = Time_Milli; -- u['s'] = Time_Second; -- u['m'] = Time_Minute; -- u['h'] = Time_Hour; -- -- return u[unit]; --} -- --static int get_time_ns(long long *pns, long long unit) --{ -- if (unit == 0) { -- return -1; -- } -- -- if (INT64_MAX / *pns >= unit) { -- *pns *= unit; -- return 0; -- } -- -- return -1; --} -- --int util_parse_time_str_to_nanoseconds(const char *value, int64_t *nanoseconds) --{ -- int ret = 0; -- long long tmp = 0; -- char unit = 0; -- size_t len = 0; -- char *num_str = NULL; -- -- if (value == NULL || nanoseconds == NULL) { -- return -1; -- } -- -- if (util_reg_match("^([0-9]+)+(ms|s|m|h)$", value) != 0) { -- return -1; -- } -- num_str = util_strdup_s(value); -- len = strlen(value); -- -- if (strstr(value, "ms") == NULL) { -- unit = *(value + len - 1); -- *(num_str + len - 1) = '\0'; -- } else { -- unit = 'M'; -- *(num_str + len - 2) = '\0'; -- } -- ret = util_safe_llong(num_str, &tmp); -- if (ret < 0) { -- ERROR("Illegal unsigned integer: %s", num_str); -- ret = -1; -- goto out; -- } -- if (tmp == 0) { -- goto out; -- } -- -- ret = get_time_ns(&tmp, get_time_unit(unit)); -- if (ret != 0) { -- ERROR("failed get nano seconds for %s", num_str); -- } -- *nanoseconds = (int64_t)tmp; -- --out: -- free(num_str); -- return ret; --} -- - /* isulad: get starttime of process pid */ - proc_t *util_get_process_proc_info(pid_t pid) - { -@@ -1031,7 +943,7 @@ int util_env_insert(char ***penv, size_t *penv_len, const char *key, size_t key_ - return -1; - } - -- ret = mem_realloc((void **)(&temp), (env_len + 1) * sizeof(char *), env, env_len * sizeof(char *)); -+ ret = util_mem_realloc((void **)(&temp), (env_len + 1) * sizeof(char *), env, env_len * sizeof(char *)); - if (ret != 0) { - ERROR("Failed to realloc memory for envionment variables"); - return -1; -@@ -1117,38 +1029,7 @@ out: - return ret; - } - --char *util_str_token(char **input, const char *delimiter) --{ -- char *str = NULL; -- char *delimiter_found = NULL; -- char *tok = NULL; -- size_t tok_length = 0; -- -- if (input == NULL || delimiter == NULL) { -- return NULL; -- } -- -- str = *input; -- -- if (str == NULL) { -- return NULL; -- } -- delimiter_found = strstr(str, delimiter); -- if (delimiter_found != NULL) { -- tok_length = delimiter_found - str; -- } else { -- tok_length = strlen(str); -- } -- tok = strndup(str, tok_length); -- if (tok == NULL) { -- ERROR("strndup failed"); -- return NULL; -- } -- *input = delimiter_found != NULL ? delimiter_found + strlen(delimiter) : NULL; -- return tok; --} -- --bool pid_max_kernel_namespaced() -+bool util_check_pid_max_kernel_namespaced() - { - bool ret = false; - FILE *fp = NULL; -@@ -1172,37 +1053,7 @@ out: - return ret; - } - --bool check_sysctl_valid(const char *sysctl_key) --{ -- size_t i = 0; -- size_t full_keys_len = 0; -- size_t key_prefixes_len = 0; -- const char *sysctl_full_keys[] = { "kernel.msgmax", "kernel.msgmnb", "kernel.msgmni", "kernel.sem", -- "kernel.shmall", "kernel.shmmax", "kernel.shmmni", "kernel.shm_rmid_forced" -- }; -- const char *sysctl_key_prefixes[] = { "net.", "fs.mqueue." }; -- -- if (sysctl_key == NULL) { -- return false; -- } -- -- full_keys_len = sizeof(sysctl_full_keys) / sizeof(char *); -- key_prefixes_len = sizeof(sysctl_key_prefixes) / sizeof(char *); -- -- for (i = 0; i < full_keys_len; i++) { -- if (strcmp(sysctl_full_keys[i], sysctl_key) == 0) { -- return true; -- } -- } -- for (i = 0; i < key_prefixes_len; i++) { -- if (strncmp(sysctl_key_prefixes[i], sysctl_key, strlen(sysctl_key_prefixes[i])) == 0) { -- return true; -- } -- } -- return false; --} -- --void free_sensitive_string(char *str) -+void util_free_sensitive_string(char *str) - { - if (!util_valid_str(str)) { - goto out; -@@ -1214,7 +1065,7 @@ out: - free(str); - } - --void memset_sensitive_string(char *str) -+void util_memset_sensitive_string(char *str) - { - if (!util_valid_str(str)) { - return; -@@ -1223,113 +1074,6 @@ void memset_sensitive_string(char *str) - (void)memset(str, 0, strlen(str)); - } - --static char *get_mtpoint(const char *line) --{ -- int i; -- const char *tmp = NULL; -- char *pend = NULL; -- char *sret = NULL; -- size_t len; -- -- if (line == NULL) { -- goto err_out; -- } -- -- tmp = line; -- -- for (i = 0; i < 4; i++) { -- tmp = strchr(tmp, ' '); -- if (tmp == NULL) { -- goto err_out; -- } -- tmp++; -- } -- pend = strchr(tmp, ' '); -- if ((pend == NULL) || pend == tmp) { -- goto err_out; -- } -- -- /* stuck a \0 after the mountpoint */ -- len = (size_t)(pend - tmp); -- sret = util_common_calloc_s(len + 1); -- if (sret == NULL) { -- goto err_out; -- } -- (void)memcpy(sret, tmp, len); -- sret[len] = '\0'; -- --err_out: -- return sret; --} -- --bool detect_mount(const char *path) --{ -- FILE *fp = NULL; -- char *line = NULL; -- char *mountpoint = NULL; -- size_t length = 0; -- bool bret = false; -- -- fp = util_fopen("/proc/self/mountinfo", "r"); -- if (fp == NULL) { -- ERROR("Failed opening /proc/self/mountinfo"); -- return false; -- } -- -- while (getline(&line, &length, fp) != -1) { -- mountpoint = get_mtpoint(line); -- if (mountpoint == NULL) { -- INFO("Error reading mountinfo: bad line '%s'", line); -- continue; -- } -- if (strcmp(mountpoint, path) == 0) { -- free(mountpoint); -- bret = true; -- goto out; -- } -- free(mountpoint); -- } --out: -- fclose(fp); -- free(line); -- return bret; --} -- --bool util_deal_with_mount_info(mount_info_call_back_t cb, const char *pattern) --{ -- FILE *fp = NULL; -- char *line = NULL; -- char *mountpoint = NULL; -- size_t length = 0; -- bool bret = true; -- int nret = 0; -- -- fp = util_fopen("/proc/self/mountinfo", "r"); -- if (fp == NULL) { -- ERROR("Failed opening /proc/self/mountinfo"); -- return false; -- } -- -- while (getline(&line, &length, fp) != -1) { -- mountpoint = get_mtpoint(line); -- if (mountpoint == NULL) { -- INFO("Error reading mountinfo: bad line '%s'", line); -- continue; -- } -- nret = cb(mountpoint, pattern); -- free(mountpoint); -- if (nret != 0) { -- bret = false; -- goto out; -- } -- } -- --out: -- fclose(fp); -- free(line); -- return bret; --} -- - static int set_echo_back(bool echo_back) - { - struct termios old, new; -@@ -1429,7 +1173,7 @@ static int util_input(char *buf, size_t maxlen, bool echo_back) - return ret; - } - --// Get input from stdin, echo back if get any charactor. -+// Get input from stdin, echo back if get any character. - int util_input_echo(char *buf, size_t maxlen) - { - return util_input(buf, maxlen, true); -@@ -1441,7 +1185,7 @@ int util_input_noecho(char *buf, size_t maxlen) - return util_input(buf, maxlen, false); - } - --void usleep_nointerupt(unsigned long usec) -+void util_usleep_nointerupt(unsigned long usec) - { - #define SECOND_TO_USECOND_MUTIPLE 1000000 - int ret = 0; -@@ -1492,71 +1236,6 @@ int util_generate_random_str(char *id, size_t len) - return 0; - } - --void add_array_elem(char **array, size_t total, size_t *pos, const char *elem) --{ -- if (*pos + 1 >= total - 1) { -- return; -- } -- array[*pos] = util_strdup_s(elem); -- *pos += 1; --} -- --void add_array_kv(char **array, size_t total, size_t *pos, const char *k, const char *v) --{ -- if (k == NULL || v == NULL) { -- return; -- } -- add_array_elem(array, total, pos, k); -- add_array_elem(array, total, pos, v); --} -- --int util_validate_env(const char *env, char **dst) --{ -- int ret = 0; -- char *value = NULL; -- -- char **arr = util_string_split_multi(env, '='); -- if (arr == NULL) { -- ERROR("Failed to split env string"); -- return -1; -- } -- if (strlen(arr[0]) == 0) { -- ERROR("Invalid environment variable: %s", env); -- ret = -1; -- goto out; -- } -- -- if (util_array_len((const char **)arr) > 1) { -- *dst = util_strdup_s(env); -- goto out; -- } -- -- value = getenv(env); -- if (value == NULL) { -- *dst = NULL; -- goto out; -- } else { -- int sret; -- size_t len = strlen(env) + 1 + strlen(value) + 1; -- *dst = (char *)util_common_calloc_s(len); -- if (*dst == NULL) { -- ERROR("Out of memory"); -- ret = -1; -- goto out; -- } -- sret = snprintf(*dst, len, "%s=%s", env, value); -- if (sret < 0 || (size_t)sret >= len) { -- ERROR("Failed to compose env string"); -- ret = -1; -- goto out; -- } -- } -- --out: -- util_free_array(arr); -- return ret; --} -- - int util_check_inherited_exclude_fds(bool closeall, int *fds_to_ignore, size_t len_fds) - { - struct dirent *pdirent = NULL; -@@ -1613,42 +1292,6 @@ restart: - return 0; - } - --int get_cpu_num_cores(void) --{ -- int ncpus = (int)sysconf(_SC_NPROCESSORS_ONLN); -- if (ncpus < 1) { -- ERROR("Cannot determine number of CPUs: assuming 1\n"); -- ncpus = 1; -- } -- return ncpus; --} -- --char *util_uint_to_string(long long unsigned int data) --{ -- char numstr[MAX_NUM_STR_LEN] = { 0 }; -- int ret; -- -- ret = snprintf(numstr, sizeof(numstr), "%llu", data); -- if (ret < 0 || (size_t)ret >= sizeof(numstr)) { -- return NULL; -- } -- -- return util_strdup_s(numstr); --} -- --char *util_int_to_string(long long int data) --{ -- char numstr[MAX_NUM_STR_LEN] = { 0 }; -- int ret; -- -- ret = snprintf(numstr, sizeof(numstr), "%lld", data); -- if (ret < 0 || (size_t)ret >= sizeof(numstr)) { -- return NULL; -- } -- -- return util_strdup_s(numstr); --} -- - static char *get_cpu_variant() - { - char *variant = NULL; -@@ -1679,7 +1322,7 @@ static char *get_cpu_variant() - util_trim_newline(start_pos); - start_pos = util_trim_space(start_pos); - -- variant = strings_to_lower(start_pos); -+ variant = util_strings_to_lower(start_pos); - - out: - free(cpuinfo); -@@ -1688,7 +1331,7 @@ out: - return variant; - } - --int normalized_host_os_arch(char **host_os, char **host_arch, char **host_variant) -+int util_normalized_host_os_arch(char **host_os, char **host_arch, char **host_variant) - { - int ret = 0; - struct utsname uts; -@@ -1705,7 +1348,7 @@ int normalized_host_os_arch(char **host_os, char **host_arch, char **host_varian - goto out; - } - -- *host_os = strings_to_lower(uts.sysname); -+ *host_os = util_strings_to_lower(uts.sysname); - - if (strcasecmp("i386", uts.machine) == 0) { - *host_arch = util_strdup_s("386"); -@@ -1792,4 +1435,41 @@ out: - free(proc); - free(p_proc); - return ret; -+} -+ -+void util_parse_user_group(const char *username, char **user, char **group, char **tmp_dup) -+{ -+ char *tmp = NULL; -+ char *pdot = NULL; -+ -+ if (user == NULL || group == NULL || tmp_dup == NULL) { -+ return; -+ } -+ -+ if (username != NULL) { -+ tmp = util_strdup_s(username); -+ -+ // for free tmp in caller -+ *tmp_dup = tmp; -+ -+ pdot = strstr(tmp, ":"); -+ if (pdot != NULL) { -+ *pdot = '\0'; -+ if (pdot != tmp) { -+ // User found -+ *user = tmp; -+ } -+ if (*(pdot + 1) != '\0') { -+ // group found -+ *group = pdot + 1; -+ } -+ } else { -+ // No : found -+ if (*tmp != '\0') { -+ *user = tmp; -+ } -+ } -+ } -+ -+ return; - } -\ No newline at end of file -diff --git a/src/utils/cutils/utils.h b/src/utils/cutils/utils.h -index ca3afb1..1ee0b14 100644 ---- a/src/utils/cutils/utils.h -+++ b/src/utils/cutils/utils.h -@@ -106,31 +106,11 @@ extern "C" { - #define SIZE_TB (1024LL * SIZE_GB) - #define SIZE_PB (1024LL * SIZE_TB) - --#define Time_Nano 1LL --#define Time_Micro (1000LL * Time_Nano) --#define Time_Milli (1000LL * Time_Micro) --#define Time_Second (1000LL * Time_Milli) --#define Time_Minute (60LL * Time_Second) --#define Time_Hour (60LL * Time_Minute) -- - /* Max regular file size for isula\isulad to open as same as docker */ - #define REGULAR_FILE_SIZE (10 * SIZE_MB) - --#define rFC339Local "2006-01-02T15:04:05" --#define rFC339NanoLocal "2006-01-02T15:04:05.999999999" --#define dateLocal "2006-01-02" --#define defaultContainerTime "0001-01-01T00:00:00Z" - #define TIME_STR_SIZE 512 - --#define HOST_NAME_REGEXP \ -- "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*" \ -- "([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])$" --#define __TagPattern "^:([A-Za-z_0-9][A-Za-z_0-9.-]{0,127})$" --#define __NamePattern \ -- "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])" \ -- "((\\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+)?(:[0-9]+)?/)?[a-z0-9]" \ -- "+((([._]|__|[-]*)[a-z0-9]+)+)?((/[a-z0-9]+((([._]|__|[-]*)[a-z0-9]+)+)?)+)?$" -- - // native umask value - #define ANNOTATION_UMAKE_KEY "native.umask" - #define UMASK_NORMAL "normal" -@@ -319,7 +299,7 @@ struct signame { - } \ - } while (0) - --int mem_realloc(void **newptr, size_t newsize, void *oldptr, size_t oldsize); -+int util_mem_realloc(void **newptr, size_t newsize, void *oldptr, size_t oldsize); - - int util_check_inherited(bool closeall, int fd_to_ignore); - -@@ -331,7 +311,7 @@ void *util_common_calloc_s(size_t size); - - char *util_strdup_s(const char *src); - --int wait_for_pid(pid_t pid); -+int util_wait_for_pid(pid_t pid); - - void util_contain_errmsg(const char *errmsg, int *exit_code); - -@@ -343,7 +323,7 @@ proc_t *util_stat2proc(const char *s, size_t len); - - bool util_process_alive(pid_t pid, unsigned long long start_time); - --int wait_for_pid_status(pid_t pid); -+int util_wait_for_pid_status(pid_t pid); - - typedef void (*exec_func_t)(void *args); - bool util_exec_cmd(exec_func_t cb_func, void *args, const char *stdin_msg, char **stdout_msg, char **stderr_msg); -@@ -352,9 +332,7 @@ typedef void (*exec_top_func_t)(char **args, const char *pid_args, size_t args_l - bool util_exec_top_cmd(exec_top_func_t cb_func, char **args, const char *pid_args, size_t args_len, char **stdout_msg, - char **stderr_msg); - --char **get_backtrace(void); -- --int util_parse_time_str_to_nanoseconds(const char *value, int64_t *nanoseconds); -+char **util_get_backtrace(void); - - proc_t *util_get_process_proc_info(pid_t pid); - -@@ -364,47 +342,29 @@ int util_env_insert(char ***penv, size_t *penv_len, const char *key, size_t key_ - int util_env_set_val(char ***penv, const size_t *penv_len, const char *key, size_t key_len, const char *newkv); - char *util_env_get_val(char **env, size_t env_len, const char *key, size_t key_len); - --char *util_str_token(char **input, const char *delimiter); --bool check_sysctl_valid(const char *sysctl_key); --bool pid_max_kernel_namespaced(); --void free_sensitive_string(char *str); --void memset_sensitive_string(char *str); -+bool util_check_pid_max_kernel_namespaced(); -+ -+void util_free_sensitive_string(char *str); -+void util_memset_sensitive_string(char *str); - - int util_input_readall(char *buf, size_t maxlen); - int util_input_echo(char *buf, size_t maxlen); - int util_input_noecho(char *buf, size_t maxlen); - --bool util_check_signal_valid(int sig); -- --void usleep_nointerupt(unsigned long usec); -+void util_usleep_nointerupt(unsigned long usec); - - int util_generate_random_str(char *id, size_t len); - --void add_array_elem(char **array, size_t total, size_t *pos, const char *elem); -- --void add_array_kv(char **array, size_t total, size_t *pos, const char *k, const char *v); -- --typedef int (*mount_info_call_back_t)(const char *, const char *); --bool util_deal_with_mount_info(mount_info_call_back_t cb, const char *); -- --int util_validate_env(const char *env, char **dst); -- - int util_check_inherited_exclude_fds(bool closeall, int *fds_to_ignore, size_t len_fds); - --int get_cpu_num_cores(void); -- --char *util_uint_to_string(long long unsigned int data); -- --char *util_int_to_string(long long int data); -+char *util_without_sha256_prefix(char *digest); - --char *without_sha256_prefix(char *digest); -- --int normalized_host_os_arch(char **host_os, char **host_arch, char **host_variant); -- --char *util_full_digest_str(char *str); -+int util_normalized_host_os_arch(char **host_os, char **host_arch, char **host_variant); - - int util_read_pid_ppid_info(uint32_t pid, pid_ppid_info_t *pid_info); - -+void util_parse_user_group(const char *username, char **user, char **group, char **tmp_dup); -+ - #ifdef __cplusplus - } - #endif -diff --git a/src/utils/cutils/utils_convert.c b/src/utils/cutils/utils_convert.c -index c14e147..077b062 100644 ---- a/src/utils/cutils/utils_convert.c -+++ b/src/utils/cutils/utils_convert.c -@@ -20,6 +20,10 @@ - #include - #include - #include -+#include -+#include "utils.h" -+ -+#define MAX_NUM_STR_LEN 21 - - static inline bool is_invalid_error_str(const char *err_str, const char *numstr) - { -@@ -107,6 +111,29 @@ int util_safe_uint(const char *numstr, unsigned int *converted) - return 0; - } - -+int util_safe_uint64(const char *numstr, uint64_t *converted) -+{ -+ char *err_str = NULL; -+ uint64_t ull; -+ -+ if (numstr == NULL || converted == NULL) { -+ return -EINVAL; -+ } -+ -+ errno = 0; -+ ull = strtoull(numstr, &err_str, 0); -+ if (errno > 0) { -+ return -errno; -+ } -+ -+ if (is_invalid_error_str(err_str, numstr)) { -+ return -EINVAL; -+ } -+ -+ *converted = (uint64_t)ull; -+ return 0; -+} -+ - int util_safe_llong(const char *numstr, long long *converted) - { - char *err_str = NULL; -@@ -180,3 +207,28 @@ int util_str_to_bool(const char *boolstr, bool *converted) - return 0; - } - -+char *util_uint_to_string(long long unsigned int data) -+{ -+ char numstr[MAX_NUM_STR_LEN] = { 0 }; -+ int ret; -+ -+ ret = snprintf(numstr, sizeof(numstr), "%llu", data); -+ if (ret < 0 || (size_t)ret >= sizeof(numstr)) { -+ return NULL; -+ } -+ -+ return util_strdup_s(numstr); -+} -+ -+char *util_int_to_string(long long int data) -+{ -+ char numstr[MAX_NUM_STR_LEN] = { 0 }; -+ int ret; -+ -+ ret = snprintf(numstr, sizeof(numstr), "%lld", data); -+ if (ret < 0 || (size_t)ret >= sizeof(numstr)) { -+ return NULL; -+ } -+ -+ return util_strdup_s(numstr); -+} -\ No newline at end of file -diff --git a/src/utils/cutils/utils_convert.h b/src/utils/cutils/utils_convert.h -index 5b4ae3d..e1c70ba 100644 ---- a/src/utils/cutils/utils_convert.h -+++ b/src/utils/cutils/utils_convert.h -@@ -28,10 +28,12 @@ int util_safe_uint(const char *numstr, unsigned int *converted); - int util_safe_llong(const char *numstr, long long *converted); - int util_safe_strtod(const char *numstr, double *converted); - int util_str_to_bool(const char *boolstr, bool *converted); -+int util_safe_uint64(const char *numstr, uint64_t *converted); -+char *util_uint_to_string(long long unsigned int data); -+char *util_int_to_string(long long int data); - - #ifdef __cplusplus - } - #endif - - #endif // UTILS_CUTILS_UTILS_CONVERT_H -- -diff --git a/src/utils/cutils/utils_file.c b/src/utils/cutils/utils_file.c -index 266afea..7a965c0 100644 ---- a/src/utils/cutils/utils_file.c -+++ b/src/utils/cutils/utils_file.c -@@ -413,7 +413,7 @@ char *util_path_join(const char *dir, const char *file) - return NULL; - } - -- if (cleanpath(path, cleaned, sizeof(cleaned)) == NULL) { -+ if (util_clean_path(path, cleaned, sizeof(cleaned)) == NULL) { - ERROR("Failed to clean path: %s", path); - return NULL; - } -@@ -567,7 +567,7 @@ int util_open(const char *filename, int flags, mode_t mode) - { - char rpath[PATH_MAX] = { 0x00 }; - -- if (cleanpath(filename, rpath, sizeof(rpath)) == NULL) { -+ if (util_clean_path(filename, rpath, sizeof(rpath)) == NULL) { - return -1; - } - if (mode) { -@@ -589,8 +589,8 @@ FILE *util_fopen(const char *filename, const char *mode) - return NULL; - } - -- if (cleanpath(filename, rpath, sizeof(rpath)) == NULL) { -- ERROR("cleanpath failed"); -+ if (util_clean_path(filename, rpath, sizeof(rpath)) == NULL) { -+ ERROR("util_clean_path failed"); - return NULL; - } - if (strncmp(mode, "a+", 2) == 0) { -@@ -840,7 +840,7 @@ int64_t util_file_size(const char *filename) - return (int64_t)st.st_size; - } - --int util_scan_subdirs(const char *directory, subdir_callback_t cb) -+int util_scan_subdirs(const char *directory, subdir_callback_t cb, void *context) - { - DIR *dir = NULL; - struct dirent *direntp = NULL; -@@ -862,7 +862,7 @@ int util_scan_subdirs(const char *directory, subdir_callback_t cb) - continue; - } - -- if (!cb(directory, direntp)) { -+ if (!cb(directory, direntp, context)) { - ERROR("Dealwith subdir: %s failed", direntp->d_name); - ret = -1; - break; -@@ -976,7 +976,7 @@ char *look_path(const char *file, char **err) - } - - /* if slash in file, directly use file and do not try PATH. */ -- if (strings_contains_any(file, "/")) { -+ if (util_strings_contains_any(file, "/")) { - int en = find_executable(file); - if (en == 0) { - return util_strdup_s(file); -@@ -1414,7 +1414,7 @@ int util_atomic_write_file(const char *fname, const char *content, size_t conten - return 0; - } - -- if (cleanpath(fname, rpath, sizeof(rpath)) == NULL) { -+ if (util_clean_path(fname, rpath, sizeof(rpath)) == NULL) { - return -1; - } - -@@ -1444,7 +1444,7 @@ free_out: - return ret; - } - --static char *isula_utils_fisula_utils_read_file(FILE *stream, size_t *length) -+static char *do_read_file(FILE *stream, size_t *length) - { - #define JSON_MAX_SIZE (10LL * 1024LL * 1024LL) - char *buf = NULL; -@@ -1504,7 +1504,7 @@ static int do_check_args(const char *path) - return 0; - } - --char *isula_utils_read_file(const char *path) -+char *util_read_content_from_file(const char *path) - { - #define FILE_MODE 0640 - char *buf = NULL; -@@ -1535,12 +1535,12 @@ char *isula_utils_read_file(const char *path) - return NULL; - } - -- buf = isula_utils_fisula_utils_read_file(fp, &length); -+ buf = do_read_file(fp, &length); - (void)fclose(fp); - return buf; - } - --int isula_utils_read_line(FILE *fp, read_line_callback_t cb, void *context) -+int util_proc_file_line_by_line(FILE *fp, read_line_callback_t cb, void *context) - { - size_t len = 0; - char *line = NULL; -diff --git a/src/utils/cutils/utils_file.h b/src/utils/cutils/utils_file.h -index 2b37fee..1bd2d69 100644 ---- a/src/utils/cutils/utils_file.h -+++ b/src/utils/cutils/utils_file.h -@@ -82,21 +82,21 @@ int util_copy_file(const char *src_file, const char *dst_file, mode_t mode); - - char *util_path_base(const char *path); - --char *isula_utils_read_file(const char *path); -+char *util_read_content_from_file(const char *path); - - void util_calculate_dir_size(const char *dirpath, int recursive_depth, int64_t *total_size, int64_t *total_inode); - - void utils_calculate_dir_size_without_hardlink(const char *dirpath, int64_t *total_size, int64_t *total_inode); - --typedef bool (*subdir_callback_t)(const char *, const struct dirent *); -+typedef bool (*subdir_callback_t)(const char *, const struct dirent *, void *context); - --int util_scan_subdirs(const char *directory, subdir_callback_t cb); -+int util_scan_subdirs(const char *directory, subdir_callback_t cb, void *context); - - int util_atomic_write_file(const char *fname, const char *content, size_t content_len, mode_t mode); - - typedef bool (*read_line_callback_t)(const char *, void *context); - --int isula_utils_read_line(FILE *fp, read_line_callback_t cb, void *context); -+int util_proc_file_line_by_line(FILE *fp, read_line_callback_t cb, void *context); - - #ifdef __cplusplus - } -diff --git a/src/utils/cutils/utils_fs.c b/src/utils/cutils/utils_fs.c -index e018744..788557f 100644 ---- a/src/utils/cutils/utils_fs.c -+++ b/src/utils/cutils/utils_fs.c -@@ -42,8 +42,8 @@ - #define VXFS_SUPER_MAGIC 0xa501fcf5 - #endif - --#ifndef OVERLAY_SUPER_MAGIC --#define OVERLAY_SUPER_MAGIC 0x794c7630 -+#ifndef OVERLAYFS_SUPER_MAGIC -+#define OVERLAYFS_SUPER_MAGIC 0x794c7630 - #endif - - #ifndef NSFS_MAGIC -@@ -386,6 +386,41 @@ out: - return bret; - } - -+bool util_deal_with_mount_info(mount_info_call_back_t cb, const char *pattern) -+{ -+ FILE *fp = NULL; -+ char *line = NULL; -+ char *mountpoint = NULL; -+ size_t length = 0; -+ bool bret = true; -+ int nret = 0; -+ -+ fp = util_fopen("/proc/self/mountinfo", "r"); -+ if (fp == NULL) { -+ ERROR("Failed opening /proc/self/mountinfo"); -+ return false; -+ } -+ -+ while (getline(&line, &length, fp) != -1) { -+ mountpoint = get_mtpoint(line); -+ if (mountpoint == NULL) { -+ INFO("Error reading mountinfo: bad line '%s'", line); -+ continue; -+ } -+ nret = cb(mountpoint, pattern); -+ free(mountpoint); -+ if (nret != 0) { -+ bret = false; -+ goto out; -+ } -+ } -+ -+out: -+ fclose(fp); -+ free(line); -+ return bret; -+} -+ - // is_remount returns true if either device name or flags identify a remount request, false otherwise. - static bool is_remount(const char *src, unsigned long mntflags) - { -@@ -577,7 +612,7 @@ child_out: - } - } - -- ret = wait_for_pid(pid); -+ ret = util_wait_for_pid(pid); - if (ret != 0) { - ERROR("Wait util_mount_from failed"); - } -diff --git a/src/utils/cutils/utils_fs.h b/src/utils/cutils/utils_fs.h -index 198e4d4..6ab6b78 100644 ---- a/src/utils/cutils/utils_fs.h -+++ b/src/utils/cutils/utils_fs.h -@@ -36,9 +36,10 @@ int util_force_mount(const char *src, const char *dst, const char *mtype, const - bool util_detect_mounted(const char *path); - int util_ensure_mounted_as(const char *dst, const char *mntopts); - int util_mount_from(const char *base, const char *src, const char *dst, const char *mtype, const char *mntopts); -+typedef int (*mount_info_call_back_t)(const char *, const char *); -+bool util_deal_with_mount_info(mount_info_call_back_t cb, const char *); - #ifdef __cplusplus - } - #endif - - #endif // UTILS_CUTILS_UTILS_FS_H -- -diff --git a/src/utils/cutils/utils_regex.c b/src/utils/cutils/utils_regex.c -index ca82227..81b1ba1 100644 ---- a/src/utils/cutils/utils_regex.c -+++ b/src/utils/cutils/utils_regex.c -@@ -72,7 +72,7 @@ static int get_regex_size_from_wildcard(const char *wildcard, const char *escape - size_t i, tmp; - - for (i = 0; i < escapes_size; i++) { -- tmp = strings_count(wildcard, escapes[i]); -+ tmp = util_strings_count(wildcard, escapes[i]); - if (tmp > SIZE_MAX - size) { - ERROR("Invalid wildcard"); - return -1; -@@ -80,7 +80,7 @@ static int get_regex_size_from_wildcard(const char *wildcard, const char *escape - size += tmp; - } - -- tmp = strings_count(wildcard, '*'); -+ tmp = util_strings_count(wildcard, '*'); - if (tmp > SIZE_MAX - size - strlen(wildcard) - 3) { - ERROR("Invalid wildcard"); - return -1; -@@ -138,4 +138,3 @@ int util_wildcard_to_regex(const char *wildcard, char **regex) - - return 0; - } -- -diff --git a/src/utils/cutils/utils_string.c b/src/utils/cutils/utils_string.c -index 6543021..d303114 100644 ---- a/src/utils/cutils/utils_string.c -+++ b/src/utils/cutils/utils_string.c -@@ -47,7 +47,7 @@ static struct unit_map_def const g_unit_map[] = { - - static size_t const g_unit_map_len = sizeof(g_unit_map) / sizeof(g_unit_map[0]); - --bool strings_contains_any(const char *str, const char *substr) -+bool util_strings_contains_any(const char *str, const char *substr) - { - size_t i = 0; - size_t j; -@@ -71,7 +71,7 @@ bool strings_contains_any(const char *str, const char *substr) - return false; - } - --bool strings_contains_word(const char *str, const char *substr) -+bool util_strings_contains_word(const char *str, const char *substr) - { - if (str == NULL || substr == NULL) { - return false; -@@ -83,7 +83,7 @@ bool strings_contains_word(const char *str, const char *substr) - return false; - } - --int strings_count(const char *str, unsigned char c) -+int util_strings_count(const char *str, unsigned char c) - { - size_t i = 0; - int res = 0; -@@ -102,9 +102,9 @@ int strings_count(const char *str, unsigned char c) - return res; - } - --// strings_in_slice tests whether a string is contained in array of strings or not. -+// util_strings_in_slice tests whether a string is contained in array of strings or not. - // Comparison is case insensitive --bool strings_in_slice(const char **strarray, size_t alen, const char *str) -+bool util_strings_in_slice(const char **strarray, size_t alen, const char *str) - { - size_t i; - -@@ -123,7 +123,7 @@ bool strings_in_slice(const char **strarray, size_t alen, const char *str) - - // Returns a string that is generated after converting - // all uppercase characters in the str to lowercase. --char *strings_to_lower(const char *str) -+char *util_strings_to_lower(const char *str) - { - char *newstr = NULL; - char *pos = NULL; -@@ -145,7 +145,7 @@ char *strings_to_lower(const char *str) - - // Returns a string that is generated after converting - // all lowercase characters in the str to uppercase. --char *strings_to_upper(const char *str) -+char *util_strings_to_upper(const char *str) - { - char *newstr = NULL; - char *pos = NULL; -@@ -182,7 +182,7 @@ static int parse_unit_multiple(const char *unit, int64_t *mltpl) - return -EINVAL; - } - --static int util_parse_size_int_and_float(const char *numstr, int64_t mlt, int64_t *converted) -+int util_parse_size_int_and_float(const char *numstr, int64_t mlt, int64_t *converted) - { - long long int_size = 0; - double float_size = 0; -@@ -461,7 +461,7 @@ err_out: - return NULL; - } - --const char *str_skip_str(const char *str, const char *skip) -+const char *util_str_skip_str(const char *str, const char *skip) - { - if (str == NULL || skip == NULL) { - return NULL; -@@ -613,7 +613,7 @@ char *util_trim_quotation(char *str) - return str; - } - --char **str_array_dup(const char **src, size_t len) -+char **util_str_array_dup(const char **src, size_t len) - { - size_t i; - char **dest = NULL; -@@ -710,7 +710,7 @@ char *util_string_append(const char *post, const char *pre) - return res_string; - } - --int dup_array_of_strings(const char **src, size_t src_len, char ***dst, size_t *dst_len) -+int util_dup_array_of_strings(const char **src, size_t src_len, char ***dst, size_t *dst_len) - { - size_t i; - -@@ -824,8 +824,7 @@ bool util_has_suffix(const char *str, const char *suffix) - return true; - } - --int util_string_array_unique(const char **elements, size_t length, char ***unique_elements, -- size_t *unique_elements_len) -+int util_string_array_unique(const char **elements, size_t length, char ***unique_elements, size_t *unique_elements_len) - { - int ret = 0; - size_t i; -@@ -885,21 +884,33 @@ out: - return ret; - } - --int util_parse_bool_string(const char *str, bool *converted) -+char *util_str_token(char **input, const char *delimiter) - { -- int ret = 0; -+ char *str = NULL; -+ char *delimiter_found = NULL; -+ char *tok = NULL; -+ size_t tok_length = 0; - -- if (str == NULL || converted == NULL) { -- return -EINVAL; -+ if (input == NULL || delimiter == NULL) { -+ return NULL; - } - -- if (strcasecmp(str, "true") == 0) { -- *converted = true; -- } else if (strcasecmp(str, "false") == 0) { -- *converted = false; -+ str = *input; -+ -+ if (str == NULL) { -+ return NULL; -+ } -+ delimiter_found = strstr(str, delimiter); -+ if (delimiter_found != NULL) { -+ tok_length = delimiter_found - str; - } else { -- ret = -EINVAL; -+ tok_length = strlen(str); - } -- -- return ret; --} -+ tok = strndup(str, tok_length); -+ if (tok == NULL) { -+ ERROR("strndup failed"); -+ return NULL; -+ } -+ *input = delimiter_found != NULL ? delimiter_found + strlen(delimiter) : NULL; -+ return tok; -+} -\ No newline at end of file -diff --git a/src/utils/cutils/utils_string.h b/src/utils/cutils/utils_string.h -index 4d48f72..48733f3 100644 ---- a/src/utils/cutils/utils_string.h -+++ b/src/utils/cutils/utils_string.h -@@ -24,17 +24,17 @@ - extern "C" { - #endif - --bool strings_contains_any(const char *str, const char *substr); -+bool util_strings_contains_any(const char *str, const char *substr); - --bool strings_contains_word(const char *str, const char *substr); -+bool util_strings_contains_word(const char *str, const char *substr); - --int strings_count(const char *str, unsigned char c); -+int util_strings_count(const char *str, unsigned char c); - --bool strings_in_slice(const char **strarray, size_t alen, const char *str); -+bool util_strings_in_slice(const char **strarray, size_t alen, const char *str); - --char *strings_to_lower(const char *str); -+char *util_strings_to_lower(const char *str); - --char *strings_to_upper(const char *str); -+char *util_strings_to_upper(const char *str); - - int util_parse_byte_size_string(const char *s, int64_t *converted); - -@@ -50,7 +50,7 @@ char **util_string_split_multi(const char *src_str, char delim); - - char **util_string_split_n(const char *src_str, char delim, size_t n); - --const char *str_skip_str(const char *str, const char *skip); -+const char *util_str_skip_str(const char *str, const char *skip); - - char *util_string_delchar(const char *ss, unsigned char c); - -@@ -60,13 +60,13 @@ char *util_trim_space(char *str); - - char *util_trim_quotation(char *str); - --char **str_array_dup(const char **src, size_t len); -+char **util_str_array_dup(const char **src, size_t len); - - char *util_string_join(const char *sep, const char **parts, size_t len); - - char *util_string_append(const char *post, const char *pre); - --int dup_array_of_strings(const char **src, size_t src_len, char ***dst, size_t *dst_len); -+int util_dup_array_of_strings(const char **src, size_t src_len, char ***dst, size_t *dst_len); - - char *util_sub_string(const char *source, size_t offset, size_t length); - -@@ -79,11 +79,11 @@ bool util_has_suffix(const char *str, const char *suffix); - int util_string_array_unique(const char **elements, size_t length, char ***unique_elements, - size_t *unique_elements_len); - --int util_parse_bool_string(const char *str, bool *converted); -+int util_parse_size_int_and_float(const char *numstr, int64_t mlt, int64_t *converted); - -+char *util_str_token(char **input, const char *delimiter); - #ifdef __cplusplus - } - #endif - - #endif // UTILS_CUTILS_UTILS_STRING_H -- -diff --git a/src/utils/cutils/utils_timestamp.c b/src/utils/cutils/utils_timestamp.c -index 41a0e1c..23f3c77 100644 ---- a/src/utils/cutils/utils_timestamp.c -+++ b/src/utils/cutils/utils_timestamp.c -@@ -77,7 +77,7 @@ int types_timestamp_cmp_nanos(const types_timestamp_t *t1, const types_timestamp - } - - /* types timestamp cmp */ --int types_timestamp_cmp(const types_timestamp_t *t1, const types_timestamp_t *t2) -+int util_types_timestamp_cmp(const types_timestamp_t *t1, const types_timestamp_t *t2) - { - int ret = 0; - -@@ -106,7 +106,7 @@ int types_timestamp_cmp(const types_timestamp_t *t1, const types_timestamp_t *t2 - } - - /* get timestamp */ --bool get_timestamp(const char *str_time, types_timestamp_t *timestamp) -+bool util_get_timestamp(const char *str_time, types_timestamp_t *timestamp) - { - int64_t seconds = 0; - int32_t nanos = 0; -@@ -118,7 +118,7 @@ bool get_timestamp(const char *str_time, types_timestamp_t *timestamp) - return false; - } - -- if (!get_tm_from_str(str_time, &tm_day, &nanos)) { -+ if (!util_get_tm_from_str(str_time, &tm_day, &nanos)) { - return false; - } - -@@ -189,12 +189,12 @@ out: - } - - /* get time buffer */ --bool get_time_buffer(const types_timestamp_t *timestamp, char *timebuffer, size_t maxsize) -+bool util_get_time_buffer(const types_timestamp_t *timestamp, char *timebuffer, size_t maxsize) - { - return get_time_buffer_help(timestamp, timebuffer, maxsize, false); - } - --bool get_now_time_stamp(types_timestamp_t *timestamp) -+bool util_get_now_time_stamp(types_timestamp_t *timestamp) - { - int err = 0; - struct timespec ts; -@@ -211,7 +211,7 @@ bool get_now_time_stamp(types_timestamp_t *timestamp) - return true; - } - --int64_t get_now_time_nanos() -+int64_t util_get_now_time_nanos() - { - int err = 0; - struct timespec ts; -@@ -226,30 +226,30 @@ int64_t get_now_time_nanos() - } - - /* get now time buffer */ --bool get_now_time_buffer(char *timebuffer, size_t maxsize) -+bool util_get_now_time_buffer(char *timebuffer, size_t maxsize) - { - types_timestamp_t timestamp; - -- if (get_now_time_stamp(×tamp) == false) { -+ if (util_get_now_time_stamp(×tamp) == false) { - return false; - } - -- return get_time_buffer(×tamp, timebuffer, maxsize); -+ return util_get_time_buffer(×tamp, timebuffer, maxsize); - } - - /* get now local utc time buffer */ --bool get_now_local_utc_time_buffer(char *timebuffer, size_t maxsize) -+bool util_get_now_local_utc_time_buffer(char *timebuffer, size_t maxsize) - { - types_timestamp_t timestamp; - -- if (get_now_time_stamp(×tamp) == false) { -+ if (util_get_now_time_stamp(×tamp) == false) { - return false; - } - - return get_time_buffer_help(×tamp, timebuffer, maxsize, true); - } - --int get_time_interval(types_timestamp_t first, types_timestamp_t last, int64_t *result) -+int util_get_time_interval(types_timestamp_t first, types_timestamp_t last, int64_t *result) - { - int64_t seconds_diff = 0; - int64_t nanos_diff = 0; -@@ -348,7 +348,7 @@ static void parsing_time_data(const char *time, struct tm *tm) - parsing_time_data_sec(tm, time, &i); - } - --bool parsing_time(const char *format, const char *time, struct tm *tm, int32_t *nanos) -+bool util_parsing_time(const char *format, const char *time, struct tm *tm, int32_t *nanos) - { - size_t len_format = 0; - size_t len_time = 0; -@@ -429,7 +429,7 @@ int get_valid_days(int mon, int year) - return valid_days; - } - --bool fix_date(struct tm *tm) -+bool util_fix_date(struct tm *tm) - { - if (tm == NULL) { - return false; -@@ -456,7 +456,7 @@ bool fix_date(struct tm *tm) - return true; - } - --bool get_tm_from_str(const char *str, struct tm *tm, int32_t *nanos) -+bool util_get_tm_from_str(const char *str, struct tm *tm, int32_t *nanos) - { - char *format = NULL; - -@@ -464,10 +464,10 @@ bool get_tm_from_str(const char *str, struct tm *tm, int32_t *nanos) - return false; - } - -- if (strings_contains_any(str, ".")) { -+ if (util_strings_contains_any(str, ".")) { - format = rFC339NanoLocal; -- } else if (strings_contains_any(str, "T")) { -- int tcolons = strings_count(str, ':'); -+ } else if (util_strings_contains_any(str, "T")) { -+ int tcolons = util_strings_count(str, ':'); - switch (tcolons) { - case 0: - format = "2016-01-02T15"; -@@ -486,12 +486,12 @@ bool get_tm_from_str(const char *str, struct tm *tm, int32_t *nanos) - format = dateLocal; - } - -- if (!parsing_time(format, str, tm, nanos)) { -+ if (!util_parsing_time(format, str, tm, nanos)) { - ERROR("Failed to parse time \"%s\" with format \"%s\"", str, format); - return false; - } - -- if (!fix_date(tm)) { -+ if (!util_fix_date(tm)) { - ERROR("\"%s\" is invalid", str); - return false; - } -@@ -578,7 +578,7 @@ static bool get_tm_zone_from_str(const char *str, struct tm *tm, int32_t *nanos, - zonestr = util_strdup_s(zp); - *zp = '\0'; - -- if (!get_tm_from_str(tmstr, tm, nanos)) { -+ if (!util_get_tm_from_str(tmstr, tm, nanos)) { - ERROR("Get tm from str failed"); - goto err_out; - } -@@ -616,7 +616,7 @@ static int64_t get_minmus_time(struct tm *tm1, struct tm *tm2) - return result; - } - --int64_t time_seconds_since(const char *in) -+int64_t util_time_seconds_since(const char *in) - { - int32_t nanos = 0; - int64_t result = 0; -@@ -835,7 +835,7 @@ static int time_format_duration_bad(char *out, size_t len) - return 1; /* format ok with bad data, return 1 */ - } - --int time_format_duration(const char *in, char *out, size_t len) -+int util_time_format_duration(const char *in, char *out, size_t len) - { - int32_t nanos = 0; - int64_t result = 0; -@@ -873,9 +873,9 @@ int time_format_duration(const char *in, char *out, size_t len) - return 0; - } - --int time_format_duration_ago(const char *in, char *out, size_t len) -+int util_time_format_duration_ago(const char *in, char *out, size_t len) - { -- if (time_format_duration(in, out, len) != 0) { -+ if (util_time_format_duration(in, out, len) != 0) { - ERROR("Get format duration"); - return -1; - } -@@ -908,7 +908,7 @@ static int time_tz_to_seconds_nanos(const char *time_tz, int64_t *seconds, int32 - time_str = util_strdup_s(time_tz); - time_str[strlen(time_str) - 1] = '\0'; /* strip last 'Z' */ - -- if (!get_tm_from_str(time_str, &t, &nano)) { -+ if (!util_get_tm_from_str(time_str, &t, &nano)) { - ERROR("get tm from string %s failed", time_str); - nret = -1; - goto err_out; -@@ -927,7 +927,7 @@ err_out: - return nret; - } - --int to_unix_nanos_from_str(const char *str, int64_t *nanos) -+int util_to_unix_nanos_from_str(const char *str, int64_t *nanos) - { - struct tm tm = { 0 }; - struct types_timezone tz; -@@ -969,3 +969,94 @@ int to_unix_nanos_from_str(const char *str, int64_t *nanos) - *nanos = mktime(&tm) * Time_Second + nano; - return 0; - } -+ -+types_timestamp_t util_to_timestamp_from_str(const char *str) -+{ -+ int64_t nanos = 0; -+ types_timestamp_t timestamp = { 0 }; -+ -+ if (util_to_unix_nanos_from_str(str, &nanos) != 0) { -+ ERROR("Failed to get created time from image config"); -+ goto out; -+ } -+ -+ timestamp.has_seconds = true; -+ timestamp.seconds = nanos / Time_Second; -+ timestamp.has_nanos = true; -+ timestamp.nanos = nanos % Time_Second; -+ -+out: -+ return timestamp; -+} -+ -+static int get_time_ns(long long *pns, long long unit) -+{ -+ if (unit == 0) { -+ return -1; -+ } -+ -+ if (INT64_MAX / *pns >= unit) { -+ *pns *= unit; -+ return 0; -+ } -+ -+ return -1; -+} -+ -+static long long get_time_unit(int unit) -+{ -+ long long u[255] = { 0 }; -+ -+ u['M'] = Time_Milli; -+ u['s'] = Time_Second; -+ u['m'] = Time_Minute; -+ u['h'] = Time_Hour; -+ -+ return u[unit]; -+} -+ -+int util_time_str_to_nanoseconds(const char *value, int64_t *nanoseconds) -+{ -+ int ret = 0; -+ long long tmp = 0; -+ char unit = 0; -+ size_t len = 0; -+ char *num_str = NULL; -+ -+ if (value == NULL || nanoseconds == NULL) { -+ return -1; -+ } -+ -+ if (util_reg_match("^([0-9]+)+(ms|s|m|h)$", value) != 0) { -+ return -1; -+ } -+ num_str = util_strdup_s(value); -+ len = strlen(value); -+ -+ if (strstr(value, "ms") == NULL) { -+ unit = *(value + len - 1); -+ *(num_str + len - 1) = '\0'; -+ } else { -+ unit = 'M'; -+ *(num_str + len - 2) = '\0'; -+ } -+ ret = util_safe_llong(num_str, &tmp); -+ if (ret < 0) { -+ ERROR("Illegal unsigned integer: %s", num_str); -+ ret = -1; -+ goto out; -+ } -+ if (tmp == 0) { -+ goto out; -+ } -+ -+ ret = get_time_ns(&tmp, get_time_unit(unit)); -+ if (ret != 0) { -+ ERROR("failed get nano seconds for %s", num_str); -+ } -+ *nanoseconds = (int64_t)tmp; -+ -+out: -+ free(num_str); -+ return ret; -+} -\ No newline at end of file -diff --git a/src/utils/cutils/utils_timestamp.h b/src/utils/cutils/utils_timestamp.h -index 603fa73..2e93a21 100644 ---- a/src/utils/cutils/utils_timestamp.h -+++ b/src/utils/cutils/utils_timestamp.h -@@ -26,6 +26,18 @@ struct tm; - extern "C" { - #endif - -+#define Time_Nano 1LL -+#define Time_Micro (1000LL * Time_Nano) -+#define Time_Milli (1000LL * Time_Micro) -+#define Time_Second (1000LL * Time_Milli) -+#define Time_Minute (60LL * Time_Second) -+#define Time_Hour (60LL * Time_Minute) -+ -+#define rFC339Local "2006-01-02T15:04:05" -+#define rFC339NanoLocal "2006-01-02T15:04:05.999999999" -+#define dateLocal "2006-01-02" -+#define defaultContainerTime "0001-01-01T00:00:00Z" -+ - typedef struct types_timestamp { - bool has_seconds; - int64_t seconds; -@@ -40,38 +52,41 @@ struct types_timezone { - - bool unix_nanos_to_timestamp(int64_t nanos, types_timestamp_t *timestamp); - --int64_t time_seconds_since(const char *in); -+int64_t util_time_seconds_since(const char *in); -+ -+int util_types_timestamp_cmp(const types_timestamp_t *t1, const types_timestamp_t *t2); - --int types_timestamp_cmp(const types_timestamp_t *t1, const types_timestamp_t *t2); -+bool util_get_timestamp(const char *str_time, types_timestamp_t *timestamp); - --bool get_timestamp(const char *str_time, types_timestamp_t *timestamp); -+bool util_get_time_buffer(const types_timestamp_t *timestamp, char *timebuffer, size_t maxsize); - --bool get_time_buffer(const types_timestamp_t *timestamp, char *timebuffer, size_t maxsize); -+bool util_get_now_time_stamp(types_timestamp_t *timestamp); - --bool get_now_time_stamp(types_timestamp_t *timestamp); -+bool util_get_now_local_utc_time_buffer(char *timebuffer, size_t maxsize); - --bool get_now_local_utc_time_buffer(char *timebuffer, size_t maxsize); -+bool util_get_now_time_buffer(char *timebuffer, size_t maxsize); - --bool get_now_time_buffer(char *timebuffer, size_t maxsize); -+int util_get_time_interval(types_timestamp_t first, types_timestamp_t last, int64_t *result); - --int get_time_interval(types_timestamp_t first, types_timestamp_t last, int64_t *result); -+int util_to_unix_nanos_from_str(const char *str, int64_t *nanos); - --int to_unix_nanos_from_str(const char *str, int64_t *nanos); -+bool util_parsing_time(const char *format, const char *time, struct tm *tm, int32_t *nanos); - --bool parsing_time(const char *format, const char *time, struct tm *tm, int32_t *nanos); -+bool util_fix_date(struct tm *tm); - --bool fix_date(struct tm *tm); -+bool util_get_tm_from_str(const char *str, struct tm *tm, int32_t *nanos); - --bool get_tm_from_str(const char *str, struct tm *tm, int32_t *nanos); -+int util_time_format_duration(const char *in, char *out, size_t len); - --int time_format_duration(const char *in, char *out, size_t len); -+int util_time_format_duration_ago(const char *in, char *out, size_t len); - --int time_format_duration_ago(const char *in, char *out, size_t len); -+types_timestamp_t util_to_timestamp_from_str(const char *str); - --int64_t get_now_time_nanos(); -+int util_time_str_to_nanoseconds(const char *value, int64_t *nanoseconds); -+ -+int64_t util_get_now_time_nanos(); - #ifdef __cplusplus - } - #endif - - #endif -- -diff --git a/src/utils/cutils/utils_verify.c b/src/utils/cutils/utils_verify.c -index 530e26b..e8bcba9 100644 ---- a/src/utils/cutils/utils_verify.c -+++ b/src/utils/cutils/utils_verify.c -@@ -225,7 +225,7 @@ bool util_valid_cap(const char *cap) - cret = false; - goto err_out; - } -- if (!strings_in_slice(g_all_caps, all_caps_len, tmpcap)) { -+ if (!util_strings_in_slice(g_all_caps, all_caps_len, tmpcap)) { - cret = false; - goto err_out; - } -@@ -640,3 +640,102 @@ bool util_valid_exec_suffix(const char *suffix) - - return util_reg_match(patten, suffix) == 0; - } -+ -+bool util_valid_positive_interger(const char *value) -+{ -+ const char *patten = "^[0-9]*$"; -+ -+ if (value == NULL) { -+ return false; -+ } -+ -+ return util_reg_match(patten, value) == 0; -+} -+ -+bool util_valid_device_cgroup_rule(const char *value) -+{ -+ const char *patten = "^([acb]) ([0-9]+|\\*):([0-9]+|\\*) ([rwm]{1,3})$"; -+ -+ if (value == NULL) { -+ return false; -+ } -+ -+ return util_reg_match(patten, value) == 0; -+} -+ -+int util_valid_env(const char *env, char **dst) -+{ -+ int ret = 0; -+ char *value = NULL; -+ -+ char **arr = util_string_split_multi(env, '='); -+ if (arr == NULL) { -+ ERROR("Failed to split env string"); -+ return -1; -+ } -+ if (strlen(arr[0]) == 0) { -+ ERROR("Invalid environment variable: %s", env); -+ ret = -1; -+ goto out; -+ } -+ -+ if (util_array_len((const char **)arr) > 1) { -+ *dst = util_strdup_s(env); -+ goto out; -+ } -+ -+ value = getenv(env); -+ if (value == NULL) { -+ *dst = NULL; -+ goto out; -+ } else { -+ int sret; -+ size_t len = strlen(env) + 1 + strlen(value) + 1; -+ *dst = (char *)util_common_calloc_s(len); -+ if (*dst == NULL) { -+ ERROR("Out of memory"); -+ ret = -1; -+ goto out; -+ } -+ sret = snprintf(*dst, len, "%s=%s", env, value); -+ if (sret < 0 || (size_t)sret >= len) { -+ ERROR("Failed to compose env string"); -+ ret = -1; -+ goto out; -+ } -+ } -+ -+out: -+ util_free_array(arr); -+ return ret; -+} -+ -+bool util_valid_sysctl(const char *sysctl_key) -+{ -+ size_t i = 0; -+ size_t full_keys_len = 0; -+ size_t key_prefixes_len = 0; -+ const char *sysctl_full_keys[] = { "kernel.msgmax", "kernel.msgmnb", "kernel.msgmni", "kernel.sem", -+ "kernel.shmall", "kernel.shmmax", "kernel.shmmni", "kernel.shm_rmid_forced" -+ }; -+ const char *sysctl_key_prefixes[] = { "net.", "fs.mqueue." }; -+ -+ if (sysctl_key == NULL) { -+ return false; -+ } -+ -+ full_keys_len = sizeof(sysctl_full_keys) / sizeof(char *); -+ key_prefixes_len = sizeof(sysctl_key_prefixes) / sizeof(char *); -+ -+ for (i = 0; i < full_keys_len; i++) { -+ if (strcmp(sysctl_full_keys[i], sysctl_key) == 0) { -+ return true; -+ } -+ } -+ for (i = 0; i < key_prefixes_len; i++) { -+ if (strncmp(sysctl_key_prefixes[i], sysctl_key, strlen(sysctl_key_prefixes[i])) == 0) { -+ return true; -+ } -+ } -+ return false; -+} -\ No newline at end of file -diff --git a/src/utils/cutils/utils_verify.h b/src/utils/cutils/utils_verify.h -index 7d431b1..26ceb34 100644 ---- a/src/utils/cutils/utils_verify.h -+++ b/src/utils/cutils/utils_verify.h -@@ -25,6 +25,15 @@ - extern "C" { - #endif - -+#define HOST_NAME_REGEXP \ -+ "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*" \ -+ "([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])$" -+#define __TagPattern "^:([A-Za-z_0-9][A-Za-z_0-9.-]{0,127})$" -+#define __NamePattern \ -+ "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])" \ -+ "((\\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+)?(:[0-9]+)?/)?[a-z0-9]" \ -+ "+((([._]|__|[-]*)[a-z0-9]+)+)?((/[a-z0-9]+((([._]|__|[-]*)[a-z0-9]+)+)?)+)?$" -+ - extern const char *g_all_caps[]; - - bool util_valid_cmd_arg(const char *arg); -@@ -99,6 +108,14 @@ bool util_valid_short_sha256_id(const char *id); - - bool util_valid_exec_suffix(const char *suffix); - -+bool util_valid_positive_interger(const char *value); -+ -+bool util_valid_device_cgroup_rule(const char *value); -+ -+int util_valid_env(const char *env, char **dst); -+ -+bool util_valid_sysctl(const char *sysctl_key); -+ - #ifdef __cplusplus - } - #endif -diff --git a/src/utils/http/parser.c b/src/utils/http/parser.c -index ec4ae43..2a69fed 100644 ---- a/src/utils/http/parser.c -+++ b/src/utils/http/parser.c -@@ -303,7 +303,7 @@ int parse_http(const char *buf, size_t len, struct parsed_http_message *m, - - nparsed = parse(buf, len, parser); - if (nparsed != len) { -- ERROR("Failed to parse it, parsed :%ld, intput:%ld \n", nparsed, len); -+ ERROR("Failed to parse it, parsed :%zu, intput:%zu \n", nparsed, len); - ret = -1; - goto free_out; - } -diff --git a/src/utils/http/rest_common.c b/src/utils/http/rest_common.c -index 7d1f1e3..1916959 100644 ---- a/src/utils/http/rest_common.c -+++ b/src/utils/http/rest_common.c -@@ -224,9 +224,9 @@ static int set_http_get_options(const char *socket, char *request_body, size_t b - - options->input_len = body_len; - raw_socket = socket; -- unix_raw_socket = str_skip_str(raw_socket, "unix://"); -+ unix_raw_socket = util_str_skip_str(raw_socket, "unix://"); - if (unix_raw_socket == NULL) { -- ERROR("Failed to str_skip_str raw_socket"); -+ ERROR("Failed to util_str_skip_str raw_socket"); - return -1; - } - options->unix_socket_path = util_strdup_s(unix_raw_socket); -@@ -291,4 +291,3 @@ void put_body(char *body) - { - free(body); - } -- -diff --git a/src/utils/sha256/sha256.c b/src/utils/sha256/sha256.c -index 31dcc9b..52f2572 100644 ---- a/src/utils/sha256/sha256.c -+++ b/src/utils/sha256/sha256.c -@@ -308,7 +308,7 @@ char *sha256_full_digest_str(char *str) - return full_digest; - } - --char *without_sha256_prefix(char *digest) -+char *util_without_sha256_prefix(char *digest) - { - if (digest == NULL || !util_has_prefix(digest, SHA256_PREFIX)) { - ERROR("Invalid digest when strip sha256 prefix"); -diff --git a/src/utils/sha256/sha256.h b/src/utils/sha256/sha256.h -index 8a40a4f..1c0750f 100644 ---- a/src/utils/sha256/sha256.h -+++ b/src/utils/sha256/sha256.h -@@ -36,7 +36,7 @@ bool sha256_valid_digest_file(const char *path, const char *digest); - - char *sha256_full_digest_str(char *str); - --char *without_sha256_prefix(char *digest); -+char *util_without_sha256_prefix(char *digest); - - #ifdef __cplusplus - } -diff --git a/src/utils/tar/isulad_tar.c b/src/utils/tar/isulad_tar.c -index 7d0088e..a3dcbaf 100644 ---- a/src/utils/tar/isulad_tar.c -+++ b/src/utils/tar/isulad_tar.c -@@ -247,21 +247,21 @@ static int get_rebase_name(const char *path, const char *real_path, - return -1; - } - -- if (specify_current_dir(path) && !specify_current_dir(real_path)) { -+ if (util_specify_current_dir(path) && !util_specify_current_dir(real_path)) { - set_char_to_separator(&resolved[strlen(resolved)]); - resolved[strlen(resolved)] = '.'; - } - -- if (has_trailing_path_separator(path) && !has_trailing_path_separator(resolved)) { -+ if (util_has_trailing_path_separator(path) && !util_has_trailing_path_separator(resolved)) { - resolved[strlen(resolved)] = '/'; - } - -- nret = split_dir_and_base_name(path, NULL, &path_base); -+ nret = util_split_dir_and_base_name(path, NULL, &path_base); - if (nret != 0) { - ERROR("split %s failed", path); - goto cleanup; - } -- nret = split_dir_and_base_name(resolved, NULL, &resolved_base); -+ nret = util_split_dir_and_base_name(resolved, NULL, &resolved_base); - if (nret != 0) { - ERROR("split %s failed", resolved); - goto cleanup; -@@ -309,7 +309,7 @@ int resolve_host_source_path(const char *path, bool follow_link, - return -1; - } - } else { -- nret = filepath_split(path, &dirpath, &basepath); -+ nret = util_filepath_split(path, &dirpath, &basepath); - if (nret < 0) { - ERROR("Can not split path %s", path); - format_errorf(err, "Can not split path %s", path); -@@ -326,19 +326,19 @@ int resolve_host_source_path(const char *path, bool follow_link, - goto cleanup; - } - *resolved_path = util_strdup_s(resolved); -- nret = split_dir_and_base_name(path, NULL, &tmp_path_base); -+ nret = util_split_dir_and_base_name(path, NULL, &tmp_path_base); - if (nret != 0) { - ERROR("split %s failed", path); - goto cleanup; - } - -- nret = split_dir_and_base_name(resolved, NULL, &tmp_resolved_base); -+ nret = util_split_dir_and_base_name(resolved, NULL, &tmp_resolved_base); - if (nret != 0) { - ERROR("split %s failed", resolved); - goto cleanup; - } - -- if (has_trailing_path_separator(path) && strcmp(tmp_path_base, tmp_resolved_base) != 0) { -+ if (util_has_trailing_path_separator(path) && strcmp(tmp_path_base, tmp_resolved_base) != 0) { - *rebase_name = tmp_path_base; - tmp_path_base = NULL; - } -@@ -413,7 +413,7 @@ static int copy_info_destination_path_ret(struct archive_copy_info *info, - } - // is not absolutely path - if (target[0] != '\0') { -- if (split_path_dir_entry(iter_path, &parent, NULL) < 0) { -+ if (util_split_path_dir_entry(iter_path, &parent, NULL) < 0) { - goto cleanup; - } - free(iter_path); -@@ -445,7 +445,7 @@ static int copy_info_destination_path_ret(struct archive_copy_info *info, - goto cleanup; - } - -- if (split_path_dir_entry(iter_path, &dst_parent, NULL) < 0) { -+ if (util_split_path_dir_entry(iter_path, &dst_parent, NULL) < 0) { - goto cleanup; - } - -@@ -503,7 +503,7 @@ cleanup: - - static bool asserts_directory(const char *path) - { -- return has_trailing_path_separator(path) || specify_current_dir(path); -+ return util_has_trailing_path_separator(path) || util_specify_current_dir(path); - } - - static char *format_transform_of_tar(const char *srcbase, const char *dstbase) -@@ -555,10 +555,10 @@ char *prepare_archive_copy(const struct archive_copy_info *srcinfo, const struct - char *srcbase = NULL; - char *dstbase = NULL; - -- if (split_path_dir_entry(dstinfo->path, &dstdir, &dstbase) < 0) { -+ if (util_split_path_dir_entry(dstinfo->path, &dstdir, &dstbase) < 0) { - goto cleanup; - } -- if (split_path_dir_entry(srcinfo->path, NULL, &srcbase) < 0) { -+ if (util_split_path_dir_entry(srcinfo->path, NULL, &srcbase) < 0) { - goto cleanup; - } - -@@ -867,7 +867,7 @@ int tar_resource_rebase(const char *path, const char *rebase, struct io_read_wra - format_errorf(err, "lstat %s: %s", path, strerror(errno)); - return -1; - } -- if (split_path_dir_entry(path, &srcdir, &srcbase) < 0) { -+ if (util_split_path_dir_entry(path, &srcdir, &srcbase) < 0) { - ERROR("Can not split path: %s", path); - goto cleanup; - } -diff --git a/src/utils/tar/util_archive.c b/src/utils/tar/util_archive.c -index fce94e5..0ae99be 100644 ---- a/src/utils/tar/util_archive.c -+++ b/src/utils/tar/util_archive.c -@@ -292,7 +292,7 @@ child_out: - } - } - -- ret = wait_for_pid(pid); -+ ret = util_wait_for_pid(pid); - if (ret != 0) { - ERROR("Wait archive_untar_handler failed"); - } -@@ -605,7 +605,7 @@ child_out: - } - } - -- ret = wait_for_pid(pid); -+ ret = util_wait_for_pid(pid); - if (ret != 0) { - ERROR("tar failed"); - fcntl(pipe_for_read[0], F_SETFL, O_NONBLOCK); -diff --git a/test/cmd/isula/CMakeLists.txt b/test/cmd/isula/CMakeLists.txt -index e30dfc6..f4701b0 100644 ---- a/test/cmd/isula/CMakeLists.txt -+++ b/test/cmd/isula/CMakeLists.txt -@@ -1,4 +1,4 @@ - project(iSulad_UT) - --add_subdirectory(infomation) -+add_subdirectory(information) - add_subdirectory(extend) -diff --git a/test/cmd/isula/extend/pause/CMakeLists.txt b/test/cmd/isula/extend/pause/CMakeLists.txt -index 9bc48e9..0179674 100644 ---- a/test/cmd/isula/extend/pause/CMakeLists.txt -+++ b/test/cmd/isula/extend/pause/CMakeLists.txt -@@ -18,7 +18,7 @@ add_executable(${EXE} - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/console/console.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula/client_arguments.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/common/err_msg.c -- ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/client/libisula.c -+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/client/connect/protocol_type.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/utils_timestamp.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/mainloop.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/error.c -diff --git a/test/cmd/isula/extend/pause/pause_ut.cc b/test/cmd/isula/extend/pause/pause_ut.cc -index 8039963..538f2d6 100644 ---- a/test/cmd/isula/extend/pause/pause_ut.cc -+++ b/test/cmd/isula/extend/pause/pause_ut.cc -@@ -78,7 +78,7 @@ TEST_F(ContainerPauseUnitTest, test_cmd_pause_main) - EXPECT_EXIT(cmd_pause_main(sizeof(argv) / sizeof(argv[0]), const_cast(argv)), - testing::ExitedWithCode(0), ""); - EXPECT_EXIT(cmd_pause_main(sizeof(argv_failure) / sizeof(argv_failure[0]), const_cast(argv_failure)), -- testing::ExitedWithCode(125), "Unkown flag found"); -+ testing::ExitedWithCode(125), "Unknown flag found"); - testing::Mock::VerifyAndClearExpectations(&m_grpcClient); - } - -diff --git a/test/cmd/isula/extend/resume/CMakeLists.txt b/test/cmd/isula/extend/resume/CMakeLists.txt -index 6e751ce..729c4d3 100644 ---- a/test/cmd/isula/extend/resume/CMakeLists.txt -+++ b/test/cmd/isula/extend/resume/CMakeLists.txt -@@ -18,7 +18,7 @@ add_executable(${EXE} - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/console/console.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula/client_arguments.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/common/err_msg.c -- ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/client/libisula.c -+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/client/connect/protocol_type.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/utils_timestamp.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/mainloop.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/error.c -diff --git a/test/cmd/isula/extend/resume/resume_ut.cc b/test/cmd/isula/extend/resume/resume_ut.cc -index e317197..48ed525 100644 ---- a/test/cmd/isula/extend/resume/resume_ut.cc -+++ b/test/cmd/isula/extend/resume/resume_ut.cc -@@ -78,7 +78,7 @@ TEST_F(ContainerResumeUnitTest, test_cmd_resume_main) - EXPECT_EXIT(cmd_resume_main(sizeof(argv) / sizeof(argv[0]), const_cast(argv)), - testing::ExitedWithCode(0), ""); - EXPECT_EXIT(cmd_resume_main(sizeof(argv_failure) / sizeof(argv_failure[0]), const_cast(argv_failure)), -- testing::ExitedWithCode(125), "Unkown flag found"); -+ testing::ExitedWithCode(125), "Unknown flag found"); - testing::Mock::VerifyAndClearExpectations(&m_grpcClient); - } - -diff --git a/test/cmd/isula/infomation/CMakeLists.txt b/test/cmd/isula/information/CMakeLists.txt -similarity index 100% -rename from test/cmd/isula/infomation/CMakeLists.txt -rename to test/cmd/isula/information/CMakeLists.txt -diff --git a/test/cmd/isula/infomation/info/CMakeLists.txt b/test/cmd/isula/information/info/CMakeLists.txt -similarity index 97% -rename from test/cmd/isula/infomation/info/CMakeLists.txt -rename to test/cmd/isula/information/info/CMakeLists.txt -index 83a51d4..2f13498 100644 ---- a/test/cmd/isula/infomation/info/CMakeLists.txt -+++ b/test/cmd/isula/information/info/CMakeLists.txt -@@ -19,7 +19,7 @@ add_executable(${EXE} - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/console/console.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula/client_arguments.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/common/err_msg.c -- ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/client/libisula.c -+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/client/connect/protocol_type.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/utils_timestamp.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/mainloop.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/error.c -diff --git a/test/cmd/isula/infomation/info/info_ut.cc b/test/cmd/isula/information/info/info_ut.cc -similarity index 98% -rename from test/cmd/isula/infomation/info/info_ut.cc -rename to test/cmd/isula/information/info/info_ut.cc -index 6a35e22..3b6efcb 100644 ---- a/test/cmd/isula/infomation/info/info_ut.cc -+++ b/test/cmd/isula/information/info/info_ut.cc -@@ -144,7 +144,7 @@ TEST_F(InfoUnitTest, test_cmd_info_main_all) - EXPECT_EXIT(cmd_info_main(sizeof(argv) / sizeof(argv[0]), const_cast(argv)), - testing::ExitedWithCode(0), ""); - EXPECT_EXIT(cmd_info_main(sizeof(argv_failure) / sizeof(argv_failure[0]), const_cast(argv_failure)), -- testing::ExitedWithCode(125), "Unkown flag found"); -+ testing::ExitedWithCode(125), "Unknown flag found"); - - std::string output = testing::internal::GetCapturedStdout(); - if (output.find("devicemapper") == std::string::npos) { -diff --git a/test/cmd/isula/infomation/ps/CMakeLists.txt b/test/cmd/isula/information/ps/CMakeLists.txt -similarity index 97% -rename from test/cmd/isula/infomation/ps/CMakeLists.txt -rename to test/cmd/isula/information/ps/CMakeLists.txt -index 2aee9d4..9659808 100644 ---- a/test/cmd/isula/infomation/ps/CMakeLists.txt -+++ b/test/cmd/isula/information/ps/CMakeLists.txt -@@ -18,7 +18,7 @@ add_executable(${EXE} - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/console/console.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/cmd/isula/client_arguments.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/common/err_msg.c -- ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/client/libisula.c -+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/client/connect/protocol_type.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/utils_timestamp.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/mainloop.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/error.c -diff --git a/test/cmd/isula/infomation/ps/ps_ut.cc b/test/cmd/isula/information/ps/ps_ut.cc -similarity index 99% -rename from test/cmd/isula/infomation/ps/ps_ut.cc -rename to test/cmd/isula/information/ps/ps_ut.cc -index 643d8fa..7436e93 100644 ---- a/test/cmd/isula/infomation/ps/ps_ut.cc -+++ b/test/cmd/isula/information/ps/ps_ut.cc -@@ -159,7 +159,7 @@ TEST_F(ContainerListUnitTest, test_cmd_list_main_all) - EXPECT_EXIT(cmd_list_main(sizeof(argv) / sizeof(argv[0]), const_cast(argv)), - testing::ExitedWithCode(0), ""); - EXPECT_EXIT(cmd_list_main(sizeof(argv_failure) / sizeof(argv_failure[0]), const_cast(argv_failure)), -- testing::ExitedWithCode(125), "Unkown flag found"); -+ testing::ExitedWithCode(125), "Unknown flag found"); - testing::Mock::VerifyAndClearExpectations(&m_grpcClient); - } - -diff --git a/test/cutils/utils_string/utils_string_ut.cc b/test/cutils/utils_string/utils_string_ut.cc -index 1d5b6e4..62e6ade 100644 ---- a/test/cutils/utils_string/utils_string_ut.cc -+++ b/test/cutils/utils_string/utils_string_ut.cc -@@ -29,59 +29,57 @@ extern "C" { - - TEST(utils_string_ut, test_strings_count) - { -- ASSERT_EQ(strings_count("aaaaaaaaaaaaaaaaaaaa", 'a'), 20); -- ASSERT_EQ(strings_count("a", 'a'), 1); -- ASSERT_EQ(strings_count("", 'a'), 0); -- ASSERT_EQ(strings_count(nullptr, 'c'), 0); -+ ASSERT_EQ(util_strings_count("aaaaaaaaaaaaaaaaaaaa", 'a'), 20); -+ ASSERT_EQ(util_strings_count("a", 'a'), 1); -+ ASSERT_EQ(util_strings_count("", 'a'), 0); -+ ASSERT_EQ(util_strings_count(nullptr, 'c'), 0); - } - - TEST(utils_string_ut, test_strings_contains_any) - { -- ASSERT_EQ(strings_contains_any("1234567890abcdefgh!@", "ijklmnopq#123456789"), true); -- ASSERT_EQ(strings_contains_any("1234567890abcdefgh!@", "ijklmnopqrstuvw)(*x&-"), false); -- ASSERT_EQ(strings_contains_any("1234567890abcdefgh!@", ""), false); -- ASSERT_EQ(strings_contains_any("1234567890abcdefgh!@", nullptr), false); -- ASSERT_EQ(strings_contains_any("a", "cedefga123415"), true); -- ASSERT_EQ(strings_contains_any("", "ijklmnopq#123456789"), false); -- ASSERT_EQ(strings_contains_any(nullptr, "ijklmnopq#123456789"), false); -+ ASSERT_EQ(util_strings_contains_any("1234567890abcdefgh!@", "ijklmnopq#123456789"), true); -+ ASSERT_EQ(util_strings_contains_any("1234567890abcdefgh!@", "ijklmnopqrstuvw)(*x&-"), false); -+ ASSERT_EQ(util_strings_contains_any("1234567890abcdefgh!@", ""), false); -+ ASSERT_EQ(util_strings_contains_any("1234567890abcdefgh!@", nullptr), false); -+ ASSERT_EQ(util_strings_contains_any("a", "cedefga123415"), true); -+ ASSERT_EQ(util_strings_contains_any("", "ijklmnopq#123456789"), false); -+ ASSERT_EQ(util_strings_contains_any(nullptr, "ijklmnopq#123456789"), false); - } - -- - TEST(utils_string_ut, test_strings_to_lower) - { - char *result = nullptr; - - std::string str = "AB&^%CDE"; -- result = strings_to_lower(str.c_str()); -+ result = util_strings_to_lower(str.c_str()); - ASSERT_STRNE(result, nullptr); - ASSERT_STREQ("ab&^%cde", result); - free(result); - - str = "abcdefg12345*()%^#@"; -- result = strings_to_lower(str.c_str()); -+ result = util_strings_to_lower(str.c_str()); - ASSERT_STRNE(result, nullptr); - ASSERT_STREQ(str.c_str(), result); - free(result); - - str = "aBcDeFg12345*()%^#@"; -- result = strings_to_lower(str.c_str()); -+ result = util_strings_to_lower(str.c_str()); - ASSERT_STRNE(result, nullptr); - ASSERT_STREQ("abcdefg12345*()%^#@", result); - free(result); - - str = ""; -- result = strings_to_lower(str.c_str()); -+ result = util_strings_to_lower(str.c_str()); - ASSERT_STRNE(result, nullptr); - ASSERT_STREQ(str.c_str(), result); - free(result); - -- result = strings_to_lower(nullptr); -+ result = util_strings_to_lower(nullptr); - ASSERT_STREQ(result, nullptr); - -- - MOCK_SET(util_strdup_s, NULL); - str = "A"; -- result = strings_to_lower(str.c_str()); -+ result = util_strings_to_lower(str.c_str()); - ASSERT_STREQ(result, NULL); - MOCK_CLEAR(util_strdup_s); - } -@@ -91,40 +89,39 @@ TEST(utils_string_ut, test_strings_to_upper) - char *result = nullptr; - - std::string str = "AB&^%CDE"; -- result = strings_to_upper(str.c_str()); -+ result = util_strings_to_upper(str.c_str()); - ASSERT_STRNE(result, nullptr); - ASSERT_STREQ(str.c_str(), result); - free(result); - - str = "abcdefg12345*()%^#@"; -- result = strings_to_upper(str.c_str()); -+ result = util_strings_to_upper(str.c_str()); - ASSERT_STRNE(result, nullptr); - ASSERT_STREQ("ABCDEFG12345*()%^#@", result); - free(result); - - str = "aBcDeFg12345*()%^#@"; -- result = strings_to_upper(str.c_str()); -+ result = util_strings_to_upper(str.c_str()); - ASSERT_STRNE(result, nullptr); - ASSERT_STREQ("ABCDEFG12345*()%^#@", result); - free(result); - - str = ""; -- result = strings_to_upper(str.c_str()); -+ result = util_strings_to_upper(str.c_str()); - ASSERT_STRNE(result, nullptr); - ASSERT_STREQ(str.c_str(), result); - free(result); - -- result = strings_to_upper(nullptr); -+ result = util_strings_to_upper(nullptr); - ASSERT_STREQ(result, nullptr); - - MOCK_SET(util_strdup_s, nullptr); - str = "a"; -- result = strings_to_upper(str.c_str()); -+ result = util_strings_to_upper(str.c_str()); - ASSERT_STREQ(result, nullptr); - MOCK_CLEAR(util_strdup_s); - } - -- - TEST(utils_string_ut, test_strings_in_slice) - { - const char *array_long[] = { "abcd", "1234", nullptr, "", "&^%abc" }; -@@ -133,14 +130,14 @@ TEST(utils_string_ut, test_strings_in_slice) - const char *array_short[] = { "abcd" }; - size_t array_short_len = sizeof(array_short) / sizeof(array_short[0]); - -- ASSERT_TRUE(strings_in_slice(array_long, array_long_len, "")); -- ASSERT_FALSE(strings_in_slice(array_long, array_long_len, "abc")); -- ASSERT_FALSE(strings_in_slice(array_long, array_long_len, nullptr)); -- ASSERT_TRUE(strings_in_slice(array_short, array_short_len, "abcd")); -- ASSERT_FALSE(strings_in_slice(array_short, array_short_len, "bcd")); -- ASSERT_FALSE(strings_in_slice(array_short, array_short_len, nullptr)); -- ASSERT_FALSE(strings_in_slice(nullptr, 0, "abcd")); -- ASSERT_FALSE(strings_in_slice(nullptr, 0, nullptr)); -+ ASSERT_TRUE(util_strings_in_slice(array_long, array_long_len, "")); -+ ASSERT_FALSE(util_strings_in_slice(array_long, array_long_len, "abc")); -+ ASSERT_FALSE(util_strings_in_slice(array_long, array_long_len, nullptr)); -+ ASSERT_TRUE(util_strings_in_slice(array_short, array_short_len, "abcd")); -+ ASSERT_FALSE(util_strings_in_slice(array_short, array_short_len, "bcd")); -+ ASSERT_FALSE(util_strings_in_slice(array_short, array_short_len, nullptr)); -+ ASSERT_FALSE(util_strings_in_slice(nullptr, 0, "abcd")); -+ ASSERT_FALSE(util_strings_in_slice(nullptr, 0, nullptr)); - } - - TEST(utils_string_ut, test_util_parse_byte_size_string) -@@ -263,7 +260,6 @@ TEST(utils_string_ut, test_util_parse_byte_size_string) - ret = util_parse_byte_size_string("1a.a1kI", &converted); - ASSERT_NE(ret, 0); - -- - ret = util_parse_byte_size_string(nullptr, &converted); - ASSERT_NE(ret, 0); - -@@ -443,25 +439,25 @@ TEST(utils_string_ut, test_str_skip_str) - const char *substr = "abcdefgh"; - const char *result = nullptr; - -- result = str_skip_str(str, substr); -+ result = util_str_skip_str(str, substr); - ASSERT_STREQ(result, "ij1234567890"); - -- result = str_skip_str(str, "habc"); -+ result = util_str_skip_str(str, "habc"); - ASSERT_STREQ(result, nullptr); - -- result = str_skip_str(str, ""); -+ result = util_str_skip_str(str, ""); - ASSERT_STREQ(result, str); - -- result = str_skip_str(str, nullptr); -+ result = util_str_skip_str(str, nullptr); - ASSERT_STREQ(result, nullptr); - -- result = str_skip_str("a", "a"); -+ result = util_str_skip_str("a", "a"); - ASSERT_STREQ(result, ""); - -- result = str_skip_str("", ""); -+ result = util_str_skip_str("", ""); - ASSERT_STREQ(result, ""); - -- result = str_skip_str(nullptr, ""); -+ result = util_str_skip_str(nullptr, ""); - ASSERT_STREQ(result, nullptr); - } - -@@ -492,10 +488,10 @@ TEST(utils_string_ut, test_util_string_delchar) - - TEST(utils_string_ut, test_util_trim_newline) - { -- char s_all[ ] = { '\n', '\n', '\n', '\n', '\0' }; -- char s_tail[ ] = { '\n', 'a', '\n', 'b', '\n', '\0' }; -- char s_not_n[ ] = { 'a', '\n', 'b', 'c', '\0' }; -- char s_empty[ ] = { '\0' }; -+ char s_all[] = { '\n', '\n', '\n', '\n', '\0' }; -+ char s_tail[] = { '\n', 'a', '\n', 'b', '\n', '\0' }; -+ char s_not_n[] = { 'a', '\n', 'b', 'c', '\0' }; -+ char s_empty[] = { '\0' }; - char *s_nullptr = nullptr; - - util_trim_newline(s_all); -@@ -516,13 +512,13 @@ TEST(utils_string_ut, test_util_trim_newline) - - TEST(utils_string_ut, test_util_trim_space) - { -- char s_all[ ] = { '\f', '\n', '\r', '\t', '\v', ' ', '\0' }; -- char s_head[ ] = { '\f', '\n', '\r', 'a', 'b', 'c', '\0' }; -- char s_tail[ ] = { 'a', 'b', 'c', '\t', '\v', ' ', '\0' }; -- char s_head_tail[ ] = { '\f', 'a', 'b', 'c', '\v', ' ', '\0' }; -- char s_mid[ ] = { 'a', 'b', '\r', '\t', '\v', 'c', '\0' }; -- char s_not_space[ ] = { 'a', 'a', 'b', 'b', 'c', 'c', '\0' }; -- char s_empty[ ] = { '\0' }; -+ char s_all[] = { '\f', '\n', '\r', '\t', '\v', ' ', '\0' }; -+ char s_head[] = { '\f', '\n', '\r', 'a', 'b', 'c', '\0' }; -+ char s_tail[] = { 'a', 'b', 'c', '\t', '\v', ' ', '\0' }; -+ char s_head_tail[] = { '\f', 'a', 'b', 'c', '\v', ' ', '\0' }; -+ char s_mid[] = { 'a', 'b', '\r', '\t', '\v', 'c', '\0' }; -+ char s_not_space[] = { 'a', 'a', 'b', 'b', 'c', 'c', '\0' }; -+ char s_empty[] = { '\0' }; - char *s_nullptr = nullptr; - char *result = nullptr; - -@@ -553,14 +549,14 @@ TEST(utils_string_ut, test_util_trim_space) - - TEST(utils_string_ut, test_util_trim_quotation) - { -- char s_all[ ] = { '"', '"', '"', '\n', '"', '\0' }; -- char s_head[ ] = { '"', '"', 'a', 'b', 'c', '\0' }; -- char s_tail_n[ ] = { 'a', 'b', 'c', '\n', '\n', '\0' }; -- char s_tail_quo[ ] = { 'a', 'b', 'c', '"', '"', '\0' }; -- char s_head_tail[ ] = { '"', '"', 'a', '\n', '"', '\0' }; -- char s_mid[ ] = { 'a', 'b', '"', '\n', 'c', '\0' }; -- char s_not_space[ ] = { 'a', 'b', 'c', 'd', 'e', '\0' }; -- char s_empty[ ] = { '\0' }; -+ char s_all[] = { '"', '"', '"', '\n', '"', '\0' }; -+ char s_head[] = { '"', '"', 'a', 'b', 'c', '\0' }; -+ char s_tail_n[] = { 'a', 'b', 'c', '\n', '\n', '\0' }; -+ char s_tail_quo[] = { 'a', 'b', 'c', '"', '"', '\0' }; -+ char s_head_tail[] = { '"', '"', 'a', '\n', '"', '\0' }; -+ char s_mid[] = { 'a', 'b', '"', '\n', 'c', '\0' }; -+ char s_not_space[] = { 'a', 'b', 'c', 'd', 'e', '\0' }; -+ char s_empty[] = { '\0' }; - char *s_nullptr = nullptr; - char *result = nullptr; - -@@ -602,7 +598,7 @@ TEST(utils_string_ut, test_str_array_dup) - - char **result = nullptr; - -- result = str_array_dup(array_long, array_long_len); -+ result = util_str_array_dup(array_long, array_long_len); - ASSERT_NE(result, nullptr); - ASSERT_STREQ(result[0], "abcd"); - free(result[0]); -@@ -616,14 +612,14 @@ TEST(utils_string_ut, test_str_array_dup) - ASSERT_STREQ(result[5], nullptr); - free(result); - -- result = str_array_dup(array_short, array_short_len); -+ result = util_str_array_dup(array_short, array_short_len); - ASSERT_NE(result, nullptr); - ASSERT_STREQ(result[0], "abcd"); - free(result[0]); - ASSERT_STREQ(result[1], nullptr); - free(result); - -- result = str_array_dup(nullptr, 0); -+ result = util_str_array_dup(nullptr, 0); - ASSERT_EQ(result, nullptr); - } - -@@ -719,7 +715,7 @@ TEST(utils_string_ut, test_dup_array_of_strings) - size_t result_len = 0; - int ret; - -- ret = dup_array_of_strings(array_long, array_long_len, &result, &result_len); -+ ret = util_dup_array_of_strings(array_long, array_long_len, &result, &result_len); - ASSERT_EQ(ret, 0); - ASSERT_EQ(array_long_len, result_len); - ASSERT_NE(result, nullptr); -@@ -734,13 +730,13 @@ TEST(utils_string_ut, test_dup_array_of_strings) - free(result[4]); - free(result); - -- ret = dup_array_of_strings(array_long, array_long_len, &result, nullptr); -+ ret = util_dup_array_of_strings(array_long, array_long_len, &result, nullptr); - ASSERT_NE(ret, 0); - -- ret = dup_array_of_strings(array_long, array_long_len, nullptr, &result_len); -+ ret = util_dup_array_of_strings(array_long, array_long_len, nullptr, &result_len); - ASSERT_NE(ret, 0); - -- ret = dup_array_of_strings(array_short, array_short_len, &result, &result_len); -+ ret = util_dup_array_of_strings(array_short, array_short_len, &result, &result_len); - ASSERT_EQ(ret, 0); - ASSERT_EQ(array_short_len, result_len); - ASSERT_NE(result, nullptr); -@@ -748,11 +744,11 @@ TEST(utils_string_ut, test_dup_array_of_strings) - free(result[0]); - free(result); - -- ret = dup_array_of_strings(nullptr, 0, &result, &result_len); -+ ret = util_dup_array_of_strings(nullptr, 0, &result, &result_len); - ASSERT_EQ(ret, 0); - - MOCK_SET(calloc, nullptr); -- ret = dup_array_of_strings(array_long, array_long_len, &result, &result_len); -+ ret = util_dup_array_of_strings(array_long, array_long_len, &result, &result_len); - ASSERT_NE(ret, 0); - MOCK_CLEAR(calloc); - } -diff --git a/test/image/oci/oci_config_merge/CMakeLists.txt b/test/image/oci/oci_config_merge/CMakeLists.txt -index 7ecce47..53f9d3f 100644 ---- a/test/image/oci/oci_config_merge/CMakeLists.txt -+++ b/test/image/oci/oci_config_merge/CMakeLists.txt -@@ -4,6 +4,7 @@ SET(EXE oci_config_merge_ut) - - add_executable(${EXE} - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/image/oci/oci_config_merge.c -+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/image/image_spec_merge.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/utils.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/utils_regex.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/utils_verify.c -@@ -11,6 +12,7 @@ add_executable(${EXE} - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/utils_string.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/utils_convert.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/utils_file.c -+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/utils_timestamp.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/map/map.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/map/rb_tree.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/util_atomic.c -@@ -47,6 +49,7 @@ target_include_directories(${EXE} PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/container/health_check - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/events - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/runtime -+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/image - ${CMAKE_BINARY_DIR}/conf - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/sha256 - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/config -diff --git a/test/image/oci/registry/registry_ut.cc b/test/image/oci/registry/registry_ut.cc -index cc51818..f656a49 100644 ---- a/test/image/oci/registry/registry_ut.cc -+++ b/test/image/oci/registry/registry_ut.cc -@@ -56,7 +56,7 @@ using ::testing::Invoke; - - std::string get_dir() - { -- char abs_path[PATH_MAX]; -+ char abs_path[PATH_MAX] { 0x00 }; - int ret = readlink("/proc/self/exe", abs_path, sizeof(abs_path)); - if (ret < 0 || (size_t)ret >= sizeof(abs_path)) { - return ""; -@@ -369,7 +369,12 @@ int invokeStorageLayerCreate(const char *layer_id, storage_layer_create_opts_t * - return 0; - } - --int invokeStorageSetHoldFlag(const char *layer_id, bool hold) -+int invokeStorageIncHoldRefs(const char *layer_id) -+{ -+ return 0; -+} -+ -+int invokeStorageDecHoldRefs(const char *layer_id) - { - return 0; - } -@@ -512,8 +517,10 @@ void mockCommonAll(MockStorage *mock, MockOciImage *oci_image_mock) - .WillRepeatedly(Invoke(invokeStorageGetImgTopLayer)); - EXPECT_CALL(*mock, StorageLayerCreate(::testing::_, ::testing::_)) - .WillRepeatedly(Invoke(invokeStorageLayerCreate)); -- EXPECT_CALL(*mock, StorageSetHoldFlag(::testing::_, ::testing::_)) -- .WillRepeatedly(Invoke(invokeStorageSetHoldFlag)); -+ EXPECT_CALL(*mock, StorageIncHoldRefs(::testing::_)) -+ .WillRepeatedly(Invoke(invokeStorageIncHoldRefs)); -+ EXPECT_CALL(*mock, StorageDecHoldRefs(::testing::_)) -+ .WillRepeatedly(Invoke(invokeStorageDecHoldRefs)); - EXPECT_CALL(*mock, StorageLayerGet(::testing::_)) - .WillRepeatedly(Invoke(invokeStorageLayerGet)); - EXPECT_CALL(*mock, StorageLayerTryRepairLowers(::testing::_, ::testing::_)) -diff --git a/test/image/oci/storage/images/storage_images_ut.cc b/test/image/oci/storage/images/storage_images_ut.cc -index 04d953a..4115e91 100644 ---- a/test/image/oci/storage/images/storage_images_ut.cc -+++ b/test/image/oci/storage/images/storage_images_ut.cc -@@ -47,7 +47,7 @@ using ::testing::_; - - std::string GetDirectory() - { -- char abs_path[PATH_MAX]; -+ char abs_path[PATH_MAX] { 0x00 }; - int ret = readlink("/proc/self/exe", abs_path, sizeof(abs_path)); - if (ret < 0 || (size_t)ret >= sizeof(abs_path)) { - return ""; -@@ -261,7 +261,7 @@ TEST_F(StorageImagesCompatibilityUnitTest, test_load_v1_image) - char store_real_path[PATH_MAX] = { 0x00 }; - struct storage_module_init_options opts; - std::string dir = GetDirectory() + "/data"; -- ASSERT_STRNE(cleanpath(dir.c_str(), store_real_path, sizeof(store_real_path)), nullptr); -+ ASSERT_STRNE(util_clean_path(dir.c_str(), store_real_path, sizeof(store_real_path)), nullptr); - - EXPECT_CALL(m_storage_mock, StorageLayersGetByCompressDigest(_)) - .WillRepeatedly(Invoke(invokeStorageLayersGetByCompressDigest)); -@@ -283,7 +283,7 @@ protected: - { - struct storage_module_init_options opts; - std::string dir = GetDirectory() + "/data"; -- ASSERT_STRNE(cleanpath(dir.c_str(), store_real_path, sizeof(store_real_path)), nullptr); -+ ASSERT_STRNE(util_clean_path(dir.c_str(), store_real_path, sizeof(store_real_path)), nullptr); - - opts.storage_root = strdup(store_real_path); - opts.driver_name = strdup("overlay"); -@@ -409,7 +409,7 @@ TEST_F(StorageImagesUnitTest, test_image_store_create) - GetDirectory() + - "/data/resources/ffc8ef7968a2acb7545006bed022001addaa262c0f760883146c4a4fae54e689/" - "=c2hhMjU2OmZmYzhlZjc5NjhhMmFjYjc1NDUwMDZiZWQwMjIwMDFhZGRhYTI2MmMwZjc2MDg4MzE0NmM0YTRmYWU1NGU2ODk="; -- ASSERT_STRNE(cleanpath(config_file.c_str(), real_path, sizeof(real_path)), "manifest"); -+ ASSERT_STRNE(util_clean_path(config_file.c_str(), real_path, sizeof(real_path)), "manifest"); - - std::ifstream t(real_path); - std::string buffer((std::istreambuf_iterator(t)), std::istreambuf_iterator()); -@@ -432,7 +432,7 @@ TEST_F(StorageImagesUnitTest, test_image_store_create) - std::string manifest_file = GetDirectory() + - "/data/resources/ffc8ef7968a2acb7545006bed022001addaa262c0f760883146c4a4fae54e689/" + - "manifest"; -- ASSERT_STRNE(cleanpath(manifest_file.c_str(), real_path, sizeof(real_path)), nullptr); -+ ASSERT_STRNE(util_clean_path(manifest_file.c_str(), real_path, sizeof(real_path)), nullptr); - - std::ifstream manifest_stream(real_path); - std::string manifest_content((std::istreambuf_iterator(manifest_stream)), std::istreambuf_iterator()); -diff --git a/test/image/oci/storage/layers/storage_driver_ut.cc b/test/image/oci/storage/layers/storage_driver_ut.cc -index 88e6f68..f99ac00 100644 ---- a/test/image/oci/storage/layers/storage_driver_ut.cc -+++ b/test/image/oci/storage/layers/storage_driver_ut.cc -@@ -42,7 +42,7 @@ using ::testing::FLAGS_gmock_catch_leaked_mocks; - - std::string GetDirectory() - { -- char abs_path[PATH_MAX]; -+ char abs_path[PATH_MAX] { 0x00 }; - int ret = readlink("/proc/self/exe", abs_path, sizeof(abs_path)); - if (ret < 0 || (size_t)ret >= sizeof(abs_path)) { - return ""; -@@ -105,7 +105,7 @@ protected: - std::string data_dir = GetDirectory() + "/data"; - struct storage_module_init_options *opts; - -- ASSERT_STRNE(cleanpath(data_dir.c_str(), data_path, sizeof(data_path)), nullptr); -+ ASSERT_STRNE(util_clean_path(data_dir.c_str(), data_path, sizeof(data_path)), nullptr); - std::string cp_command = "cp -r " + std::string(data_path) + " " + isulad_dir; - ASSERT_EQ(system(cp_command.c_str()), 0); - -diff --git a/test/image/oci/storage/layers/storage_layers_ut.cc b/test/image/oci/storage/layers/storage_layers_ut.cc -index f99c6bc..c0bc756 100644 ---- a/test/image/oci/storage/layers/storage_layers_ut.cc -+++ b/test/image/oci/storage/layers/storage_layers_ut.cc -@@ -43,7 +43,7 @@ using ::testing::_; - - std::string GetDirectory() - { -- char abs_path[PATH_MAX]; -+ char abs_path[PATH_MAX] { 0x00 }; - int ret = readlink("/proc/self/exe", abs_path, sizeof(abs_path)); - if (ret < 0 || (size_t)ret >= sizeof(abs_path)) { - return ""; -@@ -158,13 +158,13 @@ protected: - std::string run_dir = isulad_dir + "data/run"; - std::string data_dir = GetDirectory() + "/data"; - -- ASSERT_STRNE(cleanpath(data_dir.c_str(), data_path, sizeof(data_path)), nullptr); -+ ASSERT_STRNE(util_clean_path(data_dir.c_str(), data_path, sizeof(data_path)), nullptr); - std::string cp_command = "cp -r " + std::string(data_path) + " " + isulad_dir; - ASSERT_EQ(system(cp_command.c_str()), 0); - -- ASSERT_STRNE(cleanpath(root_dir.c_str(), real_path, sizeof(real_path)), nullptr); -+ ASSERT_STRNE(util_clean_path(root_dir.c_str(), real_path, sizeof(real_path)), nullptr); - opts.storage_root = strdup(real_path); -- ASSERT_STRNE(cleanpath(run_dir.c_str(), real_run_path, sizeof(real_run_path)), nullptr); -+ ASSERT_STRNE(util_clean_path(run_dir.c_str(), real_run_path, sizeof(real_run_path)), nullptr); - opts.storage_run_root = strdup(real_run_path); - opts.driver_name = strdup("overlay"); - -diff --git a/test/image/oci/storage/rootfs/storage_rootfs_ut.cc b/test/image/oci/storage/rootfs/storage_rootfs_ut.cc -index b2adc1a..a4864da 100644 ---- a/test/image/oci/storage/rootfs/storage_rootfs_ut.cc -+++ b/test/image/oci/storage/rootfs/storage_rootfs_ut.cc -@@ -35,7 +35,7 @@ std::string META_DATA_CONTENT = "metadata test"; - - std::string GetDirectory() - { -- char abs_path[PATH_MAX]; -+ char abs_path[PATH_MAX] { 0x00 }; - int ret = readlink("/proc/self/exe", abs_path, sizeof(abs_path)); - if (ret < 0 || (size_t)ret >= sizeof(abs_path)) { - return ""; -@@ -88,7 +88,7 @@ protected: - { - struct storage_module_init_options opts; - std::string dir = GetDirectory() + "/data"; -- ASSERT_STRNE(cleanpath(dir.c_str(), store_real_path, sizeof(store_real_path)), nullptr); -+ ASSERT_STRNE(util_clean_path(dir.c_str(), store_real_path, sizeof(store_real_path)), nullptr); - - opts.storage_root = strdup(store_real_path); - opts.driver_name = strdup("overlay"); -@@ -189,24 +189,6 @@ TEST_F(StorageRootfsUnitTest, test_rootfs_store_exists) - ASSERT_FALSE(rootfs_store_exists(incorrectId.c_str())); - } - --TEST_F(StorageRootfsUnitTest, test_rootfs_store_metadata) --{ -- std::string incorrectId { "ff67da98ab8540d713209" }; -- char *metadata = NULL; -- -- metadata = rootfs_store_metadata(ids.at(0).c_str()); -- ASSERT_STREQ(metadata, META_DATA_CONTENT.c_str()); -- free(metadata); -- metadata = NULL; -- -- metadata = rootfs_store_metadata(ids.at(1).c_str()); -- ASSERT_STREQ(metadata, "{}"); -- free(metadata); -- metadata = NULL; -- -- ASSERT_EQ(rootfs_store_metadata(incorrectId.c_str()), nullptr); --} -- - TEST_F(StorageRootfsUnitTest, test_rootfs_store_get_all_rootfs) - { - std::string source = std::string(store_real_path) + "/overlay-containers/" + ids.at(0); -diff --git a/test/mocks/namespace_mock.cc b/test/mocks/namespace_mock.cc -index 087cf48..823791c 100644 ---- a/test/mocks/namespace_mock.cc -+++ b/test/mocks/namespace_mock.cc -@@ -24,7 +24,7 @@ void MockNamespace_SetMock(MockNamespace* mock) - g_namespace_mock = mock; - } - --char *connected_container(const char *mode) -+char *namespace_get_connected_container(const char *mode) - { - if (g_namespace_mock != nullptr) { - return g_namespace_mock->ConnectedContainer(mode); -diff --git a/test/mocks/storage_mock.cc b/test/mocks/storage_mock.cc -index 1b50040..9976314 100644 ---- a/test/mocks/storage_mock.cc -+++ b/test/mocks/storage_mock.cc -@@ -137,10 +137,18 @@ void free_layer(struct layer *l) - return; - } - --int storage_set_hold_flag(const char *layer_id, bool hold) -+int storage_inc_hold_refs(const char *layer_id) - { - if (g_storage_mock != NULL) { -- return g_storage_mock->StorageSetHoldFlag(layer_id, hold); -+ return g_storage_mock->StorageIncHoldRefs(layer_id); -+ } -+ return -1; -+} -+ -+int storage_dec_hold_refs(const char *layer_id) -+{ -+ if (g_storage_mock != NULL) { -+ return g_storage_mock->StorageIncHoldRefs(layer_id); - } - return -1; - } -diff --git a/test/mocks/storage_mock.h b/test/mocks/storage_mock.h -index 9e34907..84eb56f 100644 ---- a/test/mocks/storage_mock.h -+++ b/test/mocks/storage_mock.h -@@ -37,7 +37,8 @@ public: - MOCK_METHOD1(StorageLayerGet, struct layer * (const char *layer_id)); - MOCK_METHOD2(StorageLayerTryRepairLowers, int(const char *layer_id, const char *last_layer_id)); - MOCK_METHOD1(FreeLayer, void(struct layer *l)); -- MOCK_METHOD2(StorageSetHoldFlag, int (const char *layer_id, bool hold)); -+ MOCK_METHOD1(StorageIncHoldRefs, int (const char *layer_id)); -+ MOCK_METHOD1(StorageDecHoldRefs, int (const char *layer_id)); - }; - - void MockStorage_SetMock(MockStorage* mock); -diff --git a/test/path/path_ut.cc b/test/path/path_ut.cc -index afd164a..ce6dcc0 100644 ---- a/test/path/path_ut.cc -+++ b/test/path/path_ut.cc -@@ -48,9 +48,7 @@ static char *getcwd_specify(char *str, size_t size) - return str; - } - --static int create_tmp_symbolic_link(const char *path, -- const char *path_file, -- const char *path_link) -+static int create_tmp_symbolic_link(const char *path, const char *path_file, const char *path_link) - { - if (path == nullptr || path_file == nullptr || path_link == nullptr) { - return -1; -@@ -93,46 +91,46 @@ TEST(path_ut, test_cleanpath) - std::string str; - char realpath[PATH_MAX]; - -- result = cleanpath(nullptr, realpath, sizeof(realpath)); -+ result = util_clean_path(nullptr, realpath, sizeof(realpath)); - ASSERT_STREQ(result, nullptr); - - str = ""; -- result = cleanpath(str.c_str(), realpath, sizeof(realpath)); -+ result = util_clean_path(str.c_str(), realpath, sizeof(realpath)); - ASSERT_STREQ(result, nullptr); - - str = "/home/dir/../file"; -- result = cleanpath(str.c_str(), realpath, sizeof(realpath)); -+ result = util_clean_path(str.c_str(), realpath, sizeof(realpath)); - ASSERT_STREQ(result, "/home/file"); - - str = "/home/dir/./file"; -- result = cleanpath(str.c_str(), realpath, sizeof(realpath)); -+ result = util_clean_path(str.c_str(), realpath, sizeof(realpath)); - ASSERT_STREQ(result, "/home/dir/file"); - - str = "./dir/file"; - MOCK_SET_V(getcwd, getcwd_specify); -- result = cleanpath(str.c_str(), realpath, sizeof(realpath)); -+ result = util_clean_path(str.c_str(), realpath, sizeof(realpath)); - ASSERT_STREQ(result, "/home/dir/file"); - MOCK_CLEAR(getcwd); - - str = "/home/file"; -- result = cleanpath(str.c_str(), realpath, PATH_LENGTH_TEST); -+ result = util_clean_path(str.c_str(), realpath, PATH_LENGTH_TEST); - ASSERT_STREQ(result, nullptr); - - str = "/home/file"; -- result = cleanpath(str.c_str(), nullptr, 0); -+ result = util_clean_path(str.c_str(), nullptr, 0); - ASSERT_STREQ(result, nullptr); - } - - TEST(path_ut, test_specify_current_dir) - { -- ASSERT_FALSE(specify_current_dir(nullptr)); -- ASSERT_TRUE(specify_current_dir("")); -- ASSERT_TRUE(specify_current_dir("/home/.")); -- ASSERT_TRUE(specify_current_dir(".")); -- ASSERT_FALSE(specify_current_dir("/home/file")); -- ASSERT_FALSE(specify_current_dir("/home/..")); -- ASSERT_FALSE(specify_current_dir("/home")); -- ASSERT_FALSE(specify_current_dir("home")); -+ ASSERT_FALSE(util_specify_current_dir(nullptr)); -+ ASSERT_TRUE(util_specify_current_dir("")); -+ ASSERT_TRUE(util_specify_current_dir("/home/.")); -+ ASSERT_TRUE(util_specify_current_dir(".")); -+ ASSERT_FALSE(util_specify_current_dir("/home/file")); -+ ASSERT_FALSE(util_specify_current_dir("/home/..")); -+ ASSERT_FALSE(util_specify_current_dir("/home")); -+ ASSERT_FALSE(util_specify_current_dir("home")); - } - - TEST(path_ut, test_follow_symlink_in_scope) -@@ -140,35 +138,35 @@ TEST(path_ut, test_follow_symlink_in_scope) - std::string fullpath, rootpath; - char *res = nullptr; - -- res = follow_symlink_in_scope(nullptr, nullptr); -+ res = util_follow_symlink_in_scope(nullptr, nullptr); - ASSERT_STREQ(res, nullptr); - free(res); - res = nullptr; - - fullpath = ""; - rootpath = ""; -- res = follow_symlink_in_scope(fullpath.c_str(), rootpath.c_str()); -+ res = util_follow_symlink_in_scope(fullpath.c_str(), rootpath.c_str()); - ASSERT_STREQ(res, nullptr); - free(res); - res = nullptr; - - fullpath = "/home/dir/file"; - rootpath = "/home"; -- res = follow_symlink_in_scope(fullpath.c_str(), rootpath.c_str()); -+ res = util_follow_symlink_in_scope(fullpath.c_str(), rootpath.c_str()); - ASSERT_STREQ(res, "/home/dir/file"); - free(res); - res = nullptr; - - fullpath = "/home/dir/file"; - rootpath = "/home/dir/../file"; -- res = follow_symlink_in_scope(fullpath.c_str(), rootpath.c_str()); -+ res = util_follow_symlink_in_scope(fullpath.c_str(), rootpath.c_str()); - ASSERT_STREQ(res, nullptr); - free(res); - res = nullptr; - - fullpath = "/home/dir/file"; - rootpath = "/home/dir/../"; -- res = follow_symlink_in_scope(fullpath.c_str(), rootpath.c_str()); -+ res = util_follow_symlink_in_scope(fullpath.c_str(), rootpath.c_str()); - ASSERT_STREQ(res, "/home/dir/file"); - free(res); - res = nullptr; -@@ -180,7 +178,7 @@ TEST(path_ut, test_follow_symlink_in_scope) - const char *path_link = "/tmp/just_for_ut/link"; - ASSERT_EQ(create_tmp_symbolic_link(path, path_file, path_link), 0); - MOCK_SET_V(readlink, readlink_specify); -- res = follow_symlink_in_scope(fullpath.c_str(), rootpath.c_str()); -+ res = util_follow_symlink_in_scope(fullpath.c_str(), rootpath.c_str()); - ASSERT_STREQ(res, "/tmp/just_for_ut/dir/file"); - MOCK_CLEAR(readlink); - ASSERT_EQ(util_recursive_rmdir("/tmp/just_for_ut", 0), 0); -@@ -193,31 +191,31 @@ TEST(path_ut, test_split_dir_and_base_name) - char *dir = nullptr; - char *base = nullptr; - -- ASSERT_EQ(split_dir_and_base_name(nullptr, &dir, &base), -1); -+ ASSERT_EQ(util_split_dir_and_base_name(nullptr, &dir, &base), -1); - free(dir); - dir = nullptr; - free(base); - base = nullptr; - -- ASSERT_EQ(split_dir_and_base_name("", &dir, &base), 0); -+ ASSERT_EQ(util_split_dir_and_base_name("", &dir, &base), 0); - free(dir); - dir = nullptr; - free(base); - base = nullptr; - -- ASSERT_EQ(split_dir_and_base_name("/home/file", &dir, &base), 0); -+ ASSERT_EQ(util_split_dir_and_base_name("/home/file", &dir, &base), 0); - free(dir); - dir = nullptr; - free(base); - base = nullptr; - -- ASSERT_EQ(split_dir_and_base_name("/home/file", nullptr, nullptr), 0); -+ ASSERT_EQ(util_split_dir_and_base_name("/home/file", nullptr, nullptr), 0); - free(dir); - dir = nullptr; - free(base); - base = nullptr; - -- split_dir_and_base_name("/home/file", &dir, &base); -+ util_split_dir_and_base_name("/home/file", &dir, &base); - ASSERT_STREQ(dir, "/home"); - ASSERT_STREQ(base, "file"); - free(dir); -@@ -231,31 +229,31 @@ TEST(path_ut, test_filepath_split) - char *dir = nullptr; - char *base = nullptr; - -- ASSERT_EQ(filepath_split(nullptr, &dir, &base), -1); -+ ASSERT_EQ(util_filepath_split(nullptr, &dir, &base), -1); - free(dir); - dir = nullptr; - free(base); - base = nullptr; - -- ASSERT_EQ(filepath_split("", &dir, &base), 0); -+ ASSERT_EQ(util_filepath_split("", &dir, &base), 0); - free(dir); - dir = nullptr; - free(base); - base = nullptr; - -- ASSERT_EQ(filepath_split("/home/file", &dir, &base), 0); -+ ASSERT_EQ(util_filepath_split("/home/file", &dir, &base), 0); - free(dir); - dir = nullptr; - free(base); - base = nullptr; - -- ASSERT_EQ(filepath_split("/home/file", nullptr, nullptr), 0); -+ ASSERT_EQ(util_filepath_split("/home/file", nullptr, nullptr), 0); - free(dir); - dir = nullptr; - free(base); - base = nullptr; - -- filepath_split("/home/file", &dir, &base); -+ util_filepath_split("/home/file", &dir, &base); - ASSERT_STREQ(dir, "/home/"); - ASSERT_STREQ(base, "file"); - free(dir); -@@ -263,7 +261,7 @@ TEST(path_ut, test_filepath_split) - free(base); - base = nullptr; - -- filepath_split("/home/", &dir, &base); -+ util_filepath_split("/home/", &dir, &base); - ASSERT_STREQ(dir, "/home/"); - ASSERT_STREQ(base, ""); - free(dir); -@@ -276,32 +274,32 @@ TEST(path_ut, test_get_resource_path) - { - char *res = nullptr; - -- res = get_resource_path(nullptr, "./test"); -+ res = util_get_resource_path(nullptr, "./test"); - ASSERT_STREQ(res, nullptr); - free(res); - res = nullptr; - -- res = get_resource_path("", ""); -+ res = util_get_resource_path("", ""); - ASSERT_STREQ(res, nullptr); - free(res); - res = nullptr; - -- res = get_resource_path("/home", "./test"); -+ res = util_get_resource_path("/home", "./test"); - ASSERT_STREQ(res, "/home/test"); - free(res); - res = nullptr; - -- res = get_resource_path("/home/dir", "tmp/.././test"); -+ res = util_get_resource_path("/home/dir", "tmp/.././test"); - ASSERT_STREQ(res, "/home/dir/test"); - free(res); - res = nullptr; - -- res = get_resource_path("/home/dir", ".././test"); -+ res = util_get_resource_path("/home/dir", ".././test"); - ASSERT_STREQ(res, nullptr); - free(res); - res = nullptr; - -- res = get_resource_path("/home////dir", ".///./././test/file"); -+ res = util_get_resource_path("/home////dir", ".///./././test/file"); - ASSERT_STREQ(res, "/home/dir/test/file"); - free(res); - res = nullptr; -@@ -313,7 +311,7 @@ TEST(path_ut, test_resolve_path) - char *resolvedpath = nullptr; - char *abspath = nullptr; - -- ASSERT_EQ(resolve_path(nullptr, nullptr, &resolvedpath, &abspath), -1); -+ ASSERT_EQ(util_resolve_path(nullptr, nullptr, &resolvedpath, &abspath), -1); - free(resolvedpath); - resolvedpath = nullptr; - free(abspath); -@@ -321,7 +319,7 @@ TEST(path_ut, test_resolve_path) - - rootpath = ""; - path = ""; -- ASSERT_EQ(resolve_path(rootpath.c_str(), path.c_str(), &resolvedpath, &abspath), -1); -+ ASSERT_EQ(util_resolve_path(rootpath.c_str(), path.c_str(), &resolvedpath, &abspath), -1); - free(resolvedpath); - resolvedpath = nullptr; - free(abspath); -@@ -329,7 +327,7 @@ TEST(path_ut, test_resolve_path) - - rootpath = "/home"; - path = "/home/dir/test"; -- ASSERT_EQ(resolve_path(rootpath.c_str(), path.c_str(), &resolvedpath, &abspath), 0); -+ ASSERT_EQ(util_resolve_path(rootpath.c_str(), path.c_str(), &resolvedpath, &abspath), 0); - free(resolvedpath); - resolvedpath = nullptr; - free(abspath); -@@ -338,10 +336,10 @@ TEST(path_ut, test_resolve_path) - - TEST(path_ut, test_has_trailing_path_separator) - { -- ASSERT_FALSE(has_trailing_path_separator(nullptr)); -- ASSERT_FALSE(has_trailing_path_separator("")); -- ASSERT_TRUE(has_trailing_path_separator("/home/")); -- ASSERT_FALSE(has_trailing_path_separator("/home")); -+ ASSERT_FALSE(util_has_trailing_path_separator(nullptr)); -+ ASSERT_FALSE(util_has_trailing_path_separator("")); -+ ASSERT_TRUE(util_has_trailing_path_separator("/home/")); -+ ASSERT_FALSE(util_has_trailing_path_separator("/home")); - } - - TEST(path_ut, test_preserve_trailing_dot_or_separator) -@@ -349,26 +347,26 @@ TEST(path_ut, test_preserve_trailing_dot_or_separator) - std::string cleanedpath, originalpath; - char *res = nullptr; - -- res = preserve_trailing_dot_or_separator(nullptr, nullptr); -+ res = util_preserve_trailing_dot_or_separator(nullptr, nullptr); - ASSERT_STREQ(res, nullptr); - free(res); - res = nullptr; - -- res = preserve_trailing_dot_or_separator("", ""); -+ res = util_preserve_trailing_dot_or_separator("", ""); - ASSERT_STREQ(res, nullptr); - free(res); - res = nullptr; - - cleanedpath = "/home/test"; - originalpath = "/home/test/."; -- res = preserve_trailing_dot_or_separator(cleanedpath.c_str(), originalpath.c_str()); -+ res = util_preserve_trailing_dot_or_separator(cleanedpath.c_str(), originalpath.c_str()); - ASSERT_STREQ(res, "/home/test/."); - free(res); - res = nullptr; - - cleanedpath = "/home/test"; - originalpath = "/home/test/"; -- res = preserve_trailing_dot_or_separator(cleanedpath.c_str(), originalpath.c_str()); -+ res = util_preserve_trailing_dot_or_separator(cleanedpath.c_str(), originalpath.c_str()); - ASSERT_STREQ(res, "/home/test/"); - free(res); - res = nullptr; -diff --git a/test/runtime/isula/CMakeLists.txt b/test/runtime/isula/CMakeLists.txt -index 9b4b350..4305997 100644 ---- a/test/runtime/isula/CMakeLists.txt -+++ b/test/runtime/isula/CMakeLists.txt -@@ -10,6 +10,7 @@ add_executable(${EXE} - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_string.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_convert.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_file.c -+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_timestamp.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/util_atomic.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/sha256/sha256.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/tar/util_gzip.c -diff --git a/test/runtime/lcr/CMakeLists.txt b/test/runtime/lcr/CMakeLists.txt -index 829027e..6f8f784 100644 ---- a/test/runtime/lcr/CMakeLists.txt -+++ b/test/runtime/lcr/CMakeLists.txt -@@ -10,6 +10,7 @@ add_executable(${EXE} - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_string.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_convert.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_file.c -+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_timestamp.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/util_atomic.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/sha256/sha256.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/path.c -diff --git a/test/specs/specs/CMakeLists.txt b/test/specs/specs/CMakeLists.txt -index c9c29b2..e64f76a 100644 ---- a/test/specs/specs/CMakeLists.txt -+++ b/test/specs/specs/CMakeLists.txt -@@ -10,6 +10,7 @@ add_executable(${EXE} - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_string.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_convert.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_file.c -+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_timestamp.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/util_atomic.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/sha256/sha256.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/path.c -diff --git a/test/specs/specs_extend/CMakeLists.txt b/test/specs/specs_extend/CMakeLists.txt -index 6193a89..50f30ad 100644 ---- a/test/specs/specs_extend/CMakeLists.txt -+++ b/test/specs/specs_extend/CMakeLists.txt -@@ -10,6 +10,7 @@ add_executable(${EXE} - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_string.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_convert.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_file.c -+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_timestamp.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/util_atomic.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/sha256/sha256.c - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/path.c --- -2.20.1 - diff --git a/0001-Add-a-solution-to-the-gpgkey-problem.patch b/0001-Add-a-solution-to-the-gpgkey-problem.patch new file mode 100644 index 0000000..d3c2702 --- /dev/null +++ b/0001-Add-a-solution-to-the-gpgkey-problem.patch @@ -0,0 +1,45 @@ +From a46546cd6c9d3e085beac143eb3b7dcff7f118e5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=E5=A4=A7=E7=BD=97=E9=A9=AC=E7=9A=84=E5=A4=AA=E9=98=B3?= + +Date: Mon, 23 Nov 2020 22:55:24 +0800 +Subject: [PATCH 1/7] Add a solution to the gpgkey problem + +--- + README.md | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/README.md b/README.md +index 08467dd..9b34d61 100644 +--- a/README.md ++++ b/README.md +@@ -25,6 +25,27 @@ Install iSulad with yum: + yum install -y iSulad + ``` + ++if you found this error ++``` ++Repository 'openEuler' is missing name in configuration, using id. ++ ++You have enabled checking of packages via GPG keys. This is a good thing. ++However, you do not have any GPG public keys installed. You need to download ++the keys for packages you wish to install and install them. ++You can do that by running the command: ++ rpm --import public.gpg.key ++ ++ ++Alternatively you can specify the url to the key you would like to use ++for a repository in the 'gpgkey' option in a repository section and YUM ++will install it for you. ++ ++For more information contact your distribution or package provider. ++ ++``` ++ ++you should run `rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-openEuler` first ++ + ### Run + We provide `systemd` service to start `iSulad`: + ```sh +-- +2.25.1 + diff --git a/0001-iSulad-modify-defattr-to-755-in-spec.patch b/0001-iSulad-modify-defattr-to-755-in-spec.patch deleted file mode 100644 index 9b2d8ec..0000000 --- a/0001-iSulad-modify-defattr-to-755-in-spec.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 44428ad14fda11c07dae69dc69f5f18d8172cae8 Mon Sep 17 00:00:00 2001 -From: gaohuatao -Date: Thu, 15 Oct 2020 09:23:19 +0800 -Subject: [PATCH 01/28] iSulad: modify defattr to 755 in spec - -Signed-off-by: gaohuatao ---- - iSulad.spec | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/iSulad.spec b/iSulad.spec -index 35bd125..534d616 100644 ---- a/iSulad.spec -+++ b/iSulad.spec -@@ -198,7 +198,7 @@ fi - %{_includedir}/isulad/* - %attr(0755,root,root) %{_libdir}/pkgconfig - %attr(0640,root,root) %{_libdir}/pkgconfig/isulad.pc --%defattr(0550,root,root,0750) -+%defattr(0755,root,root,0755) - %{_bindir}/* - %{_libdir}/* - %attr(0640,root,root) %{_sysconfdir}/sysconfig/iSulad --- -2.20.1 - diff --git a/0002-Dockerfile-update-dockerfile-to-isulad-v2.0.6-use-mu.patch b/0002-Dockerfile-update-dockerfile-to-isulad-v2.0.6-use-mu.patch deleted file mode 100644 index b34f2a8..0000000 --- a/0002-Dockerfile-update-dockerfile-to-isulad-v2.0.6-use-mu.patch +++ /dev/null @@ -1,254 +0,0 @@ -From a1cf27137ef4186f4b167b2b8becde8715c11908 Mon Sep 17 00:00:00 2001 -From: Les1ie -Date: Thu, 15 Oct 2020 18:48:27 +0800 -Subject: [PATCH 02/28] Dockerfile: update dockerfile to isulad v2.0.6; use - multi-stage to decrease the size of image; remove unused packages - -how to push docker image to dockerhub: -1. register a new user on dockerhub, username: sampleuser -2. create a new repo on dockerhub, we can name it as: isulad -3. build docker image on our own computer, run -`docker build -t sampleuser/isulad:latest .` -4. login docker hub, run command -`docker login` and input our username and password -5. run `docker push sampleuser/isulad:latest` - -we can change `latest` to other tag if we need, eg: 2.0.6 ---- - Dockerfile | 134 ++++++++++++++++++++++++++++------------------------- - 1 file changed, 72 insertions(+), 62 deletions(-) - -diff --git a/Dockerfile b/Dockerfile -index 20e714c..94b484b 100644 ---- a/Dockerfile -+++ b/Dockerfile -@@ -21,7 +21,7 @@ - # -t YOUR_IMAGE_NAME -f ./Dockerfile . - - --FROM centos:7.6.1810 -+FROM centos:7.6.1810 AS build - MAINTAINER LiFeng - - RUN echo "nameserver 8.8.8.8" > /etc/resolv.conf && \ -@@ -60,18 +60,12 @@ RUN yum clean all && yum makecache && yum install -y epel-release && yum swap -y - unzip \ - tar \ - wget \ -- gtest \ -- gtest-devel \ -- gmock \ -- gmock-devel \ - cppcheck \ - python3 \ - python3-pip \ - python \ - python-pip \ - device-mapper-devel \ -- libarchive \ -- libarchive-devel \ - libtar \ - libtar-devel \ - libcurl-devel \ -@@ -118,7 +112,7 @@ RUN set -x && \ - cd ~ && \ - git clone https://gitee.com/src-openeuler/cmake.git && \ - cd cmake && \ -- git checkout openEuler-20.03-LTS-tag && \ -+ git checkout -b openEuler-20.03-LTS-tag openEuler-20.03-LTS-tag && \ - tar -xzvf cmake-3.12.1.tar.gz && \ - cd cmake-3.12.1 && \ - ./bootstrap && make && make install && \ -@@ -131,7 +125,7 @@ RUN set -x && \ - cd ~ && \ - git clone https://gitee.com/src-openeuler/protobuf.git && \ - cd protobuf && \ -- git checkout openEuler-20.03-LTS-tag && \ -+ git checkout -b openEuler-20.03-LTS-tag openEuler-20.03-LTS-tag && \ - tar -xzvf protobuf-all-3.9.0.tar.gz && \ - cd protobuf-3.9.0 && \ - ./autogen.sh && \ -@@ -146,7 +140,7 @@ RUN export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \ - cd ~ && \ - git clone https://gitee.com/src-openeuler/c-ares.git && \ - cd c-ares && \ -- git checkout openEuler-20.03-LTS-tag && \ -+ git checkout -b openEuler-20.03-LTS-tag openEuler-20.03-LTS-tag && \ - tar -xzvf c-ares-1.15.0.tar.gz && \ - cd c-ares-1.15.0 && \ - autoreconf -if && \ -@@ -161,7 +155,7 @@ RUN export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \ - cd ~ && \ - git clone https://gitee.com/src-openeuler/grpc.git && \ - cd grpc && \ -- git checkout openEuler-20.03-LTS-tag && \ -+ git checkout -b openEuler-20.03-LTS-tag openEuler-20.03-LTS-tag && \ - tar -xzvf grpc-1.22.0.tar.gz && \ - cd grpc-1.22.0 && \ - make -j $(nproc) && \ -@@ -174,7 +168,7 @@ RUN export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \ - cd ~ && \ - git clone https://gitee.com/src-openeuler/libevent.git && \ - cd libevent && \ -- git checkout openEuler-20.03-LTS-tag && \ -+ git checkout -b openEuler-20.03-LTS-tag openEuler-20.03-LTS-tag && \ - tar -xzvf libevent-2.1.11-stable.tar.gz && \ - cd libevent-2.1.11-stable && \ - ./autogen.sh && \ -@@ -189,13 +183,11 @@ RUN export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \ - cd ~ && \ - git clone https://gitee.com/src-openeuler/libevhtp.git && \ - cd libevhtp && \ -- git checkout openEuler-20.03-LTS-tag && \ -- tar -xzvf libevhtp-1.2.18.tar.gz && \ -- cd libevhtp-1.2.18 && \ -- patch -p1 -F1 -s < ../0001-decrease-numbers-of-fd-for-shared-pipe-mode.patch && \ -- patch -p1 -F1 -s < ../0002-evhtp-enable-dynamic-thread-pool.patch && \ -- patch -p1 -F1 -s < ../0003-close-open-ssl.-we-do-NOT-use-it-in-lcrd.patch && \ -- patch -p1 -F1 -s < ../0004-Use-shared-library-instead-static-one.patch && \ -+ git checkout -b openEuler-20.03-LTS-tag openEuler-20.03-LTS-tag && \ -+ tar -xzvf libevhtp-1.2.16.tar.gz && \ -+ cd libevhtp-1.2.16 && \ -+ patch -p1 -F1 -s < ../0001-support-dynamic-threads.patch && \ -+ patch -p1 -F1 -s < ../0002-close-openssl.patch && \ - rm -rf build && \ - mkdir build && \ - cd build && \ -@@ -210,7 +202,7 @@ RUN export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \ - cd ~ && \ - git clone https://gitee.com/src-openeuler/http-parser.git && \ - cd http-parser && \ -- git checkout openEuler-20.03-LTS-tag && \ -+ git checkout -b openEuler-20.03-LTS-tag openEuler-20.03-LTS-tag && \ - tar -xzvf http-parser-2.9.2.tar.gz && \ - cd http-parser-2.9.2 && \ - make -j CFLAGS="-Wno-error" && \ -@@ -223,7 +215,7 @@ RUN export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \ - cd ~ && \ - git clone https://gitee.com/src-openeuler/libwebsockets.git && \ - cd libwebsockets && \ -- git checkout openEuler-20.03-LTS-tag && \ -+ git checkout -b openEuler-20.03-LTS-tag openEuler-20.03-LTS-tag && \ - tar -xzvf libwebsockets-2.4.2.tar.gz && \ - cd libwebsockets-2.4.2 && \ - patch -p1 -F1 -s < ../libwebsockets-fix-coredump.patch && \ -@@ -234,56 +226,74 @@ RUN export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \ - make install && \ - ldconfig - --# install lxc -+# install gtest/gmock - RUN export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \ - set -x && \ - cd ~ && \ -- git clone https://gitee.com/src-openeuler/lxc.git && \ -- cd lxc && \ -- ./apply-patches && \ -- cd lxc-4.0.3 && \ -- ./autogen.sh && \ -- ./configure && \ -- make -j $(nproc) && \ -- make install && \ -- ldconfig -- --# install lcr --RUN export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \ -- set -x && \ -- cd ~ && \ -- git clone https://gitee.com/openeuler/lcr.git && \ -- cd lcr && \ -- mkdir build && \ -+ git clone https://gitee.com/src-openeuler/gtest.git && \ -+ cd gtest && \ -+ git checkout -b openEuler-20.03-LTS-tag openEuler-20.03-LTS-tag && \ -+ tar xf release-1.8.1.tar.gz && \ -+ cd googletest-release-1.8.1 && \ -+ patch -p1 -F1 -s < ../gtest-1.8.1-null-pointer.patch && \ -+ patch -p1 -F1 -s < ../gtest-PR1839-Fix-Python3-support.patch && \ -+ patch -p1 -F1 -s < ../gtest-1.8.1-libversion.patch && \ -+ patch -p1 -F1 -s < ../gtest-1.8.1-add-missing-pkgconfig-requires.patch && \ -+ mkdir -p build && \ - cd build && \ -- cmake ../ && \ -+ cmake -DBUILD_SHARED_LIBS=ON ../ && \ - make -j $(nproc) && \ - make install && \ - ldconfig - --# install clibcni -+# install libarchive - RUN export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \ -- set -x && \ -- cd ~ && \ -- git clone https://gitee.com/openeuler/clibcni.git && \ -- cd clibcni && \ -- mkdir build && \ -- cd build && \ -- cmake ../ && \ -- make -j $(nproc) && \ -- make install && \ -- ldconfig -+ set -x && \ -+ cd ~ && \ -+ git clone https://gitee.com/src-openeuler/libarchive.git && \ -+ cd libarchive && \ -+ git checkout -b openEuler-20.03-LTS-tag openEuler-20.03-LTS-tag && \ -+ tar -zxvf libarchive-3.4.1.tar.gz && \ -+ cd libarchive-3.4.1 && \ -+ patch -p1 -F1 -s < ../libarchive-uninitialized-value.patch && \ -+ cd build && \ -+ cmake -DCMAKE_USE_SYSTEM_LIBRARIES=ON ../ && \ -+ make -j $(nproc) && \ -+ make install && \ -+ ldconfig - --# install iSulad-img - RUN export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH && \ -- set -x && \ -- cd ~ && \ -- git clone https://gitee.com/openeuler/iSulad-img.git && \ -- cd iSulad-img && \ -- ./apply-patch && \ -- make -j $(nproc) && \ -- make install && \ -- ldconfig -- -+ set -x && \ -+ cd ~ && \ -+ git clone https://gitee.com/openeuler/iSulad/ &&\ -+ cd iSulad &&\ -+ # git checkout 756c0bdc308c2845971ad9ca0c58760a84288bc0 &&\ -+ git checkout v2.0.6 &&\ -+ cd CI &&\ -+ ./install_depends.sh &&\ -+ cd .. &&\ -+ mkdir build &&\ -+ cd build &&\ -+ cmake .. &&\ -+ make -j $(nproc) && \ -+ make install && \ -+ ldconfig -+ -+FROM centos:7.6.1810 -+ -+COPY --from=build /usr/local/bin /usr/local/bin -+COPY --from=build /usr/local/lib /usr/local/lib -+COPY --from=build /usr/local/lib64 /usr/local/lib64 -+COPY --from=build /usr/lib64 /usr/lib64 -+COPY --from=build /etc/default/isulad/ /etc/default/isulad/ -+COPY --from=build /etc/isulad /etc/isulad -+ -+ -+ -+RUN echo "/usr/lib" >> /etc/ld.so.conf && \ -+ echo "/usr/local/lib" >> /etc/ld.so.conf &&\ -+ ldconfig -+ -+ - VOLUME [ "/sys/fs/cgroup" ] --CMD ["/usr/sbin/init"] -+CMD ["/usr/local/bin/isulad"] -\ No newline at end of file --- -2.20.1 - diff --git a/0002-change-default-tmp-directory-from-var-tmp-to-var-lib.patch b/0002-change-default-tmp-directory-from-var-tmp-to-var-lib.patch new file mode 100644 index 0000000..9698143 --- /dev/null +++ b/0002-change-default-tmp-directory-from-var-tmp-to-var-lib.patch @@ -0,0 +1,606 @@ +From e17d4ea9e2e6ec5555429cbc0363748e33170dea Mon Sep 17 00:00:00 2001 +From: WangFengTu +Date: Mon, 23 Nov 2020 16:52:56 +0800 +Subject: [PATCH 2/7] change default tmp directory from /var/tmp to + /var/lib/isulad/tmp + +Signed-off-by: WangFengTu +--- + src/daemon/modules/image/oci/oci_image.c | 21 +++- + src/daemon/modules/image/oci/oci_load.c | 20 ++-- + .../modules/image/oci/registry/registry.c | 20 ++-- + .../modules/image/oci/storage/storage.c | 34 ------ + .../modules/image/oci/storage/storage.h | 2 - + src/daemon/modules/image/oci/utils_images.c | 102 ++++++++++++++---- + src/daemon/modules/image/oci/utils_images.h | 3 +- + test/image/oci/registry/CMakeLists.txt | 2 +- + test/image/oci/registry/registry_ut.cc | 22 +++- + test/image/oci/storage/images/CMakeLists.txt | 2 + + .../oci/storage/images/storage_images_ut.cc | 1 + + test/image/oci/storage/rootfs/CMakeLists.txt | 4 +- + .../oci/storage/rootfs/storage_rootfs_ut.cc | 1 + + test/mocks/isulad_config_mock.cc | 16 +++ + test/mocks/isulad_config_mock.h | 2 + + 15 files changed, 160 insertions(+), 92 deletions(-) + +diff --git a/src/daemon/modules/image/oci/oci_image.c b/src/daemon/modules/image/oci/oci_image.c +index f0ba19c..f4fa1e8 100644 +--- a/src/daemon/modules/image/oci/oci_image.c ++++ b/src/daemon/modules/image/oci/oci_image.c +@@ -150,26 +150,34 @@ out: + return ret; + } + +-static void cleanup_image_tmpdir() ++static int recreate_image_tmpdir() + { + char *image_tmp_path = NULL; ++ int ret = 0; + +- image_tmp_path = get_image_tmp_path(); ++ image_tmp_path = oci_get_isulad_tmpdir(); + if (image_tmp_path == NULL) { + ERROR("failed to get image tmp path"); +- return; ++ ret = -1; ++ goto out; + } + + if (util_recursive_rmdir(image_tmp_path, 0)) { + ERROR("failed to remove directory %s", image_tmp_path); ++ ret = -1; ++ goto out; + } + + if (util_mkdir_p(image_tmp_path, TEMP_DIRECTORY_MODE)) { + ERROR("failed to create directory %s", image_tmp_path); ++ ret = -1; ++ goto out; + } ++ ++out: + free(image_tmp_path); + +- return; ++ return ret; + } + + int oci_init(const isulad_daemon_configs *args) +@@ -181,7 +189,10 @@ int oci_init(const isulad_daemon_configs *args) + return ret; + } + +- cleanup_image_tmpdir(); ++ ret = recreate_image_tmpdir(); ++ if (ret != 0) { ++ goto out; ++ } + + ret = registry_init(NULL, NULL); + if (ret != 0) { +diff --git a/src/daemon/modules/image/oci/oci_load.c b/src/daemon/modules/image/oci/oci_load.c +index 073ad55..97cff34 100644 +--- a/src/daemon/modules/image/oci/oci_load.c ++++ b/src/daemon/modules/image/oci/oci_load.c +@@ -1011,25 +1011,23 @@ static char *oci_load_path_create() + { + int ret = 0; + int nret = 0; +- char *oci_load_work_dir = NULL; ++ char *image_tmp_path = NULL; + char tmp_dir[PATH_MAX] = { 0 }; + +- oci_load_work_dir = storage_oci_load_work_dir(); +- if (oci_load_work_dir == NULL) { +- ERROR("Failed to get oci load work dir"); +- isulad_try_set_error_message("Failed to get oci load work dir"); +- ret = -1; ++ ret = makesure_isulad_tmpdir_perm_right(); ++ if (ret != 0) { ++ ERROR("failed to make sure permission of image tmp work dir"); + goto out; + } + +- if (util_mkdir_p(oci_load_work_dir, TEMP_DIRECTORY_MODE) != 0) { +- ERROR("Unable to create oci image load tmp work dir:%s", oci_load_work_dir); +- isulad_try_set_error_message("Unable to create oci image load tmp work dir:%s", oci_load_work_dir); ++ image_tmp_path = oci_get_isulad_tmpdir(); ++ if (image_tmp_path == NULL) { ++ ERROR("failed to get image tmp work dir"); + ret = -1; + goto out; + } + +- nret = snprintf(tmp_dir, PATH_MAX, "%s/oci-image-load-XXXXXX", oci_load_work_dir); ++ nret = snprintf(tmp_dir, PATH_MAX, "%s/oci-image-load-XXXXXX", image_tmp_path); + if (nret < 0 || (size_t)nret >= sizeof(tmp_dir)) { + ERROR("Path is too long"); + ret = -1; +@@ -1044,7 +1042,7 @@ static char *oci_load_path_create() + } + + out: +- free(oci_load_work_dir); ++ free(image_tmp_path); + return ret == 0 ? util_strdup_s(tmp_dir) : NULL; + } + +diff --git a/src/daemon/modules/image/oci/registry/registry.c b/src/daemon/modules/image/oci/registry/registry.c +index 2656b9b..a94d10b 100644 +--- a/src/daemon/modules/image/oci/registry/registry.c ++++ b/src/daemon/modules/image/oci/registry/registry.c +@@ -1718,7 +1718,13 @@ static int prepare_pull_desc(pull_descriptor *desc, registry_pull_options *optio + + update_host(desc); + +- image_tmp_path = get_image_tmp_path(); ++ ret = makesure_isulad_tmpdir_perm_right(); ++ if (ret != 0) { ++ ERROR("failed to make sure permission of image tmp work dir"); ++ goto out; ++ } ++ ++ image_tmp_path = oci_get_isulad_tmpdir(); + if (image_tmp_path == NULL) { + ERROR("failed to get image tmp work dir"); + ret = -1; +@@ -1859,18 +1865,6 @@ static void cached_layers_kvfree(void *key, void *value) + int registry_init(char *auths_dir, char *certs_dir) + { + int ret = 0; +- char *image_tmp_path = NULL; +- +- image_tmp_path = get_image_tmp_path(); +- if (image_tmp_path == NULL) { +- ERROR("failed to get image tmp path"); +- return -1; +- } +- +- if (util_mkdir_p(image_tmp_path, TEMP_DIRECTORY_MODE)) { +- ERROR("failed to create directory %s", image_tmp_path); +- } +- free(image_tmp_path); + + auths_set_dir(auths_dir); + certs_set_dir(certs_dir); +diff --git a/src/daemon/modules/image/oci/storage/storage.c b/src/daemon/modules/image/oci/storage/storage.c +index f15531b..0d83707 100644 +--- a/src/daemon/modules/image/oci/storage/storage.c ++++ b/src/daemon/modules/image/oci/storage/storage.c +@@ -1715,20 +1715,6 @@ out: + int storage_module_init(struct storage_module_init_options *opts) + { + int ret = 0; +- char *oci_load_work_dir = NULL; +- +- oci_load_work_dir = storage_oci_load_work_dir(); +- if (oci_load_work_dir == NULL) { +- ERROR("Get oci load work dir failed"); +- ret = -1; +- goto out; +- } +- +- ret = util_recursive_rmdir(oci_load_work_dir, 0); +- if (ret != 0) { +- ERROR("failed to remove dir %s", oci_load_work_dir); +- goto out; +- } + + if (check_module_init_opt(opts) != 0) { + ret = -1; +@@ -1783,25 +1769,5 @@ int storage_module_init(struct storage_module_init_options *opts) + } + + out: +- free(oci_load_work_dir); + return ret; + } +- +- +-char *storage_oci_load_work_dir() +-{ +- char *isulad_tmp = NULL; +- char *oci_load_work_dir = NULL; +- +- isulad_tmp = oci_get_isulad_tmpdir(); +- if (isulad_tmp == NULL) { +- ERROR("Failed to get isulad tmp dir"); +- goto out; +- } +- +- oci_load_work_dir = util_path_join(isulad_tmp, "isulad-oci-load"); +- +-out: +- free(isulad_tmp); +- return oci_load_work_dir; +-} +\ No newline at end of file +diff --git a/src/daemon/modules/image/oci/storage/storage.h b/src/daemon/modules/image/oci/storage/storage.h +index b030a3a..f214192 100644 +--- a/src/daemon/modules/image/oci/storage/storage.h ++++ b/src/daemon/modules/image/oci/storage/storage.h +@@ -179,8 +179,6 @@ int storage_rootfs_umount(const char *container_id, bool force); + + container_inspect_graph_driver *storage_get_metadata_by_container_id(const char *id); + +-char *storage_oci_load_work_dir(); +- + #ifdef __cplusplus + } + #endif +diff --git a/src/daemon/modules/image/oci/utils_images.c b/src/daemon/modules/image/oci/utils_images.c +index de0eb32..7eddd25 100644 +--- a/src/daemon/modules/image/oci/utils_images.c ++++ b/src/daemon/modules/image/oci/utils_images.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + #include "isula_libutils/log.h" + #include "utils.h" +@@ -36,10 +37,10 @@ + #include "utils_file.h" + #include "utils_string.h" + #include "utils_verify.h" ++#include "isulad_config.h" + + // nanos of 2038-01-19T03:14:07, the max valid linux time + #define MAX_NANOS 2147483647000000000 +-#define ISULAD_DEFAULT_TMP_DIR "/var/tmp" + + char *get_last_part(char **parts) + { +@@ -488,36 +489,101 @@ bool oci_valid_time(char *time) + return true; + } + ++static int makesure_path_is_dir(char *path) ++{ ++ struct stat st = {0}; ++ ++ if (lstat(path, &st) != 0) { ++ if (errno == ENOENT) { ++ return util_mkdir_p(path, TEMP_DIRECTORY_MODE); ++ } ++ ERROR("lstat %s failed: %s", path, strerror(errno)); ++ return -1; ++ } ++ ++ if (!S_ISDIR(st.st_mode)) { ++ if (util_recursive_rmdir(path, 0)) { ++ ERROR("failed to remove directory %s", path); ++ return -1; ++ } ++ } ++ ++ if (util_mkdir_p(path, TEMP_DIRECTORY_MODE) != 0) { ++ ERROR("make dir:%s failed", path); ++ return -1; ++ } ++ ++ return 0; ++} + + char *oci_get_isulad_tmpdir() + { +- char *isula_tmp = NULL; ++ char *isulad_tmpdir = NULL; ++ char *isulad_root_dir = NULL; ++ char *env_dir = NULL; ++ int ret = 0; + +- isula_tmp = getenv("ISULAD_TMPDIR"); +- if (util_valid_str(isula_tmp) && !util_dir_exists(isula_tmp)) { +- if (util_mkdir_p(isula_tmp, TEMP_DIRECTORY_MODE) != 0) { +- ERROR("make dir:%s failed", isula_tmp); +- return NULL; +- } ++ isulad_root_dir = conf_get_isulad_rootdir(); ++ if (isulad_root_dir == NULL) { ++ ERROR("get isulad root dir failed"); ++ return NULL; + } + +- return util_valid_str(isula_tmp) ? util_strdup_s(isula_tmp) : util_strdup_s(ISULAD_DEFAULT_TMP_DIR); ++ env_dir = getenv("ISULAD_TMPDIR"); ++ if (util_valid_str(env_dir)) { ++ isulad_tmpdir = util_path_join(env_dir, "isulad_tmpdir"); ++ } else { ++ isulad_tmpdir = util_path_join(isulad_root_dir, "isulad_tmpdir"); ++ } ++ if (isulad_tmpdir == NULL) { ++ ERROR("join temporary directory failed"); ++ ret = -1; ++ goto out; ++ } ++ ++out: ++ free(isulad_root_dir); ++ if (ret != 0) { ++ free(isulad_tmpdir); ++ isulad_tmpdir = NULL; ++ } ++ ++ return isulad_tmpdir; + } + +-char *get_image_tmp_path() ++int makesure_isulad_tmpdir_perm_right() + { +- char *isulad_tmp = NULL; +- char *isula_image = NULL; ++ struct stat st = {0}; ++ char *isulad_tmpdir = NULL; ++ int ret = 0; ++ ++ isulad_tmpdir = oci_get_isulad_tmpdir(); ++ if (isulad_tmpdir == NULL) { ++ return -1; ++ } + +- isulad_tmp = oci_get_isulad_tmpdir(); +- if (isulad_tmp == NULL) { +- ERROR("Failed to get isulad tmp dir"); ++ ret = makesure_path_is_dir(isulad_tmpdir); ++ if (ret != 0) { ++ goto out; ++ } ++ ++ if (lstat(isulad_tmpdir, &st) != 0) { ++ ERROR("lstat %s failed: %s", isulad_tmpdir, strerror(errno)); ++ ret = -1; + goto out; + } + +- isula_image = util_path_join(isulad_tmp, "isula-image"); ++ // chown to root ++ ret = lchown(isulad_tmpdir, 0, 0); ++ if (ret == 0 || (ret == EPERM && st.st_uid == 0 && st.st_gid == 0)) { ++ ret = 0; ++ goto out; ++ } else { ++ ERROR("lchown %s failed: %s", isulad_tmpdir, strerror(errno)); ++ } + + out: +- free(isulad_tmp); +- return isula_image; ++ free(isulad_tmpdir); ++ ++ return ret; + } +diff --git a/src/daemon/modules/image/oci/utils_images.h b/src/daemon/modules/image/oci/utils_images.h +index 5dedd56..cebcc79 100644 +--- a/src/daemon/modules/image/oci/utils_images.h ++++ b/src/daemon/modules/image/oci/utils_images.h +@@ -55,8 +55,7 @@ int add_rootfs_and_history(const layer_blob *layers, size_t layers_len, const re + bool oci_valid_time(char *time); + + char *oci_get_isulad_tmpdir(); +- +-char *get_image_tmp_path(); ++int makesure_isulad_tmpdir_perm_right(); + + #ifdef __cplusplus + } +diff --git a/test/image/oci/registry/CMakeLists.txt b/test/image/oci/registry/CMakeLists.txt +index 9e34103..36e7cab 100644 +--- a/test/image/oci/registry/CMakeLists.txt ++++ b/test/image/oci/registry/CMakeLists.txt +@@ -24,7 +24,6 @@ add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/buffer/buffer.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/utils_aes.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/image/oci/storage/image_store/image_type.c +- ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/config/isulad_config.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/image/oci/registry_type.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/common/sysinfo.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/image/oci/storage/image_store/image_store.c +@@ -37,6 +36,7 @@ add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../mocks/storage_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../mocks/oci_image_mock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../mocks/http_mock.cc ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../mocks/isulad_config_mock.cc + registry_ut.cc) + + target_include_directories(${EXE} PUBLIC +diff --git a/test/image/oci/registry/registry_ut.cc b/test/image/oci/registry/registry_ut.cc +index f656a49..25ddf69 100644 +--- a/test/image/oci/registry/registry_ut.cc ++++ b/test/image/oci/registry/registry_ut.cc +@@ -43,6 +43,7 @@ + #include "aes.h" + #include "auths.h" + #include "oci_image_mock.h" ++#include "isulad_config_mock.h" + + using ::testing::Args; + using ::testing::ByRef; +@@ -79,17 +80,21 @@ protected: + MockHttp_SetMock(&m_http_mock); + MockStorage_SetMock(&m_storage_mock); + MockOciImage_SetMock(&m_oci_image_mock); ++ MockIsuladConf_SetMock(&m_isulad_conf_mock); + } + + void TearDown() override + { + MockHttp_SetMock(nullptr); + MockStorage_SetMock(nullptr); ++ MockOciImage_SetMock(nullptr); ++ MockIsuladConf_SetMock(nullptr); + } + + NiceMock m_http_mock; + NiceMock m_storage_mock; + NiceMock m_oci_image_mock; ++ NiceMock m_isulad_conf_mock; + }; + + int invokeHttpRequestV1(const char *url, struct http_get_options *options, long *response_code, int recursive_len) +@@ -497,7 +502,12 @@ static int init_log() + return 0; + } + +-void mockCommonAll(MockStorage *mock, MockOciImage *oci_image_mock) ++static char *invokeConfGetISuladRootDir() ++{ ++ return util_strdup_s(get_dir().c_str()); ++} ++ ++void mockCommonAll(MockStorage *mock, MockOciImage *oci_image_mock, MockIsuladConf *isulad_conf_mock) + { + EXPECT_CALL(*mock, StorageImgCreate(::testing::_, ::testing::_, ::testing::_, ::testing::_)) + .WillRepeatedly(Invoke(invokeStorageImgCreate)); +@@ -531,6 +541,8 @@ void mockCommonAll(MockStorage *mock, MockOciImage *oci_image_mock) + .WillRepeatedly(Invoke(invokeFreeLayer)); + EXPECT_CALL(*oci_image_mock, OciValidTime(::testing::_)) + .WillRepeatedly(Invoke(invokeOciValidTime)); ++ EXPECT_CALL(*isulad_conf_mock, ConfGetISuladRootDir()) ++ .WillRepeatedly(Invoke(invokeConfGetISuladRootDir)); + return; + } + +@@ -588,7 +600,7 @@ TEST_F(RegistryUnitTest, test_pull_v1_image) + + EXPECT_CALL(m_http_mock, HttpRequest(::testing::_, ::testing::_, ::testing::_, ::testing::_)) + .WillRepeatedly(Invoke(invokeHttpRequestV1)); +- mockCommonAll(&m_storage_mock, &m_oci_image_mock); ++ mockCommonAll(&m_storage_mock, &m_oci_image_mock, &m_isulad_conf_mock); + ASSERT_EQ(registry_pull(&options), 0); + + ASSERT_EQ(registry_pull(&options), 0); +@@ -648,7 +660,7 @@ TEST_F(RegistryUnitTest, test_pull_v2_image) + + EXPECT_CALL(m_http_mock, HttpRequest(::testing::_, ::testing::_, ::testing::_, ::testing::_)) + .WillRepeatedly(Invoke(invokeHttpRequestV2)); +- mockCommonAll(&m_storage_mock, &m_oci_image_mock); ++ mockCommonAll(&m_storage_mock, &m_oci_image_mock, &m_isulad_conf_mock); + + // test retry success + ASSERT_EQ(registry_pull(&options), 0); +@@ -682,7 +694,7 @@ TEST_F(RegistryUnitTest, test_pull_oci_image) + options->insecure_registry = false; + EXPECT_CALL(m_http_mock, HttpRequest(::testing::_, ::testing::_, ::testing::_, ::testing::_)) + .WillRepeatedly(Invoke(invokeHttpRequestOCI)); +- mockCommonAll(&m_storage_mock, &m_oci_image_mock); ++ mockCommonAll(&m_storage_mock, &m_oci_image_mock, &m_isulad_conf_mock); + ASSERT_EQ(registry_pull(options), 0); + + free_registry_pull_options(options); +@@ -700,7 +712,7 @@ TEST_F(RegistryUnitTest, test_pull_already_exist) + + EXPECT_CALL(m_http_mock, HttpRequest(::testing::_, ::testing::_, ::testing::_, ::testing::_)) + .WillRepeatedly(Invoke(invokeHttpRequestV2)); +- mockCommonAll(&m_storage_mock, &m_oci_image_mock); ++ mockCommonAll(&m_storage_mock, &m_oci_image_mock, &m_isulad_conf_mock); + EXPECT_CALL(m_storage_mock, StorageLayerGet(::testing::_)) + .WillRepeatedly(Invoke(invokeStorageLayerGet1)); + ASSERT_EQ(registry_pull(&options), 0); +diff --git a/test/image/oci/storage/images/CMakeLists.txt b/test/image/oci/storage/images/CMakeLists.txt +index 82ad468..b00c5a0 100644 +--- a/test/image/oci/storage/images/CMakeLists.txt ++++ b/test/image/oci/storage/images/CMakeLists.txt +@@ -22,6 +22,7 @@ add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/modules/image/oci/registry_type.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/modules/image/oci/storage/image_store/image_store.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/storage_mock.cc ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/isulad_config_mock.cc + storage_images_ut.cc) + + target_include_directories(${EXE} PUBLIC +@@ -34,6 +35,7 @@ target_include_directories(${EXE} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/map + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/sha256 + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/http ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/config + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/modules/image/oci + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/modules/image/oci/storage + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/modules/image/oci/storage/image_store +diff --git a/test/image/oci/storage/images/storage_images_ut.cc b/test/image/oci/storage/images/storage_images_ut.cc +index 4115e91..234ab74 100644 +--- a/test/image/oci/storage/images/storage_images_ut.cc ++++ b/test/image/oci/storage/images/storage_images_ut.cc +@@ -33,6 +33,7 @@ + #include "isula_libutils/imagetool_images_list.h" + #include "isula_libutils/imagetool_image.h" + #include "storage_mock.h" ++#include "isulad_config_mock.h" + + using ::testing::Args; + using ::testing::ByRef; +diff --git a/test/image/oci/storage/rootfs/CMakeLists.txt b/test/image/oci/storage/rootfs/CMakeLists.txt +index 3ba56bb..8da8196 100644 +--- a/test/image/oci/storage/rootfs/CMakeLists.txt ++++ b/test/image/oci/storage/rootfs/CMakeLists.txt +@@ -21,6 +21,7 @@ add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/modules/image/oci/storage/rootfs_store/rootfs.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/modules/image/oci/storage/rootfs_store/rootfs_store.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/storage_mock.cc ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../mocks/isulad_config_mock.cc + storage_rootfs_ut.cc) + + target_include_directories(${EXE} PUBLIC +@@ -33,7 +34,8 @@ target_include_directories(${EXE} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/sha256 + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/json/schema/src + ${CMAKE_BINARY_DIR}/conf +- ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../test/mocks ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/config + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/modules/image/oci + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/modules/image/oci/storage + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/modules/image/oci/storage/rootfs_store +diff --git a/test/image/oci/storage/rootfs/storage_rootfs_ut.cc b/test/image/oci/storage/rootfs/storage_rootfs_ut.cc +index a4864da..9cf91fa 100644 +--- a/test/image/oci/storage/rootfs/storage_rootfs_ut.cc ++++ b/test/image/oci/storage/rootfs/storage_rootfs_ut.cc +@@ -30,6 +30,7 @@ + #include "utils.h" + #include "path.h" + #include "storage.h" ++#include "isulad_config_mock.h" + + std::string META_DATA_CONTENT = "metadata test"; + +diff --git a/test/mocks/isulad_config_mock.cc b/test/mocks/isulad_config_mock.cc +index 9d99315..88a74a4 100644 +--- a/test/mocks/isulad_config_mock.cc ++++ b/test/mocks/isulad_config_mock.cc +@@ -136,3 +136,19 @@ char *conf_get_isulad_storage_driver_backing_fs() + } + return nullptr; + } ++ ++char *conf_get_isulad_rootdir() ++{ ++ if (g_isulad_conf_mock != nullptr) { ++ return g_isulad_conf_mock->ConfGetISuladRootDir(); ++ } ++ return nullptr; ++} ++ ++bool conf_get_use_decrypted_key_flag() ++{ ++ if (g_isulad_conf_mock != nullptr) { ++ return g_isulad_conf_mock->ConfGetUseDecryptedKeyFlag(); ++ } ++ return true; ++} +diff --git a/test/mocks/isulad_config_mock.h b/test/mocks/isulad_config_mock.h +index fdf27cd..03af3cc 100644 +--- a/test/mocks/isulad_config_mock.h ++++ b/test/mocks/isulad_config_mock.h +@@ -34,6 +34,8 @@ public: + MOCK_METHOD1(GetSystemCpuUsage, int(uint64_t *val)); + MOCK_METHOD0(ConfGetIsuladStorageDriverBackingFs, char *()); + MOCK_METHOD0(GetMonitordPath, char *(void)); ++ MOCK_METHOD0(ConfGetISuladRootDir, char *(void)); ++ MOCK_METHOD0(ConfGetUseDecryptedKeyFlag, bool (void)); + }; + + void MockIsuladConf_SetMock(MockIsuladConf *mock); +-- +2.25.1 + diff --git a/0003-isulad-rt_isula_start-should-read-the-isulad-shim-pi.patch b/0003-isulad-rt_isula_start-should-read-the-isulad-shim-pi.patch deleted file mode 100644 index a01f0c1..0000000 --- a/0003-isulad-rt_isula_start-should-read-the-isulad-shim-pi.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 3942bcc4c3a755d33e709046edd358f9af264d11 Mon Sep 17 00:00:00 2001 -From: holyfei -Date: Wed, 21 Oct 2020 10:00:15 +0800 -Subject: [PATCH 03/28] isulad: rt_isula_start should read the isulad-shim - pidinfo - -reason: the ppid of init pid should be isulad-shim, read isulad-shim pidinfo and set the start time for init pidinfo - -Signed-off-by: yangfeiyu ---- - .../modules/runtime/isula/isula_rt_ops.c | 38 ++++++++++++++++++- - 1 file changed, 36 insertions(+), 2 deletions(-) - -diff --git a/src/daemon/modules/runtime/isula/isula_rt_ops.c b/src/daemon/modules/runtime/isula/isula_rt_ops.c -index 6e4512f..82d7aec 100644 ---- a/src/daemon/modules/runtime/isula/isula_rt_ops.c -+++ b/src/daemon/modules/runtime/isula/isula_rt_ops.c -@@ -851,8 +851,13 @@ out: - int rt_isula_start(const char *id, const char *runtime, const rt_start_params_t *params, pid_ppid_info_t *pid_info) - { - char workdir[PATH_MAX] = { 0 }; -+ char shim_pid_file_name[PATH_MAX] = { 0 }; - pid_t pid = 0; -+ pid_t shim_pid = -1; - int ret = 0; -+ int splice_ret = 0; -+ proc_t *proc = NULL; -+ proc_t *p_proc = NULL; - - if (id == NULL || runtime == NULL || params == NULL || pid_info == NULL) { - ERROR("nullptr arguments not allowed"); -@@ -863,6 +868,12 @@ int rt_isula_start(const char *id, const char *runtime, const rt_start_params_t - return -1; - } - -+ splice_ret = snprintf(shim_pid_file_name, sizeof(shim_pid_file_name), "%s/shim-pid", workdir); -+ if (splice_ret < 0 || splice_ret >= sizeof(shim_pid_file_name)) { -+ ERROR("%s: wrong shim workdir", id); -+ return -1; -+ } -+ - pid = get_container_process_pid(workdir); - if (pid < 0) { - ret = -1; -@@ -870,12 +881,32 @@ int rt_isula_start(const char *id, const char *runtime, const rt_start_params_t - goto out; - } - -- if (util_read_pid_ppid_info(pid, pid_info) != 0) { -+ file_read_int(shim_pid_file_name, &shim_pid); -+ if (shim_pid < 0) { -+ ret = -1; -+ ERROR("%s: failed to read isulad shim pid", id); -+ goto out; -+ } -+ -+ proc = util_get_process_proc_info(pid); -+ if (proc == NULL) { - ret = -1; -- ERROR("%s: failed read pid info", id); -+ ERROR("%s: failed to read pidinfo", id); - goto out; - } - -+ p_proc = util_get_process_proc_info(shim_pid); -+ if (p_proc == NULL) { -+ ret = -1; -+ ERROR("%s: failed to read isulad shim pidinfo", id); -+ goto out; -+ } -+ -+ pid_info->pid = proc->pid; -+ pid_info->start_time = proc->start_time; -+ pid_info->ppid = shim_pid; -+ pid_info->pstart_time = p_proc->start_time; -+ - if (runtime_call_simple(workdir, runtime, "start", NULL, 0, id) != 0) { - ERROR("call runtime start id failed"); - ret = -1; -@@ -888,6 +919,9 @@ out: - shim_kill_force(workdir); - } - -+ free(proc); -+ free(p_proc); -+ - return ret; - } - --- -2.20.1 - diff --git a/0003-update-api.proto-to-v1.19.3-according-to-kubelet.patch b/0003-update-api.proto-to-v1.19.3-according-to-kubelet.patch new file mode 100644 index 0000000..d8801db --- /dev/null +++ b/0003-update-api.proto-to-v1.19.3-according-to-kubelet.patch @@ -0,0 +1,102 @@ +From 5720b90e9515a698b5f9cde21a99194848f2c66a Mon Sep 17 00:00:00 2001 +From: gaohuatao +Date: Fri, 13 Nov 2020 03:21:16 -0500 +Subject: [PATCH 3/7] update api.proto to v1.19.3 according to kubelet + +Signed-off-by: gaohuatao +--- + src/api/services/cri/api.proto | 31 ++++++++++++++++++++ + src/daemon/entry/cri/cri_security_context.cc | 7 +++++ + 2 files changed, 38 insertions(+) + +diff --git a/src/api/services/cri/api.proto b/src/api/services/cri/api.proto +index 67e5527..dc0cfeb 100644 +--- a/src/api/services/cri/api.proto ++++ b/src/api/services/cri/api.proto +@@ -219,6 +219,13 @@ enum NamespaceMode { + // For example, a container with a PID namespace of NODE expects to view + // all of the processes on the host running the kubelet. + NODE = 2; ++ // TARGET targets the namespace of another container. When this is specified, ++ // a target_id must be specified in NamespaceOption and refer to a container ++ // previously created with NamespaceMode CONTAINER. This containers namespace ++ // will be made to match that of container target_id. ++ // For example, a container with a PID namespace of TARGET expects to view ++ // all of the processes that container target_id can view. ++ TARGET = 3; + } + + // NamespaceOption provides options for Linux namespaces. +@@ -236,6 +243,10 @@ message NamespaceOption { + // Note: There is currently no way to set CONTAINER scoped IPC in the Kubernetes API. + // Namespaces currently set by the kubelet: POD, NODE + NamespaceMode ipc = 3; ++ // Target Container ID for NamespaceMode of TARGET. This container must have been ++ // previously created in the same pod. It is not possible to specify different targets ++ // for each namespace. ++ string target_id = 4; + } + + // Int64Value is the wrapper of int64. +@@ -519,6 +530,10 @@ message ListPodSandboxResponse { + // future it will include more detailed information about the different image types. + message ImageSpec { + string image = 1; ++ // Unstructured key-value map holding arbitrary metadata. ++ // ImageSpec Annotations can be used to help the runtime target specific ++ // images in multi-arch images. ++ map annotations = 2; + } + + message KeyValue { +@@ -545,6 +560,19 @@ message LinuxContainerResources { + string cpuset_cpus = 6; + // CpusetMems constrains the allowed set of memory nodes. Default: "" (not specified). + string cpuset_mems = 7; ++ // List of HugepageLimits to limit the HugeTLB usage of container per page size. Default: nil (not specified). ++ repeated HugepageLimit hugepage_limits = 8; ++} ++ ++// HugepageLimit corresponds to the file`hugetlb..limit_in_byte` in container level cgroup. ++// For example, `PageSize=1GB`, `Limit=1073741824` means setting `1073741824` bytes to hugetlb.1GB.limit_in_bytes. ++message HugepageLimit { ++ // The value of PageSize has the format B (2MB, 1GB), ++ // and must match the of the corresponding control file found in `hugetlb..limit_in_bytes`. ++ // The values of are intended to be parsed using base 1024("1KB" = 1024, "1MB" = 1048576, etc). ++ string page_size = 1; ++ // limit in bytes of hugepagesize HugeTLB usage. ++ uint64 limit = 2; + } + + // SELinuxOption are the labels to be applied to the container. +@@ -1040,6 +1068,9 @@ message Image { + // User name that will run the command(s). This is used if UID is not set + // and no user is specified when creating container. + string username = 6; ++ // ImageSpec for image which includes annotations ++ ImageSpec spec = 7; ++ + } + + message ListImagesResponse { +diff --git a/src/daemon/entry/cri/cri_security_context.cc b/src/daemon/entry/cri/cri_security_context.cc +index 634e53a..1d33226 100644 +--- a/src/daemon/entry/cri/cri_security_context.cc ++++ b/src/daemon/entry/cri/cri_security_context.cc +@@ -179,6 +179,13 @@ static void ModifyContainerNamespaceOptions(const runtime::v1alpha2::NamespaceOp + hostConfig->pid_mode = util_strdup_s(sandboxNSMode.c_str()); + } + ++ ++ if (nsOpts.pid() == runtime::v1alpha2::NamespaceMode::TARGET) { ++ std::string targetPidNsMode = "container:" + nsOpts.target_id(); ++ free(hostConfig->pid_mode); ++ hostConfig->pid_mode = util_strdup_s(targetPidNsMode.c_str()); ++ } ++ + /* set common Namespace options */ + ModifyCommonNamespaceOptions(nsOpts, hostConfig); + /* modify host network option for container */ +-- +2.25.1 + diff --git a/0004-Realpath-add-get-realpath-for-root-and-state-dir.patch b/0004-Realpath-add-get-realpath-for-root-and-state-dir.patch deleted file mode 100644 index e86f87b..0000000 --- a/0004-Realpath-add-get-realpath-for-root-and-state-dir.patch +++ /dev/null @@ -1,240 +0,0 @@ -From cc721f53f64e9ec7e6329beaf24b2df2a3d1ff4e Mon Sep 17 00:00:00 2001 -From: lifeng68 -Date: Wed, 21 Oct 2020 10:21:04 +0800 -Subject: [PATCH 04/28] Realpath: add get realpath for root and state dir - -Signed-off-by: lifeng68 ---- - src/cmd/isulad/isulad_commands.c | 20 +++++++- - .../graphdriver/devmapper/deviceset.c | 48 +++++++++---------- - .../graphdriver/devmapper/driver_devmapper.c | 37 +++++++++++--- - 3 files changed, 70 insertions(+), 35 deletions(-) - -diff --git a/src/cmd/isulad/isulad_commands.c b/src/cmd/isulad/isulad_commands.c -index 2826aae..90fc51a 100644 ---- a/src/cmd/isulad/isulad_commands.c -+++ b/src/cmd/isulad/isulad_commands.c -@@ -195,6 +195,7 @@ static int check_args_graph_path(struct service_arguments *args) - { - int ret = 0; - char dstpath[PATH_MAX] = { 0 }; -+ char *real_path = NULL; - - ret = util_validate_absolute_path(args->json_confs->graph); - if (ret) { -@@ -207,8 +208,15 @@ static int check_args_graph_path(struct service_arguments *args) - ret = -1; - goto out; - } -+ -+ if (util_realpath_in_scope("/", dstpath, &real_path) != 0) { -+ ERROR("failed to get real path"); -+ ret = -1; -+ goto out; -+ } -+ - free(args->json_confs->graph); -- args->json_confs->graph = util_strdup_s(dstpath); -+ args->json_confs->graph = real_path; - - out: - return ret; -@@ -218,6 +226,7 @@ static int check_args_state_path(struct service_arguments *args) - { - int ret = 0; - char dstpath[PATH_MAX] = { 0 }; -+ char *real_path = NULL; - - ret = util_validate_absolute_path(args->json_confs->state); - if (ret != 0) { -@@ -230,8 +239,15 @@ static int check_args_state_path(struct service_arguments *args) - ret = -1; - goto out; - } -+ -+ if (util_realpath_in_scope("/", dstpath, &real_path) != 0) { -+ ERROR("failed to get real path"); -+ ret = -1; -+ goto out; -+ } -+ - free(args->json_confs->state); -- args->json_confs->state = util_strdup_s(dstpath); -+ args->json_confs->state = real_path; - - out: - return ret; -diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.c -index fb2f502..cadb061 100644 ---- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.c -+++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.c -@@ -1145,9 +1145,10 @@ static int pool_has_free_space(struct device_set *devset) - ERROR("devmapper: Thin Pool has %lu free data blocks which is less than minimum required " - "%lu free data blocks. Create more free space in thin pool or use dm.min_free_space option to change behavior", - data_total - data_used, min_free_data); -- isulad_set_error_message("devmapper: Thin Pool has %lu free data blocks which is less than minimum required " -- "%lu free data blocks. Create more free space in thin pool or use dm.min_free_space option to change behavior", -- data_total - data_used, min_free_data); -+ isulad_set_error_message( -+ "devmapper: Thin Pool has %lu free data blocks which is less than minimum required " -+ "%lu free data blocks. Create more free space in thin pool or use dm.min_free_space option to change behavior", -+ data_total - data_used, min_free_data); - ret = -1; - goto out; - } -@@ -1163,10 +1164,11 @@ static int pool_has_free_space(struct device_set *devset) - "which is less than minimum required %lu free metadata blocks. " - "Create more free metadata space in thin pool or use dm.min_free_space option to change behavior", - metadata_total - metadata_used, min_free_metadata); -- isulad_set_error_message("devmapper: Thin Pool has %lu free metadata blocks " -- "which is less than minimum required %lu free metadata blocks. " -- "Create more free metadata space in thin pool or use dm.min_free_space option to change behavior", -- metadata_total - metadata_used, min_free_metadata); -+ isulad_set_error_message( -+ "devmapper: Thin Pool has %lu free metadata blocks " -+ "which is less than minimum required %lu free metadata blocks. " -+ "Create more free metadata space in thin pool or use dm.min_free_space option to change behavior", -+ metadata_total - metadata_used, min_free_metadata); - ret = -1; - goto out; - } -@@ -1652,7 +1654,8 @@ static int take_snapshot(struct device_set *devset, const char *hash, image_devm - if (dinfo.deferred_remove != 0) { - nret = cancel_deferred_removal(devset, base_info->hash); - if (nret != 0) { -- ERROR("devmapper: cancel deferred remove for device with hash:%s failed, err:%s", base_info->hash, dev_strerror(nret)); -+ ERROR("devmapper: cancel deferred remove for device with hash:%s failed, err:%s", base_info->hash, -+ dev_strerror(nret)); - if (nret != ERR_ENXIO) { - ERROR("devmapper: cancel device(id:%s) deferred remove failed", base_info->hash); - ret = -1; -@@ -1721,7 +1724,8 @@ static int cancel_deferred_removal_if_needed(struct device_set *devset, image_de - - nret = cancel_deferred_removal(devset, info->hash); - if (nret != 0 && nret != ERR_BUSY) { -- ERROR("devmapper: cancel deferred remove for device with hash:%s failed, err:%s", info->hash, dev_strerror(nret)); -+ ERROR("devmapper: cancel deferred remove for device with hash:%s failed, err:%s", info->hash, -+ dev_strerror(nret)); - ret = -1; - goto out; - } -@@ -2563,7 +2567,8 @@ static int determine_driver_capabilities(const char *version, struct device_set - - if (major < 4) { - ERROR("devicamapper driver version:(%ld.xxx) < 4.27.0, do not surpport deferred removal", major); -- isulad_set_error_message("devicamapper driver version:(%ld.xxx) < 4.27.0, do not surpport deferred removal", major); -+ isulad_set_error_message("devicamapper driver version:(%ld.xxx) < 4.27.0, do not surpport deferred removal", -+ major); - ret = -1; - goto out; - } -@@ -2584,7 +2589,8 @@ static int determine_driver_capabilities(const char *version, struct device_set - */ - if (minor < 27) { - ERROR("devicamapper driver version (4.%ld) < 4.27.0, , do not surpport deferred removal", minor); -- isulad_set_error_message("devicamapper driver version (4.%ld) < 4.27.0, , do not surpport deferred removal", minor); -+ isulad_set_error_message("devicamapper driver version (4.%ld) < 4.27.0, , do not surpport deferred removal", -+ minor); - ret = -1; - goto out; - } -@@ -2951,17 +2957,10 @@ int unmount_device(const char *hash, const char *mount_path, struct device_set * - goto free_out; - } - -- if (util_detect_mounted(mount_path)) { -- if (umount2(mount_path, MNT_DETACH) < 0 && errno != EINVAL) { -- ERROR("Failed to umount directory %s:%s", mount_path, strerror(errno)); -- ret = -1; -- goto free_out; -- } -- } -- -- if (util_path_remove(mount_path) != 0) { -- DEBUG("devmapper: doing remove on a unmounted device %s failed", mount_path); -+ if (umount2(mount_path, MNT_DETACH) < 0 && errno != EINVAL) { -+ ERROR("Failed to umount directory %s:%s", mount_path, strerror(errno)); - ret = -1; -+ goto free_out; - } - - if (deactivate_device(devset, device_info->info) != 0) { -@@ -3167,7 +3166,6 @@ struct status *device_set_status(struct device_set *devset) - st->sem_msg = util_strdup_s(msg); - } - -- - free_out: - (void)pthread_rwlock_unlock(&devset->devmapper_driver_rwlock); - return st; -@@ -3222,10 +3220,8 @@ static int umount_deactivate_dev_all(struct device_set *devset) - continue; - } - -- if (util_detect_mounted(fname)) { -- if (umount2(fname, MNT_DETACH) < 0 && errno != EINVAL) { -- ERROR("Failed to umount directory %s:%s", fname, strerror(errno)); -- } -+ if (umount2(fname, MNT_DETACH) < 0 && errno != EINVAL) { -+ ERROR("Failed to umount directory %s:%s", fname, strerror(errno)); - } - - device_info = lookup_device(devset, entry->d_name); -diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.c -index 1043c6c..ec337a8 100644 ---- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.c -+++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.c -@@ -82,7 +82,36 @@ out: - static int do_create(const char *id, const char *parent, const struct graphdriver *driver, - const struct driver_create_opts *create_opts) - { -- return add_device(id, parent, driver->devset, create_opts->storage_opt); -+ int ret = 0; -+ char *mnt_parent_dir = NULL; -+ char *mnt_point_dir = NULL; -+ -+ mnt_parent_dir = util_path_join(driver->home, "mnt"); -+ if (mnt_parent_dir == NULL) { -+ ERROR("Failed to join devmapper mnt dir %s", id); -+ ret = -1; -+ goto out; -+ } -+ -+ mnt_point_dir = util_path_join(mnt_parent_dir, id); -+ if (mnt_point_dir == NULL) { -+ ERROR("Failed to join devampper mount point dir %s", id); -+ ret = -1; -+ goto out; -+ } -+ -+ if (util_mkdir_p(mnt_point_dir, DEFAULT_SECURE_DIRECTORY_MODE) != 0) { -+ ERROR("Failed to mkdir path:%s", mnt_point_dir); -+ ret = -1; -+ goto out; -+ } -+ -+ ret = add_device(id, parent, driver->devset, create_opts->storage_opt); -+ -+out: -+ free(mnt_parent_dir); -+ free(mnt_point_dir); -+ return ret; - } - - // devmapper_create_rw creates a layer that is writable for use as a container file system -@@ -186,12 +215,6 @@ char *devmapper_mount_layer(const char *id, const struct graphdriver *driver, - goto out; - } - -- if (util_mkdir_p(mnt_point_dir, DEFAULT_SECURE_DIRECTORY_MODE) != 0) { -- ERROR("Failed to mkdir path:%s", mnt_point_dir); -- ret = -1; -- goto out; -- } -- - if (mount_device(id, mnt_point_dir, mount_opts, driver->devset) != 0) { - ERROR("Mount device:%s to path:%s failed", id, mnt_parent_dir); - ret = -1; --- -2.20.1 - diff --git a/0004-adapt-CI-ISULAD_TMPDIR-testcases.patch b/0004-adapt-CI-ISULAD_TMPDIR-testcases.patch new file mode 100644 index 0000000..42c9715 --- /dev/null +++ b/0004-adapt-CI-ISULAD_TMPDIR-testcases.patch @@ -0,0 +1,50 @@ +From 3a15d0174b16207915ab5736ee45f5018472b251 Mon Sep 17 00:00:00 2001 +From: WangFengTu +Date: Tue, 24 Nov 2020 14:51:57 +0800 +Subject: [PATCH 4/7] adapt CI ISULAD_TMPDIR testcases + +Signed-off-by: WangFengTu +--- + CI/test_cases/image_cases/isulad_tmpdir.sh | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/CI/test_cases/image_cases/isulad_tmpdir.sh b/CI/test_cases/image_cases/isulad_tmpdir.sh +index 22a6ad4..46849ae 100644 +--- a/CI/test_cases/image_cases/isulad_tmpdir.sh ++++ b/CI/test_cases/image_cases/isulad_tmpdir.sh +@@ -58,8 +58,8 @@ function test_isulad_tmpdir() + export ISULAD_TMPDIR="/var/isula/tmp" + restart_isulad + load_pull_test +- test -d /var/isula/tmp/isula-image +- [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - isula-image not exist in ISULAD_TMPDIR" && ((ret++)) ++ test -d /var/isula/tmp/isulad_tmpdir ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - isulad_tmpdir not exist in ISULAD_TMPDIR" && ((ret++)) + + # The scene of ISULAD_TMPDIR dir is symbol link that it refers to dir exists + rm -rf /var/isula/tmp +@@ -69,8 +69,8 @@ function test_isulad_tmpdir() + export ISULAD_TMPDIR="/var/isula/tmpdir" + restart_isulad + load_pull_test +- test -d /var/isula/tmpdir/isula-image +- [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - isula-image not exist in ISULAD_TMPDIR" && ((ret++)) ++ test -d /var/isula/tmpdir/isulad_tmpdir ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - isulad_tmpdir not exist in ISULAD_TMPDIR" && ((ret++)) + + # rm dest dir of symbol link + rm -rf /var/tmpdir +@@ -86,8 +86,8 @@ function test_isulad_tmpdir() + [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - start isulad failed" && ((ret++)) + + load_pull_test +- test -d /var/tmp/isula-image +- [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - isula-image not exist in /var/tmp" && ((ret++)) ++ test -d /var/lib/isulad/isulad_tmpdir ++ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - isulad_tmpdir not exist in /var/lib/isulad" && ((ret++)) + + msg_info "${test} finished with return ${ret}..." + return ${ret} +-- +2.25.1 + diff --git a/0005-CI-add-testcase-for-root-and-run-dir-realpath.patch b/0005-CI-add-testcase-for-root-and-run-dir-realpath.patch deleted file mode 100644 index dc4aa8d..0000000 --- a/0005-CI-add-testcase-for-root-and-run-dir-realpath.patch +++ /dev/null @@ -1,318 +0,0 @@ -From 86567b77cc367a96b80c129ad13791851768b860 Mon Sep 17 00:00:00 2001 -From: lifeng68 -Date: Wed, 21 Oct 2020 10:36:07 +0800 -Subject: [PATCH 05/28] CI: add testcase for root and run dir realpath - -Signed-off-by: lifeng68 ---- - .../container_cases/graph_root_test.sh | 284 ++++++++++++++++++ - CI/test_cases/image_cases/image_tag.sh | 2 + - 2 files changed, 286 insertions(+) - create mode 100644 CI/test_cases/container_cases/graph_root_test.sh - -diff --git a/CI/test_cases/container_cases/graph_root_test.sh b/CI/test_cases/container_cases/graph_root_test.sh -new file mode 100644 -index 0000000..678d176 ---- /dev/null -+++ b/CI/test_cases/container_cases/graph_root_test.sh -@@ -0,0 +1,284 @@ -+#!/bin/bash -+# -+# attributes: isulad root and run dir realpath test -+# concurrent: NA -+# spend time: 5 -+ -+####################################################################### -+##- @Copyright (C) Huawei Technologies., 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. -+##- @Description:CI -+##- @Author: lifeng -+##- @Create: 2020-09-03 -+####################################################################### -+ -+declare -r curr_path=$(dirname $(readlink -f "$0")) -+source ../helpers.sh -+ -+function reinstall_thinpool() -+{ -+ local ret=0 -+ -+ cat /etc/isulad/daemon.json | grep driver | grep devicemapper -+ if [[ $? -ne 0 ]]; then -+ return ${ret} -+ fi -+ -+ dev_disk=`pvs | grep isulad | awk '{print$1}'` -+ rm -rf /var/lib/isulad/* -+ dmsetup remove_all -+ lvremove -f isulad/thinpool -+ lvremove -f isulad/thinpoolmeta -+ vgremove -f isulad -+ pvremove -f $dev_disk -+ mount | grep $dev_disk | grep /var/lib/isulad -+ if [ x"$?" == x"0" ]; then -+ umount /var/lib/isulad -+ fi -+ touch /etc/lvm/profile/isulad-thinpool.profile -+ cat > /etc/lvm/profile/isulad-thinpool.profile <&1 | grep "Nano CPUs and CPU Period cannot both be set" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Nano CPUs and CPU Period cannot both be set" && ((ret++)) -+ -+ isula update --cpus 1.3 --cpu-quota 20000 $c_id 2>&1 | grep "Nano CPUs and CPU Quota cannot both be set" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Nano CPUs and CPU Quota cannot both be set" && ((ret++)) -+ -+ isula update --cpu-period 20000 $c_id 2>&1 | grep "CPU Period cannot be updated as NanoCPUs has already been set" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - CPU Period cannot be updated as NanoCPUs has already been set" && ((ret++)) -+ -+ isula update --cpu-quota 20000 $c_id 2>&1 | grep "CPU Quota cannot be updated as NanoCPUs has already been set" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - CPU Quota cannot be updated as NanoCPUs has already been set" && ((ret++)) -+ -+ isula update --cpus 1.3 $c_id -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Failed to update cpus" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us" | grep "130000" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_quota_us: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us" | grep "100000" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_period_us: ${image}" && ((ret++)) -+ -+ isula restart -t 0 $c_id -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to restart container: $c_id" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us" | grep "130000" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_quota_us: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us" | grep "100000" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_period_us: ${image}" && ((ret++)) -+ -+ isula rm -f $c_id -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to rm container ${c_id}" && ((ret++)) -+ -+ check_valgrind_log -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - stop isulad failed" && ((ret++)) -+ -+ cp -f /etc/isulad/daemon.bak /etc/isulad/daemon.json -+ -+ rm -rf /var/lib/isulad/opt/test_root -+ rm -rf /opt/test_run -+ rm -rf /var/lib/isulad_test -+ rm -rf /var/run/isulad_test -+ -+ reinstall_thinpool -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - fail to reconfig isulad-thinpool" && ((ret++)) -+ -+ start_isulad_with_valgrind -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - start isulad failed" && ((ret++)) -+ -+ msg_info "${test} finished with return ${ret}..." -+ return ${ret} -+} -+ -+function test_run_root_dir_bind_realpath() -+{ -+ local ret=0 -+ local image="busybox" -+ local test="isulad root and run dir realpath test => (${FUNCNAME[@]})" -+ -+ msg_info "${test} starting..." -+ -+ check_valgrind_log -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - stop isulad failed" && ((ret++)) -+ -+ reinstall_thinpool -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - fail to reconfig isulad-thinpool" && ((ret++)) -+ -+ mkdir -p /var/lib/isulad/opt/bind_root -+ mkdir -p /opt/bind_run -+ -+ cp -f /etc/isulad/daemon.json /etc/isulad/daemon.bak -+ -+ sed -i 's#"graph": "/var/lib/isulad",#"graph": "/var/lib/isulad/bind/isulad_test",#g' /etc/isulad/daemon.json -+ sed -i 's#"state": "/var/run/isulad",#"state": "/var/run/isulad_test",#g' /etc/isulad/daemon.json -+ -+ mkdir -p /var/lib/isulad/bind/isulad_test -+ mount --bind /var/lib/isulad/opt/bind_root /var/lib/isulad/bind/isulad_test -+ -+ mkdir -p /var/run/isulad_test -+ mount --bind /opt/bind_run /var/run/isulad_test -+ -+ start_isulad_with_valgrind -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - start isulad failed" && ((ret++)) -+ -+ isula pull ${image} -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to pull image: ${image}" && ((ret++)) -+ -+ isula images | grep busybox -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - missing list image: ${image}" && ((ret++)) -+ -+ c_id=`isula run -itd --cpus 1.5 busybox sh` -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to run container with image: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us" | grep "150000" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_quota_us: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us" | grep "100000" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_period_us: ${image}" && ((ret++)) -+ -+ isula restart -t 0 $c_id -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to restart container: $c_id" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us" | grep "150000" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_quota_us: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us" | grep "100000" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_period_us: ${image}" && ((ret++)) -+ -+ isula update --cpus 1.3 --cpu-period 20000 $c_id 2>&1 | grep "Nano CPUs and CPU Period cannot both be set" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Nano CPUs and CPU Period cannot both be set" && ((ret++)) -+ -+ isula update --cpus 1.3 --cpu-quota 20000 $c_id 2>&1 | grep "Nano CPUs and CPU Quota cannot both be set" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Nano CPUs and CPU Quota cannot both be set" && ((ret++)) -+ -+ isula update --cpu-period 20000 $c_id 2>&1 | grep "CPU Period cannot be updated as NanoCPUs has already been set" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - CPU Period cannot be updated as NanoCPUs has already been set" && ((ret++)) -+ -+ isula update --cpu-quota 20000 $c_id 2>&1 | grep "CPU Quota cannot be updated as NanoCPUs has already been set" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - CPU Quota cannot be updated as NanoCPUs has already been set" && ((ret++)) -+ -+ isula update --cpus 1.3 $c_id -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Failed to update cpus" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us" | grep "130000" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_quota_us: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us" | grep "100000" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_period_us: ${image}" && ((ret++)) -+ -+ isula restart -t 0 $c_id -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to restart container: $c_id" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us" | grep "130000" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_quota_us: ${image}" && ((ret++)) -+ -+ isula exec -it $c_id sh -c "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us" | grep "100000" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to check cfs_period_us: ${image}" && ((ret++)) -+ -+ isula rm -f $c_id -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to rm container ${c_id}" && ((ret++)) -+ -+ check_valgrind_log -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - stop isulad failed" && ((ret++)) -+ -+ cp -f /etc/isulad/daemon.bak /etc/isulad/daemon.json -+ -+ umount /var/lib/isulad/bind/isulad_test -+ umount /var/run/isulad_test -+ -+ rm -rf /var/lib/isulad/opt/bind_root -+ rm -rf /opt/bind_run -+ rm -rf /var/lib/isulad/bind/isulad_test -+ rm -rf /var/run/isulad_test -+ -+ reinstall_thinpool -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - fail to reconfig isulad-thinpool" && ((ret++)) -+ -+ start_isulad_with_valgrind -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - start isulad failed" && ((ret++)) -+ -+ msg_info "${test} finished with return ${ret}..." -+ return ${ret} -+} -+ -+declare -i ans=0 -+ -+test_run_root_dir_realpath || ((ans++)) -+test_run_root_dir_bind_realpath || ((ans++)) -+ -+show_result ${ans} "${curr_path}/${0}" -diff --git a/CI/test_cases/image_cases/image_tag.sh b/CI/test_cases/image_cases/image_tag.sh -index ab04560..63d2687 100755 ---- a/CI/test_cases/image_cases/image_tag.sh -+++ b/CI/test_cases/image_cases/image_tag.sh -@@ -32,6 +32,8 @@ function test_tag_image() - - msg_info "${test} starting..." - -+ isula rm -f `isula ps -aq` -+ - isula pull $image_busybox - [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to pull image: ${image_busybox}" && ((ret++)) - --- -2.20.1 - diff --git a/0005-listening-127.0.0.1-port-in-cri-stream-websocket-ser.patch b/0005-listening-127.0.0.1-port-in-cri-stream-websocket-ser.patch new file mode 100644 index 0000000..e740dc1 --- /dev/null +++ b/0005-listening-127.0.0.1-port-in-cri-stream-websocket-ser.patch @@ -0,0 +1,75 @@ +From f3f2765e074a489ceeb2364fbb941a40d3232ff5 Mon Sep 17 00:00:00 2001 +From: wujing +Date: Tue, 24 Nov 2020 15:13:05 +0800 +Subject: [PATCH 5/7] listening 127.0.0.1:port in cri stream websocket server + +Signed-off-by: wujing +--- + src/daemon/entry/cri/websocket/service/ws_server.cc | 6 ++---- + .../modules/image/oci/storage/image_store/image_store.c | 8 ++++---- + 2 files changed, 6 insertions(+), 8 deletions(-) + +diff --git a/src/daemon/entry/cri/websocket/service/ws_server.cc b/src/daemon/entry/cri/websocket/service/ws_server.cc +index 43cecb8..735f278 100644 +--- a/src/daemon/entry/cri/websocket/service/ws_server.cc ++++ b/src/daemon/entry/cri/websocket/service/ws_server.cc +@@ -106,12 +106,10 @@ void WebsocketServer::EmitLog(int level, const char *line) + + int WebsocketServer::CreateContext() + { +- unsigned int opts = 0; + int limited; + struct lws_context_creation_info info; + struct rlimit oldLimit, newLimit; + const size_t WS_ULIMIT_FDS = 1024; +- char interface[] = "127.0.0.1"; + + m_url.SetScheme("ws"); + m_url.SetHost("localhost:" + std::to_string(m_listenPort)); +@@ -120,13 +118,13 @@ int WebsocketServer::CreateContext() + lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_INFO | LLL_DEBUG, WebsocketServer::EmitLog); + + info.port = m_listenPort; +- info.iface = interface; ++ info.iface = "127.0.0.1"; + info.protocols = m_protocols; + info.ssl_cert_filepath = nullptr; + info.ssl_private_key_filepath = nullptr; + info.gid = -1; + info.uid = -1; +- info.options = opts | LWS_SERVER_OPTION_VALIDATE_UTF8; ++ info.options = LWS_SERVER_OPTION_VALIDATE_UTF8 | LWS_SERVER_OPTION_DISABLE_IPV6; + info.max_http_header_pool = MAX_HTTP_HEADER_POOL; + info.extensions = nullptr; + +diff --git a/src/daemon/modules/image/oci/storage/image_store/image_store.c b/src/daemon/modules/image/oci/storage/image_store/image_store.c +index 0f613dd..af8573a 100644 +--- a/src/daemon/modules/image/oci/storage/image_store/image_store.c ++++ b/src/daemon/modules/image/oci/storage/image_store/image_store.c +@@ -59,8 +59,8 @@ + #define IMAGE_JSON "images.json" + + #define MAX_IMAGE_NAME_LENGTH 72 +-#define DIGIST_PREFIX "@sha256:" +-#define MAX_IMAGE_DIGST_LENGTH 64 ++#define DIGEST_PREFIX "@sha256:" ++#define MAX_IMAGE_DIGEST_LENGTH 64 + + typedef struct digest_image { + struct linked_list images_list; +@@ -2757,10 +2757,10 @@ static int resort_image_names(const char **names, size_t names_len, char **first + size_t len = strlen(names[i]); + if (strlen(names[i]) > MAX_IMAGE_NAME_LENGTH) { + prefix = util_sub_string(names[i], len - MAX_IMAGE_NAME_LENGTH, +- MAX_IMAGE_NAME_LENGTH - MAX_IMAGE_DIGST_LENGTH); ++ MAX_IMAGE_NAME_LENGTH - MAX_IMAGE_DIGEST_LENGTH); + } + +- if (prefix != NULL && strcmp(prefix, DIGIST_PREFIX) == 0) { ++ if (prefix != NULL && strcmp(prefix, DIGEST_PREFIX) == 0) { + if (util_array_append(image_digests, names[i]) != 0) { + ERROR("Failed to append image to digest: %s", names[i]); + ret = -1; +-- +2.25.1 + diff --git a/0006-info-fix-typo-driverr-to-driver.patch b/0006-info-fix-typo-driverr-to-driver.patch deleted file mode 100644 index 051315c..0000000 --- a/0006-info-fix-typo-driverr-to-driver.patch +++ /dev/null @@ -1,26 +0,0 @@ -From abffe70870a2867d423dcf24f4b97791b1df16bb Mon Sep 17 00:00:00 2001 -From: lifeng68 -Date: Thu, 22 Oct 2020 11:25:35 +0800 -Subject: [PATCH 06/28] info: fix typo driverr to driver - -Signed-off-by: lifeng68 ---- - src/cmd/isula/information/info.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/cmd/isula/information/info.c b/src/cmd/isula/information/info.c -index 07cad9d..d6f6f7b 100644 ---- a/src/cmd/isula/information/info.c -+++ b/src/cmd/isula/information/info.c -@@ -76,7 +76,7 @@ static void client_info_server(const struct isula_info_response *response) - printf("Logging Driver: %s\n", response->logging_driver); - } - if (response->cgroup_driver != NULL) { -- printf("Cgroup Driverr: %s\n", response->cgroup_driver); -+ printf("Cgroup Driver: %s\n", response->cgroup_driver); - } - if (response->huge_page_size != NULL) { - printf("Hugetlb Pagesize: %s\n", response->huge_page_size); --- -2.20.1 - diff --git a/0006-using-64-bit-unique-token-in-CRI-websockets-server-R.patch b/0006-using-64-bit-unique-token-in-CRI-websockets-server-R.patch new file mode 100644 index 0000000..ae792b1 --- /dev/null +++ b/0006-using-64-bit-unique-token-in-CRI-websockets-server-R.patch @@ -0,0 +1,50 @@ +From 7b59f3cead750d00bafe406ab2150f3abd189acb Mon Sep 17 00:00:00 2001 +From: wujing +Date: Tue, 24 Nov 2020 17:09:08 +0800 +Subject: [PATCH 6/7] using 64 bit unique token in CRI websockets server + Request Cache + +Signed-off-by: wujing +--- + src/daemon/entry/cri/request_cache.cc | 10 ++++++---- + src/daemon/entry/cri/request_cache.h | 2 +- + 2 files changed, 7 insertions(+), 5 deletions(-) + +diff --git a/src/daemon/entry/cri/request_cache.cc b/src/daemon/entry/cri/request_cache.cc +index 5209bca..a3cb377 100644 +--- a/src/daemon/entry/cri/request_cache.cc ++++ b/src/daemon/entry/cri/request_cache.cc +@@ -86,11 +86,13 @@ std::string RequestCache::UniqueToken() + std::default_random_engine e1(r()); + std::uniform_int_distribution uniform_dist(1, 254); + // Number of bytes to be TokenLen when base64 encoded. +- const int tokenSize { 16 }; +- char rawToken[tokenSize + 1] { 0 }; ++ const int tokenSize = ceil(static_cast(TokenLen) * 6 / 8); ++ char rawToken[tokenSize + 1]; ++ (void)memset(rawToken, 0, sizeof(rawToken)); + for (int i {}; i < maxTries; ++i) { +- char buf[40] { 0 }; +- for (size_t j {}; j < tokenSize; ++j) { ++ char buf[TokenLen + 1]; ++ (void)memset(buf, 0, sizeof(buf)); ++ for (int j {}; j < tokenSize; ++j) { + rawToken[j] = (char)uniform_dist(e1); + } + lws_b64_encode_string(rawToken, (int)strlen(rawToken), buf, (int)sizeof(buf)); +diff --git a/src/daemon/entry/cri/request_cache.h b/src/daemon/entry/cri/request_cache.h +index b0b7f49..024f3ba 100644 +--- a/src/daemon/entry/cri/request_cache.h ++++ b/src/daemon/entry/cri/request_cache.h +@@ -52,7 +52,7 @@ private: + static std::mutex m_mutex; + static std::atomic m_instance; + const size_t MaxInFlight { 1000 }; +- const size_t TokenLen { 8 }; ++ const size_t TokenLen { 64 }; + }; + + #endif // DAEMON_ENTRY_CRI_REQUEST_CACHE_H +-- +2.25.1 + diff --git a/0007-add-mock-conf_get_use_decrypted_key_flag-and-setup-a.patch b/0007-add-mock-conf_get_use_decrypted_key_flag-and-setup-a.patch new file mode 100644 index 0000000..ab1ca9c --- /dev/null +++ b/0007-add-mock-conf_get_use_decrypted_key_flag-and-setup-a.patch @@ -0,0 +1,56 @@ +From c84953295a615da574aa1b42348a6f60105d5482 Mon Sep 17 00:00:00 2001 +From: WangFengTu +Date: Tue, 24 Nov 2020 20:00:42 +0800 +Subject: [PATCH 7/7] add mock conf_get_use_decrypted_key_flag and setup all + common mocks + +Signed-off-by: WangFengTu +--- + test/image/oci/registry/registry_ut.cc | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/test/image/oci/registry/registry_ut.cc b/test/image/oci/registry/registry_ut.cc +index 25ddf69..4b26442 100644 +--- a/test/image/oci/registry/registry_ut.cc ++++ b/test/image/oci/registry/registry_ut.cc +@@ -73,6 +73,8 @@ std::string get_dir() + return static_cast(abs_path) + "../../../../../test/image/oci/registry"; + } + ++void mockCommonAll(MockStorage *mock, MockOciImage *oci_image_mock, MockIsuladConf *isulad_conf_mock); ++ + class RegistryUnitTest : public testing::Test { + protected: + void SetUp() override +@@ -81,6 +83,7 @@ protected: + MockStorage_SetMock(&m_storage_mock); + MockOciImage_SetMock(&m_oci_image_mock); + MockIsuladConf_SetMock(&m_isulad_conf_mock); ++ mockCommonAll(&m_storage_mock, &m_oci_image_mock, &m_isulad_conf_mock); + } + + void TearDown() override +@@ -507,6 +510,11 @@ static char *invokeConfGetISuladRootDir() + return util_strdup_s(get_dir().c_str()); + } + ++static bool invokeConfGetUseDecryptedKeyFlag() ++{ ++ return true; ++} ++ + void mockCommonAll(MockStorage *mock, MockOciImage *oci_image_mock, MockIsuladConf *isulad_conf_mock) + { + EXPECT_CALL(*mock, StorageImgCreate(::testing::_, ::testing::_, ::testing::_, ::testing::_)) +@@ -543,6 +551,8 @@ void mockCommonAll(MockStorage *mock, MockOciImage *oci_image_mock, MockIsuladCo + .WillRepeatedly(Invoke(invokeOciValidTime)); + EXPECT_CALL(*isulad_conf_mock, ConfGetISuladRootDir()) + .WillRepeatedly(Invoke(invokeConfGetISuladRootDir)); ++ EXPECT_CALL(*isulad_conf_mock, ConfGetUseDecryptedKeyFlag()) ++ .WillRepeatedly(Invoke(invokeConfGetUseDecryptedKeyFlag)); + return; + } + +-- +2.25.1 + diff --git a/0007-create-fix-wrong-ret-code.patch b/0007-create-fix-wrong-ret-code.patch deleted file mode 100644 index 8cf2ec9..0000000 --- a/0007-create-fix-wrong-ret-code.patch +++ /dev/null @@ -1,48 +0,0 @@ -From ba32dabc6d6304410ed6c731c2f276c1f50a9b06 Mon Sep 17 00:00:00 2001 -From: lifeng68 -Date: Fri, 23 Oct 2020 10:05:07 +0800 -Subject: [PATCH 07/28] create: fix wrong ret code - -Signed-off-by: lifeng68 ---- - src/cmd/isula/base/create.c | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/src/cmd/isula/base/create.c b/src/cmd/isula/base/create.c -index 12903ce..96ca483 100644 ---- a/src/cmd/isula/base/create.c -+++ b/src/cmd/isula/base/create.c -@@ -1249,24 +1249,24 @@ int client_create(struct client_arguments *args) - request->image = util_strdup_s(args->image_name); - - container_spec = request_pack_custom_conf(args); -- if (container_spec == 0) { -- ret = -1; -+ if (container_spec == NULL) { -+ ret = EINVALIDARGS; - goto out; - } - - if (generate_container_config(container_spec, &request->container_spec_json) != 0) { -- ret = -1; -+ ret = EINVALIDARGS; - goto out; - } - - host_spec = request_pack_host_config(args); -- if (host_spec == 0) { -- ret = -1; -+ if (host_spec == NULL) { -+ ret = EINVALIDARGS; - goto out; - } - - if (generate_hostconfig(host_spec, &request->host_spec_json) != 0) { -- ret = -1; -+ ret = EINVALIDARGS; - goto out; - } - --- -2.20.1 - diff --git a/0008-add-iSulad-s-build-guide-for-RISC-V.patch b/0008-add-iSulad-s-build-guide-for-RISC-V.patch deleted file mode 100644 index 23ad535..0000000 --- a/0008-add-iSulad-s-build-guide-for-RISC-V.patch +++ /dev/null @@ -1,319 +0,0 @@ -From 2033d9ff15d01f1a2ccd62b4376eb345bd438280 Mon Sep 17 00:00:00 2001 -From: shentalon <13212105191@163.com> -Date: Sat, 24 Oct 2020 14:55:22 +0000 -Subject: [PATCH 08/28] add iSulad's build guide for RISC-V -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -背景说明:我今年参加了summer2020活动,选题是`在 RISC-V 架构 openEuler 平台上提供 iSulad`。之前答应老师陆续上传一些阶段性工作,因为秋招无力分身,只能在最后索性写一个相对完整的方案。下面的内容大致有:RISC-V虚拟环境的搭建、依赖安装的说明、编译安装指南及内核及内核模块编译,撰写的过程中,我参考了和各位指导老师的邮件及社区交流记录,同时还有自己在本地进行的问题记录。出于让开发者能简洁、顺畅地使用指南,里面只收录了成功编译的方法而没有加入报错的记录和尝试解决错误的过程部分,整理的可能不够详细,如果有问题欢迎[联系我](https://gitee.com/shentalon)。 ---- - docs/build_guide_riscv.md | 296 ++++++++++++++++++++++++++++++++++++++ - 1 file changed, 296 insertions(+) - create mode 100644 docs/build_guide_riscv.md - -diff --git a/docs/build_guide_riscv.md b/docs/build_guide_riscv.md -new file mode 100644 -index 0000000..76f97c9 ---- /dev/null -+++ b/docs/build_guide_riscv.md -@@ -0,0 +1,296 @@ -+ -+# ISulad在RISC-V构架的openEuler的支持工作 -+ -+ -+--- -+ -+## RISC-V虚拟环境的搭建 -+>RISC-V的环境我们是通过在host上使用QEMU虚拟机实现的,我们要做的是使用任意一Linux发行版作为host安装QEMU虚拟机,在虚拟机中启动RISC-V的openEuler镜像,在虚拟机镜像中完成iSulad的安装。 -+### 1. 安装虚拟机 -+ -+首先是在host上安装QEMU,打开终端,依次输入以下命令: -+```shell -+wget https://download.qemu.org/qemu-5.1.0.tar.xz -+tar xvJf qemu-5.1.0.tar.xz -+cd qemu-5.1.0 -+./configure --target-list=riscv64-softmmu -+make -+make install -+``` -+### 2. 启动文件准备 -+安装好支持RISC-V的QEMU之后,就可以使用它来启动虚拟机的镜像,镜像的下载和安装可以参考[openEuler RISC-V 移植版的获取和运行](https://gitee.com/openeuler/RISC-V/blob/master/documents/Installing.md),启动QEMU的虚拟机Linux环境,应该有以下几个文件: -+ -+1. [oe-rv-rv64g-30G.qcow2](https://isrc.iscas.ac.cn/mirror/openeuler-sig-riscv/images/oe-rv-rv64g-30G.qcow2) -+ -+2. [fw_payload_oe.elf](https://isrc.iscas.ac.cn/mirror/openeuler-sig-riscv/images/fw_payload_oe.elf) -+ -+3. run_oe1_rv64.sh(可选) -+ -+ -+可以创建一个shell文件,内容来自[installing.md](https://gitee.com/openeuler/RISC-V/blob/master/documents/Installing.md),如下: -+ -+ -+```shell -+#!/bin/sh -+ -+qemu-system-riscv64 \ -+ -machine virt \ -+ -nographic \ -+ -smp 8 \ -+ -m 124G \ -+ -drive file=oe-rv-base-expand.qcow2,format=qcow2,id=hd0 \ -+ -object rng-random,filename=/dev/urandom,id=rng0 \ -+ -device virtio-rng-device,rng=rng0 \ -+ -device virtio-blk-device,drive=hd0 \ -+ -netdev user,id=usernet,hostfwd=tcp::12055-:22 \ -+ -device virtio-net-device,netdev=usernet \ -+ -append 'root=/dev/vda1 systemd.default_timeout_start_sec=600 selinux=0 rw highres=off console=ttyS0 mem=4096M earlycon' \ -+ -kernel fw_payload.elf \ -+``` -+ -+里面是一些参数的设定,可以查看QEMU的参数说明根据本地计算机配置进行调整。 -+### 3.启动虚拟机 -+可以采用两种方式: -+1. 在终端直接输入shell文件中的内容 -+2. 如果创建了shell文件,只需要在终端里输入 `sh run_oe1_rv64.sh` -+ -+默认的登陆用户名/密码是:root/openEuler12#$ -+ -+## 依赖安装 -+ -+正式编译项目之前,要在系统上安装编译工具、代码版本控制等用途的软件包。 -+这个过程会使用yum工具来对rpm软件包进行安装,如果刚刚使用`oe-rv-rv64g-30G.qcow2`,里面并没有提供yum工具,可以使用下面的命令进行yum的安装: -+ -+```shell -+wget https://isrc.iscas.ac.cn/mirror/openeuler-sig-riscv/oe-RISCV-repo/noarch/yum-4.2.15-8.noarch.rpm --no-check-certificate -+rpm -ivh yum-4.2.15-8.noarch.rpm -+``` -+之后,可以使用yum工具进行所需软件包的安装: -+```shell -+sudo yum --enablerepo='*' install -y automake autoconf libtool cmake make libcap libcap-devel libselinux libselinux-devel libseccomp libseccomp-devel yajl-devel git libcgroup tar python3 python3-pip device-mapper-devel libarchive libarchive-devel libcurl-devel zlib-devel glibc-headers openssl-devel gcc gcc-c++ systemd-devel systemd-libs libtar libtar-devel vim -+``` -+软件包的所需依赖参考了[build_guide](https://gitee.com/openeuler/iSulad/blob/master/docs/build_guide.md),和参考文档相比,去掉了golang(iSulad转为全C开发,不再使用GO语言),增加了vim(镜像没有文本编辑工具)。 -+要修改yum源的配置,在 /etc/yum.repos.d/下打开`oe-rv.repo`文件,一般使用[Index of /oe-RISCV-repo/](https://isrc.iscas.ac.cn/mirror/openeuler-sig-riscv/oe-RISCV-repo/)为yum源的地址。 -+ -+## 源码编译及安装 -+> 整个过程参考了[build_guide](https://gitee.com/openeuler/iSulad/blob/master/docs/build_guide.md),编译过程中出现了一些错误,做了修改,整理成下面的编译指南。 -+### 正式编译之前的准备工作及提示 -+##### 1.设置 ldconfig and pkgconfig(若编译中断,再次进入系统时在源码编译之前都必须运行一次!) -+ -+```javascript -+$ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH -+$ export LD_LIBRARY_PATH=/usr/local/lib:/usr/lib:$LD_LIBRARY_PATH -+$ sudo -E echo "/usr/local/lib" >> /etc/ld.so.conf -+``` -+##### 2.调整虚拟机时间为本地时间(否则编译的过程中会输出`Clock skew detected`的警告。这或许不是最好的方法,但却很简单有效,大家也可以自己找其他的方法消除警告) -+时间调整命令的格式如下: date -s 2020-09-28 -+ -+##### 3.建议创建一个合适的目录,如:build_isulad(后面编译的源码都将放在这个目录下面,每次`git clone`的时候,请先切换到此目录) -+##### 4.protobuf、grpc需要匹配所用系统的编译器版本,如:grpc-1.22 不支持GCC 9+。由于目前使用的虚拟机下编译器版本都一致,这一点不需要考虑 -+ -+### 源码编译安装protobuf(这部分的编译安装相对于参考的[build_guide](https://gitee.com/openeuler/iSulad/blob/master/docs/build_guide.md),做了比较大的调整,以满足后面的grpc能够顺利编译) -+```javascript -+$ pkg-config --cflags protobuf -+$ pkg-config --libs protobuf -+$ pkg-config --cflags --libs protobuf -+ -+ -+$ git clone https://gitee.com/src-openeuler/protobuf.git -+$ cd protobuf -+$ git checkout openEuler-20.03-LTS-tag -+$ tar -xzvf protobuf-all-3.9.0.tar.gz -+$ cd protobuf-3.9.0 -+``` -+> 此过程参考了[stack overflow](https://stackoverflow.com/questions/53586540/c-terminate-called-after-throwing-an-instance-of-stdsystem-error),如果按照[build_guide](https://gitee.com/openeuler/iSulad/blob/master/docs/build_guide.md)编译,在编译grpc时,会报` 'std::system_error'`这样的问题。 -+在编译之前要对文件做一些修改,使用如下命令打开protobuf源文件下的src/google/protobuf/stubs/common.cc文件: -+``` -+vi src/google/protobuf/stubs/common.cc -+``` -+在这个文件中,把有关 _WIN32 的所有代码都注释掉,如下: -+``` -+// updated by Aimer on linux platform -+ -+//#ifdef _WIN32 -+//#define WIN32_LEAN_AND_MEAN // We only need minimal includes -+//#include -+//#define snprintf _snprintf // see comment in strutil.cc -+//#elif defined(HAVE_PTHREAD) -+#include -+//#else -+//#error "No suitable threading library available." -+//#endif -+``` -+>此处参考了[protobuf 安装流程](http://blog.chinaunix.net/uid-28595538-id-5082366.html) -+``` shell -+$ sudo -E ./autogen.sh -+$ sudo -E ./configure CXXFLAGS="$(pkg-config --cflags protobuf)" LIBS="$(pkg-config --libs protobuf)" -+$ sudo -E make -j $(nproc) -+$ sudo -E make install -+$ sudo -E ldconfig -+``` -+ -+#### 编译成功验证 -+``` -+protoc --version -+``` -+输出:libprotoc 3.9.0(或其他的版本号) -+#### 第二种安装方法 -+由protobuf和grpc的安装的依赖关系,我们可以将它们视为一个组合,除了顺次编译外,还可以先编译grpc,再在third_party文件夹下的protobuf目录下安装protobuf,相关的编译方法网上能查到一些(可以搜protobuf+grpc编译),之前试了一下但编译成功率很低。 -+ -+### 源码编译安装c-cares -+ -+```shell -+$ git clone https://gitee.com/src-openeuler/c-ares.git -+$ cd c-ares -+$ git checkout openEuler-20.03-LTS-tag -+$ tar -xzvf c-ares-1.15.0.tar.gz -+$ cd c-ares-1.15.0 -+$ sudo -E autoreconf -if -+$ sudo -E ./configure --enable-shared --disable-dependency-tracking -+$ sudo -E make -j $(nproc) -+$ sudo -E make install -+$ sudo -E ldconfig -+``` -+### 源码编译安装grpc -+ -+```shell -+$ git clone https://gitee.com/src-openeuler/grpc.git -+$ cd grpc -+$ git checkout openEuler-20.03-LTS-tag -+$ tar -xzvf grpc-1.22.0.tar.gz -+$ cd grpc-1.22.0 -+``` -+修改源码: -+ -+* 在`include/grpcpp/impl/codegen/call_op_set.h` line 90添加 -+ -+```shell -+ /// Default assignment operator -+ WriteOptions& operator=(const WriteOptions& other) = default; -+``` -+ -+* 将`src/core/lib/gpr/log_linux.cc`、`src/core/lib/gpr/log_posix.cc`、`src/core/lib/iomgr/ev_epollex_linux.cc`这几个文件中的 -+ `gettid()`改为`sys_gettid()` -+ -+>参考[protobuf+grpc源码编译安装过程](https://blog.csdn.net/Sindweller5530/article/details/104414856) -+ -+```shell -+$ sudo -E make -j $(nproc) -+$ sudo -E make install -+$ sudo -E ldconfig -+``` -+之后会遇到'cannot find -latomic'的问题,按[链接中的](https://www.cnblogs.com/mafy/p/13380332.html)处理即可: -+ -+ -+grpc测试用例 -+``` -+cd examples/cpp/helloworld/ -+make //编译 -+./greeter_server //服务器 -+./greeter_client //客户端(重新开一个服务器连接) -+``` -+### 源码编译安装http-parser -+ -+```javascript -+$ git clone https://gitee.com/src-openeuler/http-parser.git -+$ cd http-parser -+$ git checkout openEuler-20.03-LTS-tag -+$ tar -xzvf http-parser-2.9.2.tar.gz -+$ cd http-parser-2.9.2 -+$ sudo -E make -j CFLAGS="-Wno-error" -+$ sudo -E make CFLAGS="-Wno-error" install -+$ sudo -E ldconfig -+``` -+ -+ -+### 源码编译安装libwebsockets -+```shell -+$ git clone https://gitee.com/src-openeuler/libwebsockets.git -+$ cd libwebsockets -+$ git checkout openEuler-20.03-LTS-tag -+$ tar -xzvf libwebsockets-2.4.2.tar.gz -+$ cd libwebsockets-2.4.2 -+$ patch -p1 -F1 -s < ../libwebsockets-fix-coredump.patch -+$ mkdir build -+$ cd build -+$ sudo -E cmake -DLWS_WITH_SSL=0 -DLWS_MAX_SMP=32 -DCMAKE_BUILD_TYPE=Debug ../ -+$ sudo -E make -j $(nproc) -+$ sudo -E make install -+$ sudo -E ldconfig -+``` -+ -+### 源码编译安装lxc -+```shell -+$ git clone https://gitee.com/src-openeuler/lxc.git -+$ cd lxc -+$ tar -zxf lxc-4.0.3.tar.gz -+$ ./apply-patches -+$ cd lxc-4.0.3 -+$ sudo -E ./autogen.sh -+$ sudo -E ./configure -+$ sudo -E make -j -+$ sudo -E make install -+$ sudo -E ldconfig -+``` -+在编译的过程中会遇到两个问题: -+1. 关于`__NR_signalfd` -+解决方案:[lxc的issue](https://github.com/lxc/lxc/pull/3501/files) -+2. 再次遇到'cannot find -latomic'的问题 -+这次不能使用上次的方法,这次是缺少静态链接库,使用find命令搜到libatomic.a复制到/usr/lib下,编译通过。 -+### 源码编译安装lcr -+```shell -+$ git clone https://gitee.com/openeuler/lcr.git -+$ cd lcr -+$ mkdir build -+$ cd build -+$ sudo -E cmake .. -+$ sudo -E make -j -+$ sudo -E make install -+$ sudo -E ldconfig -+``` -+### 源码编译安装clibcni -+```shell -+$ git clone https://gitee.com/openeuler/clibcni.git -+$ cd clibcni -+$ mkdir build -+$ cd build -+$ sudo -E cmake .. -+$ sudo -E make -j -+$ sudo -E make install -+$ sudo -E ldconfig -+``` -+### 源码编译安装iSulad -+```shell -+$ git clone https://gitee.com/openeuler/iSulad.git -+$ cd iSulad -+$ mkdir build -+$ cd build -+$ sudo -E cmake .. -+$ sudo -E make -+$ sudo -E make install -+$ sudo -E ldconfig -+``` -+## 内核编译及内核模块的编译 -+在完成上述工作之后,iSulad的启动还需要一个`overlay`的内核模块。虚拟机镜像默认没有提供,需要我们开启此模块和编译封装。 -+1. 下载与当前镜像系统一致的版本的内核源码(内核版本可以使用`uname -a`命令来查看) -+```shell -+git clone https://gitee.com/openeuler/kernel.git -+git checkout 某一分支 -+``` -+2. 在内核源码的目录下,执行make menuconfig,在配置界面找到File systems ---> 在Overlay filesystem support前配置成[M]或[*](单击空格键切换),之后保存并退出; -+3. 使用make Image命令,在/内核源码路径/arch/riscv/boot/ 下生成Image文件; -+4. 下载内核封装工具opensbi: -+```shell -+git clone https://gitee.com/src-openeuler/opensbi.git -+cd opensbi -+unzip v0.6.zip -+cd opensbi-0.6 -+make O=build-oe/qemu-virt PLATFORM=qemu/virt FW_PAYLOAD=y FW_PAYLOAD_PATH=/生成的Image路径/Image -+``` -+这一步会生成elf文件,编译结束会提示elf文件所在位置。 -+5. 将elf文件拷贝至host,拷贝可以使用`scp`工具进行。将.qcow2文件、.elf文件、.sh文件放在同一路径下,修改run_oe1-rv64.sh中的kernel 参数处的elf文件名为新添加的elf文件名。 -+6. 执行sh run_oe1-rv64.sh -+### 参考链接: -+* https://arkingc.github.io/2018/09/05/2018-09-05-linux-kernel/ -+* https://gitee.com/src-openeuler/risc-v-kernel/blob/master/kernel.spec -+* https://gitee.com/src-openeuler/opensbi/blob/master/opensbi.spec --- -2.20.1 - diff --git a/0009-add-non-root-group.patch b/0009-add-non-root-group.patch deleted file mode 100644 index 11f0d10..0000000 --- a/0009-add-non-root-group.patch +++ /dev/null @@ -1,190 +0,0 @@ -From 0c21cb71efd5f81164c67f493f6070714ff3c287 Mon Sep 17 00:00:00 2001 -From: gaohuatao -Date: Wed, 21 Oct 2020 09:19:45 -0400 -Subject: [PATCH 09/28] add non root group - -Signed-off-by: gaohuatao ---- - src/cmd/isulad/main.c | 20 ++++++++++++----- - src/common/constants.h | 2 ++ - src/daemon/config/isulad_config.c | 31 +------------------------- - src/utils/cutils/utils_file.c | 36 +++++++++++++++++++++++++++++++ - src/utils/cutils/utils_file.h | 2 ++ - 5 files changed, 56 insertions(+), 35 deletions(-) - -diff --git a/src/cmd/isulad/main.c b/src/cmd/isulad/main.c -index 7a932b6..9297aad 100644 ---- a/src/cmd/isulad/main.c -+++ b/src/cmd/isulad/main.c -@@ -81,20 +81,30 @@ static int create_client_run_path(const char *group) - { - int ret = 0; - const char *rundir = "/var/run/isula"; -+ - if (group == NULL) { - return -1; - } -- ret = util_mkdir_p(rundir, DEFAULT_SECURE_DIRECTORY_MODE); -- if (ret < 0) { -+ -+ if (util_mkdir_p(rundir, ISULA_CLIENT_DIRECTORY_MODE) < 0) { - ERROR("Unable to create client run directory %s.", rundir); -- return ret; -+ ret = -1; -+ goto out; - } - -- ret = chmod(rundir, DEFAULT_SECURE_DIRECTORY_MODE); -- if (ret < 0) { -+ if (chmod(rundir, ISULA_CLIENT_DIRECTORY_MODE) < 0) { - ERROR("Failed to chmod for client run path: %s", rundir); -+ ret = -1; -+ goto out; - } - -+ if (util_set_file_group(rundir, group) != 0) { -+ ERROR("set group of the path: %s failed", rundir); -+ ret = -1; -+ goto out; -+ } -+ -+out: - return ret; - } - -diff --git a/src/common/constants.h b/src/common/constants.h -index 420ac92..52bb0a8 100644 ---- a/src/common/constants.h -+++ b/src/common/constants.h -@@ -26,6 +26,8 @@ extern "C" { - - #define DEFAULT_SECURE_DIRECTORY_MODE 0750 - -+#define ISULA_CLIENT_DIRECTORY_MODE 0770 -+ - #define USER_REMAP_DIRECTORY_MODE 0751 - - #define ROOTFS_MNT_DIRECTORY_MODE 0640 -diff --git a/src/daemon/config/isulad_config.c b/src/daemon/config/isulad_config.c -index c79c6a1..4832985 100644 ---- a/src/daemon/config/isulad_config.c -+++ b/src/daemon/config/isulad_config.c -@@ -13,7 +13,6 @@ - * Description: provide container configure definition - ******************************************************************************/ - #include --#include - #include - #include - #include -@@ -1157,34 +1156,6 @@ out: - return ret; - } - --/* set path group */ --static int set_path_group(const char *rpath, const char *group) --{ -- struct group *grp = NULL; -- gid_t gid; -- -- grp = getgrnam(group); -- -- if (grp != NULL) { -- gid = grp->gr_gid; -- DEBUG("Group %s found, gid: %d", group, gid); -- if (chown(rpath, -1, gid) != 0) { -- DEBUG("Failed to chown %s to gid: %d", rpath, gid); -- return -1; -- } -- } else { -- if (strcmp(group, "docker") == 0 || strcmp(group, "isula") == 0) { -- DEBUG("Warning: could not change group %s to %s", rpath, group); -- } else { -- ERROR("Group %s not found", group); -- isulad_set_error_message("Group %s not found", group); -- return -1; -- } -- } -- -- return 0; --} -- - /* set socket group */ - int set_unix_socket_group(const char *socket, const char *group) - { -@@ -1205,7 +1176,7 @@ int set_unix_socket_group(const char *socket, const char *group) - goto out; - } - INFO("set socket: %s with group: %s", socket, group); -- nret = set_path_group(rpath, group); -+ nret = util_set_file_group(rpath, group); - if (nret < 0) { - ERROR("set group of the path: %s failed", rpath); - ret = -1; -diff --git a/src/utils/cutils/utils_file.c b/src/utils/cutils/utils_file.c -index 7a965c0..92e032b 100644 ---- a/src/utils/cutils/utils_file.c -+++ b/src/utils/cutils/utils_file.c -@@ -29,6 +29,8 @@ - #include - #include - #include -+#include -+#include - - #include "constants.h" - #include "isula_libutils/log.h" -@@ -1574,3 +1576,37 @@ out: - free(line); - return ret; - } -+ -+int util_set_file_group(const char *fname, const char *group) -+{ -+ int ret = 0; -+ struct group *grp = NULL; -+ gid_t gid; -+ -+ if (fname == NULL || group == NULL) { -+ ERROR("Invalid NULL params"); -+ return -1; -+ } -+ -+ grp = getgrnam(group); -+ if (grp != NULL) { -+ gid = grp->gr_gid; -+ DEBUG("Group %s found, gid: %d", group, gid); -+ if (chown(fname, -1, gid) != 0) { -+ ERROR("Failed to chown %s to gid: %d", fname, gid); -+ ret = -1; -+ goto out; -+ } -+ } else { -+ if (strcmp(group, "docker") == 0 || strcmp(group, "isula") == 0) { -+ DEBUG("Warning: could not change group %s to %s", fname, group); -+ } else { -+ ERROR("Group %s not found", group); -+ ret = -1; -+ goto out; -+ } -+ } -+ -+out: -+ return ret; -+} -diff --git a/src/utils/cutils/utils_file.h b/src/utils/cutils/utils_file.h -index 1bd2d69..3aff3d6 100644 ---- a/src/utils/cutils/utils_file.h -+++ b/src/utils/cutils/utils_file.h -@@ -98,6 +98,8 @@ typedef bool (*read_line_callback_t)(const char *, void *context); - - int util_proc_file_line_by_line(FILE *fp, read_line_callback_t cb, void *context); - -+int util_set_file_group(const char *fname, const char *group); -+ - #ifdef __cplusplus - } - #endif --- -2.20.1 - diff --git a/0010-add-nonroot-execute-CI.patch b/0010-add-nonroot-execute-CI.patch deleted file mode 100644 index d1189d3..0000000 --- a/0010-add-nonroot-execute-CI.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 79b2027b87dd1b7f110d73721b8d47941d993e0e Mon Sep 17 00:00:00 2001 -From: gaohuatao -Date: Mon, 26 Oct 2020 13:57:07 +0800 -Subject: [PATCH 10/28] add nonroot execute CI - -Signed-off-by: gaohuatao ---- - CI/test_cases/container_cases/nonroot.sh | 70 ++++++++++++++++++++++++ - 1 file changed, 70 insertions(+) - create mode 100755 CI/test_cases/container_cases/nonroot.sh - -diff --git a/CI/test_cases/container_cases/nonroot.sh b/CI/test_cases/container_cases/nonroot.sh -new file mode 100755 -index 0000000..b123d70 ---- /dev/null -+++ b/CI/test_cases/container_cases/nonroot.sh -@@ -0,0 +1,70 @@ -+#!/bin/bash -+# -+# attributes: isulad inheritance start -+# concurrent: YES -+# spend time: 11 -+ -+####################################################################### -+##- @Copyright (C) Huawei Technologies., 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. -+##- @Description:CI -+##- @Author: gaohuatao -+##- @Create: 2020-10-19 -+####################################################################### -+ -+curr_path=$(dirname $(readlink -f "$0")) -+data_path=$(realpath $curr_path/../data) -+source ../helpers.sh -+group="isula" -+user="nonroot_test" -+container="test_nonroot_user" -+ -+function do_test_t() -+{ -+ local ret=0 -+ local test="isula execute with non root => (${FUNCNAME[@]})" -+ -+ msg_info "${test} starting..." -+ -+ userdel $user -+ useradd -g $group $user -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - add user $user and add to group $group failed" && ((ret++)) -+ -+ su - $user -c "isula run -tid --name $container busybox /bin/bash" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - run container failed" && ((ret++)) -+ -+ su - $user -c "isula inspect $container" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - inspect container failed" && ((ret++)) -+ -+ su - $user -c "isula restart $container" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - restart container failed" && ((ret++)) -+ -+ su - $user -c "isula exec $container pwd" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - exec container failed" && ((ret++)) -+ -+ su - $user -c "isula stop $container" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - stop container failed" && ((ret++)) -+ -+ su - $user -c "isula rm $container" -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - rm container failed" && ((ret++)) -+ -+ userdel $user -+ -+ return $TC_RET_T -+} -+ -+ret=0 -+ -+do_test_t -+if [ $? -ne 0 ];then -+ let "ret=$ret + 1" -+fi -+ -+show_result $ret "basic start" --- -2.20.1 - diff --git a/0011-cni-support-extension-data-transmission.patch b/0011-cni-support-extension-data-transmission.patch deleted file mode 100644 index ac48e36..0000000 --- a/0011-cni-support-extension-data-transmission.patch +++ /dev/null @@ -1,91 +0,0 @@ -From c24f26ead1803db98fd2cd7e4d95a34239c15221 Mon Sep 17 00:00:00 2001 -From: haozi007 -Date: Mon, 26 Oct 2020 11:13:53 +0800 -Subject: [PATCH 11/28] cni: support extension data transmission - -Signed-off-by: haozi007 ---- - src/daemon/entry/cri/cni_network_plugin.cc | 15 +++++++++++++-- - src/daemon/entry/cri/cri_helpers.cc | 2 ++ - src/daemon/entry/cri/cri_helpers.h | 2 ++ - 3 files changed, 17 insertions(+), 2 deletions(-) - -diff --git a/src/daemon/entry/cri/cni_network_plugin.cc b/src/daemon/entry/cri/cni_network_plugin.cc -index c1a4e1e..4676a97 100644 ---- a/src/daemon/entry/cri/cni_network_plugin.cc -+++ b/src/daemon/entry/cri/cni_network_plugin.cc -@@ -581,10 +581,11 @@ void CniNetworkPlugin::DeleteFromNetwork(CNINetwork *network, const std::string - - static void PrepareRuntimeConf(const std::string &podName, const std::string &podNs, const std::string &interfaceName, - const std::string &podSandboxID, const std::string &podNetnsPath, -+ const std::map &annotations, - const std::map &options, struct runtime_conf **cni_rc, - Errors &err) - { -- const size_t defaultLen = 5; -+ size_t defaultLen = 5; - if (cni_rc == nullptr) { - err.Errorf("Invalid arguments"); - ERROR("Invalid arguments"); -@@ -596,6 +597,12 @@ static void PrepareRuntimeConf(const std::string &podName, const std::string &po - if (iter != options.end()) { - podUID = iter->second; - } -+ std::string cniExtentionVal; -+ iter = annotations.find(CRIHelpers::Constants::CNI_MUTL_NET_EXTENSION_KEY); -+ if (iter != annotations.end()) { -+ cniExtentionVal = iter->second; -+ defaultLen++; -+ } - - struct runtime_conf *rt = (struct runtime_conf *)util_common_calloc_s(sizeof(struct runtime_conf)); - if (rt == nullptr) { -@@ -625,6 +632,10 @@ static void PrepareRuntimeConf(const std::string &podName, const std::string &po - rt->args[3][1] = util_strdup_s(podSandboxID.c_str()); - rt->args[4][0] = util_strdup_s("K8S_POD_UID"); - rt->args[4][1] = util_strdup_s(podUID.c_str()); -+ if (defaultLen > 5) { -+ rt->args[5][0] = util_strdup_s(CRIHelpers::Constants::CNI_MUTL_NET_EXTENSION_ARGS_KEY.c_str()); -+ rt->args[5][1] = util_strdup_s(cniExtentionVal.c_str()); -+ } - - *cni_rc = rt; - return; -@@ -639,7 +650,7 @@ void CniNetworkPlugin::BuildCNIRuntimeConf(const std::string &podName, const std - const std::map &options, - struct runtime_conf **cni_rc, Errors &err) - { -- PrepareRuntimeConf(podName, podNs, interfaceName, podSandboxID, podNetnsPath, options, cni_rc, err); -+ PrepareRuntimeConf(podName, podNs, interfaceName, podSandboxID, podNetnsPath, annotations, options, cni_rc, err); - if (err.NotEmpty()) { - return; - } -diff --git a/src/daemon/entry/cri/cri_helpers.cc b/src/daemon/entry/cri/cri_helpers.cc -index 8aa939c..4fb9feb 100644 ---- a/src/daemon/entry/cri/cri_helpers.cc -+++ b/src/daemon/entry/cri/cri_helpers.cc -@@ -51,6 +51,8 @@ const std::string Constants::CONTAINER_TYPE_ANNOTATION_SANDBOX { "sandbox" }; - const std::string Constants::SANDBOX_ID_ANNOTATION_KEY { "io.kubernetes.cri.sandbox-id" }; - const std::string Constants::NET_PLUGIN_EVENT_POD_CIDR_CHANGE { "pod-cidr-change" }; - const std::string Constants::NET_PLUGIN_EVENT_POD_CIDR_CHANGE_DETAIL_CIDR { "pod-cidr" }; -+const std::string Constants::CNI_MUTL_NET_EXTENSION_KEY { "extension.network.kubernetes.io/cni" }; -+const std::string Constants::CNI_MUTL_NET_EXTENSION_ARGS_KEY { "CNI_MUTLINET_EXTENSION" }; - - const char *InternalLabelKeys[] = { CRIHelpers::Constants::CONTAINER_TYPE_LABEL_KEY.c_str(), - CRIHelpers::Constants::CONTAINER_LOGPATH_LABEL_KEY.c_str(), -diff --git a/src/daemon/entry/cri/cri_helpers.h b/src/daemon/entry/cri/cri_helpers.h -index 9dd3630..824d1a6 100644 ---- a/src/daemon/entry/cri/cri_helpers.h -+++ b/src/daemon/entry/cri/cri_helpers.h -@@ -56,6 +56,8 @@ public: - - static const std::string NET_PLUGIN_EVENT_POD_CIDR_CHANGE; - static const std::string NET_PLUGIN_EVENT_POD_CIDR_CHANGE_DETAIL_CIDR; -+ static const std::string CNI_MUTL_NET_EXTENSION_KEY; -+ static const std::string CNI_MUTL_NET_EXTENSION_ARGS_KEY; - }; - - auto GetDefaultSandboxImage(Errors &err) -> std::string; --- -2.20.1 - diff --git a/0012-unpack-add-remove-target-file-in-handle-.wh.patch b/0012-unpack-add-remove-target-file-in-handle-.wh.patch deleted file mode 100644 index 500bf68..0000000 --- a/0012-unpack-add-remove-target-file-in-handle-.wh.patch +++ /dev/null @@ -1,386 +0,0 @@ -From 9cbd114034321e232dfe2540216c9c8c3094e362 Mon Sep 17 00:00:00 2001 -From: lifeng68 -Date: Tue, 27 Oct 2020 16:31:37 +0800 -Subject: [PATCH 12/28] unpack: add remove target file in handle .wh. - -Signed-off-by: lifeng68 ---- - src/cmd/isulad/main.c | 2 +- - .../graphdriver/devmapper/driver_devmapper.c | 2 +- - src/utils/cutils/utils_file.c | 29 ++- - src/utils/cutils/utils_file.h | 3 + - src/utils/tar/util_archive.c | 172 +++++++++++++++++- - src/utils/tar/util_archive.h | 5 +- - 6 files changed, 198 insertions(+), 15 deletions(-) - -diff --git a/src/cmd/isulad/main.c b/src/cmd/isulad/main.c -index 9297aad..5cad285 100644 ---- a/src/cmd/isulad/main.c -+++ b/src/cmd/isulad/main.c -@@ -103,7 +103,7 @@ static int create_client_run_path(const char *group) - ret = -1; - goto out; - } -- -+ - out: - return ret; - } -diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.c -index ec337a8..1674c28 100644 ---- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.c -+++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.c -@@ -339,7 +339,7 @@ int devmapper_apply_diff(const char *id, const struct graphdriver *driver, const - goto out; - } - -- options.whiteout_format = OVERLAY_WHITEOUT_FORMATE; -+ options.whiteout_format = REMOVE_WHITEOUT_FORMATE; - if (archive_unpack(content, layer_fs, &options) != 0) { - ERROR("devmapper: failed to unpack to :%s", layer_fs); - ret = -1; -diff --git a/src/utils/cutils/utils_file.c b/src/utils/cutils/utils_file.c -index 92e032b..9f7f5fe 100644 ---- a/src/utils/cutils/utils_file.c -+++ b/src/utils/cutils/utils_file.c -@@ -282,7 +282,7 @@ static int recursive_rmdir_helper(const char *dirpath, int recursive_depth, int - struct dirent *pdirent = NULL; - DIR *directory = NULL; - int failure = 0; -- char fname[MAXPATHLEN]; -+ char fname[PATH_MAX]; - - directory = opendir(dirpath); - if (directory == NULL) { -@@ -300,8 +300,8 @@ static int recursive_rmdir_helper(const char *dirpath, int recursive_depth, int - - (void)memset(fname, 0, sizeof(fname)); - -- pathname_len = snprintf(fname, MAXPATHLEN, "%s/%s", dirpath, pdirent->d_name); -- if (pathname_len < 0 || pathname_len >= MAXPATHLEN) { -+ pathname_len = snprintf(fname, PATH_MAX, "%s/%s", dirpath, pdirent->d_name); -+ if (pathname_len < 0 || pathname_len >= PATH_MAX) { - ERROR("Pathname too long"); - failure = 1; - continue; -@@ -1142,7 +1142,7 @@ static void recursive_cal_dir_size_helper(const char *dirpath, int recursive_dep - struct dirent *pdirent = NULL; - DIR *directory = NULL; - struct stat fstat; -- char fname[MAXPATHLEN]; -+ char fname[PATH_MAX]; - - // cal dir self node and size - nret = lstat(dirpath, &fstat); -@@ -1169,8 +1169,8 @@ static void recursive_cal_dir_size_helper(const char *dirpath, int recursive_dep - - (void)memset(fname, 0, sizeof(fname)); - -- pathname_len = snprintf(fname, MAXPATHLEN, "%s/%s", dirpath, pdirent->d_name); -- if (pathname_len < 0 || pathname_len >= MAXPATHLEN) { -+ pathname_len = snprintf(fname, PATH_MAX, "%s/%s", dirpath, pdirent->d_name); -+ if (pathname_len < 0 || pathname_len >= PATH_MAX) { - ERROR("Pathname too long"); - continue; - } -@@ -1239,7 +1239,7 @@ static void recursive_cal_dir_size__without_hardlink_helper(const char *dirpath, - int nret = 0; - struct dirent *pdirent = NULL; - DIR *directory = NULL; -- char fname[MAXPATHLEN]; -+ char fname[PATH_MAX]; - - directory = opendir(dirpath); - if (directory == NULL) { -@@ -1257,8 +1257,8 @@ static void recursive_cal_dir_size__without_hardlink_helper(const char *dirpath, - - (void)memset(fname, 0, sizeof(fname)); - -- pathname_len = snprintf(fname, MAXPATHLEN, "%s/%s", dirpath, pdirent->d_name); -- if (pathname_len < 0 || pathname_len >= MAXPATHLEN) { -+ pathname_len = snprintf(fname, PATH_MAX, "%s/%s", dirpath, pdirent->d_name); -+ if (pathname_len < 0 || pathname_len >= PATH_MAX) { - ERROR("Pathname too long"); - continue; - } -@@ -1610,3 +1610,14 @@ int util_set_file_group(const char *fname, const char *group) - out: - return ret; - } -+ -+int util_recursive_remove_path(const char *path) -+{ -+ int ret = 0; -+ -+ if (unlink(path) != 0 && errno != ENOENT) { -+ ret = util_recursive_rmdir(path, 0); -+ } -+ -+ return ret; -+} -\ No newline at end of file -diff --git a/src/utils/cutils/utils_file.h b/src/utils/cutils/utils_file.h -index 3aff3d6..a873114 100644 ---- a/src/utils/cutils/utils_file.h -+++ b/src/utils/cutils/utils_file.h -@@ -100,6 +100,9 @@ int util_proc_file_line_by_line(FILE *fp, read_line_callback_t cb, void *context - - int util_set_file_group(const char *fname, const char *group); - -+// try to remove the path, path is file or dir -+int util_recursive_remove_path(const char *path); -+ - #ifdef __cplusplus - } - #endif -diff --git a/src/utils/tar/util_archive.c b/src/utils/tar/util_archive.c -index 0ae99be..04603a2 100644 ---- a/src/utils/tar/util_archive.c -+++ b/src/utils/tar/util_archive.c -@@ -61,7 +61,7 @@ ssize_t read_content(struct archive *a, void *client_data, const void **buff) - return mydata->content->read(mydata->content->context, mydata->buff, sizeof(mydata->buff)); - } - --static bool whiteout_convert_read(struct archive_entry *entry, const char *dst_path) -+static bool overlay_whiteout_convert_read(struct archive_entry *entry, const char *dst_path, map_t *unpacked_path_map) - { - bool do_write = true; - char *base = NULL; -@@ -143,6 +143,149 @@ static int copy_data(struct archive *ar, struct archive *aw) - } - } - -+static int remove_files_in_opq_dir(const char *dirpath, int recursive_depth, map_t *unpacked_path_map) -+{ -+ struct dirent *pdirent = NULL; -+ DIR *directory = NULL; -+ int ret = 0; -+ char fname[PATH_MAX] = { 0 }; -+ -+ if ((recursive_depth + 1) > MAX_PATH_DEPTH) { -+ ERROR("Reach max path depth: %s", dirpath); -+ return -1; -+ } -+ -+ directory = opendir(dirpath); -+ if (directory == NULL) { -+ ERROR("Failed to open %s", dirpath); -+ return -1; -+ } -+ pdirent = readdir(directory); -+ for (; pdirent != NULL; pdirent = readdir(directory)) { -+ struct stat fstat; -+ int pathname_len; -+ -+ if (!strcmp(pdirent->d_name, ".") || !strcmp(pdirent->d_name, "..")) { -+ continue; -+ } -+ -+ (void)memset(fname, 0, sizeof(fname)); -+ -+ pathname_len = snprintf(fname, PATH_MAX, "%s/%s", dirpath, pdirent->d_name); -+ if (pathname_len < 0 || pathname_len >= PATH_MAX) { -+ ERROR("Pathname too long"); -+ ret = -1; -+ continue; -+ } -+ -+ // not exist in unpacked paths map, just remove the path -+ if (map_search(unpacked_path_map, (void *)fname) == NULL) { -+ if (util_recursive_remove_path(fname) != 0) { -+ ERROR("Failed to remove path %s", fname); -+ ret = -1; -+ } -+ continue; -+ } -+ -+ if (lstat(fname, &fstat) != 0) { -+ ERROR("Failed to stat %s", fname); -+ ret = -1; -+ continue; -+ } -+ -+ if (S_ISDIR(fstat.st_mode)) { -+ if (remove_files_in_opq_dir(fname, recursive_depth + 1, unpacked_path_map) != 0) { -+ ret = -1; -+ continue; -+ } -+ } -+ } -+ -+ if (closedir(directory) != 0) { -+ ERROR("Failed to close directory %s", dirpath); -+ ret = -1; -+ } -+ -+ return ret; -+} -+ -+static bool remove_whiteout_convert(struct archive_entry *entry, const char *dst_path, map_t *unpacked_path_map) -+{ -+ bool do_write = true; -+ char *base = NULL; -+ char *dir = NULL; -+ char *originalpath = NULL; -+ -+ base = util_path_base(dst_path); -+ if (base == NULL) { -+ ERROR("Failed to get base of %s", dst_path); -+ goto out; -+ } -+ -+ dir = util_path_dir(dst_path); -+ if (dir == NULL) { -+ ERROR("Failed to get dir of %s", dst_path); -+ goto out; -+ } -+ -+ if (strcmp(base, WHITEOUT_OPAQUEDIR) == 0) { -+ if (remove_files_in_opq_dir(dir, 0, unpacked_path_map) != 0) { -+ SYSERROR("Failed to remove files in opq dir %s", dir); -+ goto out; -+ } -+ do_write = false; -+ goto out; -+ } -+ -+ if (strncmp(base, WHITEOUT_PREFIX, strlen(WHITEOUT_PREFIX)) == 0) { -+ char *origin_base = &base[strlen(WHITEOUT_PREFIX)]; -+ originalpath = util_path_join(dir, origin_base); -+ if (originalpath == NULL) { -+ ERROR("Failed to get original path of %s", dst_path); -+ goto out; -+ } -+ -+ if (util_recursive_remove_path(originalpath) != 0) { -+ ERROR("Failed to delete original path %s", originalpath); -+ goto out; -+ } -+ -+ do_write = false; -+ goto out; -+ } -+ -+out: -+ free(base); -+ free(dir); -+ free(originalpath); -+ return do_write; -+} -+ -+typedef bool (*whiteout_convert_call_back_t)(struct archive_entry *entry, const char *dst_path, -+ map_t *unpacked_path_map); -+ -+struct whiteout_convert_map { -+ whiteout_format_type type; -+ whiteout_convert_call_back_t wh_cb; -+}; -+ -+struct whiteout_convert_map g_wh_cb_map[] = { { OVERLAY_WHITEOUT_FORMATE, overlay_whiteout_convert_read }, -+ { REMOVE_WHITEOUT_FORMATE, remove_whiteout_convert } -+}; -+ -+static whiteout_convert_call_back_t get_whiteout_convert_cb(whiteout_format_type whiteout_type) -+{ -+ size_t i = 0; -+ -+ for (i = 0; i < sizeof(g_wh_cb_map) / sizeof(g_wh_cb_map[0]); i++) { -+ if (whiteout_type == g_wh_cb_map[i].type) { -+ return g_wh_cb_map[i].wh_cb; -+ } -+ } -+ -+ return NULL; -+} -+ - int archive_unpack_handler(const struct io_read_wrapper *content, const char *dstdir, - const struct archive_options *options) - { -@@ -153,6 +296,15 @@ int archive_unpack_handler(const struct io_read_wrapper *content, const char *ds - struct archive_entry *entry = NULL; - char *dst_path = NULL; - int flags; -+ whiteout_convert_call_back_t wh_handle_cb = NULL; -+ map_t *unpacked_path_map = NULL; // used for hanling opaque dir, marke paths had been unpacked -+ -+ unpacked_path_map = map_new(MAP_STR_BOOL, MAP_DEFAULT_CMP_FUNC, MAP_DEFAULT_FREE_FUNC); -+ if (unpacked_path_map == NULL) { -+ ERROR("Out of memory"); -+ ret = -1; -+ goto out; -+ } - - mydata = util_common_calloc_s(sizeof(struct archive_content_data)); - if (mydata == NULL) { -@@ -187,6 +339,8 @@ int archive_unpack_handler(const struct io_read_wrapper *content, const char *ds - goto out; - } - -+ wh_handle_cb = get_whiteout_convert_cb(options->whiteout_format); -+ - for (;;) { - free(dst_path); - dst_path = NULL; -@@ -217,28 +371,42 @@ int archive_unpack_handler(const struct io_read_wrapper *content, const char *ds - goto out; - } - -- if (options->whiteout_format == OVERLAY_WHITEOUT_FORMATE && !whiteout_convert_read(entry, dst_path)) { -+ if (wh_handle_cb != NULL && !wh_handle_cb(entry, dst_path, unpacked_path_map)) { - continue; - } - - ret = archive_write_header(ext, entry); - if (ret != ARCHIVE_OK) { - ERROR("Fail to handle tar header: %s", archive_error_string(ext)); -+ ret = -1; -+ goto out; - } else if (archive_entry_size(entry) > 0) { - ret = copy_data(a, ext); - if (ret != ARCHIVE_OK) { - ERROR("Failed to do copy tar data: %s", archive_error_string(ext)); -+ ret = -1; -+ goto out; - } - } - ret = archive_write_finish_entry(ext); - if (ret != ARCHIVE_OK) { - ERROR("Failed to freeing archive entry: %s\n", archive_error_string(ext)); -+ ret = -1; -+ goto out; -+ } -+ -+ bool b = true; -+ if (!map_replace(unpacked_path_map, (void *)dst_path, (void *)(&b))) { -+ ERROR("Failed to replace unpacked path map element"); -+ ret = -1; -+ goto out; - } - } - - ret = 0; - - out: -+ map_free(unpacked_path_map); - free(dst_path); - archive_read_close(a); - archive_read_free(a); -diff --git a/src/utils/tar/util_archive.h b/src/utils/tar/util_archive.h -index 4c4e4a1..6f65daa 100644 ---- a/src/utils/tar/util_archive.h -+++ b/src/utils/tar/util_archive.h -@@ -30,8 +30,9 @@ extern "C" { - #endif - - typedef enum { -- NONE_WHITEOUT_FORMATE = 0, -- OVERLAY_WHITEOUT_FORMATE = 1, -+ NONE_WHITEOUT_FORMATE = 0, // handle whiteouts as normal files -+ OVERLAY_WHITEOUT_FORMATE = 1, // handle whiteouts as the way as overlay -+ REMOVE_WHITEOUT_FORMATE = 2, // handle whiteouts by removing the target files - } whiteout_format_type; - - struct archive_options { --- -2.20.1 - diff --git a/0013-iSulad-internal-change.patch b/0013-iSulad-internal-change.patch deleted file mode 100644 index dba3725..0000000 --- a/0013-iSulad-internal-change.patch +++ /dev/null @@ -1,476 +0,0 @@ -From 8eaec71c30695317bb91c881824e201c4009db67 Mon Sep 17 00:00:00 2001 -From: lifeng68 -Date: Thu, 29 Oct 2020 14:43:36 +0800 -Subject: [PATCH 13/28] iSulad: internal change - -Signed-off-by: lifeng68 ---- - cmake/protoc.cmake | 20 +---- - src/api/services/cri/api.proto | 3 + - src/api/services/health/health.proto | 54 ------------ - src/api/services/images/images.proto | 88 +++---------------- - src/api/types/descriptor.proto | 49 ----------- - src/client/connect/CMakeLists.txt | 4 +- - src/daemon/entry/connect/CMakeLists.txt | 4 +- - .../entry/connect/grpc/grpc_images_service.h | 8 +- - .../graphdriver/quota/project_quota.h | 56 +++++------- - 9 files changed, 43 insertions(+), 243 deletions(-) - delete mode 100644 src/api/services/health/health.proto - delete mode 100644 src/api/types/descriptor.proto - -diff --git a/cmake/protoc.cmake b/cmake/protoc.cmake -index 352c0db..c10d4c3 100644 ---- a/cmake/protoc.cmake -+++ b/cmake/protoc.cmake -@@ -1,22 +1,11 @@ - set(PROTOS_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/api/services) --set(TYPES_PROTOS_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/api/types) - - set(GRPC_OUT_PRE_PATH ${CMAKE_BINARY_DIR}/grpc) --set(TYPES_PROTOS_OUT_PATH ${GRPC_OUT_PRE_PATH}/src/api/types) - set(CONTAINER_PROTOS_OUT_PATH ${GRPC_OUT_PRE_PATH}/src/api/services/containers) - set(IMAGE_PROTOS_OUT_PATH ${GRPC_OUT_PRE_PATH}/src/api/services/images) - set(CRI_PROTOS_OUT_PATH ${GRPC_OUT_PRE_PATH}/src/api/services/cri) - set(IMAGE_SERVICE_PROTOS_OUT_PATH ${GRPC_OUT_PRE_PATH}/src/api/image_client) - --execute_process(COMMAND mkdir -p ${TYPES_PROTOS_OUT_PATH}) -- --execute_process(COMMAND ${CMD_PROTOC} -I ${TYPES_PROTOS_PATH} --cpp_out=${TYPES_PROTOS_OUT_PATH} -- ${TYPES_PROTOS_PATH}/descriptor.proto ERROR_VARIABLE types_err) --if (types_err) -- message("Parse types.proto failed: ") -- message(FATAL_ERROR ${types_err}) --endif() -- - if (GRPC_CONNECTOR) - message("---------------Generate GRPC proto-----------------------") - execute_process(COMMAND mkdir -p ${CONTAINER_PROTOS_OUT_PATH}) -@@ -29,22 +18,19 @@ if (GRPC_CONNECTOR) - message(FATAL_ERROR ${containers_err}) - endif() - -- execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/containers --grpc_out=${CONTAINER_PROTOS_OUT_PATH} -- --plugin=protoc-gen-grpc=${CMD_GRPC_CPP_PLUGIN} ${PROTOS_PATH}/containers/container.proto ERROR_VARIABLE containers_err) -+ execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/containers --grpc_out=${CONTAINER_PROTOS_OUT_PATH} --plugin=protoc-gen-grpc=${CMD_GRPC_CPP_PLUGIN} ${PROTOS_PATH}/containers/container.proto ERROR_VARIABLE containers_err) - if (containers_err) - message("Parse containers.proto plugin failed: ") - message(FATAL_ERROR ${containers_err}) - endif() - -- execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/images -I ${TYPES_PROTOS_PATH} -- --cpp_out=${IMAGE_PROTOS_OUT_PATH} ${PROTOS_PATH}/images/images.proto ERROR_VARIABLE images_err) -+ execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/images --cpp_out=${IMAGE_PROTOS_OUT_PATH} ${PROTOS_PATH}/images/images.proto ERROR_VARIABLE images_err) - if (images_err) - message("Parse images.proto failed: ") - message(FATAL_ERROR ${images_err}) - endif() - -- execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/images -I ${TYPES_PROTOS_PATH} --grpc_out=${IMAGE_PROTOS_OUT_PATH} -- --plugin=protoc-gen-grpc=${CMD_GRPC_CPP_PLUGIN} ${PROTOS_PATH}/images/images.proto ERROR_VARIABLE images_err) -+ execute_process(COMMAND ${CMD_PROTOC} -I ${PROTOS_PATH}/images --grpc_out=${IMAGE_PROTOS_OUT_PATH} --plugin=protoc-gen-grpc=${CMD_GRPC_CPP_PLUGIN} ${PROTOS_PATH}/images/images.proto ERROR_VARIABLE images_err) - if (images_err) - message("Parse images.proto plugin failed: ") - message(FATAL_ERROR ${images_err}) -diff --git a/src/api/services/cri/api.proto b/src/api/services/cri/api.proto -index 022fa51..8aba0d3 100644 ---- a/src/api/services/cri/api.proto -+++ b/src/api/services/cri/api.proto -@@ -1,5 +1,8 @@ - /* - Copyright 2018 The Kubernetes Authors. -+Copyright (C) Huawei Technologies., Ltd. 2019. All rights reserved. -+ modify descripe: remove unused options for example: -+ remove import "github.com/gogo/protobuf/gogoproto/gogo.proto" - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. -diff --git a/src/api/services/health/health.proto b/src/api/services/health/health.proto -deleted file mode 100644 -index a3d3537..0000000 ---- a/src/api/services/health/health.proto -+++ /dev/null -@@ -1,54 +0,0 @@ --// ####################################################################### --// ##- @Copyright (C) Huawei Technologies., Ltd. 2019-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. --// ##- @Description: generate grpc --// ##- @Author: tanyifeng --// ##- @Create: 2020-01-16 --// ####################################################################### --// --// Since some of this code is derived from grpc, their copyright --// is retained here.... --// --// Copyright 2015 The gRPC Authors --// --// Licensed under the Apache License, Version 2.0 (the "License"); --// you may not use this file except in compliance with the License. --// You may obtain a copy of the License at --// --// http://www.apache.org/licenses/LICENSE-2.0 --// --// Unless required by applicable law or agreed to in writing, software --// distributed under the License is distributed on an "AS IS" BASIS, --// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --// See the License for the specific language governing permissions and --// limitations under the License. -- --// The canonical version of this proto can be found at --// https://github.com/grpc/grpc-proto/blob/master/grpc/health/v1/health.proto -- --syntax = "proto3"; --option optimize_for = CODE_SIZE; -- --message HealthCheckRequest { -- string service = 1; --} -- --message HealthCheckResponse { -- enum ServingStatus { -- UNKNOWN = 0; -- SERVING = 1; -- NOT_SERVING = 2; -- } -- ServingStatus status = 1; --} -- --service HealthService{ -- rpc Check(HealthCheckRequest) returns (HealthCheckResponse); --} -diff --git a/src/api/services/images/images.proto b/src/api/services/images/images.proto -index bdec2f8..71cce22 100644 ---- a/src/api/services/images/images.proto -+++ b/src/api/services/images/images.proto -@@ -9,109 +9,43 @@ - // # - PURPOSE. - // # - See the Mulan PSL v2 for more details. - // ##- @Description: generate grpc --// ##- @Author: wujing --// ##- @Create: 2020-01-16 -+// ##- @Author: lifeng -+// ##- @Create: 2019-04-25 - // ####################################################################### - -- --/* --Since some of this code is derived from containerd, their copyright --is retained here.... -- --Copyright 2013-2016 Docker, Inc. -- --Licensed under the Apache License, Version 2.0 (the "License"); --you may not use this file except in compliance with the License. --You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- --Unless required by applicable law or agreed to in writing, software --distributed under the License is distributed on an "AS IS" BASIS, --WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --See the License for the specific language governing permissions and --limitations under the License. --*/ -- - syntax = "proto3"; - option optimize_for = CODE_SIZE; - - import "google/protobuf/timestamp.proto"; --import "descriptor.proto"; - - package images; - --// Images is a service that allows one to register images with containerd. --// --// In containerd, an image is merely the mapping of a name to a content root, --// described by a descriptor. The behavior and state of image is purely --// dictated by the type of the descriptor. --// --// From the perspective of this service, these references are mostly shallow, --// in that the existence of the required content won't be validated until --// required by consuming services. --// --// As such, this can really be considered a "metadata service". - service ImagesService { -- // List returns a list of all images known to containerd. - rpc List(ListImagesRequest) returns (ListImagesResponse); -- -- // Delete deletes the image by name. - rpc Delete(DeleteImageRequest) returns (DeleteImageResponse); -- -- // load image from archive. - rpc Load(LoadImageRequest) returns (LoadImageResponse); -- -- //inspect image - rpc Inspect(InspectImageRequest) returns (InspectImageResponse); -- -- // Login to a Docker registry - rpc Login(LoginRequest) returns (LoginResponse); -- -- // Logout from a Docker registry - rpc Logout(LogoutRequest) returns (LogoutResponse); -- -- // Add a tag to the image - rpc Tag(TagImageRequest) returns (TagImageResponse); -- -- // Import rootfs to be image - rpc Import(ImportRequest) returns (ImportResponse); - } - -+message Descriptor { -+ string media_type = 1; -+ string digest = 2; -+ int64 size = 3; -+} -+ - message Image { -- // Name provides a unique name for the image. -- // -- // Containerd treats this as the primary identifier. - string name = 1; -- -- // Labels provides free form labels for the image. These are runtime only -- // and do not get inherited into the package image in any way. -- // -- // Labels may be updated using the field mask. -- // The combined size of a key/value pair cannot exceed 4096 bytes. - map labels = 2; -- -- // Target describes the content entry point of the image. -- containerd.types.Descriptor target = 3; -- -- // CreatedAt is the time the image was first created. -- google.protobuf.Timestamp created_at = 7; -- -- // UpdatedAt is the last time the image was mutated. -- google.protobuf.Timestamp updated_at = 8; -+ Descriptor target = 3; -+ google.protobuf.Timestamp created_at = 4; -+ google.protobuf.Timestamp updated_at = 5; - } - - message ListImagesRequest { -- // Filters contains one or more filters using the syntax defined in the -- // containerd filter package. -- // -- // The returned result will be those that match any of the provided -- // filters. Expanded, images that match the following will be -- // returned: -- // -- // filters[0] or filters[1] or ... or filters[n-1] or filters[n] -- // -- // If filters is zero-length or nil, all items will be returned. - map filters = 1; - } - -diff --git a/src/api/types/descriptor.proto b/src/api/types/descriptor.proto -deleted file mode 100644 -index 38b9d19..0000000 ---- a/src/api/types/descriptor.proto -+++ /dev/null -@@ -1,49 +0,0 @@ --// ####################################################################### --// ##- @Copyright (C) Huawei Technologies., Ltd. 2019-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. --// ##- @Description: generate grpc --// ##- @Author: wujing --// ##- @Create: 2019-01-16 --// ####################################################################### -- --/* --Since some of this code is derived from containerd, their copyright --is retained here.... -- --Copyright 2013-2016 Docker, Inc. -- --Licensed under the Apache License, Version 2.0 (the "License"); --you may not use this file except in compliance with the License. --You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- --Unless required by applicable law or agreed to in writing, software --distributed under the License is distributed on an "AS IS" BASIS, --WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --See the License for the specific language governing permissions and --limitations under the License. --*/ -- --syntax = "proto3"; --option optimize_for = CODE_SIZE; -- --package containerd.types; -- --// Descriptor describes a blob in a content store. --// --// This descriptor can be used to reference content from an --// oci descriptor found in a manifest. --// See https://godoc.org/github.com/opencontainers/image-spec/specs-go/v1#Descriptor --message Descriptor { -- string media_type = 1; -- string digest = 2; -- int64 size = 3; --} -diff --git a/src/client/connect/CMakeLists.txt b/src/client/connect/CMakeLists.txt -index 60a3429..1097d16 100644 ---- a/src/client/connect/CMakeLists.txt -+++ b/src/client/connect/CMakeLists.txt -@@ -9,16 +9,14 @@ add_subdirectory(grpc) - - if (GRPC_CONNECTOR) - list(APPEND local_client_connect_srcs ${CLIENT_GRPC_SRCS}) -- aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/types CONNECT_API_TYPES) - aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/containers CONNECT_API_CONTAINERS) - aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/images CONNECT_API_IMAGES) - aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/cri CONNECT_API_CRI) -- set(CONNECT_API ${CONNECT_API_TYPES} ${CONNECT_API_CONTAINERS} ${CONNECT_API_IMAGES} ${CONNECT_API_CRI}) -+ set(CONNECT_API ${CONNECT_API_CONTAINERS} ${CONNECT_API_IMAGES} ${CONNECT_API_CRI}) - list(APPEND local_client_connect_srcs ${CONNECT_API}) - - list(APPEND local_client_connect_incs ${CMAKE_CURRENT_SOURCE_DIR}/grpc) - list(APPEND local_client_connect_incs -- ${CMAKE_BINARY_DIR}/grpc/src/api/types - ${CMAKE_BINARY_DIR}/grpc/src/api/services/containers - ${CMAKE_BINARY_DIR}/grpc/src/api/services/images - ${CMAKE_BINARY_DIR}/grpc/src/api/services/cri -diff --git a/src/daemon/entry/connect/CMakeLists.txt b/src/daemon/entry/connect/CMakeLists.txt -index 0220319..3b174df 100644 ---- a/src/daemon/entry/connect/CMakeLists.txt -+++ b/src/daemon/entry/connect/CMakeLists.txt -@@ -15,15 +15,13 @@ endif() - - if (GRPC_CONNECTOR) - # GRPC -- aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/types CONNECT_API_TYPES) - aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/containers CONNECT_API_CONTAINERS) - aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/images CONNECT_API_IMAGES) - aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/cri CONNECT_API_CRI) -- set(CONNECT_API ${CONNECT_API_TYPES} ${CONNECT_API_CONTAINERS} ${CONNECT_API_IMAGES} ${CONNECT_API_CRI}) -+ set(CONNECT_API ${CONNECT_API_CONTAINERS} ${CONNECT_API_IMAGES} ${CONNECT_API_CRI}) - list(APPEND local_server_connect_srcs ${CONNECT_API}) - - list(APPEND local_server_connect_incs -- ${CMAKE_BINARY_DIR}/grpc/src/api/types - ${CMAKE_BINARY_DIR}/grpc/src/api/services/containers - ${CMAKE_BINARY_DIR}/grpc/src/api/services/images - ${CMAKE_BINARY_DIR}/grpc/src/api/services/cri -diff --git a/src/daemon/entry/connect/grpc/grpc_images_service.h b/src/daemon/entry/connect/grpc/grpc_images_service.h -index 3c498f4..921d64f 100644 ---- a/src/daemon/entry/connect/grpc/grpc_images_service.h -+++ b/src/daemon/entry/connect/grpc/grpc_images_service.h -@@ -33,7 +33,6 @@ using grpc::StatusCode; - using google::protobuf::Timestamp; - - using namespace images; --using namespace containerd::types; - - // Implement of images service - class ImagesServiceImpl final : public ImagesService::Service { -@@ -55,11 +54,9 @@ public: - - Status Inspect(ServerContext *context, const InspectImageRequest *request, InspectImageResponse *reply) override; - -- Status Login(ServerContext *context, const LoginRequest *request, -- LoginResponse *reply) override; -+ Status Login(ServerContext *context, const LoginRequest *request, LoginResponse *reply) override; - -- Status Logout(ServerContext *context, const LogoutRequest *request, -- LogoutResponse *reply) override; -+ Status Logout(ServerContext *context, const LogoutRequest *request, LogoutResponse *reply) override; - - private: - template -@@ -99,4 +96,3 @@ private: - }; - - #endif // DAEMON_ENTRY_CONNECT_GRPC_GRPC_IMAGES_SERVICE_H -- -diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/quota/project_quota.h b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/quota/project_quota.h -index d88ac30..2aae6bc 100644 ---- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/quota/project_quota.h -+++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/quota/project_quota.h -@@ -44,46 +44,34 @@ - extern "C" { - #endif - --/* -- * Check whether we have to define FS_IOC_FS[GS]ETXATTR ourselves. These -- * are a copy of the definitions moved to linux/uapi/fs.h in the 4.5 kernel, -- * so this is purely for supporting builds against old kernel headers. -- */ - #if !defined FS_IOC_FSGETXATTR -+// if did not define the fsxattr, define by ourself - struct fsxattr { -- __u32 fsx_xflags; /* xflags field value (get/set) */ -- __u32 fsx_extsize; /* extsize field value (get/set)*/ -- __u32 fsx_nextents; /* nextents field value (get) */ -- __u32 fsx_projid; /* project identifier (get/set) */ -- __u32 fsx_cowextsize; /* cow extsize field value (get/set) */ -- unsigned char fsx_pad[8]; -+ __u32 fsx_xflags, fsx_extsize, fsx_nextents, fsx_projid, fsx_cowextsize; -+ unsigned char fsx_pad[8]; - }; - #endif - - #ifndef FS_IOC_FSGETXATTR --/* -- * Flags for the fsx_xflags field -- */ --#define FS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */ --#define FS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */ --#define FS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */ --#define FS_XFLAG_APPEND 0x00000010 /* all writes append */ --#define FS_XFLAG_SYNC 0x00000020 /* all writes synchronous */ --#define FS_XFLAG_NOATIME 0x00000040 /* do not update access time */ --#define FS_XFLAG_NODUMP 0x00000080 /* do not include in backups */ --#define FS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */ --#define FS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */ --#define FS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */ --#define FS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */ --#define FS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */ --#define FS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */ --#define FS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */ --#define FS_XFLAG_DAX 0x00008000 /* use DAX for IO */ --#define FS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ -- --#define FS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr) --#define FS_IOC_FSSETXATTR _IOW ('X', 32, struct fsxattr) -- -+// if did not define the FSGETXATTR, define by ourself -+#define FS_XFLAG_REALTIME 0x00000001 -+#define FS_XFLAG_PREALLOC 0x00000002 -+#define FS_XFLAG_IMMUTABLE 0x00000008 -+#define FS_XFLAG_APPEND 0x00000010 -+#define FS_XFLAG_SYNC 0x00000020 -+#define FS_XFLAG_NOATIME 0x00000040 -+#define FS_XFLAG_NODUMP 0x00000080 -+#define FS_XFLAG_RTINHERIT 0x00000100 -+#define FS_XFLAG_PROJINHERIT 0x00000200 -+#define FS_XFLAG_NOSYMLINKS 0x00000400 -+#define FS_XFLAG_EXTSIZE 0x00000800 -+#define FS_XFLAG_EXTSZINHERIT 0x00001000 -+#define FS_XFLAG_NODEFRAG 0x00002000 -+#define FS_XFLAG_FILESTREAM 0x00004000 -+#define FS_XFLAG_DAX 0x00008000 -+#define FS_XFLAG_HASATTR 0x80000000 -+#define FS_IOC_FSGETXATTR _IOR('X', 31, struct fsxattr) -+#define FS_IOC_FSSETXATTR _IOW('X', 32, struct fsxattr) - #endif - - struct pquota_control { --- -2.20.1 - diff --git a/0014-unlink-etc-dir-when-link-exists.patch b/0014-unlink-etc-dir-when-link-exists.patch deleted file mode 100644 index 623ae08..0000000 --- a/0014-unlink-etc-dir-when-link-exists.patch +++ /dev/null @@ -1,26 +0,0 @@ -From c4980da3192c4ee2d8a2251c520cec6ea857523a Mon Sep 17 00:00:00 2001 -From: gaohuatao -Date: Thu, 29 Oct 2020 21:29:04 +0800 -Subject: [PATCH 14/28] unlink etc dir when link exists - -Signed-off-by: gaohuatao ---- - src/daemon/modules/service/service_container.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/src/daemon/modules/service/service_container.c b/src/daemon/modules/service/service_container.c -index 4e830d3..cc4e85e 100644 ---- a/src/daemon/modules/service/service_container.c -+++ b/src/daemon/modules/service/service_container.c -@@ -130,6 +130,8 @@ static int create_mtab_link(const oci_runtime_spec *oci_spec) - goto out; - } - -+ (void)unlink(dir); -+ - if (!util_dir_exists(dir)) { - ret = util_mkdir_p(dir, ETC_FILE_MODE); - if (ret != 0) { --- -2.20.1 - diff --git a/0015-support-variable-extension-cni-args.patch b/0015-support-variable-extension-cni-args.patch deleted file mode 100644 index 63e3a89..0000000 --- a/0015-support-variable-extension-cni-args.patch +++ /dev/null @@ -1,182 +0,0 @@ -From 9fba9e85a4e379a94fa0418969e56587bc72f55d Mon Sep 17 00:00:00 2001 -From: haozi007 -Date: Sat, 31 Oct 2020 15:26:08 +0800 -Subject: [PATCH 15/28] support variable extension cni args - -Signed-off-by: haozi007 ---- - src/daemon/entry/cri/cni_network_plugin.cc | 103 ++++++++++++++------- - src/daemon/entry/cri/cri_helpers.cc | 1 + - src/daemon/entry/cri/cri_helpers.h | 1 + - 3 files changed, 72 insertions(+), 33 deletions(-) - -diff --git a/src/daemon/entry/cri/cni_network_plugin.cc b/src/daemon/entry/cri/cni_network_plugin.cc -index 4676a97..f15eba3 100644 ---- a/src/daemon/entry/cri/cni_network_plugin.cc -+++ b/src/daemon/entry/cri/cni_network_plugin.cc -@@ -579,68 +579,105 @@ void CniNetworkPlugin::DeleteFromNetwork(CNINetwork *network, const std::string - free(serr); - } - -+static bool CheckCNIArgValue(const std::string &val) -+{ -+ if (val.find(';') != std::string::npos) { -+ return false; -+ } -+ if (std::count(val.begin(), val.end(), '=') != 1) { -+ return false; -+ } -+ return true; -+} -+ -+static void GetExtensionCNIArgs(const std::map &annotations, -+ std::map &args) -+{ -+ // get cni multinetwork extension -+ auto iter = annotations.find(CRIHelpers::Constants::CNI_MUTL_NET_EXTENSION_KEY); -+ if (iter != annotations.end()) { -+ if (!CheckCNIArgValue(iter->second)) { -+ WARN("Ignore: invalid multinetwork cni args: %s", iter->second.c_str()); -+ } else { -+ args[CRIHelpers::Constants::CNI_MUTL_NET_EXTENSION_ARGS_KEY] = iter->second; -+ } -+ } -+ -+ for (const auto &work : annotations) { -+ if (work.first.find(CRIHelpers::Constants::CNI_ARGS_EXTENSION_PREFIX_KEY) != 0) { -+ continue; -+ } -+ if (!CheckCNIArgValue(work.second)) { -+ WARN("Ignore: invalid extension cni args: %s", work.second.c_str()); -+ continue; -+ } -+ auto strs = CXXUtils::Split(work.second, '='); -+ iter = annotations.find(work.first); -+ if (iter != annotations.end()) { -+ WARN("Ignore: Same key cni args: %s", work.first.c_str()); -+ continue; -+ } -+ args[strs[0]] = strs[1]; -+ } -+} -+ - static void PrepareRuntimeConf(const std::string &podName, const std::string &podNs, const std::string &interfaceName, - const std::string &podSandboxID, const std::string &podNetnsPath, - const std::map &annotations, - const std::map &options, struct runtime_conf **cni_rc, - Errors &err) - { -- size_t defaultLen = 5; -+ size_t workLen = 5; -+ std::map cniArgs; -+ - if (cni_rc == nullptr) { - err.Errorf("Invalid arguments"); - ERROR("Invalid arguments"); - return; - } - -- auto iter = options.find("UID"); -- std::string podUID; -- if (iter != options.end()) { -- podUID = iter->second; -- } -- std::string cniExtentionVal; -- iter = annotations.find(CRIHelpers::Constants::CNI_MUTL_NET_EXTENSION_KEY); -- if (iter != annotations.end()) { -- cniExtentionVal = iter->second; -- defaultLen++; -- } -- - struct runtime_conf *rt = (struct runtime_conf *)util_common_calloc_s(sizeof(struct runtime_conf)); - if (rt == nullptr) { - ERROR("Out of memory"); - err.SetError("Out of memory"); - return; - } -- - rt->container_id = util_strdup_s(podSandboxID.c_str()); - rt->netns = util_strdup_s(podNetnsPath.c_str()); - rt->ifname = util_strdup_s(interfaceName.c_str()); - -- rt->args = (char *(*)[2])util_common_calloc_s(sizeof(char *) * 2 * defaultLen); -+ auto iter = options.find("UID"); -+ std::string podUID; -+ if (iter != options.end()) { -+ podUID = iter->second; -+ } -+ -+ cniArgs["K8S_POD_UID"] = podUID; -+ cniArgs["IgnoreUnknown"] = "1"; -+ cniArgs["K8S_POD_NAMESPACE"] = podNs; -+ cniArgs["K8S_POD_NAME"] = podName; -+ cniArgs["K8S_POD_INFRA_CONTAINER_ID"] = podSandboxID; -+ -+ GetExtensionCNIArgs(annotations, cniArgs); -+ workLen = cniArgs.size(); -+ -+ rt->args = (char *(*)[2])util_common_calloc_s(sizeof(char *) * 2 * workLen); - if (rt->args == nullptr) { - ERROR("Out of memory"); - err.SetError("Out of memory"); -- goto free_out; -+ free_runtime_conf(rt); -+ return; - } -- rt->args_len = defaultLen; -- rt->args[0][0] = util_strdup_s("IgnoreUnknown"); -- rt->args[0][1] = util_strdup_s("1"); -- rt->args[1][0] = util_strdup_s("K8S_POD_NAMESPACE"); -- rt->args[1][1] = util_strdup_s(podNs.c_str()); -- rt->args[2][0] = util_strdup_s("K8S_POD_NAME"); -- rt->args[2][1] = util_strdup_s(podName.c_str()); -- rt->args[3][0] = util_strdup_s("K8S_POD_INFRA_CONTAINER_ID"); -- rt->args[3][1] = util_strdup_s(podSandboxID.c_str()); -- rt->args[4][0] = util_strdup_s("K8S_POD_UID"); -- rt->args[4][1] = util_strdup_s(podUID.c_str()); -- if (defaultLen > 5) { -- rt->args[5][0] = util_strdup_s(CRIHelpers::Constants::CNI_MUTL_NET_EXTENSION_ARGS_KEY.c_str()); -- rt->args[5][1] = util_strdup_s(cniExtentionVal.c_str()); -+ rt->args_len = workLen; -+ -+ workLen = 0; -+ for (const auto &work : cniArgs) { -+ rt->args[workLen][0] = util_strdup_s(work.first.c_str()); -+ rt->args[workLen][1] = util_strdup_s(work.second.c_str()); -+ workLen++; - } - - *cni_rc = rt; -- return; --free_out: -- free_runtime_conf(rt); - } - - void CniNetworkPlugin::BuildCNIRuntimeConf(const std::string &podName, const std::string &podNs, -diff --git a/src/daemon/entry/cri/cri_helpers.cc b/src/daemon/entry/cri/cri_helpers.cc -index 4fb9feb..ee633b7 100644 ---- a/src/daemon/entry/cri/cri_helpers.cc -+++ b/src/daemon/entry/cri/cri_helpers.cc -@@ -53,6 +53,7 @@ const std::string Constants::NET_PLUGIN_EVENT_POD_CIDR_CHANGE { "pod-cidr-change - const std::string Constants::NET_PLUGIN_EVENT_POD_CIDR_CHANGE_DETAIL_CIDR { "pod-cidr" }; - const std::string Constants::CNI_MUTL_NET_EXTENSION_KEY { "extension.network.kubernetes.io/cni" }; - const std::string Constants::CNI_MUTL_NET_EXTENSION_ARGS_KEY { "CNI_MUTLINET_EXTENSION" }; -+const std::string Constants::CNI_ARGS_EXTENSION_PREFIX_KEY { "extension.network.kubernetes.io/cniargs/" }; - - const char *InternalLabelKeys[] = { CRIHelpers::Constants::CONTAINER_TYPE_LABEL_KEY.c_str(), - CRIHelpers::Constants::CONTAINER_LOGPATH_LABEL_KEY.c_str(), -diff --git a/src/daemon/entry/cri/cri_helpers.h b/src/daemon/entry/cri/cri_helpers.h -index 824d1a6..3ea9ba6 100644 ---- a/src/daemon/entry/cri/cri_helpers.h -+++ b/src/daemon/entry/cri/cri_helpers.h -@@ -58,6 +58,7 @@ public: - static const std::string NET_PLUGIN_EVENT_POD_CIDR_CHANGE_DETAIL_CIDR; - static const std::string CNI_MUTL_NET_EXTENSION_KEY; - static const std::string CNI_MUTL_NET_EXTENSION_ARGS_KEY; -+ static const std::string CNI_ARGS_EXTENSION_PREFIX_KEY; - }; - - auto GetDefaultSandboxImage(Errors &err) -> std::string; --- -2.20.1 - diff --git a/0016-CI-for-support-variable-extension-cni-args.patch b/0016-CI-for-support-variable-extension-cni-args.patch deleted file mode 100644 index fde7e67..0000000 --- a/0016-CI-for-support-variable-extension-cni-args.patch +++ /dev/null @@ -1,112 +0,0 @@ -From c62b1266dfbc4c28b5fd4dafea8438523826549d Mon Sep 17 00:00:00 2001 -From: haozi007 -Date: Sat, 31 Oct 2020 15:48:09 +0800 -Subject: [PATCH 16/28] CI for support variable extension cni args - -Signed-off-by: haozi007 ---- - CI/test_cases/container_cases/cni_test.sh | 55 +++++++++++++++++++ - .../container_cases/criconfigs/mock.json | 9 +++ - .../criconfigs/sandbox-config.json | 5 ++ - 3 files changed, 69 insertions(+) - create mode 100644 CI/test_cases/container_cases/criconfigs/mock.json - -diff --git a/CI/test_cases/container_cases/cni_test.sh b/CI/test_cases/container_cases/cni_test.sh -index 115e031..8173cb5 100644 ---- a/CI/test_cases/container_cases/cni_test.sh -+++ b/CI/test_cases/container_cases/cni_test.sh -@@ -154,6 +154,61 @@ function new_cni_config() - do_test_help "10\.2\." - } - -+function check_annotation() -+{ -+ cp ${data_path}/mock.json /etc/cni/net.d/bridge.json -+ sync;sync; -+ tail $ISUALD_LOG -+ # wait cni updated -+ s=`date "+%s"` -+ for ((i=0;i<30;i++)); do -+ sleep 1 -+ cur=`date "+%s"` -+ let "t=cur-s" -+ if [ $t -gt 6 ];then -+ break -+ fi -+ done -+ tail $ISUALD_LOG -+ -+ sid=`crictl runp ${data_path}/sandbox-config.json` -+ if [ $? -ne 0 ]; then -+ msg_err "Failed to run sandbox" -+ TC_RET_T=$(($TC_RET_T+1)) -+ fi -+ -+ basepath=/tmp/cnilogs/ -+ cat ${basepath}/${sid}.env | grep CNI_MUTLINET_EXTENSION -+ if [ $? -ne 0 ];then -+ msg_err "lost extension for mutl network args" -+ TC_RET_T=$(($TC_RET_T+1)) -+ fi -+ cat ${basepath}/${sid}.env | grep "extension=first" -+ if [ $? -ne 0 ];then -+ msg_err "lost extension for first cni args" -+ TC_RET_T=$(($TC_RET_T+1)) -+ fi -+ cat ${basepath}/${sid}.env | grep "extension=second" -+ if [ $? -ne 0 ];then -+ msg_err "lost extension for second cni args" -+ TC_RET_T=$(($TC_RET_T+1)) -+ fi -+ -+ crictl stopp $sid -+ if [ $? -ne 0 ];then -+ msg_err "stop sandbox failed" -+ TC_RET_T=$(($TC_RET_T+1)) -+ fi -+ -+ crictl rmp $sid -+ if [ $? -ne 0 ];then -+ msg_err "rm sandbox failed" -+ TC_RET_T=$(($TC_RET_T+1)) -+ fi -+ -+ return $TC_RET_T -+} -+ - ret=0 - - do_pre -diff --git a/CI/test_cases/container_cases/criconfigs/mock.json b/CI/test_cases/container_cases/criconfigs/mock.json -new file mode 100644 -index 0000000..85bb91e ---- /dev/null -+++ b/CI/test_cases/container_cases/criconfigs/mock.json -@@ -0,0 +1,9 @@ -+{ -+ "cniVersion": "0.3.1", -+ "name": "mock", -+ "type": "isulad-cni", -+ "ipam": { -+ "type": "isulad-cni", -+ "subnet": "10.3.0.0/16" -+ } -+} -diff --git a/CI/test_cases/container_cases/criconfigs/sandbox-config.json b/CI/test_cases/container_cases/criconfigs/sandbox-config.json -index c63dc0e..e9151e8 100644 ---- a/CI/test_cases/container_cases/criconfigs/sandbox-config.json -+++ b/CI/test_cases/container_cases/criconfigs/sandbox-config.json -@@ -7,5 +7,10 @@ - "uid": "hdishd83djaidwnduwk28bcsb" - }, - "linux": { -+ }, -+ "annotations": { -+ "extension.network.kubernetes.io/cni": "[multinetwork]", -+ "extension.network.kubernetes.io/cniargs/first": "extension=first", -+ "extension.network.kubernetes.io/cniargs/second": "extension=second" - } - } --- -2.20.1 - diff --git a/0017-add-unlink-dir-comments.patch b/0017-add-unlink-dir-comments.patch deleted file mode 100644 index 9b19c90..0000000 --- a/0017-add-unlink-dir-comments.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 45b91002a3c8fa7c4e96db8154354be1cd4296bb Mon Sep 17 00:00:00 2001 -From: gaohuatao -Date: Mon, 2 Nov 2020 08:58:04 +0800 -Subject: [PATCH 17/28] add unlink dir comments - -Signed-off-by: gaohuatao ---- - src/daemon/modules/service/service_container.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/daemon/modules/service/service_container.c b/src/daemon/modules/service/service_container.c -index cc4e85e..7a89618 100644 ---- a/src/daemon/modules/service/service_container.c -+++ b/src/daemon/modules/service/service_container.c -@@ -129,7 +129,7 @@ static int create_mtab_link(const oci_runtime_spec *oci_spec) - ret = -1; - goto out; - } -- -+ // When dir is symbol link, unlink dir to assure creating dir success following - (void)unlink(dir); - - if (!util_dir_exists(dir)) { --- -2.20.1 - diff --git a/0018-iSulad-add-ISULAD_TMPDIR-env-variable.patch b/0018-iSulad-add-ISULAD_TMPDIR-env-variable.patch deleted file mode 100644 index dd0b783..0000000 --- a/0018-iSulad-add-ISULAD_TMPDIR-env-variable.patch +++ /dev/null @@ -1,398 +0,0 @@ -From 4509f2a6d4b5ff7b0cb1df5177bf557950c67d15 Mon Sep 17 00:00:00 2001 -From: gaohuatao -Date: Tue, 3 Nov 2020 11:17:13 +0800 -Subject: [PATCH 18/28] iSulad: add ISULAD_TMPDIR env variable - -Signed-off-by: gaohuatao ---- - src/common/constants.h | 2 +- - src/contrib/config/iSulad.sysconfig | 4 ++ - src/daemon/modules/image/oci/oci_image.c | 17 ++++-- - src/daemon/modules/image/oci/oci_load.c | 58 +++++++++++++++---- - .../modules/image/oci/registry/registry.c | 31 ++++++++-- - src/daemon/modules/image/oci/registry_type.h | 1 - - .../modules/image/oci/storage/storage.c | 32 +++++++++- - .../modules/image/oci/storage/storage.h | 3 +- - src/daemon/modules/image/oci/utils_images.c | 35 +++++++++++ - src/daemon/modules/image/oci/utils_images.h | 5 +- - 10 files changed, 162 insertions(+), 26 deletions(-) - -diff --git a/src/common/constants.h b/src/common/constants.h -index 52bb0a8..457e242 100644 ---- a/src/common/constants.h -+++ b/src/common/constants.h -@@ -44,7 +44,7 @@ extern "C" { - - #define LOG_DIRECTORY_MODE 0750 - --#define TEMP_DIRECTORY_MODE 0750 -+#define TEMP_DIRECTORY_MODE 0700 - - #define CONSOLE_FIFO_DIRECTORY_MODE 0770 - -diff --git a/src/contrib/config/iSulad.sysconfig b/src/contrib/config/iSulad.sysconfig -index 580d6de..5d222f9 100644 ---- a/src/contrib/config/iSulad.sysconfig -+++ b/src/contrib/config/iSulad.sysconfig -@@ -20,3 +20,7 @@ - #SYSMONITOR_OPTIONS='-H unix:///var/run/isulad.sock' - #SYSMONITOR_OPTIONS='-H tcp://127.0.0.1:2375' - #SYSMONITOR_OPTIONS='-H tcp://127.0.0.1:2375 --tlsverify --tlscacert=/root/.iSulad/ca.pem --tlscert=/root/.iSulad/cert.pem --tlskey=/root/.iSulad/key.pem' -+ -+# Location used for temporary files, such as those created by isula load and pull operations. -+# Default is /var/tmp. Can be overridden by setting the following env variable. -+# ISULAD_TMPDIR=/var/tmp -\ No newline at end of file -diff --git a/src/daemon/modules/image/oci/oci_image.c b/src/daemon/modules/image/oci/oci_image.c -index f544019..f0ba19c 100644 ---- a/src/daemon/modules/image/oci/oci_image.c -+++ b/src/daemon/modules/image/oci/oci_image.c -@@ -152,13 +152,22 @@ out: - - static void cleanup_image_tmpdir() - { -- if (util_recursive_rmdir(IMAGE_TMP_PATH, 0)) { -- ERROR("failed to remove directory %s", IMAGE_TMP_PATH); -+ char *image_tmp_path = NULL; -+ -+ image_tmp_path = get_image_tmp_path(); -+ if (image_tmp_path == NULL) { -+ ERROR("failed to get image tmp path"); -+ return; -+ } -+ -+ if (util_recursive_rmdir(image_tmp_path, 0)) { -+ ERROR("failed to remove directory %s", image_tmp_path); - } - -- if (util_mkdir_p(IMAGE_TMP_PATH, 0600)) { -- ERROR("failed to create directory %s", IMAGE_TMP_PATH); -+ if (util_mkdir_p(image_tmp_path, TEMP_DIRECTORY_MODE)) { -+ ERROR("failed to create directory %s", image_tmp_path); - } -+ free(image_tmp_path); - - return; - } -diff --git a/src/daemon/modules/image/oci/oci_load.c b/src/daemon/modules/image/oci/oci_load.c -index 5511c04..073ad55 100644 ---- a/src/daemon/modules/image/oci/oci_load.c -+++ b/src/daemon/modules/image/oci/oci_load.c -@@ -44,7 +44,6 @@ - - #define MANIFEST_BIG_DATA_KEY "manifest" - #define OCI_SCHEMA_VERSION 2 --#define OCI_LOAD_TMP_DIR OCI_LOAD_TMP_WORK_DIR "/oci-image-load-XXXXXX" - - static image_manifest_items_element **load_manifest(const char *fname, size_t *length) - { -@@ -1008,6 +1007,47 @@ out: - return res; - } - -+static char *oci_load_path_create() -+{ -+ int ret = 0; -+ int nret = 0; -+ char *oci_load_work_dir = NULL; -+ char tmp_dir[PATH_MAX] = { 0 }; -+ -+ oci_load_work_dir = storage_oci_load_work_dir(); -+ if (oci_load_work_dir == NULL) { -+ ERROR("Failed to get oci load work dir"); -+ isulad_try_set_error_message("Failed to get oci load work dir"); -+ ret = -1; -+ goto out; -+ } -+ -+ if (util_mkdir_p(oci_load_work_dir, TEMP_DIRECTORY_MODE) != 0) { -+ ERROR("Unable to create oci image load tmp work dir:%s", oci_load_work_dir); -+ isulad_try_set_error_message("Unable to create oci image load tmp work dir:%s", oci_load_work_dir); -+ ret = -1; -+ goto out; -+ } -+ -+ nret = snprintf(tmp_dir, PATH_MAX, "%s/oci-image-load-XXXXXX", oci_load_work_dir); -+ if (nret < 0 || (size_t)nret >= sizeof(tmp_dir)) { -+ ERROR("Path is too long"); -+ ret = -1; -+ goto out; -+ } -+ -+ if (mkdtemp(tmp_dir) == NULL) { -+ ERROR("make temporary dir failed: %s", strerror(errno)); -+ isulad_try_set_error_message("make temporary dir failed: %s", strerror(errno)); -+ ret = -1; -+ goto out; -+ } -+ -+out: -+ free(oci_load_work_dir); -+ return ret == 0 ? util_strdup_s(tmp_dir) : NULL; -+} -+ - int oci_do_load(const im_load_request *request) - { - int ret = 0; -@@ -1019,23 +1059,16 @@ int oci_do_load(const im_load_request *request) - size_t manifest_len = 0; - load_image_t *im = NULL; - char *digest = NULL; -- char dstdir[] = OCI_LOAD_TMP_DIR; -+ char *dstdir = NULL; - - if (request == NULL || request->file == NULL) { - ERROR("Invalid input arguments, cannot load image"); - return -1; - } - -- if (util_mkdir_p(OCI_LOAD_TMP_WORK_DIR, TEMP_DIRECTORY_MODE) != 0) { -- ERROR("Unable to create oci image load tmp work dir:%s", OCI_LOAD_TMP_WORK_DIR); -- isulad_try_set_error_message("Unable to create oci image load tmp work dir:%s", OCI_LOAD_TMP_WORK_DIR); -- ret = -1; -- goto out; -- } -- -- if (mkdtemp(dstdir) == NULL) { -- ERROR("make temporary direcory failed: %s", strerror(errno)); -- isulad_try_set_error_message("make temporary direcory failed: %s", strerror(errno)); -+ dstdir = oci_load_path_create(); -+ if (dstdir == NULL) { -+ ERROR("create temporary direcory failed"); - ret = -1; - goto out; - } -@@ -1132,5 +1165,6 @@ out: - if (util_recursive_rmdir(dstdir, 0)) { - WARN("failed to remove directory %s", dstdir); - } -+ free(dstdir); - return ret; - } -diff --git a/src/daemon/modules/image/oci/registry/registry.c b/src/daemon/modules/image/oci/registry/registry.c -index 2d38ea5..e4cffdc 100644 ---- a/src/daemon/modules/image/oci/registry/registry.c -+++ b/src/daemon/modules/image/oci/registry/registry.c -@@ -1682,8 +1682,9 @@ static int prepare_pull_desc(pull_descriptor *desc, registry_pull_options *optio - { - int ret = 0; - int sret = 0; -- char blobpath[] = REGISTRY_TMP_DIR; -+ char blobpath[PATH_MAX] = { 0 }; - char scope[PATH_MAX] = { 0 }; -+ char *image_tmp_path = NULL; - - if (desc == NULL || options == NULL) { - ERROR("Invalid NULL param"); -@@ -1717,6 +1718,20 @@ static int prepare_pull_desc(pull_descriptor *desc, registry_pull_options *optio - - update_host(desc); - -+ image_tmp_path = get_image_tmp_path(); -+ if (image_tmp_path == NULL) { -+ ERROR("failed to get image tmp work dir"); -+ ret = -1; -+ goto out; -+ } -+ -+ sret = snprintf(blobpath, PATH_MAX, "%s/registry-XXXXXX", image_tmp_path); -+ if (sret < 0 || (size_t)sret > PATH_MAX) { -+ ERROR("image tmp work path too long"); -+ ret = -1; -+ goto out; -+ } -+ - if (mkdtemp(blobpath) == NULL) { - ERROR("make temporary direcory failed: %s", strerror(errno)); - ret = -1; -@@ -1752,7 +1767,7 @@ static int prepare_pull_desc(pull_descriptor *desc, registry_pull_options *optio - } - - out: -- -+ free(image_tmp_path); - return ret; - } - -@@ -1844,10 +1859,18 @@ static void cached_layers_kvfree(void *key, void *value) - int registry_init(char *auths_dir, char *certs_dir) - { - int ret = 0; -+ char *image_tmp_path = NULL; -+ -+ image_tmp_path = get_image_tmp_path(); -+ if (image_tmp_path == NULL) { -+ ERROR("failed to get image tmp path"); -+ return -1; -+ } - -- if (util_mkdir_p(IMAGE_TMP_PATH, 0600)) { -- ERROR("failed to create directory %s", IMAGE_TMP_PATH); -+ if (util_mkdir_p(image_tmp_path, TEMP_DIRECTORY_MODE)) { -+ ERROR("failed to create directory %s", image_tmp_path); - } -+ free(image_tmp_path); - - auths_set_dir(auths_dir); - certs_set_dir(certs_dir); -diff --git a/src/daemon/modules/image/oci/registry_type.h b/src/daemon/modules/image/oci/registry_type.h -index 9592587..e2047cb 100644 ---- a/src/daemon/modules/image/oci/registry_type.h -+++ b/src/daemon/modules/image/oci/registry_type.h -@@ -25,7 +25,6 @@ - // 8 is enough for challenge, usually only one challenge is provided. - #define CHALLENGE_MAX 8 - --#define REGISTRY_TMP_DIR IMAGE_TMP_PATH "registry-XXXXXX" - - #define MAX_LAYER_NUM 125 - #define ROOTFS_TYPE "layers" -diff --git a/src/daemon/modules/image/oci/storage/storage.c b/src/daemon/modules/image/oci/storage/storage.c -index 6e83665..f15531b 100644 ---- a/src/daemon/modules/image/oci/storage/storage.c -+++ b/src/daemon/modules/image/oci/storage/storage.c -@@ -1715,10 +1715,18 @@ out: - int storage_module_init(struct storage_module_init_options *opts) - { - int ret = 0; -+ char *oci_load_work_dir = NULL; - -- ret = util_recursive_rmdir(OCI_LOAD_TMP_WORK_DIR, 0); -+ oci_load_work_dir = storage_oci_load_work_dir(); -+ if (oci_load_work_dir == NULL) { -+ ERROR("Get oci load work dir failed"); -+ ret = -1; -+ goto out; -+ } -+ -+ ret = util_recursive_rmdir(oci_load_work_dir, 0); - if (ret != 0) { -- ERROR("failed to remove dir %s", OCI_LOAD_TMP_WORK_DIR); -+ ERROR("failed to remove dir %s", oci_load_work_dir); - goto out; - } - -@@ -1775,5 +1783,25 @@ int storage_module_init(struct storage_module_init_options *opts) - } - - out: -+ free(oci_load_work_dir); - return ret; - } -+ -+ -+char *storage_oci_load_work_dir() -+{ -+ char *isulad_tmp = NULL; -+ char *oci_load_work_dir = NULL; -+ -+ isulad_tmp = oci_get_isulad_tmpdir(); -+ if (isulad_tmp == NULL) { -+ ERROR("Failed to get isulad tmp dir"); -+ goto out; -+ } -+ -+ oci_load_work_dir = util_path_join(isulad_tmp, "isulad-oci-load"); -+ -+out: -+ free(isulad_tmp); -+ return oci_load_work_dir; -+} -\ No newline at end of file -diff --git a/src/daemon/modules/image/oci/storage/storage.h b/src/daemon/modules/image/oci/storage/storage.h -index d3c4420..b030a3a 100644 ---- a/src/daemon/modules/image/oci/storage/storage.h -+++ b/src/daemon/modules/image/oci/storage/storage.h -@@ -32,7 +32,6 @@ - extern "C" { - #endif - --#define OCI_LOAD_TMP_WORK_DIR "/var/tmp/isulad-oci-load" - - struct layer { - char *id; -@@ -180,6 +179,8 @@ int storage_rootfs_umount(const char *container_id, bool force); - - container_inspect_graph_driver *storage_get_metadata_by_container_id(const char *id); - -+char *storage_oci_load_work_dir(); -+ - #ifdef __cplusplus - } - #endif -diff --git a/src/daemon/modules/image/oci/utils_images.c b/src/daemon/modules/image/oci/utils_images.c -index 42831cc..4bd2b1d 100644 ---- a/src/daemon/modules/image/oci/utils_images.c -+++ b/src/daemon/modules/image/oci/utils_images.c -@@ -39,6 +39,7 @@ - - // nanos of 2038-01-19T03:14:07, the max valid linux time - #define MAX_NANOS 2147483647000000000 -+#define ISULAD_DEFAULT_TMP_DIR "/var/tmp" - - char *get_last_part(char **parts) - { -@@ -486,3 +487,37 @@ bool oci_valid_time(char *time) - - return true; - } -+ -+ -+char *oci_get_isulad_tmpdir() -+{ -+ char *isula_tmp = NULL; -+ -+ isula_tmp = getenv("ISULAD_TMPDIR"); -+ if (util_valid_str(isula_tmp) && !util_dir_exists(isula_tmp)) { -+ if (util_mkdir_p(isula_tmp, TEMP_DIRECTORY_MODE) != 0) { -+ ERROR("make dir:%s failed", isula_tmp); -+ return NULL; -+ } -+ } -+ -+ return util_valid_str(isula_tmp) ? util_strdup_s(isula_tmp) : util_strdup_s(ISULAD_DEFAULT_TMP_DIR); -+} -+ -+char *get_image_tmp_path() -+{ -+ char *isulad_tmp = NULL; -+ char *isula_image = NULL; -+ -+ isulad_tmp = oci_get_isulad_tmpdir(); -+ if (isulad_tmp == NULL) { -+ ERROR("Failed to get isulad tmp dir"); -+ goto out; -+ } -+ -+ isula_image = util_path_join(isulad_tmp, "isula-image"); -+ -+out: -+ free(isulad_tmp); -+ return isula_image; -+} -diff --git a/src/daemon/modules/image/oci/utils_images.h b/src/daemon/modules/image/oci/utils_images.h -index 4ab4afc..5dedd56 100644 ---- a/src/daemon/modules/image/oci/utils_images.h -+++ b/src/daemon/modules/image/oci/utils_images.h -@@ -39,7 +39,6 @@ extern "C" { - #define REPO_PREFIX_TO_STRIP "library/" - #define MAX_ID_BUF_LEN 256 - --#define IMAGE_TMP_PATH "/var/tmp/isula-image/" - - char *oci_get_host(const char *name); - char *oci_host_from_mirror(const char *mirror); -@@ -55,6 +54,10 @@ int add_rootfs_and_history(const layer_blob *layers, size_t layers_len, const re - docker_image_config_v2 *config); - bool oci_valid_time(char *time); - -+char *oci_get_isulad_tmpdir(); -+ -+char *get_image_tmp_path(); -+ - #ifdef __cplusplus - } - #endif --- -2.20.1 - diff --git a/0020-add-ISULAD_TMPDIR-env-CI.patch b/0020-add-ISULAD_TMPDIR-env-CI.patch deleted file mode 100644 index 3fbe36b..0000000 --- a/0020-add-ISULAD_TMPDIR-env-CI.patch +++ /dev/null @@ -1,120 +0,0 @@ -From a174c586d1a6fa5dd367dc0eee72b39ffb1c6d25 Mon Sep 17 00:00:00 2001 -From: gaohuatao -Date: Thu, 5 Nov 2020 16:27:01 +0800 -Subject: [PATCH 20/28] add ISULAD_TMPDIR env CI - -Signed-off-by: gaohuatao ---- - CI/test_cases/image_cases/isulad_tmpdir.sh | 100 +++++++++++++++++++++ - 1 file changed, 100 insertions(+) - create mode 100644 CI/test_cases/image_cases/isulad_tmpdir.sh - -diff --git a/CI/test_cases/image_cases/isulad_tmpdir.sh b/CI/test_cases/image_cases/isulad_tmpdir.sh -new file mode 100644 -index 0000000..22a6ad4 ---- /dev/null -+++ b/CI/test_cases/image_cases/isulad_tmpdir.sh -@@ -0,0 +1,100 @@ -+#!/bin/bash -+# -+# attributes: isulad basic container hook -+# concurrent: NA -+# spend time: 4 -+ -+####################################################################### -+##- @Copyright (C) Huawei Technologies., 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. -+##- @Description:CI -+##- @Author: gaohuatao -+##- @Create: 2020-11-05 -+####################################################################### -+ -+declare -r curr_path=$(dirname $(readlink -f "$0")) -+source ../helpers.sh -+busybox_image="${curr_path}/busybox.tar" -+image_name="busybox:latest" -+ -+function restart_isulad() -+{ -+ check_valgrind_log -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - stop isulad failed" && ((ret++)) -+ -+ start_isulad_with_valgrind -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - start isulad failed" && ((ret++)) -+ -+} -+ -+function load_pull_test() -+{ -+ isula load -i $busybox_image -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - load image failed: ${busybox_image} with" && ((ret++)) -+ -+ isula rmi $image_name -+ -+ isula pull ${image_name} -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to pull image: ${image_name}" && return ${FAILURE} -+} -+ -+function test_isulad_tmpdir() -+{ -+ local ret=0 -+ local test="ISULAD_TMPDIR env test => (${FUNCNAME[@]})" -+ -+ msg_info "${test} starting..." -+ isula rm -f `isula ps -qa` -+ isula rmi `isula images | awk '{if (NR>1){print $3}}'` -+ -+ # The scene of ISULAD_TMPDIR dir is not exists -+ export ISULAD_TMPDIR="/var/isula/tmp" -+ restart_isulad -+ load_pull_test -+ test -d /var/isula/tmp/isula-image -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - isula-image not exist in ISULAD_TMPDIR" && ((ret++)) -+ -+ # The scene of ISULAD_TMPDIR dir is symbol link that it refers to dir exists -+ rm -rf /var/isula/tmp -+ mkdir -p /var/tmpdir -+ ln -sf /var/tmpdir /var/isula/tmpdir -+ unset ISULAD_TMPDIR -+ export ISULAD_TMPDIR="/var/isula/tmpdir" -+ restart_isulad -+ load_pull_test -+ test -d /var/isula/tmpdir/isula-image -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - isula-image not exist in ISULAD_TMPDIR" && ((ret++)) -+ -+ # rm dest dir of symbol link -+ rm -rf /var/tmpdir -+ check_valgrind_log -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - stop isulad failed" && ((ret++)) -+ -+ start_isulad_with_valgrind -+ [[ $? -eq 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - start isulad failed" && ((ret++)) -+ -+ # default no ISULAD_TMPDIR env -+ unset ISULAD_TMPDIR -+ start_isulad_with_valgrind -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - start isulad failed" && ((ret++)) -+ -+ load_pull_test -+ test -d /var/tmp/isula-image -+ [[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - isula-image not exist in /var/tmp" && ((ret++)) -+ -+ msg_info "${test} finished with return ${ret}..." -+ return ${ret} -+} -+ -+declare -i ans=0 -+ -+test_isulad_tmpdir || ((ans++)) -+ -+show_result ${ans} "${curr_path}/${0}" --- -2.20.1 - diff --git a/0021-iSulad-fix-memory-leak-in-inspect-grpc-service.patch b/0021-iSulad-fix-memory-leak-in-inspect-grpc-service.patch deleted file mode 100644 index 2317e1e..0000000 --- a/0021-iSulad-fix-memory-leak-in-inspect-grpc-service.patch +++ /dev/null @@ -1,41 +0,0 @@ -From e5df207d89c8467971fd0e0529703a782bca8dfa Mon Sep 17 00:00:00 2001 -From: zhangxiaoyu -Date: Sat, 7 Nov 2020 09:57:27 +0800 -Subject: [PATCH 21/28] iSulad: fix memory leak in inspect grpc service - -Signed-off-by: zhangxiaoyu ---- - .../entry/connect/grpc/grpc_containers_service.cc | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/src/daemon/entry/connect/grpc/grpc_containers_service.cc b/src/daemon/entry/connect/grpc/grpc_containers_service.cc -index 54417c6..60b1e44 100644 ---- a/src/daemon/entry/connect/grpc/grpc_containers_service.cc -+++ b/src/daemon/entry/connect/grpc/grpc_containers_service.cc -@@ -781,6 +781,11 @@ Status ContainerServiceImpl::Inspect(ServerContext *context, const InspectContai - container_inspect_request *container_req = nullptr; - container_inspect_response *container_res = nullptr; - -+ Status status = GrpcServerTlsAuth::auth(context, "container_inspect"); -+ if (!status.ok()) { -+ return status; -+ } -+ - cb = get_service_executor(); - if (cb == nullptr || cb->container.inspect == nullptr) { - return Status(StatusCode::UNIMPLEMENTED, "Unimplemented callback"); -@@ -793,11 +798,6 @@ Status ContainerServiceImpl::Inspect(ServerContext *context, const InspectContai - return Status::OK; - } - -- Status status = GrpcServerTlsAuth::auth(context, "container_inspect"); -- if (!status.ok()) { -- return status; -- } -- - ret = cb->container.inspect(container_req, &container_res); - tret = inspect_response_to_grpc(container_res, reply); - --- -2.20.1 - diff --git a/0022-clean-code-remove-unused-code-in-connect.patch b/0022-clean-code-remove-unused-code-in-connect.patch deleted file mode 100644 index 1c4e01e..0000000 --- a/0022-clean-code-remove-unused-code-in-connect.patch +++ /dev/null @@ -1,1424 +0,0 @@ -From c85763f9327bf3aa76d14580eb04876901aea936 Mon Sep 17 00:00:00 2001 -From: lifeng68 -Date: Sat, 7 Nov 2020 11:11:14 +0800 -Subject: [PATCH 22/28] clean code: remove unused code in connect - -Signed-off-by: lifeng68 ---- - .../connect/grpc/grpc_containers_service.cc | 252 ++++++------------ - .../connect/grpc/grpc_containers_service.h | 42 +-- - .../grpc/grpc_containers_service_private.cc | 117 ++++---- - .../entry/connect/grpc/grpc_images_service.cc | 104 +++----- - .../entry/connect/grpc/grpc_images_service.h | 12 +- - 5 files changed, 204 insertions(+), 323 deletions(-) - -diff --git a/src/daemon/entry/connect/grpc/grpc_containers_service.cc b/src/daemon/entry/connect/grpc/grpc_containers_service.cc -index 60b1e44..4e8f55d 100644 ---- a/src/daemon/entry/connect/grpc/grpc_containers_service.cc -+++ b/src/daemon/entry/connect/grpc/grpc_containers_service.cc -@@ -149,7 +149,7 @@ bool grpc_copy_to_container_read_function(void *reader, void *data) - - Status ContainerServiceImpl::Version(ServerContext *context, const VersionRequest *request, VersionResponse *reply) - { -- int ret, tret; -+ int tret; - service_executor_t *cb = nullptr; - container_version_request *container_req = nullptr; - container_version_response *container_res = nullptr; -@@ -170,22 +170,18 @@ Status ContainerServiceImpl::Version(ServerContext *context, const VersionReques - return Status::OK; - } - -- ret = cb->container.version(container_req, &container_res); -- tret = version_response_to_grpc(container_res, reply); -+ (void)cb->container.version(container_req, &container_res); -+ version_response_to_grpc(container_res, reply); - - free_container_version_request(container_req); - free_container_version_response(container_res); -- if (tret != 0) { -- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); -- reply->set_cc(ISULAD_ERR_INTERNAL); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - - Status ContainerServiceImpl::Info(ServerContext *context, const InfoRequest *request, InfoResponse *reply) - { -- int ret, tret; -+ int tret; - service_executor_t *cb = nullptr; - host_info_request *container_req = nullptr; - host_info_response *container_res = nullptr; -@@ -206,22 +202,18 @@ Status ContainerServiceImpl::Info(ServerContext *context, const InfoRequest *req - return Status::OK; - } - -- ret = cb->container.info(container_req, &container_res); -- tret = info_response_to_grpc(container_res, reply); -+ (void)cb->container.info(container_req, &container_res); -+ info_response_to_grpc(container_res, reply); - - free_host_info_request(container_req); - free_host_info_response(container_res); -- if (tret != 0) { -- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); -- reply->set_cc(ISULAD_ERR_INTERNAL); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - - Status ContainerServiceImpl::Create(ServerContext *context, const CreateRequest *request, CreateResponse *reply) - { -- int ret, tret; -+ int tret; - service_executor_t *cb = nullptr; - container_create_response *container_res = nullptr; - container_create_request *container_req = nullptr; -@@ -242,22 +234,18 @@ Status ContainerServiceImpl::Create(ServerContext *context, const CreateRequest - return Status::OK; - } - -- ret = cb->container.create(container_req, &container_res); -- tret = create_response_to_grpc(container_res, reply); -+ (void)cb->container.create(container_req, &container_res); -+ create_response_to_grpc(container_res, reply); - - free_container_create_request(container_req); - free_container_create_response(container_res); -- if (tret != 0) { -- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); -- reply->set_cc(ISULAD_ERR_INTERNAL); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - - Status ContainerServiceImpl::Start(ServerContext *context, const StartRequest *request, StartResponse *reply) - { -- int ret, tret; -+ int tret; - service_executor_t *cb = nullptr; - container_start_request *req = nullptr; - container_start_response *res = nullptr; -@@ -278,16 +266,12 @@ Status ContainerServiceImpl::Start(ServerContext *context, const StartRequest *r - return Status::CANCELLED; - } - -- ret = cb->container.start(req, &res, -1, nullptr, nullptr); -- tret = response_to_grpc(res, reply); -+ (void)cb->container.start(req, &res, -1, nullptr, nullptr); -+ response_to_grpc(res, reply); - - free_container_start_request(req); - free_container_start_response(res); -- if (tret != 0) { -- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); -- reply->set_cc(ISULAD_ERR_INTERNAL); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - -@@ -415,7 +399,7 @@ Status ContainerServiceImpl::RemoteStart(ServerContext *context, - - Status ContainerServiceImpl::Top(ServerContext *context, const TopRequest *request, TopResponse *reply) - { -- int ret, tret; -+ int tret; - service_executor_t *cb = nullptr; - container_top_request *req = nullptr; - container_top_response *res = nullptr; -@@ -436,22 +420,18 @@ Status ContainerServiceImpl::Top(ServerContext *context, const TopRequest *reque - return Status::CANCELLED; - } - -- ret = cb->container.top(req, &res); -- tret = top_response_to_grpc(res, reply); -+ (void)cb->container.top(req, &res); -+ top_response_to_grpc(res, reply); - - free_container_top_request(req); - free_container_top_response(res); -- if (tret != 0) { -- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); -- reply->set_cc(ISULAD_ERR_INTERNAL); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - - Status ContainerServiceImpl::Stop(ServerContext *context, const StopRequest *request, StopResponse *reply) - { -- int ret, tret; -+ int tret; - service_executor_t *cb = nullptr; - container_stop_request *container_req = nullptr; - container_stop_response *container_res = nullptr; -@@ -472,22 +452,18 @@ Status ContainerServiceImpl::Stop(ServerContext *context, const StopRequest *req - return Status::OK; - } - -- ret = cb->container.stop(container_req, &container_res); -- tret = response_to_grpc(container_res, reply); -+ (void)cb->container.stop(container_req, &container_res); -+ response_to_grpc(container_res, reply); - - free_container_stop_request(container_req); - free_container_stop_response(container_res); -- if (tret != 0) { -- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); -- reply->set_cc(ISULAD_ERR_INTERNAL); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - - Status ContainerServiceImpl::Restart(ServerContext *context, const RestartRequest *request, RestartResponse *reply) - { -- int ret, tret; -+ int tret; - service_executor_t *cb = nullptr; - container_restart_request *container_req = nullptr; - container_restart_response *container_res = nullptr; -@@ -508,22 +484,18 @@ Status ContainerServiceImpl::Restart(ServerContext *context, const RestartReques - return Status::OK; - } - -- ret = cb->container.restart(container_req, &container_res); -- tret = response_to_grpc(container_res, reply); -+ (void)cb->container.restart(container_req, &container_res); -+ response_to_grpc(container_res, reply); - - free_container_restart_request(container_req); - free_container_restart_response(container_res); -- if (tret != 0) { -- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); -- reply->set_cc(ISULAD_ERR_INTERNAL); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - - Status ContainerServiceImpl::Kill(ServerContext *context, const KillRequest *request, KillResponse *reply) - { -- int ret, tret; -+ int tret; - service_executor_t *cb = nullptr; - container_kill_request *container_req = nullptr; - container_kill_response *container_res = nullptr; -@@ -544,22 +516,18 @@ Status ContainerServiceImpl::Kill(ServerContext *context, const KillRequest *req - return Status::OK; - } - -- ret = cb->container.kill(container_req, &container_res); -- tret = response_to_grpc(container_res, reply); -+ (void)cb->container.kill(container_req, &container_res); -+ response_to_grpc(container_res, reply); - - free_container_kill_request(container_req); - free_container_kill_response(container_res); -- if (tret != 0) { -- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); -- reply->set_cc(ISULAD_ERR_INTERNAL); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - - Status ContainerServiceImpl::Delete(ServerContext *context, const DeleteRequest *request, DeleteResponse *reply) - { -- int ret, tret; -+ int tret; - service_executor_t *cb = nullptr; - container_delete_request *container_req = nullptr; - container_delete_response *container_res = nullptr; -@@ -580,22 +548,18 @@ Status ContainerServiceImpl::Delete(ServerContext *context, const DeleteRequest - return Status::OK; - } - -- ret = cb->container.remove(container_req, &container_res); -- tret = delete_response_to_grpc(container_res, reply); -+ (void)cb->container.remove(container_req, &container_res); -+ delete_response_to_grpc(container_res, reply); - - free_container_delete_request(container_req); - free_container_delete_response(container_res); -- if (tret != 0) { -- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); -- reply->set_cc(ISULAD_ERR_INTERNAL); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - - Status ContainerServiceImpl::Exec(ServerContext *context, const ExecRequest *request, ExecResponse *reply) - { -- int ret, tret; -+ int tret; - service_executor_t *cb = nullptr; - container_exec_request *container_req = nullptr; - container_exec_response *container_res = nullptr; -@@ -616,16 +580,12 @@ Status ContainerServiceImpl::Exec(ServerContext *context, const ExecRequest *req - return Status::CANCELLED; - } - -- ret = cb->container.exec(container_req, &container_res, -1, nullptr, nullptr); -- tret = exec_response_to_grpc(container_res, reply); -+ (void)cb->container.exec(container_req, &container_res, -1, nullptr, nullptr); -+ exec_response_to_grpc(container_res, reply); - - free_container_exec_request(container_req); - free_container_exec_response(container_res); -- if (tret != 0) { -- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); -- reply->set_cc(ISULAD_ERR_INTERNAL); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - -@@ -776,7 +736,7 @@ Status ContainerServiceImpl::RemoteExec(ServerContext *context, - Status ContainerServiceImpl::Inspect(ServerContext *context, const InspectContainerRequest *request, - InspectContainerResponse *reply) - { -- int ret, tret; -+ int tret; - service_executor_t *cb = nullptr; - container_inspect_request *container_req = nullptr; - container_inspect_response *container_res = nullptr; -@@ -798,22 +758,18 @@ Status ContainerServiceImpl::Inspect(ServerContext *context, const InspectContai - return Status::OK; - } - -- ret = cb->container.inspect(container_req, &container_res); -- tret = inspect_response_to_grpc(container_res, reply); -+ (void)cb->container.inspect(container_req, &container_res); -+ inspect_response_to_grpc(container_res, reply); - - free_container_inspect_request(container_req); - free_container_inspect_response(container_res); -- if (tret != 0) { -- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); -- reply->set_cc(ISULAD_ERR_INTERNAL); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - - Status ContainerServiceImpl::List(ServerContext *context, const ListRequest *request, ListResponse *reply) - { -- int ret, tret; -+ int tret; - service_executor_t *cb = nullptr; - container_list_request *container_req = nullptr; - container_list_response *container_res = nullptr; -@@ -834,16 +790,12 @@ Status ContainerServiceImpl::List(ServerContext *context, const ListRequest *req - return Status::OK; - } - -- ret = cb->container.list(container_req, &container_res); -- tret = list_response_to_grpc(container_res, reply); -+ (void)cb->container.list(container_req, &container_res); -+ list_response_to_grpc(container_res, reply); - - free_container_list_request(container_req); - free_container_list_response(container_res); -- if (tret != 0) { -- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); -- reply->set_cc(ISULAD_ERR_INTERNAL); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - -@@ -990,7 +942,7 @@ Status ContainerServiceImpl::Attach(ServerContext *context, ServerReaderWritercontainer.pause(container_req, &container_res); -- tret = response_to_grpc(container_res, reply); -+ (void)cb->container.pause(container_req, &container_res); -+ response_to_grpc(container_res, reply); - - free_container_pause_request(container_req); - free_container_pause_response(container_res); -- if (tret != 0) { -- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); -- reply->set_cc(ISULAD_ERR_INTERNAL); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - - Status ContainerServiceImpl::Resume(ServerContext *context, const ResumeRequest *request, ResumeResponse *reply) - { -- int ret, tret; -+ int tret; - service_executor_t *cb = nullptr; - container_resume_request *container_req = nullptr; - container_resume_response *container_res = nullptr; -@@ -1047,22 +995,18 @@ Status ContainerServiceImpl::Resume(ServerContext *context, const ResumeRequest - return Status::OK; - } - -- ret = cb->container.resume(container_req, &container_res); -- tret = response_to_grpc(container_res, reply); -+ (void)cb->container.resume(container_req, &container_res); -+ response_to_grpc(container_res, reply); - - free_container_resume_request(container_req); - free_container_resume_response(container_res); -- if (tret != 0) { -- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); -- reply->set_cc(ISULAD_ERR_INTERNAL); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - - Status ContainerServiceImpl::Export(ServerContext *context, const ExportRequest *request, ExportResponse *reply) - { -- int ret, tret; -+ int tret; - service_executor_t *cb = nullptr; - container_export_request *container_req = nullptr; - container_export_response *container_res = nullptr; -@@ -1083,22 +1027,18 @@ Status ContainerServiceImpl::Export(ServerContext *context, const ExportRequest - return Status::OK; - } - -- ret = cb->container.export_rootfs(container_req, &container_res); -- tret = response_to_grpc(container_res, reply); -+ (void)cb->container.export_rootfs(container_req, &container_res); -+ response_to_grpc(container_res, reply); - - free_container_export_request(container_req); - free_container_export_response(container_res); -- if (tret != 0) { -- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); -- reply->set_cc(ISULAD_ERR_INTERNAL); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - - Status ContainerServiceImpl::Rename(ServerContext *context, const RenameRequest *request, RenameResponse *reply) - { -- int ret, tret; -+ int tret; - service_executor_t *cb = nullptr; - struct isulad_container_rename_request *isuladreq = nullptr; - struct isulad_container_rename_response *isuladres = nullptr; -@@ -1120,22 +1060,18 @@ Status ContainerServiceImpl::Rename(ServerContext *context, const RenameRequest - return Status::OK; - } - -- ret = cb->container.rename(isuladreq, &isuladres); -- tret = container_rename_response_to_grpc(isuladres, reply); -+ (void)cb->container.rename(isuladreq, &isuladres); -+ container_rename_response_to_grpc(isuladres, reply); - - isulad_container_rename_request_free(isuladreq); - isulad_container_rename_response_free(isuladres); -- if (tret != 0) { -- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); -- reply->set_cc(ISULAD_ERR_INTERNAL); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - - Status ContainerServiceImpl::Resize(ServerContext *context, const ResizeRequest *request, ResizeResponse *reply) - { -- int ret, tret; -+ int tret; - service_executor_t *cb = nullptr; - struct isulad_container_resize_request *isuladreq = nullptr; - struct isulad_container_resize_response *isuladres = nullptr; -@@ -1157,22 +1093,18 @@ Status ContainerServiceImpl::Resize(ServerContext *context, const ResizeRequest - return Status::OK; - } - -- ret = cb->container.resize(isuladreq, &isuladres); -- tret = container_resize_response_to_grpc(isuladres, reply); -+ (void)cb->container.resize(isuladreq, &isuladres); -+ container_resize_response_to_grpc(isuladres, reply); - - isulad_container_resize_request_free(isuladreq); - isulad_container_resize_response_free(isuladres); -- if (tret != 0) { -- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); -- reply->set_cc(ISULAD_ERR_INTERNAL); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - - Status ContainerServiceImpl::Update(ServerContext *context, const UpdateRequest *request, UpdateResponse *reply) - { -- int ret, tret; -+ int tret; - service_executor_t *cb = nullptr; - container_update_request *container_req = nullptr; - container_update_response *container_res = nullptr; -@@ -1193,22 +1125,18 @@ Status ContainerServiceImpl::Update(ServerContext *context, const UpdateRequest - return Status::OK; - } - -- ret = cb->container.update(container_req, &container_res); -- tret = update_response_to_grpc(container_res, reply); -+ (void)cb->container.update(container_req, &container_res); -+ update_response_to_grpc(container_res, reply); - - free_container_update_request(container_req); - free_container_update_response(container_res); -- if (tret != 0) { -- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); -- reply->set_cc(ISULAD_ERR_INTERNAL); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - - Status ContainerServiceImpl::Stats(ServerContext *context, const StatsRequest *request, StatsResponse *reply) - { -- int ret, tret; -+ int tret; - service_executor_t *cb = nullptr; - container_stats_request *container_req = nullptr; - container_stats_response *container_res = nullptr; -@@ -1229,22 +1157,18 @@ Status ContainerServiceImpl::Stats(ServerContext *context, const StatsRequest *r - return Status::OK; - } - -- ret = cb->container.stats(container_req, &container_res); -- tret = stats_response_to_grpc(container_res, reply); -+ (void)cb->container.stats(container_req, &container_res); -+ stats_response_to_grpc(container_res, reply); - - free_container_stats_request(container_req); - free_container_stats_response(container_res); -- if (tret != 0) { -- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); -- reply->set_cc(ISULAD_ERR_INTERNAL); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - - Status ContainerServiceImpl::Wait(ServerContext *context, const WaitRequest *request, WaitResponse *reply) - { -- int ret, tret; -+ int tret; - service_executor_t *cb = nullptr; - container_wait_request *container_req = nullptr; - container_wait_response *container_res = nullptr; -@@ -1265,22 +1189,18 @@ Status ContainerServiceImpl::Wait(ServerContext *context, const WaitRequest *req - return Status::OK; - } - -- ret = cb->container.wait(container_req, &container_res); -- tret = wait_response_to_grpc(container_res, reply); -+ (void)cb->container.wait(container_req, &container_res); -+ wait_response_to_grpc(container_res, reply); - - free_container_wait_request(container_req); - free_container_wait_response(container_res); -- if (tret != 0) { -- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); -- reply->set_cc(ISULAD_ERR_INTERNAL); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - - Status ContainerServiceImpl::Events(ServerContext *context, const EventsRequest *request, ServerWriter *writer) - { -- int ret, tret; -+ int tret; - service_executor_t *cb = nullptr; - isulad_events_request *isuladreq = nullptr; - stream_func_wrapper stream = { 0 }; -@@ -1305,9 +1225,9 @@ Status ContainerServiceImpl::Events(ServerContext *context, const EventsRequest - stream.write_func = &grpc_event_write_function; - stream.writer = (void *)writer; - -- ret = cb->container.events(isuladreq, &stream); -+ tret = cb->container.events(isuladreq, &stream); - isulad_events_request_free(isuladreq); -- if (ret != 0) { -+ if (tret != 0) { - return Status(StatusCode::INTERNAL, "Failed to execute events callback"); - } - -@@ -1317,7 +1237,7 @@ Status ContainerServiceImpl::Events(ServerContext *context, const EventsRequest - Status ContainerServiceImpl::CopyFromContainer(ServerContext *context, const CopyFromContainerRequest *request, - ServerWriter *writer) - { -- int ret, tret; -+ int tret; - service_executor_t *cb = nullptr; - isulad_copy_from_container_request *isuladreq = nullptr; - -@@ -1344,11 +1264,11 @@ Status ContainerServiceImpl::CopyFromContainer(ServerContext *context, const Cop - stream.writer = (void *)writer; - - char *err = nullptr; -- ret = cb->container.copy_from_container(isuladreq, &stream, &err); -+ tret = cb->container.copy_from_container(isuladreq, &stream, &err); - isulad_copy_from_container_request_free(isuladreq); - std::string errmsg = (err != nullptr) ? err : "Failed to execute copy_from_container callback"; - free(err); -- if (ret != 0) { -+ if (tret != 0) { - return Status(StatusCode::UNKNOWN, errmsg); - } - return Status::OK; -diff --git a/src/daemon/entry/connect/grpc/grpc_containers_service.h b/src/daemon/entry/connect/grpc/grpc_containers_service.h -index 30de091..4865c41 100644 ---- a/src/daemon/entry/connect/grpc/grpc_containers_service.h -+++ b/src/daemon/entry/connect/grpc/grpc_containers_service.h -@@ -106,36 +106,36 @@ public: - - private: - template -- int response_to_grpc(const T1 *response, T2 *gresponse) -+ void response_to_grpc(const T1 *response, T2 *gresponse) - { - if (response == nullptr) { - gresponse->set_cc(ISULAD_ERR_MEMOUT); -- return 0; -+ return; - } - gresponse->set_cc(response->cc); - if (response->errmsg != nullptr) { - gresponse->set_errmsg(response->errmsg); - } -- return 0; -+ return; - } - - int version_request_from_grpc(const VersionRequest *grequest, container_version_request **request); - -- int version_response_to_grpc(const container_version_response *response, VersionResponse *gresponse); -+ void version_response_to_grpc(const container_version_response *response, VersionResponse *gresponse); - - int info_request_from_grpc(const InfoRequest *grequest, host_info_request **request); - -- int info_response_to_grpc(const host_info_response *response, InfoResponse *gresponse); -+ void info_response_to_grpc(const host_info_response *response, InfoResponse *gresponse); - - int create_request_from_grpc(const CreateRequest *grequest, container_create_request **request); - -- int create_response_to_grpc(const container_create_response *response, CreateResponse *gresponse); -+ void create_response_to_grpc(const container_create_response *response, CreateResponse *gresponse); - - int start_request_from_grpc(const StartRequest *grequest, container_start_request **request); - - int top_request_from_grpc(const TopRequest *grequest, container_top_request **request); - -- int top_response_to_grpc(const container_top_response *response, TopResponse *gresponse); -+ void top_response_to_grpc(const container_top_response *response, TopResponse *gresponse); - - int stop_request_from_grpc(const StopRequest *grequest, container_stop_request **request); - -@@ -145,19 +145,19 @@ private: - - int delete_request_from_grpc(const DeleteRequest *grequest, container_delete_request **request); - -- int delete_response_to_grpc(const container_delete_response *response, DeleteResponse *gresponse); -+ void delete_response_to_grpc(const container_delete_response *response, DeleteResponse *gresponse); - - int exec_request_from_grpc(const ExecRequest *grequest, container_exec_request **request); - -- int exec_response_to_grpc(const container_exec_response *response, ExecResponse *gresponse); -+ void exec_response_to_grpc(const container_exec_response *response, ExecResponse *gresponse); - - int inspect_request_from_grpc(const InspectContainerRequest *grequest, container_inspect_request **request); - -- int inspect_response_to_grpc(const container_inspect_response *response, InspectContainerResponse *gresponse); -+ void inspect_response_to_grpc(const container_inspect_response *response, InspectContainerResponse *gresponse); - - int list_request_from_grpc(const ListRequest *grequest, container_list_request **request); - -- int list_response_to_grpc(const container_list_response *response, ListResponse *gresponse); -+ void list_response_to_grpc(const container_list_response *response, ListResponse *gresponse); - - int pause_request_from_grpc(const PauseRequest *grequest, container_pause_request **request); - -@@ -166,26 +166,26 @@ private: - int container_rename_request_from_grpc(const RenameRequest *grequest, - struct isulad_container_rename_request **request); - -- int container_rename_response_to_grpc(const struct isulad_container_rename_response *response, -- RenameResponse *gresponse); -+ void container_rename_response_to_grpc(const struct isulad_container_rename_response *response, -+ RenameResponse *gresponse); - - int container_resize_request_from_grpc(const ResizeRequest *grequest, - struct isulad_container_resize_request **request); - -- int container_resize_response_to_grpc(const struct isulad_container_resize_response *response, -- ResizeResponse *gresponse); -+ void container_resize_response_to_grpc(const struct isulad_container_resize_response *response, -+ ResizeResponse *gresponse); - - int update_request_from_grpc(const UpdateRequest *grequest, container_update_request **request); - -- int update_response_to_grpc(const container_update_response *response, UpdateResponse *gresponse); -+ void update_response_to_grpc(const container_update_response *response, UpdateResponse *gresponse); - - int stats_request_from_grpc(const StatsRequest *grequest, container_stats_request **request); - -- int stats_response_to_grpc(const container_stats_response *response, StatsResponse *gresponse); -+ void stats_response_to_grpc(const container_stats_response *response, StatsResponse *gresponse); - - int wait_request_from_grpc(const WaitRequest *grequest, container_wait_request **request); - -- int wait_response_to_grpc(const container_wait_response *response, WaitResponse *gresponse); -+ void wait_response_to_grpc(const container_wait_response *response, WaitResponse *gresponse); - - int events_request_from_grpc(const EventsRequest *grequest, struct isulad_events_request **request); - -@@ -211,11 +211,11 @@ private: - - int export_request_from_grpc(const ExportRequest *grequest, container_export_request **request); - -- int pack_os_info_to_grpc(const host_info_response *response, InfoResponse *gresponse); -+ void pack_os_info_to_grpc(const host_info_response *response, InfoResponse *gresponse); - -- int pack_proxy_info_to_grpc(const host_info_response *response, InfoResponse *gresponse); -+ void pack_proxy_info_to_grpc(const host_info_response *response, InfoResponse *gresponse); - -- int pack_driver_info_to_grpc(const host_info_response *response, InfoResponse *gresponse); -+ void pack_driver_info_to_grpc(const host_info_response *response, InfoResponse *gresponse); - - int logs_request_from_grpc(const LogsRequest *grequest, struct isulad_logs_request **request); - }; -diff --git a/src/daemon/entry/connect/grpc/grpc_containers_service_private.cc b/src/daemon/entry/connect/grpc/grpc_containers_service_private.cc -index 4d1f657..c09021c 100644 ---- a/src/daemon/entry/connect/grpc/grpc_containers_service_private.cc -+++ b/src/daemon/entry/connect/grpc/grpc_containers_service_private.cc -@@ -30,12 +30,12 @@ int ContainerServiceImpl::version_request_from_grpc(const VersionRequest *greque - return 0; - } - --int ContainerServiceImpl::version_response_to_grpc(const container_version_response *response, -- VersionResponse *gresponse) -+void ContainerServiceImpl::version_response_to_grpc(const container_version_response *response, -+ VersionResponse *gresponse) - { - if (response == nullptr) { - gresponse->set_cc(ISULAD_ERR_MEMOUT); -- return 0; -+ return; - } - gresponse->set_cc(response->cc); - if (response->errmsg != nullptr) { -@@ -54,7 +54,7 @@ int ContainerServiceImpl::version_response_to_grpc(const container_version_respo - gresponse->set_root_path(response->root_path); - } - -- return 0; -+ return; - } - - int ContainerServiceImpl::info_request_from_grpc(const InfoRequest *grequest, host_info_request **request) -@@ -68,11 +68,11 @@ int ContainerServiceImpl::info_request_from_grpc(const InfoRequest *grequest, ho - return 0; - } - --int ContainerServiceImpl::info_response_to_grpc(const host_info_response *response, InfoResponse *gresponse) -+void ContainerServiceImpl::info_response_to_grpc(const host_info_response *response, InfoResponse *gresponse) - { - if (response == nullptr) { - gresponse->set_cc(ISULAD_ERR_MEMOUT); -- return 0; -+ return; - } - - gresponse->set_cc(response->cc); -@@ -92,9 +92,8 @@ int ContainerServiceImpl::info_response_to_grpc(const host_info_response *respon - - gresponse->set_images_num(response->images_num); - -- if (pack_os_info_to_grpc(response, gresponse)) { -- return -1; -- } -+ -+ pack_os_info_to_grpc(response, gresponse); - - if (response->logging_driver != nullptr) { - gresponse->set_logging_driver(response->logging_driver); -@@ -106,15 +105,11 @@ int ContainerServiceImpl::info_response_to_grpc(const host_info_response *respon - - gresponse->set_total_mem(response->total_mem); - -- if (pack_proxy_info_to_grpc(response, gresponse)) { -- return -1; -- } -+ pack_proxy_info_to_grpc(response, gresponse); - -- if (pack_driver_info_to_grpc(response, gresponse)) { -- return -1; -- } -+ pack_driver_info_to_grpc(response, gresponse); - -- return 0; -+ return; - } - - int ContainerServiceImpl::create_request_from_grpc(const CreateRequest *grequest, container_create_request **request) -@@ -151,11 +146,11 @@ int ContainerServiceImpl::create_request_from_grpc(const CreateRequest *grequest - } - - --int ContainerServiceImpl::create_response_to_grpc(const container_create_response *response, CreateResponse *gresponse) -+void ContainerServiceImpl::create_response_to_grpc(const container_create_response *response, CreateResponse *gresponse) - { - if (response == nullptr) { - gresponse->set_cc(ISULAD_ERR_MEMOUT); -- return 0; -+ return; - } - gresponse->set_cc(response->cc); - if (response->errmsg != nullptr) { -@@ -164,7 +159,7 @@ int ContainerServiceImpl::create_response_to_grpc(const container_create_respons - if (response->id != nullptr) { - gresponse->set_id(response->id); - } -- return 0; -+ return; - } - - int ContainerServiceImpl::start_request_from_grpc(const StartRequest *grequest, container_start_request **request) -@@ -234,11 +229,11 @@ int ContainerServiceImpl::top_request_from_grpc(const TopRequest *grequest, cont - return 0; - } - --int ContainerServiceImpl::top_response_to_grpc(const container_top_response *response, TopResponse *gresponse) -+void ContainerServiceImpl::top_response_to_grpc(const container_top_response *response, TopResponse *gresponse) - { - if (response == nullptr) { - gresponse->set_cc(ISULAD_ERR_MEMOUT); -- return 0; -+ return; - } - gresponse->set_cc(response->cc); - if (response->errmsg != nullptr) { -@@ -253,7 +248,7 @@ int ContainerServiceImpl::top_response_to_grpc(const container_top_response *res - gresponse->add_processes(response->processes[i]); - } - -- return 0; -+ return; - } - - int ContainerServiceImpl::stop_request_from_grpc(const StopRequest *grequest, container_stop_request **request) -@@ -328,11 +323,11 @@ int ContainerServiceImpl::delete_request_from_grpc(const DeleteRequest *grequest - return 0; - } - --int ContainerServiceImpl::delete_response_to_grpc(const container_delete_response *response, DeleteResponse *gresponse) -+void ContainerServiceImpl::delete_response_to_grpc(const container_delete_response *response, DeleteResponse *gresponse) - { - if (response == nullptr) { - gresponse->set_cc(ISULAD_ERR_MEMOUT); -- return 0; -+ return; - } - gresponse->set_cc(response->cc); - if (response->id != nullptr) { -@@ -341,7 +336,7 @@ int ContainerServiceImpl::delete_response_to_grpc(const container_delete_respons - if (response->errmsg != nullptr) { - gresponse->set_errmsg(response->errmsg); - } -- return 0; -+ return; - } - - int ContainerServiceImpl::exec_request_from_grpc(const ExecRequest *grequest, container_exec_request **request) -@@ -418,11 +413,11 @@ int ContainerServiceImpl::exec_request_from_grpc(const ExecRequest *grequest, co - return 0; - } - --int ContainerServiceImpl::exec_response_to_grpc(const container_exec_response *response, ExecResponse *gresponse) -+void ContainerServiceImpl::exec_response_to_grpc(const container_exec_response *response, ExecResponse *gresponse) - { - if (response == nullptr) { - gresponse->set_cc(ISULAD_ERR_MEMOUT); -- return 0; -+ return; - } - - gresponse->set_cc(response->cc); -@@ -430,7 +425,7 @@ int ContainerServiceImpl::exec_response_to_grpc(const container_exec_response *r - if (response->errmsg != nullptr) { - gresponse->set_errmsg(response->errmsg); - } -- return 0; -+ return; - } - - int ContainerServiceImpl::inspect_request_from_grpc(const InspectContainerRequest *grequest, -@@ -454,12 +449,12 @@ int ContainerServiceImpl::inspect_request_from_grpc(const InspectContainerReques - return 0; - } - --int ContainerServiceImpl::inspect_response_to_grpc(const container_inspect_response *response, -- InspectContainerResponse *gresponse) -+void ContainerServiceImpl::inspect_response_to_grpc(const container_inspect_response *response, -+ InspectContainerResponse *gresponse) - { - if (response == nullptr) { - gresponse->set_cc(ISULAD_ERR_MEMOUT); -- return 0; -+ return; - } - - gresponse->set_cc(response->cc); -@@ -469,7 +464,7 @@ int ContainerServiceImpl::inspect_response_to_grpc(const container_inspect_respo - if (response->errmsg != nullptr) { - gresponse->set_errmsg(response->errmsg); - } -- return 0; -+ return; - } - - int ContainerServiceImpl::list_request_from_grpc(const ListRequest *grequest, container_list_request **request) -@@ -534,11 +529,11 @@ cleanup: - return -1; - } - --int ContainerServiceImpl::list_response_to_grpc(const container_list_response *response, ListResponse *gresponse) -+void ContainerServiceImpl::list_response_to_grpc(const container_list_response *response, ListResponse *gresponse) - { - if (response == nullptr) { - gresponse->set_cc(ISULAD_ERR_MEMOUT); -- return 0; -+ return; - } - - gresponse->set_cc(response->cc); -@@ -579,7 +574,7 @@ int ContainerServiceImpl::list_response_to_grpc(const container_list_response *r - } - container->set_created(response->containers[i]->created); - } -- return 0; -+ return; - } - - int ContainerServiceImpl::pause_request_from_grpc(const PauseRequest *grequest, container_pause_request **request) -@@ -637,12 +632,12 @@ int ContainerServiceImpl::container_rename_request_from_grpc(const RenameRequest - return 0; - } - --int ContainerServiceImpl::container_rename_response_to_grpc(const struct isulad_container_rename_response *response, -- RenameResponse *gresponse) -+void ContainerServiceImpl::container_rename_response_to_grpc(const struct isulad_container_rename_response *response, -+ RenameResponse *gresponse) - { - if (response == nullptr) { - gresponse->set_cc(ISULAD_ERR_MEMOUT); -- return 0; -+ return; - } - - gresponse->set_cc(response->cc); -@@ -653,7 +648,7 @@ int ContainerServiceImpl::container_rename_response_to_grpc(const struct isulad_ - gresponse->set_id(response->id); - } - -- return 0; -+ return; - } - - int ContainerServiceImpl::container_resize_request_from_grpc(const ResizeRequest *grequest, -@@ -682,12 +677,12 @@ int ContainerServiceImpl::container_resize_request_from_grpc(const ResizeRequest - return 0; - } - --int ContainerServiceImpl::container_resize_response_to_grpc(const struct isulad_container_resize_response *response, -- ResizeResponse *gresponse) -+void ContainerServiceImpl::container_resize_response_to_grpc(const struct isulad_container_resize_response *response, -+ ResizeResponse *gresponse) - { - if (response == nullptr) { - gresponse->set_cc(ISULAD_ERR_MEMOUT); -- return 0; -+ return; - } - - gresponse->set_cc(response->cc); -@@ -698,7 +693,7 @@ int ContainerServiceImpl::container_resize_response_to_grpc(const struct isulad_ - gresponse->set_id(response->id); - } - -- return 0; -+ return; - } - - int ContainerServiceImpl::update_request_from_grpc(const UpdateRequest *grequest, container_update_request **request) -@@ -722,11 +717,11 @@ int ContainerServiceImpl::update_request_from_grpc(const UpdateRequest *grequest - return 0; - } - --int ContainerServiceImpl::update_response_to_grpc(const container_update_response *response, UpdateResponse *gresponse) -+void ContainerServiceImpl::update_response_to_grpc(const container_update_response *response, UpdateResponse *gresponse) - { - if (response == nullptr) { - gresponse->set_cc(ISULAD_ERR_MEMOUT); -- return 0; -+ return; - } - - gresponse->set_cc(response->cc); -@@ -736,7 +731,7 @@ int ContainerServiceImpl::update_response_to_grpc(const container_update_respons - if (response->errmsg != nullptr) { - gresponse->set_errmsg(response->errmsg); - } -- return 0; -+ return; - } - - int ContainerServiceImpl::stats_request_from_grpc(const StatsRequest *grequest, container_stats_request **request) -@@ -766,11 +761,11 @@ int ContainerServiceImpl::stats_request_from_grpc(const StatsRequest *grequest, - return 0; - } - --int ContainerServiceImpl::stats_response_to_grpc(const container_stats_response *response, StatsResponse *gresponse) -+void ContainerServiceImpl::stats_response_to_grpc(const container_stats_response *response, StatsResponse *gresponse) - { - if (response == nullptr) { - gresponse->set_cc(ISULAD_ERR_MEMOUT); -- return 0; -+ return; - } - - if (response->container_stats && response->container_stats_len) { -@@ -803,7 +798,7 @@ int ContainerServiceImpl::stats_response_to_grpc(const container_stats_response - if (response->errmsg != nullptr) { - gresponse->set_errmsg(response->errmsg); - } -- return 0; -+ return; - } - - int ContainerServiceImpl::wait_request_from_grpc(const WaitRequest *grequest, container_wait_request **request) -@@ -824,11 +819,11 @@ int ContainerServiceImpl::wait_request_from_grpc(const WaitRequest *grequest, co - return 0; - } - --int ContainerServiceImpl::wait_response_to_grpc(const container_wait_response *response, WaitResponse *gresponse) -+void ContainerServiceImpl::wait_response_to_grpc(const container_wait_response *response, WaitResponse *gresponse) - { - if (response == nullptr) { - gresponse->set_cc(ISULAD_ERR_MEMOUT); -- return 0; -+ return; - } - - gresponse->set_cc(response->cc); -@@ -836,7 +831,7 @@ int ContainerServiceImpl::wait_response_to_grpc(const container_wait_response *r - if (response->errmsg != nullptr) { - gresponse->set_errmsg(response->errmsg); - } -- return 0; -+ return; - } - - int ContainerServiceImpl::events_request_from_grpc(const EventsRequest *grequest, -@@ -1059,11 +1054,11 @@ int ContainerServiceImpl::export_request_from_grpc(const ExportRequest *grequest - return 0; - } - --int ContainerServiceImpl::pack_os_info_to_grpc(const host_info_response *response, InfoResponse *gresponse) -+void ContainerServiceImpl::pack_os_info_to_grpc(const host_info_response *response, InfoResponse *gresponse) - { - if (response == nullptr) { - gresponse->set_cc(ISULAD_ERR_MEMOUT); -- return 0; -+ return; - } - - if (response->kversion != nullptr) { -@@ -1096,14 +1091,14 @@ int ContainerServiceImpl::pack_os_info_to_grpc(const host_info_response *respons - gresponse->set_huge_page_size(response->huge_page_size); - } - -- return 0; -+ return; - } - --int ContainerServiceImpl::pack_proxy_info_to_grpc(const host_info_response *response, InfoResponse *gresponse) -+void ContainerServiceImpl::pack_proxy_info_to_grpc(const host_info_response *response, InfoResponse *gresponse) - { - if (response == nullptr) { - gresponse->set_cc(ISULAD_ERR_MEMOUT); -- return 0; -+ return; - } - - if (response->http_proxy != nullptr) { -@@ -1118,14 +1113,14 @@ int ContainerServiceImpl::pack_proxy_info_to_grpc(const host_info_response *resp - gresponse->set_no_proxy(response->no_proxy); - } - -- return 0; -+ return; - } - --int ContainerServiceImpl::pack_driver_info_to_grpc(const host_info_response *response, InfoResponse *gresponse) -+void ContainerServiceImpl::pack_driver_info_to_grpc(const host_info_response *response, InfoResponse *gresponse) - { - if (response == nullptr) { - gresponse->set_cc(ISULAD_ERR_MEMOUT); -- return 0; -+ return; - } - - if (response->driver_name != nullptr) { -@@ -1136,5 +1131,5 @@ int ContainerServiceImpl::pack_driver_info_to_grpc(const host_info_response *res - gresponse->set_driver_status(response->driver_status); - } - -- return 0; -+ return; - } -diff --git a/src/daemon/entry/connect/grpc/grpc_images_service.cc b/src/daemon/entry/connect/grpc/grpc_images_service.cc -index 533467c..57a51ee 100644 ---- a/src/daemon/entry/connect/grpc/grpc_images_service.cc -+++ b/src/daemon/entry/connect/grpc/grpc_images_service.cc -@@ -88,11 +88,11 @@ cleanup: - return -1; - } - --int ImagesServiceImpl::image_list_response_to_grpc(image_list_images_response *response, ListImagesResponse *gresponse) -+void ImagesServiceImpl::image_list_response_to_grpc(image_list_images_response *response, ListImagesResponse *gresponse) - { - if (response == nullptr) { - gresponse->set_cc(ISULAD_ERR_MEMOUT); -- return 0; -+ return; - } - - gresponse->set_cc(response->cc); -@@ -109,7 +109,8 @@ int ImagesServiceImpl::image_list_response_to_grpc(image_list_images_response *r - target = new (std::nothrow) Descriptor; - if (target == nullptr) { - ERROR("Out of memory"); -- return -1; -+ gresponse->set_cc(ISULAD_ERR_MEMOUT); -+ return; - } - if (response->images[i]->target->digest != nullptr) { - target->set_digest(response->images[i]->target->digest); -@@ -117,8 +118,8 @@ int ImagesServiceImpl::image_list_response_to_grpc(image_list_images_response *r - Timestamp *timestamp = image->mutable_created_at(); - if (timestamp == nullptr) { - delete target; -- ERROR("Out of memory"); -- return -1; -+ gresponse->set_cc(ISULAD_ERR_MEMOUT); -+ return; - } - timestamp->set_seconds(response->images[i]->created_at->seconds); - timestamp->set_nanos(response->images[i]->created_at->nanos); -@@ -129,7 +130,7 @@ int ImagesServiceImpl::image_list_response_to_grpc(image_list_images_response *r - image->set_allocated_target(target); - } - -- return 0; -+ return; - } - - int ImagesServiceImpl::image_remove_request_from_grpc(const DeleteImageRequest *grequest, -@@ -232,11 +233,12 @@ int ImagesServiceImpl::inspect_request_from_grpc(const InspectImageRequest *greq - return 0; - } - --int ImagesServiceImpl::inspect_response_to_grpc(const image_inspect_response *response, InspectImageResponse *gresponse) -+void ImagesServiceImpl::inspect_response_to_grpc(const image_inspect_response *response, -+ InspectImageResponse *gresponse) - { - if (response == nullptr) { - gresponse->set_cc(ISULAD_ERR_MEMOUT); -- return 0; -+ return; - } - - gresponse->set_cc(response->cc); -@@ -246,7 +248,7 @@ int ImagesServiceImpl::inspect_response_to_grpc(const image_inspect_response *re - if (response->errmsg != nullptr) { - gresponse->set_errmsg(response->errmsg); - } -- return 0; -+ return; - } - - Status ImagesServiceImpl::List(ServerContext *context, const ListImagesRequest *request, ListImagesResponse *reply) -@@ -269,16 +271,12 @@ Status ImagesServiceImpl::List(ServerContext *context, const ListImagesRequest * - } - - image_list_images_response *image_res = nullptr; -- int ret = cb->image.list(image_req, &image_res); -- tret = image_list_response_to_grpc(image_res, reply); -+ (void)cb->image.list(image_req, &image_res); -+ image_list_response_to_grpc(image_res, reply); - - free_image_list_images_request(image_req); - free_image_list_images_response(image_res); -- if (tret != 0) { -- reply->set_errmsg(util_strdup_s(errno_to_error_message(ISULAD_ERR_INTERNAL))); -- reply->set_cc(ISULAD_ERR_INPUT); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - -@@ -302,16 +300,12 @@ Status ImagesServiceImpl::Delete(ServerContext *context, const DeleteImageReques - } - - image_delete_image_response *image_res = nullptr; -- int ret = cb->image.remove(image_req, &image_res); -- tret = response_to_grpc(image_res, reply); -+ (void)cb->image.remove(image_req, &image_res); -+ response_to_grpc(image_res, reply); - - free_image_delete_image_request(image_req); - free_image_delete_image_response(image_res); -- if (tret != 0) { -- reply->set_errmsg(util_strdup_s(errno_to_error_message(ISULAD_ERR_INTERNAL))); -- reply->set_cc(ISULAD_ERR_INPUT); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - -@@ -335,24 +329,20 @@ Status ImagesServiceImpl::Tag(ServerContext *context, const TagImageRequest *req - } - - image_tag_image_response *image_res = nullptr; -- int ret = cb->image.tag(image_req, &image_res); -- tret = response_to_grpc(image_res, reply); -+ (void)cb->image.tag(image_req, &image_res); -+ response_to_grpc(image_res, reply); - - free_image_tag_image_request(image_req); - free_image_tag_image_response(image_res); -- if (tret != 0) { -- reply->set_errmsg(util_strdup_s(errno_to_error_message(ISULAD_ERR_INTERNAL))); -- reply->set_cc(ISULAD_ERR_INPUT); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - --int ImagesServiceImpl::import_response_to_grpc(const image_import_response *response, ImportResponse *gresponse) -+void ImagesServiceImpl::import_response_to_grpc(const image_import_response *response, ImportResponse *gresponse) - { - if (response == nullptr) { - gresponse->set_cc(ISULAD_ERR_MEMOUT); -- return 0; -+ return; - } - - gresponse->set_cc(response->cc); -@@ -362,7 +352,7 @@ int ImagesServiceImpl::import_response_to_grpc(const image_import_response *resp - if (response->errmsg != nullptr) { - gresponse->set_errmsg(response->errmsg); - } -- return 0; -+ return; - } - - Status ImagesServiceImpl::Import(ServerContext *context, const ImportRequest *request, ImportResponse *reply) -@@ -385,16 +375,11 @@ Status ImagesServiceImpl::Import(ServerContext *context, const ImportRequest *re - } - - image_import_response *image_res = nullptr; -- int ret = cb->image.import(image_req, &image_res); -- tret = import_response_to_grpc(image_res, reply); -+ (void)cb->image.import(image_req, &image_res); -+ import_response_to_grpc(image_res, reply); - - free_image_import_request(image_req); - free_image_import_response(image_res); -- if (tret != 0) { -- reply->set_errmsg(util_strdup_s(errno_to_error_message(ISULAD_ERR_INTERNAL))); -- reply->set_cc(ISULAD_ERR_INPUT); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } - - return Status::OK; - } -@@ -419,16 +404,11 @@ Status ImagesServiceImpl::Load(ServerContext *context, const LoadImageRequest *r - } - - image_load_image_response *image_res = nullptr; -- int ret = cb->image.load(image_req, &image_res); -- tret = response_to_grpc(image_res, reply); -+ (void)cb->image.load(image_req, &image_res); -+ response_to_grpc(image_res, reply); - - free_image_load_image_request(image_req); - free_image_load_image_response(image_res); -- if (tret != 0) { -- reply->set_errmsg(util_strdup_s(errno_to_error_message(ISULAD_ERR_INTERNAL))); -- reply->set_cc(ISULAD_ERR_INPUT); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } - - return Status::OK; - } -@@ -436,7 +416,7 @@ Status ImagesServiceImpl::Load(ServerContext *context, const LoadImageRequest *r - Status ImagesServiceImpl::Inspect(ServerContext *context, const InspectImageRequest *request, - InspectImageResponse *reply) - { -- int ret, tret; -+ int tret; - service_executor_t *cb = nullptr; - image_inspect_request *image_req = nullptr; - image_inspect_response *image_res = nullptr; -@@ -458,16 +438,12 @@ Status ImagesServiceImpl::Inspect(ServerContext *context, const InspectImageRequ - return Status::OK; - } - -- ret = cb->image.inspect(image_req, &image_res); -- tret = inspect_response_to_grpc(image_res, reply); -+ (void)cb->image.inspect(image_req, &image_res); -+ inspect_response_to_grpc(image_res, reply); - - free_image_inspect_request(image_req); - free_image_inspect_response(image_res); -- if (tret != 0) { -- reply->set_errmsg(errno_to_error_message(ISULAD_ERR_INTERNAL)); -- reply->set_cc(ISULAD_ERR_INTERNAL); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } -+ - return Status::OK; - } - -@@ -535,16 +511,11 @@ Status ImagesServiceImpl::Login(ServerContext *context, const LoginRequest *requ - } - - image_login_response *image_res = nullptr; -- int ret = cb->image.login(image_req, &image_res); -- tret = response_to_grpc(image_res, reply); -+ (void)cb->image.login(image_req, &image_res); -+ response_to_grpc(image_res, reply); - - free_image_login_request(image_req); - free_image_login_response(image_res); -- if (tret != 0) { -- reply->set_errmsg(util_strdup_s(errno_to_error_message(ISULAD_ERR_INTERNAL))); -- reply->set_cc(ISULAD_ERR_INPUT); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } - - return Status::OK; - } -@@ -569,16 +540,11 @@ Status ImagesServiceImpl::Logout(ServerContext *context, const LogoutRequest *re - } - - image_logout_response *image_res = nullptr; -- int ret = cb->image.logout(image_req, &image_res); -- tret = response_to_grpc(image_res, reply); -+ (void)cb->image.logout(image_req, &image_res); -+ response_to_grpc(image_res, reply); - - free_image_logout_request(image_req); - free_image_logout_response(image_res); -- if (tret != 0) { -- reply->set_errmsg(util_strdup_s(errno_to_error_message(ISULAD_ERR_INTERNAL))); -- reply->set_cc(ISULAD_ERR_INPUT); -- ERROR("Failed to translate response to grpc, operation is %s", ret ? "failed" : "success"); -- } - - return Status::OK; - } -diff --git a/src/daemon/entry/connect/grpc/grpc_images_service.h b/src/daemon/entry/connect/grpc/grpc_images_service.h -index 921d64f..92334b5 100644 ---- a/src/daemon/entry/connect/grpc/grpc_images_service.h -+++ b/src/daemon/entry/connect/grpc/grpc_images_service.h -@@ -60,21 +60,21 @@ public: - - private: - template -- int response_to_grpc(const T1 *response, T2 *gresponse) -+ void response_to_grpc(const T1 *response, T2 *gresponse) - { - if (response == nullptr) { - gresponse->set_cc(ISULAD_ERR_MEMOUT); -- return 0; -+ return; - } - gresponse->set_cc(response->cc); - if (response->errmsg != nullptr) { - gresponse->set_errmsg(response->errmsg); - } -- return 0; -+ return; - } - int image_list_request_from_grpc(const ListImagesRequest *grequest, image_list_images_request **request); - -- int image_list_response_to_grpc(image_list_images_response *response, ListImagesResponse *gresponse); -+ void image_list_response_to_grpc(image_list_images_response *response, ListImagesResponse *gresponse); - - int image_remove_request_from_grpc(const DeleteImageRequest *grequest, image_delete_image_request **request); - -@@ -82,13 +82,13 @@ private: - - int image_import_request_from_grpc(const ImportRequest *grequest, image_import_request **request); - -- int import_response_to_grpc(const image_import_response *response, ImportResponse *gresponse); -+ void import_response_to_grpc(const image_import_response *response, ImportResponse *gresponse); - - int image_load_request_from_grpc(const LoadImageRequest *grequest, image_load_image_request **request); - - int inspect_request_from_grpc(const InspectImageRequest *grequest, image_inspect_request **request); - -- int inspect_response_to_grpc(const image_inspect_response *response, InspectImageResponse *gresponse); -+ void inspect_response_to_grpc(const image_inspect_response *response, InspectImageResponse *gresponse); - - int image_login_request_from_grpc(const LoginRequest *grequest, image_login_request **request); - --- -2.20.1 - diff --git a/0023-add-newline-character-at-end-of-iSulad.sysconfig.patch b/0023-add-newline-character-at-end-of-iSulad.sysconfig.patch deleted file mode 100644 index c2a3c20..0000000 --- a/0023-add-newline-character-at-end-of-iSulad.sysconfig.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 3260ec3e2b95e93618d5650b0b9874c65521e6b2 Mon Sep 17 00:00:00 2001 -From: gaohuatao -Date: Mon, 9 Nov 2020 17:14:34 +0800 -Subject: [PATCH 23/28] add newline character at end of iSulad.sysconfig - -Signed-off-by: gaohuatao ---- - src/contrib/config/iSulad.sysconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/contrib/config/iSulad.sysconfig b/src/contrib/config/iSulad.sysconfig -index 5d222f9..43ba7cb 100644 ---- a/src/contrib/config/iSulad.sysconfig -+++ b/src/contrib/config/iSulad.sysconfig -@@ -23,4 +23,4 @@ - - # Location used for temporary files, such as those created by isula load and pull operations. - # Default is /var/tmp. Can be overridden by setting the following env variable. --# ISULAD_TMPDIR=/var/tmp -\ No newline at end of file -+# ISULAD_TMPDIR=/var/tmp --- -2.20.1 - diff --git a/0024-clean-code-remove-unused-in-code.patch b/0024-clean-code-remove-unused-in-code.patch deleted file mode 100644 index 2b877a6..0000000 --- a/0024-clean-code-remove-unused-in-code.patch +++ /dev/null @@ -1,46 +0,0 @@ -From d0a258a731d2cd4ad057c02a7d91762380b2c906 Mon Sep 17 00:00:00 2001 -From: lifeng68 -Date: Mon, 9 Nov 2020 17:32:16 +0800 -Subject: [PATCH 24/28] clean code: remove unused ";" in code - -Signed-off-by: lifeng68 ---- - src/daemon/entry/connect/grpc/grpc_containers_service.cc | 2 -- - src/daemon/executor/container_cb/execution_network.c | 1 - - 2 files changed, 3 deletions(-) - -diff --git a/src/daemon/entry/connect/grpc/grpc_containers_service.cc b/src/daemon/entry/connect/grpc/grpc_containers_service.cc -index 4e8f55d..123fee8 100644 ---- a/src/daemon/entry/connect/grpc/grpc_containers_service.cc -+++ b/src/daemon/entry/connect/grpc/grpc_containers_service.cc -@@ -340,7 +340,6 @@ Status ContainerServiceImpl::RemoteStart(ServerContext *context, - - if (sem_init(&sem, 0, 0) != 0) { - return grpc::Status(grpc::StatusCode::UNKNOWN, "Semaphore initialization failed"); -- ; - } - - int read_pipe_fd[2]; -@@ -867,7 +866,6 @@ Status ContainerServiceImpl::AttachInit(ServerContext *context, service_executor - if (sem_init(sem_stderr, 0, 0) != 0) { - free_container_attach_request(*req); - return grpc::Status(grpc::StatusCode::UNKNOWN, "Semaphore initialization failed"); -- ; - } - - if ((pipe2(pipefd, O_NONBLOCK | O_CLOEXEC)) < 0) { -diff --git a/src/daemon/executor/container_cb/execution_network.c b/src/daemon/executor/container_cb/execution_network.c -index f15707e..6b6c626 100644 ---- a/src/daemon/executor/container_cb/execution_network.c -+++ b/src/daemon/executor/container_cb/execution_network.c -@@ -965,7 +965,6 @@ out: - static int write_default_resolve(const char *file_path) - { - const char *default_ipv4_dns = "\nnameserver 8.8.8.8\nnameserver 8.8.4.4\n"; -- ; - - return util_write_file(file_path, default_ipv4_dns, strlen(default_ipv4_dns), NETWORK_MOUNT_FILE_MODE); - } --- -2.20.1 - diff --git a/0025-utils-add-fdatasync-when-do-atomic-write-file.patch b/0025-utils-add-fdatasync-when-do-atomic-write-file.patch deleted file mode 100644 index bb6dffb..0000000 --- a/0025-utils-add-fdatasync-when-do-atomic-write-file.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 8888ca136de8f864df919f6823b357238a328488 Mon Sep 17 00:00:00 2001 -From: lifeng68 -Date: Tue, 10 Nov 2020 10:08:56 +0800 -Subject: [PATCH 25/28] utils: add fdatasync when do atomic write file - -Signed-off-by: lifeng68 ---- - src/utils/cutils/utils_file.c | 35 ++++++++++++++++++++++++++++++++++- - 1 file changed, 34 insertions(+), 1 deletion(-) - -diff --git a/src/utils/cutils/utils_file.c b/src/utils/cutils/utils_file.c -index 9f7f5fe..744b425 100644 ---- a/src/utils/cutils/utils_file.c -+++ b/src/utils/cutils/utils_file.c -@@ -1403,6 +1403,39 @@ out: - return result; - } - -+static int do_atomic_write_file(const char *fname, const char *content, size_t content_len, mode_t mode) -+{ -+ int ret = 0; -+ int dst_fd = -1; -+ ssize_t len = 0; -+ -+ dst_fd = util_open(fname, O_WRONLY | O_CREAT | O_TRUNC, mode); -+ if (dst_fd < 0) { -+ ERROR("Creat file: %s, failed: %s", fname, strerror(errno)); -+ ret = -1; -+ goto free_out; -+ } -+ -+ len = util_write_nointr(dst_fd, content, content_len); -+ if (len < 0 || ((size_t)len) != content_len) { -+ ret = -1; -+ ERROR("Write file failed: %s", strerror(errno)); -+ goto free_out; -+ } -+ -+ if (fdatasync(dst_fd) != 0) { -+ ret = -1; -+ SYSERROR("Failed to sync data of file:%s", fname); -+ goto free_out; -+ } -+ -+free_out: -+ if (dst_fd >= 0) { -+ close(dst_fd); -+ } -+ return ret; -+} -+ - int util_atomic_write_file(const char *fname, const char *content, size_t content_len, mode_t mode) - { - int ret = 0; -@@ -1427,7 +1460,7 @@ int util_atomic_write_file(const char *fname, const char *content, size_t conten - goto free_out; - } - -- ret = util_write_file(tmp_file, content, content_len, mode); -+ ret = do_atomic_write_file(tmp_file, content, content_len, mode); - if (ret != 0) { - ERROR("Failed to write content to tmp file for %s", tmp_file); - ret = -1; --- -2.20.1 - diff --git a/0026-network-support-mutlnetworks.patch b/0026-network-support-mutlnetworks.patch deleted file mode 100644 index aab1113..0000000 --- a/0026-network-support-mutlnetworks.patch +++ /dev/null @@ -1,975 +0,0 @@ -From aa35a1a1621d911cf9b76eba232814775ea6b4d9 Mon Sep 17 00:00:00 2001 -From: haozi007 -Date: Mon, 2 Nov 2020 11:15:34 +0800 -Subject: [PATCH 26/28] network: support mutlnetworks - -1. support mutlnetworks -2. support dualstack for default network - -Signed-off-by: haozi007 ---- - src/api/services/cri/api.proto | 6 + - src/daemon/entry/cri/cni_network_plugin.cc | 221 +++++++++++++++++++-- - src/daemon/entry/cri/cni_network_plugin.h | 14 +- - src/daemon/entry/cri/cri_helpers.cc | 4 +- - src/daemon/entry/cri/cri_helpers.h | 2 +- - src/daemon/entry/cri/cri_runtime_service.h | 13 +- - src/daemon/entry/cri/cri_sandbox.cc | 202 +++++++++---------- - src/daemon/entry/cri/network_plugin.cc | 120 +++++++---- - src/daemon/entry/cri/network_plugin.h | 10 +- - 9 files changed, 414 insertions(+), 178 deletions(-) - -diff --git a/src/api/services/cri/api.proto b/src/api/services/cri/api.proto -index 8aba0d3..67e5527 100644 ---- a/src/api/services/cri/api.proto -+++ b/src/api/services/cri/api.proto -@@ -399,10 +399,16 @@ message PodSandboxStatusRequest { - bool verbose = 2; - } - -+// PodIP represents an ip of a Pod -+message PodIP { -+ // an ip is a string representation of an IPV4 or an IPV6 -+ string ip = 1; -+} - // PodSandboxNetworkStatus is the status of the network for a PodSandbox. - message PodSandboxNetworkStatus { - // IP address of the PodSandbox. - string ip = 1; -+ repeated PodIP additional_ips = 2; - } - - // Namespace contains paths to the namespaces. -diff --git a/src/daemon/entry/cri/cni_network_plugin.cc b/src/daemon/entry/cri/cni_network_plugin.cc -index f15eba3..9cb5722 100644 ---- a/src/daemon/entry/cri/cni_network_plugin.cc -+++ b/src/daemon/entry/cri/cni_network_plugin.cc -@@ -80,7 +80,7 @@ auto CNINetwork::GetPaths(Errors &err) -> char ** - { - char **paths = CRIHelpers::StringVectorToCharArray(m_path); - if (paths == nullptr) { -- err.SetError("Get char ** path failed"); -+ err.SetError("Get cni network paths failed"); - } - return paths; - } -@@ -124,6 +124,26 @@ void CniNetworkPlugin::SetDefaultNetwork(std::unique_ptr network, st - } - } - -+void CniNetworkPlugin::UpdateMutlNetworks(std::vector> &multNets, -+ std::vector &binDirs, Errors &err) -+{ -+ if (multNets.size() == 0) { -+ return; -+ } -+ WLockNetworkMap(err); -+ if (err.NotEmpty()) { -+ return; -+ } -+ -+ m_mutlNetworks.clear(); -+ for (auto iter = multNets.begin(); iter != multNets.end(); ++iter) { -+ (*iter)->SetPaths(binDirs); -+ m_mutlNetworks[(*iter)->GetName()] = std::move(*iter); -+ } -+ -+ UnlockNetworkMap(err); -+} -+ - CniNetworkPlugin::CniNetworkPlugin(std::vector &binDirs, const std::string &confDir, - const std::string &podCidr) - : m_confDir(confDir) -@@ -139,6 +159,7 @@ CniNetworkPlugin::~CniNetworkPlugin() - if (m_syncThread.joinable()) { - m_syncThread.join(); - } -+ m_mutlNetworks.clear(); - } - - void CniNetworkPlugin::PlatformInit(Errors &error) -@@ -259,7 +280,9 @@ out: - void CniNetworkPlugin::GetDefaultCNINetwork(const std::string &confDir, std::vector &binDirs, Errors &err) - { - std::vector files; -- bool found = false; -+ std::vector> mutlNets; -+ char *default_net_name = nullptr; -+ std::string message = { "" }; - - if (GetCNIConfFiles(confDir, files, err) != 0) { - goto free_out; -@@ -279,17 +302,33 @@ void CniNetworkPlugin::GetDefaultCNINetwork(const std::string &confDir, std::vec - n_list = nullptr; - continue; - } -+ DEBUG("parse cni network: %s", n_list->name); - -- SetDefaultNetwork(std::unique_ptr(new (std::nothrow) CNINetwork(n_list->name, n_list)), binDirs, -- err); -- found = true; -- break; -+ if (default_net_name == nullptr) { -+ SetDefaultNetwork(std::unique_ptr(new (std::nothrow) CNINetwork(n_list->name, n_list)), binDirs, err); -+ default_net_name = util_strdup_s(n_list->name); -+ message += default_net_name; -+ continue; -+ } -+ if (strcmp(default_net_name, n_list->name) == 0) { -+ WARN("Use same name of default net: %s", default_net_name); -+ continue; -+ } -+ mutlNets.push_back(std::unique_ptr(new (std::nothrow) CNINetwork(n_list->name, n_list))); -+ message += ", " + std::string(n_list->name); - } -- if (!found) { -+ if (default_net_name == nullptr) { - err.Errorf("No valid networks found in %s", confDir.c_str()); -+ goto free_out; -+ } -+ UpdateMutlNetworks(mutlNets, binDirs, err); -+ if (err.NotEmpty()) { -+ goto free_out; - } -+ INFO("Loaded cni plugins successfully, [ %s ]", message.c_str()); - - free_out: -+ free(default_net_name); - return; - } - -@@ -350,6 +389,71 @@ void CniNetworkPlugin::Status(Errors &err) - CheckInitialized(err); - } - -+ -+bool CniNetworkPlugin::SetupMultNetworks(const std::string &ns, const std::string &defaultInterface, -+ const std::string &name, -+ const std::string &netnsPath, const std::string &podSandboxID, -+ const std::map &annotations, -+ const std::map &options, Errors &err) -+{ -+ bool ret = false; -+ int defaultIdx = -1; -+ size_t len = 0; -+ cri_pod_network_element **networks = CRIHelpers::GetNetworkPlaneFromPodAnno(annotations, &len, err); -+ if (err.NotEmpty()) { -+ ERROR("Couldn't get network plane from pod annotations: %s", err.GetCMessage()); -+ err.Errorf("Couldn't get network plane from pod annotations: %s", err.GetCMessage()); -+ goto cleanup; -+ } -+ -+ for (size_t i = 0; i < len; i++) { -+ if (networks[i] == nullptr || networks[i]->name == nullptr || networks[i]->interface == nullptr) { -+ continue; -+ } -+ struct result *preResult = nullptr; -+ auto netIter = m_mutlNetworks.find(networks[i]->name); -+ if (netIter == m_mutlNetworks.end()) { -+ err.Errorf("Cannot found user defined net: %s", networks[i]->name); -+ break; -+ } -+ if (defaultInterface == networks[i]->interface) { -+ defaultIdx = i; -+ continue; -+ } -+ AddToNetwork((netIter->second).get(), name, ns, networks[i]->interface, podSandboxID, netnsPath, annotations, options, -+ &preResult, err); -+ free_result(preResult); -+ if (err.NotEmpty()) { -+ ERROR("Do setup user defined net: %s, failed: %s", networks[i]->name, err.GetCMessage()); -+ break; -+ } -+ INFO("Setup user defained net: %s success", networks[i]->name); -+ } -+ -+ // mask default network pod, if user defined net use same interface -+ if (defaultIdx >= 0) { -+ auto netIter = m_mutlNetworks.find(networks[defaultIdx]->name); -+ if (netIter == m_mutlNetworks.end()) { -+ err.Errorf("Cannot found user defined net: %s", networks[defaultIdx]->name); -+ goto cleanup; -+ } -+ -+ struct result *preResult = nullptr; -+ AddToNetwork((netIter->second).get(), name, ns, networks[defaultIdx]->interface, podSandboxID, netnsPath, annotations, -+ options, &preResult, err); -+ free_result(preResult); -+ if (err.NotEmpty()) { -+ ERROR("Do setup user defined net: %s, failed: %s", networks[defaultIdx]->name, err.GetCMessage()); -+ goto cleanup; -+ } -+ INFO("Setup default net: %s success", networks[defaultIdx]->name); -+ ret = true; -+ } -+cleanup: -+ free_cri_pod_network(networks, len); -+ return ret; -+} -+ - void CniNetworkPlugin::SetUpPod(const std::string &ns, const std::string &name, const std::string &interfaceName, - const std::string &id, const std::map &annotations, - const std::map &options, Errors &err) -@@ -381,17 +485,83 @@ void CniNetworkPlugin::SetUpPod(const std::string &ns, const std::string &name, - return; - } - -- AddToNetwork(m_defaultNetwork.get(), name, ns, interfaceName, id, netnsPath, annotations, options, &preResult, err); -+ bool setedDefaultNet = SetupMultNetworks(ns, interfaceName, name, netnsPath, id, annotations, options, err); -+ if (err.NotEmpty()) { -+ goto unlock; -+ } -+ -+ if (setedDefaultNet) { -+ goto unlock; -+ } - -+ AddToNetwork(m_defaultNetwork.get(), name, ns, interfaceName, id, netnsPath, annotations, options, &preResult, err); - free_result(preResult); -- preResult = nullptr; - if (err.NotEmpty()) { - ERROR("Error while adding to cni network: %s", err.GetCMessage()); - } - -+unlock: - UnlockNetworkMap(err); - } - -+bool CniNetworkPlugin::TearDownMultNetworks(const std::string &ns, const std::string &defaultInterface, -+ const std::string &name, -+ const std::string &netnsPath, const std::string &podSandboxID, const std::map &annotations, -+ Errors &err) -+{ -+ bool ret = false; -+ int defaultIdx = -1; -+ size_t len = 0; -+ cri_pod_network_element **networks = CRIHelpers::GetNetworkPlaneFromPodAnno(annotations, &len, err); -+ if (err.NotEmpty()) { -+ ERROR("Couldn't get network plane from pod annotations: %s", err.GetCMessage()); -+ err.Errorf("Couldn't get network plane from pod annotations: %s", err.GetCMessage()); -+ goto cleanup; -+ } -+ -+ for (size_t i = 0; i < len; i++) { -+ if (networks[i] == nullptr || networks[i]->name == nullptr || networks[i]->interface == nullptr) { -+ continue; -+ } -+ auto netIter = m_mutlNetworks.find(networks[i]->name); -+ if (netIter == m_mutlNetworks.end()) { -+ WARN("Cannot found user defined net: %s", networks[i]->name); -+ continue; -+ } -+ if (defaultInterface == networks[i]->interface) { -+ defaultIdx = i; -+ continue; -+ } -+ DeleteFromNetwork((netIter->second).get(), name, ns, networks[i]->interface, podSandboxID, netnsPath, annotations, err); -+ if (err.NotEmpty()) { -+ ERROR("Do teardown user defined net: %s, failed: %s", networks[i]->name, err.GetCMessage()); -+ break; -+ } -+ INFO("Teardown user defained net: %s success", networks[i]->name); -+ } -+ -+ // mask default network pod, if user defined net use same interface -+ if (defaultIdx >= 0) { -+ auto netIter = m_mutlNetworks.find(networks[defaultIdx]->name); -+ if (netIter == m_mutlNetworks.end()) { -+ err.Errorf("Cannot found user defined net: %s", networks[defaultIdx]->name); -+ goto cleanup; -+ } -+ -+ DeleteFromNetwork((netIter->second).get(), name, ns, networks[defaultIdx]->interface, podSandboxID, netnsPath, -+ annotations, err); -+ if (err.NotEmpty()) { -+ ERROR("Do teardown user defined net: %s, failed: %s", networks[defaultIdx]->name, err.GetCMessage()); -+ goto cleanup; -+ } -+ INFO("Teardown default net: %s success", networks[defaultIdx]->name); -+ ret = true; -+ } -+cleanup: -+ free_cri_pod_network(networks, len); -+ return ret; -+} -+ - void CniNetworkPlugin::TearDownPod(const std::string &ns, const std::string &name, const std::string &interfaceName, - const std::string &id, const std::map &annotations, - Errors &err) -@@ -400,6 +570,7 @@ void CniNetworkPlugin::TearDownPod(const std::string &ns, const std::string &nam - if (err.NotEmpty()) { - return; - } -+ Errors tmpErr; - - std::string netnsPath = m_criImpl->GetNetNS(id, err); - if (err.NotEmpty()) { -@@ -413,8 +584,21 @@ void CniNetworkPlugin::TearDownPod(const std::string &ns, const std::string &nam - return; - } - -- DeleteFromNetwork(m_defaultNetwork.get(), name, ns, interfaceName, id, netnsPath, annotations, err); -+ bool defaultNetDone = TearDownMultNetworks(ns, interfaceName, name, netnsPath, id, annotations, err); -+ if (defaultNetDone) { -+ goto unlock; -+ } -+ if (err.NotEmpty()) { -+ WARN("Teardown user defined networks failed: %s", err.GetCMessage()); -+ } -+ -+ DeleteFromNetwork(m_defaultNetwork.get(), name, ns, interfaceName, id, netnsPath, annotations, tmpErr); -+ if (tmpErr.NotEmpty()) { -+ WARN("Teardown default network failed: %s", tmpErr.GetCMessage()); -+ err.AppendError(tmpErr.GetMessage()); -+ } - -+unlock: - UnlockNetworkMap(err); - } - -@@ -464,7 +648,7 @@ void CniNetworkPlugin::GetPodNetworkStatus(const std::string & /*ns*/, const std - PodNetworkStatus &status, Errors &err) - { - std::string netnsPath; -- std::string ip; -+ std::vector ips; - Errors tmpErr; - - if (podSandboxID.empty()) { -@@ -482,15 +666,15 @@ void CniNetworkPlugin::GetPodNetworkStatus(const std::string & /*ns*/, const std - podSandboxID.c_str()); - goto out; - } -- ip = GetPodIP(m_nsenterPath, netnsPath, interfaceName, err); -+ GetPodIP(m_nsenterPath, netnsPath, interfaceName, ips, err); - if (err.NotEmpty()) { - ERROR("GetPodIP failed: %s", err.GetCMessage()); - goto out; - } -- status.SetIP(ip); -+ status.SetIPs(ips); - - out: -- INFO("get_pod_network_status: %s", podSandboxID.c_str()); -+ INFO("Get pod: %s network status success", podSandboxID.c_str()); - } - - void CniNetworkPlugin::AddToNetwork(CNINetwork *snetwork, const std::string &podName, const std::string &podNamespace, -@@ -761,7 +945,8 @@ void CniNetworkPlugin::RLockNetworkMap(Errors &error) - { - int ret = pthread_rwlock_rdlock(&m_netsLock); - if (ret != 0) { -- error.Errorf("Get read lock failed: %s", strerror(ret)); -+ error.Errorf("Failed to get read lock"); -+ ERROR("Get read lock failed: %s", strerror(ret)); - } - } - -@@ -769,7 +954,8 @@ void CniNetworkPlugin::WLockNetworkMap(Errors &error) - { - int ret = pthread_rwlock_wrlock(&m_netsLock); - if (ret != 0) { -- error.Errorf("Get write lock failed: %s", strerror(ret)); -+ error.Errorf("Failed to get write lock"); -+ ERROR("Get write lock failed: %s", strerror(ret)); - } - } - -@@ -777,7 +963,8 @@ void CniNetworkPlugin::UnlockNetworkMap(Errors &error) - { - int ret = pthread_rwlock_unlock(&m_netsLock); - if (ret != 0) { -- error.Errorf("Unlock failed: %s", strerror(ret)); -+ error.Errorf("Failed to unlock"); -+ ERROR("Unlock failed: %s", strerror(ret)); - } - } - -diff --git a/src/daemon/entry/cri/cni_network_plugin.h b/src/daemon/entry/cri/cni_network_plugin.h -index 02c95fb..c59c200 100644 ---- a/src/daemon/entry/cri/cni_network_plugin.h -+++ b/src/daemon/entry/cri/cni_network_plugin.h -@@ -146,6 +146,9 @@ private: - void RLockNetworkMap(Errors &error); - void WLockNetworkMap(Errors &error); - void UnlockNetworkMap(Errors &error); -+ -+ void UpdateMutlNetworks(std::vector> &multNets, std::vector &binDirs, -+ Errors &err); - void SetDefaultNetwork(std::unique_ptr network, std::vector &binDirs, Errors &err); - void SetPodCidr(const std::string &podCidr); - static auto GetCNIConfFiles(const std::string &pluginDir, std::vector &vect_files, Errors &err) -> int; -@@ -155,10 +158,19 @@ private: - void ResetCNINetwork(std::map> &newNets, Errors &err); - void UpdateDefaultNetwork(); - -+ bool SetupMultNetworks(const std::string &ns, const std::string &defaultInterface, const std::string &name, -+ const std::string &netnsPath, const std::string &podSandboxID, const std::map &annotations, -+ const std::map &options, Errors &err); -+ -+ bool TearDownMultNetworks(const std::string &ns, const std::string &defaultInterface, const std::string &name, -+ const std::string &netnsPath, const std::string &podSandboxID, const std::map &annotations, -+ Errors &err); -+ - NoopNetworkPlugin m_noop; - std::unique_ptr m_loNetwork { nullptr }; -- - std::unique_ptr m_defaultNetwork { nullptr }; -+ std::map> m_mutlNetworks; -+ - CRIRuntimeServiceImpl *m_criImpl { nullptr }; - std::string m_nsenterPath; - std::string m_confDir; -diff --git a/src/daemon/entry/cri/cri_helpers.cc b/src/daemon/entry/cri/cri_helpers.cc -index ee633b7..34d32e5 100644 ---- a/src/daemon/entry/cri/cri_helpers.cc -+++ b/src/daemon/entry/cri/cri_helpers.cc -@@ -389,7 +389,7 @@ auto sha256(const char *val) -> std::string - return outputBuffer; - } - --auto GetNetworkPlaneFromPodAnno(const google::protobuf::Map &annotations, size_t *len, -+auto GetNetworkPlaneFromPodAnno(const std::map &annotations, size_t *len, - Errors &error) -> cri_pod_network_element ** - { - auto iter = annotations.find(CRIHelpers::Constants::POD_NETWORK_ANNOTATION_KEY); -@@ -399,7 +399,7 @@ auto GetNetworkPlaneFromPodAnno(const google::protobuf::Mapsecond.c_str(), nullptr, &err, len); - if (result == nullptr) { -- error.Errorf("parse pod network json failed: %s", err); -+ error.Errorf("parse pod network json: %s failed: %s", iter->second.c_str(), err); - } - free(err); - } -diff --git a/src/daemon/entry/cri/cri_helpers.h b/src/daemon/entry/cri/cri_helpers.h -index 3ea9ba6..b9fb153 100644 ---- a/src/daemon/entry/cri/cri_helpers.h -+++ b/src/daemon/entry/cri/cri_helpers.h -@@ -94,7 +94,7 @@ auto IsImageNotFoundError(const std::string &err) -> bool; - - auto sha256(const char *val) -> std::string; - --auto GetNetworkPlaneFromPodAnno(const google::protobuf::Map &annotations, -+auto GetNetworkPlaneFromPodAnno(const std::map &annotations, - size_t *len, Errors &error) -> cri_pod_network_element **; - - auto CheckpointToSandbox(const std::string &id, -diff --git a/src/daemon/entry/cri/cri_runtime_service.h b/src/daemon/entry/cri/cri_runtime_service.h -index 66837e9..1a0f601 100644 ---- a/src/daemon/entry/cri/cri_runtime_service.h -+++ b/src/daemon/entry/cri/cri_runtime_service.h -@@ -210,9 +210,12 @@ private: - void ConstructPodSandboxCheckpoint(const runtime::v1alpha2::PodSandboxConfig &config, - cri::PodSandboxCheckpoint &checkpoint); - -- auto GetIP(const std::string &podSandboxID, container_inspect *inspect, const std::string &networkInterface, -- Errors &error) -> std::string; -- auto GetIPFromPlugin(container_inspect *inspect, const std::string &networkInterface, Errors &error) -> std::string; -+ void GetIPs(const std::string &podSandboxID, container_inspect *inspect, const std::string &networkInterface, -+ std::vector &ips, Errors &error); -+ void GetFormatIPsForMultNet(container_inspect *inspect, const std::string &defaultInterface, -+ const runtime::v1alpha2::PodSandboxMetadata &metadata, std::vector &result, Errors &error); -+ auto GetIPsFromPlugin(container_inspect *inspect, const std::string &networkInterface, -+ Errors &error) -> std::vector; - auto GetNetworkReady(const std::string &podSandboxID, Errors &error) -> bool; - void SetNetworkReady(const std::string &podSandboxID, bool ready, Errors &error); - void ClearNetworkReady(const std::string &podSandboxID); -@@ -247,9 +250,6 @@ private: - - void SetupSandboxNetwork(const runtime::v1alpha2::PodSandboxConfig &config, const std::string &response_id, - const std::string &jsonCheckpoint, Errors &error); -- void SetupUserDefinedNetworkPlane(const runtime::v1alpha2::PodSandboxConfig &config, const std::string &response_id, -- container_inspect *inspect_data, std::map &stdAnnos, -- std::map &options, Errors &error); - void StartSandboxContainer(const std::string &response_id, Errors &error); - auto CreateSandboxContainer(const runtime::v1alpha2::PodSandboxConfig &config, const std::string &image, - std::string &jsonCheckpoint, const std::string &runtimeHandler, -@@ -273,6 +273,7 @@ private: - auto ClearCniNetwork(const std::string &realSandboxID, bool hostNetwork, const std::string &ns, - const std::string &name, std::vector &errlist, - std::map &stdAnnos, Errors &error) -> int; -+ - auto RemoveAllContainersInSandbox(const std::string &realSandboxID, std::vector &errors) -> int; - auto DoRemovePodSandbox(const std::string &realSandboxID, std::vector &errors) -> int; - static void MergeSecurityContextToHostConfig(const runtime::v1alpha2::PodSandboxConfig &c, host_config *hc, -diff --git a/src/daemon/entry/cri/cri_sandbox.cc b/src/daemon/entry/cri/cri_sandbox.cc -index 6db9616..b44c86c 100644 ---- a/src/daemon/entry/cri/cri_sandbox.cc -+++ b/src/daemon/entry/cri/cri_sandbox.cc -@@ -458,44 +458,6 @@ void CRIRuntimeServiceImpl::StartSandboxContainer(const std::string &response_id - free_container_start_response(start_response); - } - --void CRIRuntimeServiceImpl::SetupUserDefinedNetworkPlane(const runtime::v1alpha2::PodSandboxConfig &config, -- const std::string &response_id, -- container_inspect *inspect_data, -- std::map &stdAnnos, -- std::map &options, Errors &error) --{ -- google::protobuf::Map annotations; -- CRIHelpers::ExtractAnnotations(inspect_data->config->annotations, annotations); -- -- size_t len = 0; -- cri_pod_network_element **networks = CRIHelpers::GetNetworkPlaneFromPodAnno(annotations, &len, error); -- if (error.NotEmpty()) { -- ERROR("Couldn't get network plane from pod annotations: %s", error.GetCMessage()); -- error.Errorf("Couldn't get network plane from pod annotations: %s", error.GetCMessage()); -- goto cleanup; -- } -- for (size_t i = 0; i < len; i++) { -- if ((networks[i] != nullptr) && (networks[i]->name != nullptr) && (networks[i]->interface != nullptr) && -- strcmp(networks[i]->name, Network::DEFAULT_NETWORK_PLANE_NAME.c_str()) != 0) { -- INFO("SetupPod net: %s", networks[i]->name); -- m_pluginManager->SetUpPod(config.metadata().namespace_(), config.metadata().name(), networks[i]->interface, -- response_id, stdAnnos, options, error); -- if (error.Empty()) { -- continue; -- } -- Errors tmpErr; -- StopContainerHelper(response_id, tmpErr); -- if (tmpErr.NotEmpty()) { -- WARN("Failed to stop sandbox container %s for pod %s: %s", response_id.c_str(), networks[i]->name, -- tmpErr.GetCMessage()); -- } -- goto cleanup; -- } -- } --cleanup: -- free_cri_pod_network(networks, len); --} -- - void CRIRuntimeServiceImpl::SetupSandboxNetwork(const runtime::v1alpha2::PodSandboxConfig &config, - const std::string &response_id, const std::string &jsonCheckpoint, - Errors &error) -@@ -685,45 +647,6 @@ cleanup: - return ret; - } - --auto CRIRuntimeServiceImpl::TearDownPodCniNetwork(const std::string &realSandboxID, std::vector &errlist, -- std::map &stdAnnos, const std::string &ns, -- const std::string &name, Errors &error) -> int --{ -- int ret = 0; -- cri_pod_network_element **networks = nullptr; -- container_inspect *inspect_data = InspectContainer(realSandboxID, error); -- if (inspect_data == nullptr) { -- return -1; -- } -- -- google::protobuf::Map annotations; -- CRIHelpers::ExtractAnnotations(inspect_data->config->annotations, annotations); -- size_t len = 0; -- -- networks = CRIHelpers::GetNetworkPlaneFromPodAnno(annotations, &len, error); -- if (error.NotEmpty()) { -- ERROR("Couldn't get network plane from pod annotations: %s", error.GetCMessage()); -- error.Errorf("Couldn't get network plane from pod annotations: %s", error.GetCMessage()); -- ret = -1; -- goto cleanup; -- } -- for (size_t i = 0; i < len; i++) { -- if ((networks[i] != nullptr) && (networks[i]->name != nullptr) && (networks[i]->interface != nullptr) && -- strcmp(networks[i]->name, Network::DEFAULT_NETWORK_PLANE_NAME.c_str()) != 0) { -- Errors tmpErr; -- m_pluginManager->TearDownPod(ns, name, networks[i]->interface, inspect_data->id, stdAnnos, tmpErr); -- if (tmpErr.NotEmpty()) { -- WARN("TearDownPod cni network failed: %s", tmpErr.GetCMessage()); -- errlist.push_back(tmpErr.GetMessage()); -- } -- } -- } --cleanup: -- free_cri_pod_network(networks, len); -- free_container_inspect(inspect_data); -- return ret; --} -- - auto CRIRuntimeServiceImpl::ClearCniNetwork(const std::string &realSandboxID, bool hostNetwork, const std::string &ns, - const std::string &name, std::vector &errlist, - std::map &stdAnnos, Errors & -@@ -966,8 +889,19 @@ void CRIRuntimeServiceImpl::SetSandboxStatusNetwork(container_inspect *inspect, - std::unique_ptr &podStatus, - Errors &error) - { -- std::string interfaceIP = GetIP(podSandboxID, inspect, Network::DEFAULT_NETWORK_INTERFACE_NAME, error); -- podStatus->mutable_network()->set_ip(interfaceIP); -+ std::vector ips; -+ size_t i; -+ -+ GetIPs(podSandboxID, inspect, Network::DEFAULT_NETWORK_INTERFACE_NAME, ips, error); -+ if (ips.size() == 0) { -+ return; -+ } -+ podStatus->mutable_network()->set_ip(ips[0]); -+ -+ for (i = 1; i < ips.size(); i++) { -+ auto tPoint = podStatus->mutable_network()->add_additional_ips(); -+ tPoint->set_ip(ips[i]); -+ } - } - - void CRIRuntimeServiceImpl::PodSandboxStatusToGRPC(container_inspect *inspect, const std::string &podSandboxID, -@@ -1019,66 +953,126 @@ void CRIRuntimeServiceImpl::PodSandboxStatusToGRPC(container_inspect *inspect, c - } - } - --auto CRIRuntimeServiceImpl::GetIPFromPlugin(container_inspect *inspect, const std::string &networkInterface, -- Errors &error) -> std::string -+void CRIRuntimeServiceImpl::GetFormatIPsForMultNet(container_inspect *inspect, const std::string &defaultInterface, -+ const runtime::v1alpha2::PodSandboxMetadata &metadata, std::vector &result, Errors &error) - { -- if (inspect == nullptr || inspect->id == nullptr || inspect->name == nullptr) { -- error.SetError("Empty arguments"); -- return ""; -+ size_t len = 0; -+ cri_pod_network_element **elems { nullptr }; -+ parser_error jerr { nullptr }; -+ -+ if (inspect->config == nullptr || inspect->config->annotations == nullptr) { -+ return; -+ } -+ -+ for (size_t i = 0; i < inspect->config->annotations->len; i++) { -+ if (strcmp(inspect->config->annotations->keys[i], CRIHelpers::Constants::POD_NETWORK_ANNOTATION_KEY.c_str()) != 0) { -+ continue; -+ } -+ elems = cri_pod_network_parse_data(inspect->config->annotations->values[i], nullptr, &jerr, &len); -+ if (elems == nullptr) { -+ ERROR("parse mutlnetwork config failed: %s", jerr); -+ error.SetError("parse mutlnetwork config failed"); -+ goto out; -+ } -+ break; -+ } -+ -+ for (size_t i = 0; i < len; i++) { -+ if (elems[i]->interface == nullptr || strcmp(elems[i]->interface, defaultInterface.c_str()) == 0) { -+ continue; -+ } -+ Network::PodNetworkStatus status; -+ m_pluginManager->GetPodNetworkStatus(metadata.namespace_(), metadata.name(), elems[i]->interface, inspect->id, status, -+ error); -+ if (error.NotEmpty()) { -+ goto out; -+ } -+ // add a sentry to make ips of mutlnetwork store from position 2 -+ if (result.size() < 2) { -+ result.push_back(""); -+ } -+ -+ result.push_back(std::string(elems[i]->name) + "@" + std::string(elems[i]->interface) + "@[" + CXXUtils::StringsJoin( -+ status.GetIPs(), ", ") + "]"); -+ } -+out: -+ for (size_t i = 0; i < len; i++) { -+ free_cri_pod_network_element(elems[i]); -+ elems[i] = nullptr; - } -+ free(elems); -+ free(jerr); -+} - -+auto CRIRuntimeServiceImpl::GetIPsFromPlugin(container_inspect *inspect, const std::string &networkInterface, -+ Errors &error) -> std::vector -+{ -+ std::vector ret; - runtime::v1alpha2::PodSandboxMetadata metadata; -+ std::string defaultInterface = networkInterface; -+ -+ if (inspect == nullptr || inspect->id == nullptr || inspect->name == nullptr) { -+ error.SetError("Empty arguments"); -+ return ret; -+ } - CRINaming::ParseSandboxName(inspect->name, metadata, error); - if (error.NotEmpty()) { -- return ""; -+ return ret; - } -- std::string cid = inspect->id; -- Network::PodNetworkStatus status; -- if (networkInterface.empty()) { -- m_pluginManager->GetPodNetworkStatus(metadata.namespace_(), metadata.name(), -- Network::DEFAULT_NETWORK_INTERFACE_NAME, cid, status, error); -- } else { -- m_pluginManager->GetPodNetworkStatus(metadata.namespace_(), metadata.name(), networkInterface, cid, status, -- error); -+ if (defaultInterface.empty()) { -+ defaultInterface = Network::DEFAULT_NETWORK_INTERFACE_NAME; - } -+ -+ // step 1: get ips of default network -+ Network::PodNetworkStatus status; -+ m_pluginManager->GetPodNetworkStatus(metadata.namespace_(), metadata.name(), defaultInterface, inspect->id, status, -+ error); - if (error.NotEmpty()) { -- return ""; -+ return ret; -+ } -+ for (auto &iter : status.GetIPs()) { -+ ret.push_back(iter); - } - -- return status.GetIP(); -+ // step 2: get ips of mutl networks -+ GetFormatIPsForMultNet(inspect, defaultInterface, metadata, ret, error); -+ -+ return ret; - } - --auto CRIRuntimeServiceImpl::GetIP(const std::string &podSandboxID, container_inspect *inspect, -- const std::string &networkInterface, Errors &error) -> std::string -+void CRIRuntimeServiceImpl::GetIPs(const std::string &podSandboxID, container_inspect *inspect, -+ const std::string &networkInterface, std::vector &ips, Errors &error) - { - if (inspect == nullptr || inspect->network_settings == nullptr) { -- return ""; -+ return; - } - if (SharesHostNetwork(inspect) != 0) { - // For sandboxes using host network, the shim is not responsible for reporting the IP. -- return ""; -+ return; - } - - bool ready = GetNetworkReady(podSandboxID, error); - if (error.Empty() && !ready) { - WARN("Network %s do not ready", podSandboxID.c_str()); -- return ""; -+ return; - } - - error.Clear(); -- auto ip = GetIPFromPlugin(inspect, networkInterface, error); -+ auto tmpIPs = GetIPsFromPlugin(inspect, networkInterface, error); - if (error.Empty()) { -- return ip; -+ for (const auto &iter : tmpIPs) { -+ ips.push_back(iter); -+ } -+ return; - } - - if (inspect->network_settings->ip_address != nullptr) { - WARN("Use container inspect ip info: %s", error.GetCMessage()); - error.Clear(); -- return inspect->network_settings->ip_address; -+ ips.push_back(inspect->network_settings->ip_address); - } - - WARN("Failed to read pod IP from plugin/docker: %s", error.GetCMessage()); -- return ""; - } - - std::unique_ptr -diff --git a/src/daemon/entry/cri/network_plugin.cc b/src/daemon/entry/cri/network_plugin.cc -index 0cab31a..311ebb6 100644 ---- a/src/daemon/entry/cri/network_plugin.cc -+++ b/src/daemon/entry/cri/network_plugin.cc -@@ -65,25 +65,58 @@ static void runGetIP(void *cmdArgs) - execvp(tmpArgs[0], args); - } - --static std::string GetOnePodIP(std::string nsenterPath, std::string netnsPath, std::string interfaceName, -- std::string addrType, Errors &error) -+static std::string ParseIPFromLine(const char *line, const char *stdout_str) - { -- char *stderr_str { nullptr }; -- char *stdout_str { nullptr }; -- char *strErr { nullptr }; -- char **lines { nullptr }; -+ char *cIP { nullptr }; - char **fields { nullptr }; -+ char *strErr { nullptr }; - struct ipnet *ipnet_val { - nullptr - }; -+ std::string ret; -+ -+ fields = util_string_split(line, ' '); -+ if (fields == nullptr) { -+ ERROR("Out of memory"); -+ goto out; -+ } -+ if (util_array_len((const char **)fields) < 4) { -+ ERROR("Unexpected address output %s ", line); -+ goto out; -+ } -+ -+ if (parse_cidr(fields[3], &ipnet_val, &strErr) != 0) { -+ ERROR("CNI failed to parse ip from output %s due to %s", stdout_str, strErr); -+ goto out; -+ } -+ cIP = ip_to_string(ipnet_val->ip, ipnet_val->ip_len); -+ if (cIP == nullptr) { -+ ERROR("Out of memory"); -+ goto out; -+ } -+ -+ ret = cIP; -+out: -+ free(cIP); -+ free(strErr); -+ free_ipnet_type(ipnet_val); -+ util_free_array(fields); -+ return ret; -+} -+ -+static void GetOnePodIP(std::string nsenterPath, std::string netnsPath, std::string interfaceName, -+ std::string addrType, std::vector &ips, Errors &error) -+{ -+ char *stderr_str { nullptr }; -+ char *stdout_str { nullptr }; -+ char **lines { nullptr }; - char **args { nullptr }; -- std::string result { "" }; -- char *cIP { nullptr }; -+ size_t i; - - args = (char **)util_common_calloc_s(sizeof(char *) * 5); - if (args == nullptr) { - error.SetError("Out of memory"); -- return result; -+ return; - } - - args[0] = util_strdup_s(nsenterPath.c_str()); -@@ -102,52 +135,55 @@ static std::string GetOnePodIP(std::string nsenterPath, std::string netnsPath, s - error.SetError("Out of memory"); - goto free_out; - } -- if (util_array_len((const char **)lines) < 1) { -- error.Errorf("Unexpected command output %s", stdout_str); -- goto free_out; -- } - -- fields = util_string_split(lines[0], ' '); -- if (fields == nullptr) { -- error.SetError("Out of memory"); -- goto free_out; -- } -- if (util_array_len((const char **)fields) < 4) { -- error.Errorf("Unexpected address output %s ", lines[0]); -+ if (util_array_len((const char **)lines) == 0) { -+ error.Errorf("Unexpected command output %s", stdout_str); - goto free_out; - } - -- if (parse_cidr(fields[3], &ipnet_val, &strErr) != 0) { -- error.Errorf("CNI failed to parse ip from output %s due to %s", stdout_str, strErr); -- goto free_out; -- } -- cIP = ip_to_string(ipnet_val->ip, ipnet_val->ip_len); -- if (cIP == nullptr) { -- error.SetError("Out of memory"); -- goto free_out; -+ for (i = 0; i < util_array_len((const char **)lines); i++) { -+ // ip string min length must bigger than 4 -+ if (lines[i] == nullptr || strlen(lines[i]) < 4) { -+ continue; -+ } -+ std::string tIP = ParseIPFromLine(lines[i], stdout_str); -+ if (tIP.empty()) { -+ error.Errorf("parse %s to ip failed", lines[i]); -+ break; -+ } -+ ips.push_back(tIP); - } -- result = cIP; -- free(cIP); - - free_out: -- free_ipnet_type(ipnet_val); - free(stdout_str); - free(stderr_str); - util_free_array(args); - util_free_array(lines); -- util_free_array(fields); -- return result; - } - --std::string GetPodIP(const std::string &nsenterPath, const std::string &netnsPath, const std::string &interfaceName, -- Errors &error) -+void GetPodIP(const std::string &nsenterPath, const std::string &netnsPath, const std::string &interfaceName, -+ std::vector &getIPs, Errors &error) - { -- std::string ip = GetOnePodIP(nsenterPath, netnsPath, interfaceName, "-4", error); -+ Errors tmpErr; -+ -+ GetOnePodIP(nsenterPath, netnsPath, interfaceName, "-4", getIPs, tmpErr); -+ if (tmpErr.NotEmpty()) { -+ WARN("Get ipv4 failed: %s", tmpErr.GetCMessage()); -+ } -+ -+ GetOnePodIP(nsenterPath, netnsPath, interfaceName, "-6", getIPs, error); - if (error.NotEmpty()) { -- return GetOnePodIP(nsenterPath, netnsPath, interfaceName, "-6", error); -+ WARN("Get ipv6 failed: %s", tmpErr.GetCMessage()); - } - -- return ip; -+ if (getIPs.size() > 0) { -+ error.Clear(); -+ return; -+ } -+ -+ if (tmpErr.NotEmpty()) { -+ error.AppendError(tmpErr.GetMessage()); -+ } - } - - void InitNetworkPlugin(std::vector> *plugins, std::string networkPluginName, -@@ -290,14 +326,14 @@ void PodNetworkStatus::SetAPIVersion(const std::string &version) - m_apiVersion = version; - } - --const std::string &PodNetworkStatus::GetIP() const -+const std::vector &PodNetworkStatus::GetIPs() const - { -- return m_ip; -+ return m_ips; - } - --void PodNetworkStatus::SetIP(const std::string &ip) -+void PodNetworkStatus::SetIPs(std::vector &ips) - { -- m_ip = ip; -+ m_ips = ips; - } - - void PluginManager::Lock(const std::string &fullPodName, Errors &error) -diff --git a/src/daemon/entry/cri/network_plugin.h b/src/daemon/entry/cri/network_plugin.h -index 5a46eb8..24afd71 100644 ---- a/src/daemon/entry/cri/network_plugin.h -+++ b/src/daemon/entry/cri/network_plugin.h -@@ -82,13 +82,13 @@ public: - void SetKind(const std::string &kind); - const std::string &GetAPIVersion() const; - void SetAPIVersion(const std::string &version); -- const std::string &GetIP() const; -- void SetIP(const std::string &ip); -+ const std::vector &GetIPs() const; -+ void SetIPs(std::vector &ips); - - private: - std::string m_kind; - std::string m_apiVersion; -- std::string m_ip; -+ std::vector m_ips; - }; - - class NetworkPlugin { -@@ -227,8 +227,8 @@ void InitNetworkPlugin(std::vector> *plugins, std - void ProbeNetworkPlugins(const std::string &pluginDir, const std::string &binDir, - std::vector> *plugins); - --std::string GetPodIP(const std::string &nsenterPath, const std::string &netnsPath, const std::string &interfaceName, -- Errors &error); -+void GetPodIP(const std::string &nsenterPath, const std::string &netnsPath, const std::string &interfaceName, -+ std::vector &getIPs, Errors &error); - - const std::string &GetInterfaceName(); - } // namespace Network --- -2.20.1 - diff --git a/0027-add-testcases-for-mutl-networks.patch b/0027-add-testcases-for-mutl-networks.patch deleted file mode 100644 index 0e05dcd..0000000 --- a/0027-add-testcases-for-mutl-networks.patch +++ /dev/null @@ -1,159 +0,0 @@ -From c8eaab912c22d2a46edf308a4dd71c609d8b683c Mon Sep 17 00:00:00 2001 -From: haozi007 -Date: Tue, 10 Nov 2020 10:51:31 +0800 -Subject: [PATCH 27/28] add testcases for mutl networks - -Signed-off-by: haozi007 ---- - CI/install_depends.sh | 7 +++-- - CI/test_cases/container_cases/cni_test.sh | 31 ++++++++++++++++--- - .../container_cases/criconfigs/bridge.json | 17 +++++----- - .../criconfigs/mutlnet_pod.json | 17 ++++++++++ - 4 files changed, 57 insertions(+), 15 deletions(-) - create mode 100644 CI/test_cases/container_cases/criconfigs/mutlnet_pod.json - -diff --git a/CI/install_depends.sh b/CI/install_depends.sh -index 61dd67d..5dd2543 100755 ---- a/CI/install_depends.sh -+++ b/CI/install_depends.sh -@@ -38,10 +38,13 @@ mkdir -p ${builddir}/systemd/system - function make_crictl() - { - cd ~ -- git clone -b release-1.14 https://gitee.com/duguhaotian/cri-tools.git -+ git clone https://gitee.com/duguhaotian/cri-tools.git -+ go version - cd cri-tools -+ git checkout v1.18.0 - make -j $nproc -- cp ./_output/bin/crictl ${builddir}/bin/ -+ echo "make cri-tools: $?" -+ cp ./_output/crictl ${builddir}/bin/ - } - - #install cni plugins -diff --git a/CI/test_cases/container_cases/cni_test.sh b/CI/test_cases/container_cases/cni_test.sh -index 8173cb5..c9e1e1a 100644 ---- a/CI/test_cases/container_cases/cni_test.sh -+++ b/CI/test_cases/container_cases/cni_test.sh -@@ -53,7 +53,7 @@ function do_test_help() - TC_RET_T=$(($TC_RET_T+1)) - fi - -- sid=`crictl runp ${data_path}/sandbox-config.json` -+ sid=`crictl runp ${data_path}/$1` - if [ $? -ne 0 ]; then - msg_err "Failed to run sandbox" - TC_RET_T=$(($TC_RET_T+1)) -@@ -66,7 +66,7 @@ function do_test_help() - TC_RET_T=$(($TC_RET_T+1)) - fi - -- cid=`crictl create $sid ${data_path}/container-config.json ${data_path}/sandbox-config.json` -+ cid=`crictl create $sid ${data_path}/container-config.json ${data_path}/$1` - if [ $? -ne 0 ];then - msg_err "create container failed" - TC_RET_T=$(($TC_RET_T+1)) -@@ -96,12 +96,33 @@ function do_test_help() - nsenter -t $con_pid -n ifconfig eth0 - TC_RET_T=$(($TC_RET_T+1)) - fi -- nsenter -t $pod_pid -n ifconfig eth0 | grep "$1" -+ nsenter -t $pod_pid -n ifconfig eth0 | grep "$2" - if [ $? -ne 0 ];then - msg_err "expect ip: $1, get: " - nsenter -t $pod_pid -n ifconfig eth0 - TC_RET_T=$(($TC_RET_T+1)) - fi -+ crictl inspectp $sid | grep "$2" -+ if [ $? -ne 0 ];then -+ msg_err "inspectp: expect ip: $1, get: " -+ crictl inspectp $sid -+ TC_RET_T=$(($TC_RET_T+1)) -+ fi -+ -+ if [ "x$3" != "x" ];then -+ nsenter -t $pod_pid -n ifconfig eth1 | grep "$3" -+ if [ $? -ne 0 ];then -+ msg_err "expect ip: $2, get: " -+ nsenter -t $pod_pid -n ifconfig eth1 -+ TC_RET_T=$(($TC_RET_T+1)) -+ fi -+ crictl inspectp $sid | grep "$3" -+ if [ $? -ne 0 ];then -+ msg_err "inspectp expect ip: $2, get: " -+ crictl inspectp $sid -+ TC_RET_T=$(($TC_RET_T+1)) -+ fi -+ fi - - crictl stop $cid - if [ $? -ne 0 ];then -@@ -132,7 +153,7 @@ function do_test_help() - - function default_cni_config() - { -- do_test_help "10\.1\." -+ do_test_help "sandbox-config.json" "10\.1\." - } - - function new_cni_config() -@@ -151,7 +172,7 @@ function new_cni_config() - fi - done - tail $ISUALD_LOG -- do_test_help "10\.2\." -+ do_test_help "mutlnet_pod.json" "10\.2\." "10\.1\." - } - - function check_annotation() -diff --git a/CI/test_cases/container_cases/criconfigs/bridge.json b/CI/test_cases/container_cases/criconfigs/bridge.json -index 4d19fa7..7686e26 100644 ---- a/CI/test_cases/container_cases/criconfigs/bridge.json -+++ b/CI/test_cases/container_cases/criconfigs/bridge.json -@@ -1,10 +1,11 @@ - { -- "cniVersion": "0.3.0", -- "name": "ok", -- "type": "bridge", -- "bridge": "cni0", -- "ipam": { -- "type": "host-local", -- "subnet": "10.2.0.0/16" -- } -+ "cniVersion": "0.3.0", -+ "name": "ok", -+ "type": "bridge", -+ "bridge": "cni0", -+ "isGateway": true, -+ "ipam": { -+ "type": "host-local", -+ "subnet": "10.2.0.0/16" -+ } - } -diff --git a/CI/test_cases/container_cases/criconfigs/mutlnet_pod.json b/CI/test_cases/container_cases/criconfigs/mutlnet_pod.json -new file mode 100644 -index 0000000..f860620 ---- /dev/null -+++ b/CI/test_cases/container_cases/criconfigs/mutlnet_pod.json -@@ -0,0 +1,17 @@ -+{ -+ "port_mappings":[{"protocol": 1, "container_port": 80, "host_port": 8080}], -+ "metadata": { -+ "name": "test", -+ "namespace": "default", -+ "attempt": 1, -+ "uid": "hdishd83djaidwnduwk28bcsb" -+ }, -+ "linux": { -+ }, -+ "annotations": { -+ "network.alpha.kubernetes.io/network": "[{\"name\":\"good\",\"interface\":\"eth1\"}]", -+ "extension.network.kubernetes.io/cni": "[multinetwork]", -+ "extension.network.kubernetes.io/cniargs/first": "extension=first", -+ "extension.network.kubernetes.io/cniargs/second": "extension=second" -+ } -+} --- -2.20.1 - diff --git a/0028-add-filter-to-get-only-non-sandbox-containers.patch b/0028-add-filter-to-get-only-non-sandbox-containers.patch deleted file mode 100644 index 77c3bbd..0000000 --- a/0028-add-filter-to-get-only-non-sandbox-containers.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 1a01070d00c9bf9ff65308522486edcfe16ed46c Mon Sep 17 00:00:00 2001 -From: gaohuatao -Date: Wed, 11 Nov 2020 11:10:36 +0800 -Subject: [PATCH 28/28] add filter to get only non-sandbox containers - -Signed-off-by: gaohuatao ---- - src/daemon/entry/cri/cri_container.cc | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/src/daemon/entry/cri/cri_container.cc b/src/daemon/entry/cri/cri_container.cc -index c6d9599..e23e59e 100644 ---- a/src/daemon/entry/cri/cri_container.cc -+++ b/src/daemon/entry/cri/cri_container.cc -@@ -788,6 +788,12 @@ void CRIRuntimeServiceImpl::ListContainersFromGRPC(const runtime::v1alpha2::Cont - error.SetError("Out of memory"); - return; - } -+ // Add filter to get only non-sandbox containers -+ if (CRIHelpers::FiltersAddLabel((*request)->filters, CRIHelpers::Constants::CONTAINER_TYPE_LABEL_KEY, -+ CRIHelpers::Constants::CONTAINER_TYPE_LABEL_CONTAINER) != 0) { -+ error.SetError("Failed to add filter"); -+ return; -+ } - - if (filter != nullptr) { - if (!filter->id().empty()) { -@@ -811,12 +817,6 @@ void CRIRuntimeServiceImpl::ListContainersFromGRPC(const runtime::v1alpha2::Cont - } - } - -- // Add some label -- if (CRIHelpers::FiltersAddLabel((*request)->filters, CRIHelpers::Constants::CONTAINER_TYPE_LABEL_KEY, -- CRIHelpers::Constants::CONTAINER_TYPE_LABEL_CONTAINER) != 0) { -- error.SetError("Failed to add filter"); -- return; -- } - for (auto &iter : filter->label_selector()) { - if (CRIHelpers::FiltersAddLabel((*request)->filters, iter.first, iter.second) != 0) { - error.SetError("Failed to add filter"); --- -2.20.1 - diff --git a/iSulad.spec b/iSulad.spec index 246952a..206efcc 100644 --- a/iSulad.spec +++ b/iSulad.spec @@ -1,5 +1,5 @@ %global _version 2.0.5 -%global _release 20201112.192302.gitedce3879 +%global _release 20201125.170623.git98ee627e %global is_systemd 1 Name: iSulad @@ -12,35 +12,14 @@ Source: https://gitee.com/openeuler/iSulad/repository/archive/v%{version}.tar BuildRoot: {_tmppath}/iSulad-%{version} ExclusiveArch: x86_64 aarch64 -Patch6000: 0000-update-from-v2.0.5-to-v2.0.6.patch -Patch6001: 0001-iSulad-modify-defattr-to-755-in-spec.patch -Patch6002: 0002-Dockerfile-update-dockerfile-to-isulad-v2.0.6-use-mu.patch -Patch6003: 0003-isulad-rt_isula_start-should-read-the-isulad-shim-pi.patch -Patch6004: 0004-Realpath-add-get-realpath-for-root-and-state-dir.patch -Patch6005: 0005-CI-add-testcase-for-root-and-run-dir-realpath.patch -Patch6006: 0006-info-fix-typo-driverr-to-driver.patch -Patch6007: 0007-create-fix-wrong-ret-code.patch -Patch6008: 0008-add-iSulad-s-build-guide-for-RISC-V.patch -Patch6009: 0009-add-non-root-group.patch -Patch6010: 0010-add-nonroot-execute-CI.patch -Patch6011: 0011-cni-support-extension-data-transmission.patch -Patch6012: 0012-unpack-add-remove-target-file-in-handle-.wh.patch -Patch6013: 0013-iSulad-internal-change.patch -Patch6014: 0014-unlink-etc-dir-when-link-exists.patch -Patch6015: 0015-support-variable-extension-cni-args.patch -Patch6016: 0016-CI-for-support-variable-extension-cni-args.patch -Patch6017: 0017-add-unlink-dir-comments.patch -Patch6018: 0018-iSulad-add-ISULAD_TMPDIR-env-variable.patch -Patch6019: 0019-CI-remove-test-data-from-iSulad-repo.patch -Patch6020: 0020-add-ISULAD_TMPDIR-env-CI.patch -Patch6021: 0021-iSulad-fix-memory-leak-in-inspect-grpc-service.patch -Patch6022: 0022-clean-code-remove-unused-code-in-connect.patch -Patch6023: 0023-add-newline-character-at-end-of-iSulad.sysconfig.patch -Patch6024: 0024-clean-code-remove-unused-in-code.patch -Patch6025: 0025-utils-add-fdatasync-when-do-atomic-write-file.patch -Patch6026: 0026-network-support-mutlnetworks.patch -Patch6027: 0027-add-testcases-for-mutl-networks.patch -Patch6028: 0028-add-filter-to-get-only-non-sandbox-containers.patch +Patch6000: 0000-update-from-2.0.5-to-2.0.7.patch +Patch6001: 0001-Add-a-solution-to-the-gpgkey-problem.patch +Patch6002: 0002-change-default-tmp-directory-from-var-tmp-to-var-lib.patch +Patch6003: 0003-update-api.proto-to-v1.19.3-according-to-kubelet.patch +Patch6004: 0004-adapt-CI-ISULAD_TMPDIR-testcases.patch +Patch6005: 0005-listening-127.0.0.1-port-in-cri-stream-websocket-ser.patch +Patch6006: 0006-using-64-bit-unique-token-in-CRI-websockets-server-R.patch +Patch6007: 0007-add-mock-conf_get_use_decrypted_key_flag-and-setup-a.patch %ifarch x86_64 aarch64 Provides: libhttpclient.so()(64bit) @@ -64,7 +43,7 @@ BuildRequires: grpc grpc-plugins grpc-devel protobuf-devel BuildRequires: libcurl libcurl-devel sqlite-devel libarchive-devel device-mapper-devel BuildRequires: http-parser-devel BuildRequires: libseccomp-devel libcap-devel libselinux-devel libwebsockets libwebsockets-devel -BuildRequires: systemd-devel git +BuildRequires: systemd-devel git chrpath Requires: lcr lxc clibcni Requires: grpc protobuf @@ -92,6 +71,7 @@ cd build install -d $RPM_BUILD_ROOT/%{_libdir} install -m 0644 ./src/libisula.so %{buildroot}/%{_libdir}/libisula.so install -m 0644 ./src/utils/http/libhttpclient.so %{buildroot}/%{_libdir}/libhttpclient.so +chrpath -d ./src/daemon/modules/image/libisulad_img.so install -m 0644 ./src/daemon/modules/image/libisulad_img.so %{buildroot}/%{_libdir}/libisulad_img.so chmod +x %{buildroot}/%{_libdir}/libisula.so chmod +x %{buildroot}/%{_libdir}/libhttpclient.so @@ -101,12 +81,12 @@ install -d $RPM_BUILD_ROOT/%{_libdir}/pkgconfig install -m 0640 ./conf/isulad.pc %{buildroot}/%{_libdir}/pkgconfig/isulad.pc install -d $RPM_BUILD_ROOT/%{_bindir} -install -m 0755 ./src/isula %{buildroot}/%{_bindir}/isula -install -m 0755 ./src/isulad-shim %{buildroot}/%{_bindir}/isulad-shim -install -m 0755 ./src/isulad %{buildroot}/%{_bindir}/isulad chrpath -d ./src/isula +install -m 0755 ./src/isula %{buildroot}/%{_bindir}/isula chrpath -d ./src/isulad-shim +install -m 0755 ./src/isulad-shim %{buildroot}/%{_bindir}/isulad-shim chrpath -d ./src/isulad +install -m 0755 ./src/isulad %{buildroot}/%{_bindir}/isulad install -d $RPM_BUILD_ROOT/%{_includedir}/isulad install -m 0644 ../src/daemon/modules/api/image_api.h %{buildroot}/%{_includedir}/isulad/image_api.h @@ -243,6 +223,12 @@ fi %endif %changelog ++* Wed Nov 25 2020 - 2.0.5-20201125.170623.git98ee627e ++- Type:update from openeuler ++- ID:NA ++- SUG:NA ++- DESC: update from openeuler + +* Thu Nov 12 2020 - 2.0.5-20201112.192302.gitedce3879 +- Type:update from openeuler +- ID:NA -- Gitee