#include <config.hpp>
#include "security-containers-client-impl.hpp"
+#include "utils.hpp"
#include <dbus/connection.hpp>
#include <dbus/exception.hpp>
#include <utils/glib-loop.hpp>
#include <cstring>
#include <cassert>
+#include <fstream>
using namespace std;
using namespace dbus;
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
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);
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;
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);
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
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Piotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
+ *
+ * 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 <boost/algorithm/string.hpp>
+
+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/<id>.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<id>.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);
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Piotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
+ *
+ * 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 <string>
+
+bool parseContainerIdFromCpuSet(const std::string& cpuset, std::string& id);
+
+#endif // SECURITY_CONTAINERS_CLIENT_UTILS_HPP
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Piotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
+ *
+ * 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 <config.hpp>
+#include "ut.hpp"
+#include <utils.hpp>
+
+
+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()
}
}
+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<std::string> 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()