From 11ddb3bab10b043797aca9eaa491070aa8510f3d Mon Sep 17 00:00:00 2001
From: Piotr Bartosiewicz
Date: Thu, 18 Sep 2014 10:07:15 +0200
Subject: [PATCH] New get_container_id_by_pid API function
[Bug/Feature] Introduce new API function: sc_get_container_id_by_pid
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run tests
Change-Id: I8bee78c062bcbbe29fc9e2c651989570c26869d1
---
client/security-containers-client-impl.cpp | 36 +++++++++
client/security-containers-client-impl.hpp | 5 ++
client/security-containers-client.cpp | 5 ++
client/security-containers-client.h | 11 +++
client/utils.cpp | 118 ++++++++++++++++++++++++++++
client/utils.hpp | 32 ++++++++
tests/unit_tests/client/ut-client-utils.cpp | 55 +++++++++++++
tests/unit_tests/client/ut-client.cpp | 37 +++++++++
8 files changed, 299 insertions(+)
create mode 100644 client/utils.cpp
create mode 100644 client/utils.hpp
create mode 100644 tests/unit_tests/client/ut-client-utils.cpp
diff --git a/client/security-containers-client-impl.cpp b/client/security-containers-client-impl.cpp
index 8486ae7..a2c51ba 100644
--- a/client/security-containers-client-impl.cpp
+++ b/client/security-containers-client-impl.cpp
@@ -25,6 +25,7 @@
#include
#include "security-containers-client-impl.hpp"
+#include "utils.hpp"
#include
#include
#include
@@ -33,6 +34,7 @@
#include
#include
+#include
using namespace std;
using namespace dbus;
@@ -122,6 +124,17 @@ ScStatus toStatus(const std::exception& ex)
return SCCLIENT_OTHER_ERROR;
}
+bool readFirstLineOfFile(const std::string& path, std::string& ret)
+{
+ std::ifstream file(path);
+ if (!file) {
+ return false;
+ }
+
+ std::getline(file, ret);
+ return true;
+}
+
} //namespace
ScStatus Client::sc_start_glib_loop() noexcept
@@ -309,6 +322,29 @@ ScStatus Client::sc_get_active_container_id(ScString* id) noexcept
return ret;
}
+ScStatus Client::sc_get_container_id_by_pid(int pid, ScString* id) noexcept
+{
+ assert(id);
+
+ const std::string path = "/proc/" + std::to_string(pid) + "/cpuset";
+
+ std::string cpuset;
+ if (!readFirstLineOfFile(path, cpuset)) {
+ mStatus = Status(SCCLIENT_INVALID_ARGUMENT, "Process not found");
+ return sc_get_status();
+ }
+
+ std::string containerId;
+ if (!parseContainerIdFromCpuSet(cpuset, containerId)) {
+ mStatus = Status(SCCLIENT_OTHER_ERROR, "unknown format of cpuset");
+ return sc_get_status();
+ }
+
+ *id = strdup(containerId.c_str());
+ mStatus = Status();
+ return sc_get_status();;
+}
+
ScStatus Client::sc_set_active_container(const char* id) noexcept
{
assert(id);
diff --git a/client/security-containers-client-impl.hpp b/client/security-containers-client-impl.hpp
index 10aecaf..f1bfacb 100644
--- a/client/security-containers-client-impl.hpp
+++ b/client/security-containers-client-impl.hpp
@@ -117,6 +117,11 @@ public:
ScStatus sc_get_active_container_id(ScString* id) noexcept;
/**
+ * @see ::sc_get_container_id_by_pid
+ */
+ ScStatus sc_get_container_id_by_pid(int pid, ScString* id) noexcept;
+
+ /**
* @see ::sc_set_active_container
*/
ScStatus sc_set_active_container(const char* id) noexcept;
diff --git a/client/security-containers-client.cpp b/client/security-containers-client.cpp
index b1eb521..cb22544 100644
--- a/client/security-containers-client.cpp
+++ b/client/security-containers-client.cpp
@@ -121,6 +121,11 @@ API ScStatus sc_get_active_container_id(ScClient client, ScString* id)
return getClient(client).sc_get_active_container_id(id);
}
+API ScStatus sc_get_container_id_by_pid(ScClient client, int pid, ScString* id)
+{
+ return getClient(client).sc_get_container_id_by_pid(pid, id);
+}
+
API ScStatus sc_set_active_container(ScClient client, const char* id)
{
return getClient(client).sc_set_active_container(id);
diff --git a/client/security-containers-client.h b/client/security-containers-client.h
index c56e9de..4d37c3c 100644
--- a/client/security-containers-client.h
+++ b/client/security-containers-client.h
@@ -247,6 +247,17 @@ ScStatus sc_get_container_ids(ScClient client, ScArrayString* array);
ScStatus sc_get_active_container_id(ScClient client, ScString* id);
/**
+ * Get container name of process with given pid.
+ *
+ * @param[in] client security-containers-server's client
+ * @param[in] pid process id
+ * @param[out] id active container name
+ * @return status of this function call
+ * @remark Use @p sc_string_free() to free memory occupied by @p id.
+ */
+ScStatus sc_get_container_id_by_pid(ScClient client, int pid, ScString* id);
+
+/**
* Set active (foreground) container.
*
* @param[in] client security-containers-server's client
diff --git a/client/utils.cpp b/client/utils.cpp
new file mode 100644
index 0000000..98b6905
--- /dev/null
+++ b/client/utils.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Piotr Bartosiewicz
+ *
+ * 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
+ */
+
+/**
+ * @file
+ * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief Utility functions definition
+ */
+
+#include "config.hpp"
+#include "utils.hpp"
+
+#include
+
+namespace {
+
+const std::string CPUSET_HOST = "/";
+const std::string CPUSET_LIBVIRT_PREFIX_OLD = "/machine/";
+const std::string CPUSET_LIBVIRT_SUFFIX_OLD = ".libvirt-lxc";
+const std::string CPUSET_LIBVIRT_PREFIX = "/machine.slice/machine-lxc\\x2d";
+const std::string CPUSET_LIBVIRT_SUFFIX = ".scope";
+
+bool parseOldFormat(const std::string& cpuset, std::string& id)
+{
+ // '/machine/.libvirt-lxc'
+ if (!boost::starts_with(cpuset, CPUSET_LIBVIRT_PREFIX_OLD)) {
+ return false;
+ }
+
+ if (!boost::ends_with(cpuset, CPUSET_LIBVIRT_SUFFIX_OLD)) {
+ return false;
+ }
+
+ id.assign(cpuset,
+ CPUSET_LIBVIRT_PREFIX_OLD.size(),
+ cpuset.size() - CPUSET_LIBVIRT_PREFIX_OLD.size() - CPUSET_LIBVIRT_SUFFIX_OLD.size());
+ return true;
+}
+
+inline int unhex(char c)
+{
+ if (c >= '0' && c <= '9') {
+ return c - '0';
+ }
+ if (c >= 'a' && c <= 'f') {
+ return c - 'a' + 10;
+ }
+ if (c >= 'A' && c <= 'F') {
+ return c - 'A' + 10;
+ }
+ return -1;
+}
+
+void unescape(std::string& value)
+{
+ const size_t len = value.size();
+ size_t inPos = 0;
+ size_t outPos = 0;
+ while (inPos < len) {
+ const char c = value[inPos++];
+ if (c == '-') {
+ value[outPos++] = '/';
+ } else if (c == '\\' && value[inPos] == 'x') {
+ const char a = unhex(value[inPos+1]);
+ const char b = unhex(value[inPos+2]);
+ value[outPos++] = (char) ((a << 4) | b);
+ inPos += 3;
+ } else {
+ value[outPos++] = c;
+ }
+ }
+ value.resize(outPos);
+}
+
+bool parseNewFormat(const std::string& cpuset, std::string& id)
+{
+ // '/machine.slice/machine-lxc\x2d.scope'
+ if (!boost::starts_with(cpuset, CPUSET_LIBVIRT_PREFIX)) {
+ return false;
+ }
+
+ if (!boost::ends_with(cpuset, CPUSET_LIBVIRT_SUFFIX)) {
+ return false;
+ }
+
+ id = cpuset.substr(CPUSET_LIBVIRT_PREFIX.size(),
+ cpuset.size() - CPUSET_LIBVIRT_PREFIX.size() - CPUSET_LIBVIRT_SUFFIX.size());
+ unescape(id);
+ return true;
+}
+
+} // namespace
+
+bool parseContainerIdFromCpuSet(const std::string& cpuset, std::string& id)
+{
+ if (cpuset == CPUSET_HOST) {
+ id = "host";
+ return true;
+ }
+
+ return parseNewFormat(cpuset, id) || parseOldFormat(cpuset, id);
+}
+
diff --git a/client/utils.hpp b/client/utils.hpp
new file mode 100644
index 0000000..49b83c0
--- /dev/null
+++ b/client/utils.hpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Piotr Bartosiewicz
+ *
+ * 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
+ */
+
+/**
+ * @file
+ * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief Utility functions declaration
+ */
+
+#ifndef SECURITY_CONTAINERS_CLIENT_UTILS_HPP
+#define SECURITY_CONTAINERS_CLIENT_UTILS_HPP
+
+#include
+
+bool parseContainerIdFromCpuSet(const std::string& cpuset, std::string& id);
+
+#endif // SECURITY_CONTAINERS_CLIENT_UTILS_HPP
diff --git a/tests/unit_tests/client/ut-client-utils.cpp b/tests/unit_tests/client/ut-client-utils.cpp
new file mode 100644
index 0000000..ac4c1fd
--- /dev/null
+++ b/tests/unit_tests/client/ut-client-utils.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Piotr Bartosiewicz
+ *
+ * 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
+ */
+
+
+/**
+ * @file
+ * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief Unit tests of the client utils
+ */
+
+#include
+#include "ut.hpp"
+#include
+
+
+BOOST_AUTO_TEST_SUITE(ClientUtils)
+
+BOOST_AUTO_TEST_CASE(ParseContainerIdFromCpuSetTest)
+{
+ auto testBad = [](const std::string& input) {
+ std::string ret;
+ BOOST_CHECK(!parseContainerIdFromCpuSet(input, ret));
+ };
+
+ auto testOK = [](const std::string& input, const std::string& expected) {
+ std::string ret;
+ BOOST_CHECK(parseContainerIdFromCpuSet(input, ret));
+ BOOST_CHECK_EQUAL(expected, ret);
+ };
+
+ testBad("");
+ testBad("/foo");
+
+ testOK("/", "host");
+ testOK("/machine/a-b.libvirt-lxc", "a-b");
+ testOK("/machine.slice/machine-lxc\\x2da\\x2db.scope", "a-b");
+ testOK("/machine.slice/machine-lxc\\x2da-b.scope", "a/b");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/unit_tests/client/ut-client.cpp b/tests/unit_tests/client/ut-client.cpp
index bbf2013..574be39 100644
--- a/tests/unit_tests/client/ut-client.cpp
+++ b/tests/unit_tests/client/ut-client.cpp
@@ -256,4 +256,41 @@ BOOST_AUTO_TEST_CASE(NotificationTest)
}
}
+BOOST_AUTO_TEST_CASE(GetContainerIdByPidTest1)
+{
+ ScClient client = sc_client_create();
+ ScString container;
+ ScStatus status = sc_get_container_id_by_pid(client, 1, &container);
+ BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status);
+
+ BOOST_CHECK_EQUAL(container, std::string("host"));
+
+ sc_string_free(container);
+ sc_client_free(client);
+}
+
+BOOST_AUTO_TEST_CASE(GetContainerIdByPidTest2)
+{
+ std::set ids;
+
+ ScClient client = sc_client_create();
+ for (int n = 0; n < 100000; ++n) {
+ ScString container;
+ ScStatus status = sc_get_container_id_by_pid(client, n, &container);
+ if (status == SCCLIENT_SUCCESS) {
+ ids.insert(container);
+ sc_string_free(container);
+ } else {
+ BOOST_WARN_MESSAGE(status == SCCLIENT_INVALID_ARGUMENT, sc_get_status_message(client));
+ }
+ }
+ sc_client_free(client);
+
+ BOOST_CHECK(ids.count("host") == 1);
+
+ for (const auto& dbus : EXPECTED_DBUSES_STARTED) {
+ BOOST_CHECK(ids.count(dbus.first) == 1);
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
--
2.7.4