Subsystem::Subsystem(const std::string& name, const std::string& mountPoint) : mName(name) { if (mName.empty()) { const std::string msg = "CGroup name is empty"; LOGE(msg); throw CGroupException(msg); } //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 (!mountPoint.empty() && mountPoint != path) { continue; } if (it->compare("cgroup") != 0) { //filesystem type continue; } it++; //skip filesystem type if (it->find(mName) != std::string::npos) { mPath = std::move(path); break; } } }
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()); } }
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; }
const std::string& Subsystem::getMountPoint() const { if (!isAttached()) { const std::string msg = "CGroup '" + mName + "' is not attached"; LOGE(msg); throw CGroupException(msg); } return mPath; }
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(); }
std::string getCGroupName(const std::string& s) { auto p = s.find(':'); if (p == std::string::npos) { const std::string msg = "wrong cgroup format " + s; LOGE(msg); throw CGroupException(msg); } return s.substr(p + 1); }
void Subsystem::detach(const std::string& path) { LOGI("Subsystem::detach " + path); // if happens (1/100) umount fails with EBUSY // in fact I don't know why this filesystem (subsystem hierarchy) can be busy // probably modyfying sth in hierarchy by other process in the system // following can be considered as workarround for (int retry = 10; retry > 0; ) { if (utils::umount(path)) { if (retry != 10) { LOGW("umount done afer " << (10 - retry) << " tries"); } return ; } LOGW("umount retry..."); --retry; usleep(1); } 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; }