From: Sungbae Yoo Date: Wed, 31 May 2017 11:23:37 +0000 (+0900) Subject: Add cgroup class for management of cgroupfs X-Git-Tag: submit/tizen/20170621.051505^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=77ee808f47d0eea5c629a93f346d221c8096dcef;p=platform%2Fcore%2Fsecurity%2Fklay.git Add cgroup class for management of cgroupfs Signed-off-by: Sungbae Yoo Change-Id: If0f280c8484c424117727aa04fa88b523056e590 --- diff --git a/include/klay/cgroup.h b/include/klay/cgroup.h new file mode 100644 index 0000000..a9cb217 --- /dev/null +++ b/include/klay/cgroup.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 + */ + +#ifndef __RUNTIME_CGROUP_H__ +#define __RUNTIME_CGROUP_H__ + +#include +#include + +namespace runtime { + +class Cgroup final { +public: + Cgroup() = delete; + + static bool existSubsystem(const std::string& name); + static void createSubsystem(const std::string& name); + static void destroySubsystem(const std::string& name); + + static bool exist(const std::string& subsystem, const std::string& path); + static void create(const std::string& subsystem, const std::string& path); + static void destroy(const std::string& subsystem, const std::string& path); + + static void addProcess(const std::string& subsystem, + const std::string& path, const pid_t pid); + static std::vector getProcessList(const std::string& subsystem, + const std::string& path); + + static const std::string getPath(const std::string& subsystem, const pid_t pid); +}; + +} // namespace runtime + +#endif //!__RUNTIME_CGROUP_H__ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1e5f8ec..a1fb0bc 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,6 +14,7 @@ # limitations under the License. # SET (KLAY_SOURCES ${KLAY_SRC}/error.cpp + ${KLAY_SRC}/cgroup.cpp ${KLAY_SRC}/process.cpp ${KLAY_SRC}/eventfd.cpp ${KLAY_SRC}/mainloop.cpp diff --git a/src/cgroup.cpp b/src/cgroup.cpp new file mode 100644 index 0000000..0087226 --- /dev/null +++ b/src/cgroup.cpp @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + + +namespace runtime { + +namespace { + +static std::regex namePattern("^[A-Za-z_][A-Za-z0-9_-]*"); +static std::regex pathPattern("(/*[A-Za-z_][A-Za-z0-9_-]*)*"); + +} // namespace + +bool Cgroup::existSubsystem(const std::string& name) +{ + if (!std::regex_match(name, namePattern)) { + return false; + } + + runtime::File dir("/sys/fs/cgroup/" + name); + if (dir.exists()) { + if (dir.isDirectory()) { + return true; + } + throw runtime::Exception("Invalid subsystem name"); + } + + return false; +} + +void Cgroup::createSubsystem(const std::string& name) +{ + if (!std::regex_match(name, namePattern)) { + throw runtime::Exception("Invalid subsystem name"); + } + + if (existSubsystem(name)) { + return; + } + + runtime::File subsystem("/sys/fs/cgroup/" + name); + if (::mount(NULL, "/sys/fs/cgroup/", NULL, MS_REMOUNT | + MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME, + "mode=755")) { + throw runtime::Exception("Failed to remount cgroupfs as the writable"); + } + + if (!subsystem.exists()) { + subsystem.makeDirectory(true); + } + + if (::mount(name.c_str(), subsystem.getPath().c_str(), + "cgroup", MS_NODEV | MS_NOSUID | MS_NOEXEC, + ("none,name=" + name).c_str())) { + subsystem.remove(false); + throw runtime::Exception("Failed to mount cgroup subsystem"); + } + + if (::mount(NULL, "/sys/fs/cgroup/", NULL, MS_REMOUNT | MS_RDONLY | + MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME, + "mode=755")) { + throw runtime::Exception("Failed to remount cgroupfs as the read-only"); + } +} + +void Cgroup::destroySubsystem(const std::string& name) +{ + if (!existSubsystem(name)) { + throw runtime::Exception("No such subsystem"); + } + + if (::mount(NULL, "/sys/fs/cgroup/", NULL, MS_REMOUNT | + MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME, + "mode=755")) { + throw runtime::Exception("Failed to remount cgroupfs as the writable"); + } + + runtime::File subsystem("/sys/fs/cgroup/" + name); + ::umount2(subsystem.getPath().c_str(), MNT_EXPIRE); + + subsystem.remove(false); + + if (::mount(NULL, "/sys/fs/cgroup/", NULL, MS_REMOUNT | MS_RDONLY | + MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME, + "mode=755")) { + throw runtime::Exception("Failed to remount cgroupfs as the read-only"); + } +} + +bool Cgroup::exist(const std::string& subsystem, const std::string& path) +{ + if (!std::regex_match(path, pathPattern)) { + return false; + } + + runtime::File dir("/sys/fs/cgroup/" + subsystem + "/" + path); + if (dir.exists()) { + if (dir.isDirectory()) { + return true; + } + throw runtime::Exception("Invalid path"); + } + + return false; +} + +void Cgroup::create(const std::string& subsystem, const std::string& path) +{ + if (!std::regex_match(path, pathPattern)) { + throw runtime::Exception("Invalid path"); + } + + if (exist(subsystem, path)) { + return; + } + + runtime::File dir("/sys/fs/cgroup/" + subsystem + "/" + path); + dir.makeDirectory(true); +} + +void Cgroup::destroy(const std::string& subsystem, const std::string& path) +{ + if (!exist(subsystem, path)) { + throw runtime::Exception("No such path in subsystem"); + } + + runtime::File dir("/sys/fs/cgroup/" + subsystem + "/" + path); + dir.remove(false); +} + +void Cgroup::addProcess(const std::string& subsystem, const std::string& path, const pid_t pid) +{ + if (!exist(subsystem, path)) { + throw runtime::Exception("No such path in subsystem"); + } + + std::ofstream ofs("/sys/fs/cgroup/" + subsystem + "/" + path + + "/tasks"); + + ofs << pid << std::endl; +} + +std::vector Cgroup::getProcessList(const std::string& subsystem, const std::string& path) +{ + std::vector ret; + std::ifstream ifs("/sys/fs/cgroup/" + subsystem + "/" + path + + "/tasks"); + + while (ifs.good()) { + pid_t pid; + ifs >> pid; + ret.push_back(pid); + } + + return ret; +} + +const std::string Cgroup::getPath(const std::string& subsystem, const pid_t pid) +{ + std::ifstream ifs("/proc/" + std::to_string(pid) + "/cgroup"); + std::string ret = "/", line; + + while (std::getline(ifs, line)) { + std::stringstream lineStream(line); + std::string name; + + //the first getline is for removing the first argument + std::getline(lineStream, name, ':'); + std::getline(lineStream, name, ':'); + + if (name == subsystem || name == "name=" + subsystem) { + ret = line.substr(line.find('/')); + } + } + return ret; +} + +} // namespace runtime