bool umount(const std::string& path)
{
if (::umount(path.c_str()) != 0) {
- LOGD("Umount failed for '" << path << "': " << getSystemErrorMessage());
+ LOGE("Umount failed for '" << path << "': " << getSystemErrorMessage());
return false;
}
return true;
*/
#include "utils/text.hpp"
+#include <sstream>
namespace utils {
namespace {
return s;
}
+std::string join(const std::vector<std::string>& vec, const char *delim)
+{
+ std::stringstream res;
+ for (const auto& s : vec) {
+ if (res.tellp() > 0) {
+ res << delim;
+ }
+ res << s;
+ }
+ return res.str();
+}
+
+std::vector<std::string> split(const std::string& str, const std::string& delim)
+{
+ std::vector<std::string> tokens;
+ if (str.empty()) {
+ return tokens;
+ }
+
+ for (std::string::size_type startPos = 0; ; ) {
+ std::string::size_type endPos = str.find_first_of(delim, startPos);
+ tokens.push_back(str.substr(startPos, endPos));
+ if (endPos == std::string::npos) {
+ break;
+ }
+ startPos = endPos + 1;
+ }
+ return tokens;
+}
+
} // namespace utils
#define COMMON_UTILS_TEXT_HPP
#include <string>
+#include <vector>
namespace utils {
-/**
- * Convert binary bytes array to hex string representation
- */
-std::string toHexString(const void *data, unsigned len);
-
inline bool beginsWith(std::string const &value, std::string const &part)
{
if (part.size() > value.size()) {
return std::equal(part.rbegin(), part.rend(), value.rbegin());
}
+/**
+ * Convert binary bytes array to hex string representation
+ */
+std::string toHexString(const void *data, unsigned len);
+
+std::string join(const std::vector<std::string>& vec, const char *delim);
+std::vector<std::string> split(const std::string& str, const std::string& delim);
+
} // namespace utils
#endif // COMMON_UTILS_TEXT_HPP
*/
#include "lxcpp/cgroups/cgroup.hpp"
+#include "lxcpp/exception.hpp"
+#include "utils/fs.hpp"
+#include "logger/logger.hpp"
-// added this file now, to make hpp go through compilation
+namespace fs = boost::filesystem;
+
+namespace lxcpp {
+
+namespace {
+std::string getSubsysName(const std::string& s) {
+ auto p = s.find(':');
+ if (p == std::string::npos) {
+ const std::string msg = "wgrong cgroup format";
+ LOGE(msg);
+ throw CGroupException(msg);
+ }
+ return s.substr(0, p);
+}
+std::string getCGroupName(const std::string& s) {
+ auto p = s.find(':');
+ if (p == std::string::npos) {
+ const std::string msg = "wgrong cgroup format";
+ LOGE(msg);
+ throw CGroupException(msg);
+ }
+ return s.substr(p + 1);
+}
+} // namespace
+
+CGroup::CGroup(const std::string& subsysAndCgroup) :
+ mSubsys(std::move(getSubsysName(subsysAndCgroup))),
+ mName(std::move(getCGroupName(subsysAndCgroup)))
+{
+}
+
+bool CGroup::exists() const
+{
+ const fs::path path = fs::path(mSubsys.getMountPoint()) / mName;
+ return fs::is_directory(path);
+}
+
+void CGroup::create()
+{
+ const fs::path path = fs::path(mSubsys.getMountPoint()) / mName;
+ fs::create_directory(path);
+}
+
+void CGroup::destroy()
+{
+ const fs::path path = fs::path(mSubsys.getMountPoint()) / mName;
+ fs::remove_all(path);
+}
+
+void CGroup::setValue(const std::string& param, const std::string& value)
+{
+ const fs::path path = fs::path(mSubsys.getMountPoint()) / mName / (mSubsys.getName() + "." + param);
+ utils::saveFileContent(path.string(), value);
+}
+
+std::string CGroup::getValue(const std::string& param) const
+{
+ const fs::path path = fs::path(mSubsys.getMountPoint()) / mName / (mSubsys.getName() + "." + param);
+ return utils::readFileContent(path.string());
+}
+
+void CGroup::assignProcess(pid_t pid)
+{
+ const fs::path path = fs::path(mSubsys.getMountPoint()) / mName / "tasks";
+ utils::saveFileContent(path.string(), std::to_string(pid));
+}
+
+} //namespace lxcpp
#include "lxcpp/cgroups/subsystem.hpp"
+namespace lxcpp {
+
class CGroup {
public:
/**
* Define control-group object
*/
- CGroup(const Subsystem& subsys, const std::string& name) :
+ CGroup(const std::string& subsys, const std::string& name) :
mSubsys(subsys),
mName(name)
{
}
/**
+ * Define control-group object (format "subsys:cgroup_path")
+ */
+ CGroup(const std::string& subsysAndCgroup);
+
+ /**
* Check if cgroup exists
* @return true if cgroup path (subsys.path / mName) exists
*/
- bool exists();
+ bool exists() const;
/**
* Create cgroup directory
* Get cgroup parameter
* Equivalent of: cat mSubsys_path/mName/mSubsys_name.param
*/
- std::string getValue(const std::string& key);
+ std::string getValue(const std::string& param) const;
/**
- * Move process to this cgroup (process can't be removed from a cgroup)
+ * Assign process to this cgroup (will be removed from previous cgroup automatically)
* Equivalent of: echo pid > mSubsys_path/mName/tasks
*/
- void moveProcess(pid_t pid);
+ void assignProcess(pid_t pid);
private:
- const Subsystem& mSubsys; // referred subsystem
- const std::string& mName; // path relative to subsystem "root"
+ const Subsystem mSubsys; // referred subsystem
+ const std::string mName; // path relative to subsystem "root"
};
+} //namespace lxcpp
+
#endif // LXCPP_CGROUPS_CGROUP_HPP
--- /dev/null
+/*
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * @author Krzysztof Dynowski (k.dynowski@samsumg.com)
+ * @brief Control-groups management
+ */
+
+#include "lxcpp/cgroups/subsystem.hpp"
+#include "lxcpp/exception.hpp"
+
+#include "utils/exception.hpp"
+#include "utils/text.hpp"
+#include "utils/fs.hpp"
+#include "logger/logger.hpp"
+
+#include <istream>
+#include <sstream>
+#include <iterator>
+#include <algorithm>
+#include <iostream>
+
+namespace lxcpp {
+
+Subsystem::Subsystem(const std::string& name) : mName(name)
+{
+ if (mName.empty()) {
+ const std::string msg = "CGroup name is empty";
+ LOGE(msg);
+ throw CGroupException(msg);
+ }
+
+ std::vector<std::string> av = availableSubsystems();
+ //find mount point for a name
+ std::ifstream fileStream("/proc/mounts");
+ if (!fileStream.good()) {
+ const std::string msg = "Failed to open /proc/mounts";
+ LOGE(msg);
+ throw CGroupException(msg);
+ }
+
+ std::string line;
+ while (std::getline(fileStream, line).good()) {
+ std::istringstream iss(line);
+ auto it = std::istream_iterator<std::string>(iss);
+ it++; //skip device name (fake for cgroup filesystem type)
+ std::string path = *it++; //mount point
+ if (it->compare("cgroup") != 0) { //filesystem type
+ continue;
+ }
+ it++; //skip filesystem type
+ if (it->find(mName) != std::string::npos) {
+ mPath = std::move(path);
+ break;
+ }
+ }
+}
+
+bool Subsystem::isAvailable() const
+{
+ if (mName.empty()) {
+ const std::string msg = "CGroup name is empty";
+ LOGE(msg);
+ throw CGroupException(msg);
+ }
+ std::vector<std::string> av = availableSubsystems();
+ return std::find(av.begin(), av.end(), mName) != av.end();
+}
+
+bool Subsystem::isAttached() const
+{
+ return !mPath.empty();
+}
+
+const std::string& Subsystem::getMountPoint() const
+{
+ if (!isAttached()) {
+ const std::string msg = "CGroup '" + mName + "' is not attached";
+ LOGE(msg);
+ throw CGroupException(msg);
+ }
+ return mPath;
+}
+
+void Subsystem::attach(const std::string& path, const std::vector<std::string>& subs)
+{
+ if (path.empty()) {
+ const std::string msg = "Trying attach to emtpy path";
+ LOGE(msg);
+ throw CGroupException(msg);
+ }
+ if (!utils::createDirs(path,0777)) {
+ throw CGroupException("Can't create mount point: " + path + ", " + utils::getSystemErrorMessage());
+ }
+ if (!utils::mount("cgroup", path, "cgroup", 0, utils::join(subs,","))) {
+ throw CGroupException("Can't mount cgroup: " + path + ", " + utils::getSystemErrorMessage());
+ }
+}
+
+void Subsystem::detach(const std::string& path)
+{
+ if (!utils::umount(path)) {
+ throw CGroupException("Can't umount cgroup: " + path + ", " + utils::getSystemErrorMessage());
+ }
+}
+
+std::vector<std::string> Subsystem::availableSubsystems()
+{
+ std::ifstream fileStream("/proc/cgroups");
+ if (!fileStream.good()) {
+ const std::string msg = "Failed to open /proc/cgroups";
+ LOGE(msg);
+ throw CGroupException(msg);
+ }
+
+ std::vector<std::string> subs;
+ std::string line;
+ while (std::getline(fileStream, line).good()) {
+ if (utils::beginsWith(line, "#")) {
+ continue;
+ }
+ std::istringstream iss(line);
+ auto it = std::istream_iterator<std::string>(iss);
+ std::string n = *it++; //subsystem name
+ subs.push_back(n);
+ }
+ return subs;
+}
+
+std::vector<std::string> Subsystem::getCGroups(pid_t pid)
+{
+ std::ifstream fileStream("/proc/" + std::to_string(pid) + "/cgroup");
+ if (!fileStream.good()) {
+ const std::string msg = "Failed to open /proc/<pid>/cgroup";
+ LOGE(msg);
+ throw CGroupException(msg);
+ }
+
+ std::vector<std::string> subs;
+ std::string line;
+ while (std::getline(fileStream, line).good()) {
+ if (utils::beginsWith(line, "#")) {
+ continue;
+ }
+ // istream_iterator does not support delimiter
+ std::istringstream iss(line);
+ std::string n, p;
+ std::getline(iss, n, ':'); // ignore
+ std::getline(iss, n, ':'); // subsystem name
+ std::getline(iss, p, ':'); // cgroup path
+ subs.push_back(n + ":" + p);
+ }
+ return subs;
+}
+
+} //namespace lxcpp
#include <string>
#include <vector>
+namespace lxcpp {
+
class Subsystem {
public:
/**
*/
Subsystem(const std::string& name);
+ const std::string& getName() const
+ {
+ return mName;
+ }
+
/**
* Check if named subsystem is supported by the kernel
* @return true if subsystem is listed in /proc/cgroups
*/
- bool isAvailable();
+ bool isAvailable() const;
/**
* Check if named subsystem is mounted (added to hierarchy)
* @return true if subsystem has a mount point (as read from /proc/mounts)
*/
- bool isAttached();
+ bool isAttached() const;
+
+ /**
+ * Get mount point of this subsystem
+ * @return subsystem mount point (as read from /proc/mounts)
+ */
+ const std::string& getMountPoint() const;
/**
* Attach subsystem hierarchy to filesystem
- * Equivalent of: mount -t cgroup -o subs(coma-sep) subs(underln-sep) path
+ * Equivalent of: mount -t cgroup -o subs(coma-sep) cgroup path
+ * Note: cgroup root must be already mounted (eg. /sys/fs/cgroup) as tmpfs
*/
- static void attach(const std::string& path, std::vector<std::string> subs);
+ static void attach(const std::string& path, const std::vector<std::string>& subs);
/**
* Detach subsstem hierarchy from filesystem
static std::vector<std::string> getCGroups(pid_t pid);
private:
- const std::string& mName;
+ std::string mName;
std::string mPath;
};
+} //namespace lxcpp
+
#endif // LXCPP_CGROUPS_SUBSYSTEM_HPP
: Exception(message) {}
};
+struct CGroupException : public Exception {
+ explicit CGroupException (const std::string& message = "Error during setting up a cgroup")
+ : Exception(message) {}
+};
+
struct ConfigureException: public Exception {
explicit ConfigureException(const std::string& message = "Error while configuring a container")
: Exception(message) {}
--- /dev/null
+/*
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * @author Krzysztof Dynowski (k.dynowski@samsung.com)
+ * @brief Unit tests of lxcpp cgroups managment
+ */
+
+#include "config.hpp"
+#include "ut.hpp"
+#include "logger/logger.hpp"
+
+#include "lxcpp/cgroups/subsystem.hpp"
+
+namespace {
+
+struct Fixture {
+ Fixture() {}
+ ~Fixture() {}
+};
+
+} // namespace
+
+BOOST_FIXTURE_TEST_SUITE(LxcppCGroupsSuite, Fixture)
+
+using namespace lxcpp;
+
+// assume cgroups are supprted by the system
+BOOST_AUTO_TEST_CASE(GetAvailable)
+{
+ std::vector<std::string> subs;
+ BOOST_CHECK_NO_THROW(subs = Subsystem::availableSubsystems());
+ BOOST_CHECK(subs.size() > 0);
+ for (auto n : subs){
+ Subsystem s(n);
+ LOGD(s.getName() << ": " << (s.isAttached()?s.getMountPoint():"[not attached]"));
+ }
+}
+
+BOOST_AUTO_TEST_CASE(GetCGroupsByPid)
+{
+ std::vector<std::string> cg;
+ BOOST_CHECK_NO_THROW(cg=Subsystem::getCGroups(::getpid()));
+ BOOST_CHECK(cg.size() > 0);
+}
+
+BOOST_AUTO_TEST_CASE(SubsysAttach)
+{
+ Subsystem sub("freezer");
+ BOOST_CHECK_MESSAGE(sub.getName() == "freezer", "freezer not equal");
+ BOOST_CHECK_MESSAGE(sub.isAvailable(), "freezer not found");
+
+ if (!sub.isAvailable()) return ;
+
+
+ if (sub.isAttached()) {
+ std::string mp = sub.getMountPoint();
+ BOOST_CHECK_NO_THROW(Subsystem::detach(mp));
+ BOOST_CHECK_NO_THROW(Subsystem::attach(mp, {sub.getName()}));
+ }
+ else {
+ std::string mp = "/sys/fs/cgroup/" + sub.getName();
+ BOOST_CHECK_NO_THROW(Subsystem::attach(mp, {sub.getName()}));
+ BOOST_CHECK_NO_THROW(Subsystem::detach(mp));
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
#include "ut.hpp"
#include <iostream>
-#include <sched.h>
#include <net/if.h>
--- /dev/null
+/*
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * @author Krzysztof Dynowski (k.dynowski@samsung.com)
+ * @brief Unit tests of text helpers
+ */
+
+#include "config.hpp"
+#include "ut.hpp"
+
+#include "utils/text.hpp"
+
+BOOST_AUTO_TEST_SUITE(TextUtilsSuite)
+
+BOOST_AUTO_TEST_CASE(SplitText)
+{
+ std::vector<std::string> v;
+ v = utils::split("", ",");
+ BOOST_CHECK(v.size() == 0);
+ v = utils::split("a", ",");
+ BOOST_CHECK(v.size() == 1);
+ v = utils::split(",", ",");
+ BOOST_CHECK(v.size() == 2);
+ v = utils::split("1,2", ",");
+ BOOST_CHECK(v.size() == 2);
+}
+
+BOOST_AUTO_TEST_SUITE_END()