compute-runtime/level_zero/tools/source/sysman/linux/fs_access.cpp

535 lines
14 KiB
C++
Raw Normal View History

/*
* Copyright (C) 2020 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "level_zero/tools/source/sysman/linux/fs_access.h"
#include <climits>
#include <array>
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <dirent.h>
#include <unistd.h>
namespace L0 {
static ze_result_t getResult(int err) {
if ((EPERM == err) || (EACCES == err)) {
return ZE_RESULT_ERROR_INSUFFICIENT_PERMISSIONS;
} else if (ENOENT == err) {
return ZE_RESULT_ERROR_NOT_AVAILABLE;
} else {
return ZE_RESULT_ERROR_UNKNOWN;
}
}
// Generic Filesystem Access
FsAccess::FsAccess() {
}
FsAccess *FsAccess::create() {
return new FsAccess();
}
ze_result_t FsAccess::read(const std::string file, uint64_t &val) {
// Read a single line from text file without trailing newline
std::ifstream fs;
fs.open(file.c_str());
if (fs.fail()) {
return getResult(errno);
}
fs >> val;
if (fs.fail()) {
fs.close();
return getResult(errno);
}
fs.close();
return ZE_RESULT_SUCCESS;
}
ze_result_t FsAccess::read(const std::string file, double &val) {
// Read a single line from text file without trailing newline
std::ifstream fs;
fs.open(file.c_str());
if (fs.fail()) {
return getResult(errno);
}
fs >> val;
if (fs.fail()) {
fs.close();
return getResult(errno);
}
fs.close();
return ZE_RESULT_SUCCESS;
}
ze_result_t FsAccess::read(const std::string file, uint32_t &val) {
// Read a single line from text file without trailing newline
std::ifstream fs;
fs.open(file.c_str());
if (fs.fail()) {
return getResult(errno);
}
fs >> val;
if (fs.fail()) {
fs.close();
return getResult(errno);
}
fs.close();
return ZE_RESULT_SUCCESS;
}
ze_result_t FsAccess::read(const std::string file, std::string &val) {
// Read a single line from text file without trailing newline
std::ifstream fs;
val.clear();
fs.open(file.c_str());
if (fs.fail()) {
return getResult(errno);
}
fs >> val;
if (fs.fail()) {
fs.close();
return getResult(errno);
}
fs.close();
// Strip trailing newline
if (val.back() == '\n') {
val.pop_back();
}
return ZE_RESULT_SUCCESS;
}
ze_result_t FsAccess::read(const std::string file, std::vector<std::string> &val) {
// Read a entire text file, one line per vector entry
std::string line;
std::ifstream fs;
val.clear();
fs.open(file.c_str());
if (fs.fail()) {
return getResult(errno);
}
while (std::getline(fs, line)) {
if (fs.fail()) {
fs.close();
return getResult(errno);
}
if (line.back() == '\n') {
line.pop_back();
}
val.push_back(line);
}
fs.close();
return ZE_RESULT_SUCCESS;
}
ze_result_t FsAccess::write(const std::string file, const std::string val) {
std::ofstream sysfs;
sysfs.open(file.c_str());
if (sysfs.fail()) {
return getResult(errno);
}
sysfs << val << std::endl;
if (sysfs.fail()) {
sysfs.close();
return getResult(errno);
}
sysfs.close();
return ZE_RESULT_SUCCESS;
}
ze_result_t FsAccess::canRead(const std::string file) {
if (access(file.c_str(), F_OK)) {
return ZE_RESULT_ERROR_UNKNOWN;
}
if (access(file.c_str(), R_OK)) {
return ZE_RESULT_ERROR_INSUFFICIENT_PERMISSIONS;
}
return ZE_RESULT_SUCCESS;
}
ze_result_t FsAccess::canWrite(const std::string file) {
if (access(file.c_str(), F_OK)) {
return ZE_RESULT_ERROR_UNKNOWN;
}
if (access(file.c_str(), W_OK)) {
return ZE_RESULT_ERROR_INSUFFICIENT_PERMISSIONS;
}
return ZE_RESULT_SUCCESS;
}
ze_result_t FsAccess::getFileMode(const std::string file, ::mode_t &mode) {
struct stat sb;
if (0 != stat(file.c_str(), &sb)) {
return getResult(errno);
}
mode = sb.st_mode;
return ZE_RESULT_SUCCESS;
}
ze_result_t FsAccess::readSymLink(const std::string path, std::string &val) {
// returns the value of symlink at path
char buf[PATH_MAX];
ssize_t len = ::readlink(path.c_str(), buf, PATH_MAX - 1);
if (len < 0) {
return getResult(errno);
}
buf[len] = '\0';
val = std::string(buf);
return ZE_RESULT_SUCCESS;
}
ze_result_t FsAccess::getRealPath(const std::string path, std::string &val) {
// returns the real file path after resolving all symlinks in path
char buf[PATH_MAX];
char *realPath = ::realpath(path.c_str(), buf);
if (!realPath) {
return getResult(errno);
}
val = std::string(buf);
return ZE_RESULT_SUCCESS;
}
ze_result_t FsAccess::listDirectory(const std::string path, std::vector<std::string> &list) {
list.clear();
::DIR *procDir = ::opendir(path.c_str());
if (!procDir) {
return getResult(errno);
}
struct ::dirent *ent;
while (NULL != (ent = ::readdir(procDir))) {
// Ignore . and ..
std::string name = std::string(ent->d_name);
if (!name.compare(".") || !name.compare("..")) {
continue;
}
list.push_back(std::string(ent->d_name));
}
::closedir(procDir);
// Check if in above while loop, readdir encountered any error.
if ((errno != 0) && (errno != ENOENT)) {
list.clear();
return getResult(errno);
}
return ZE_RESULT_SUCCESS;
}
std::string FsAccess::getBaseName(const std::string path) {
size_t pos = path.rfind("/");
if (std::string::npos == pos) {
return path;
}
return path.substr(pos + 1, std::string::npos);
}
std::string FsAccess::getDirName(const std::string path) {
size_t pos = path.rfind("/");
if (std::string::npos == pos) {
return std::string("");
}
// Include trailing slash
return path.substr(0, pos);
}
bool FsAccess::fileExists(const std::string file) {
struct stat sb;
if (stat(file.c_str(), &sb) == 0) {
return true;
}
return false;
}
// Procfs Access
const std::string ProcfsAccess::procDir = "/proc/";
const std::string ProcfsAccess::fdDir = "/fd/";
std::string ProcfsAccess::fullPath(const ::pid_t pid) {
// Returns the full path for proc entry for process pid
return std::string(procDir + std::to_string(pid));
}
std::string ProcfsAccess::fdDirPath(const ::pid_t pid) {
// Returns the full path to file descritpor directory
// for process pid
return std::string(fullPath(pid) + fdDir);
}
std::string ProcfsAccess::fullFdPath(const ::pid_t pid, const int fd) {
// Returns the full path for filedescriptor fd
// for process pid
return std::string(fdDirPath(pid) + std::to_string(fd));
}
ProcfsAccess *ProcfsAccess::create() {
return new ProcfsAccess();
}
ze_result_t ProcfsAccess::listProcesses(std::vector<::pid_t> &list) {
// Returns a vector with all the active process ids in the system
list.clear();
std::vector<std::string> dir;
ze_result_t result = FsAccess::listDirectory(procDir, dir);
if (ZE_RESULT_SUCCESS != result) {
return result;
}
for (auto &&file : dir) {
::pid_t pid;
std::istringstream stream(file);
stream >> pid;
if (stream.fail()) {
// Non numeric filename, not a process, skip
continue;
}
list.push_back(pid);
}
return ZE_RESULT_SUCCESS;
}
ze_result_t ProcfsAccess::getFileDescriptors(const ::pid_t pid, std::vector<int> &list) {
// Returns a vector with all the filedescriptor numbers opened by a pid
list.clear();
std::vector<std::string> dir;
ze_result_t result = FsAccess::listDirectory(fdDirPath(pid), dir);
if (ZE_RESULT_SUCCESS != result) {
return result;
}
for (auto &&file : dir) {
int fd;
std::istringstream stream(file);
stream >> fd;
if (stream.fail()) {
// Non numeric filename, not a file descriptor
continue;
}
list.push_back(fd);
}
return ZE_RESULT_SUCCESS;
}
ze_result_t ProcfsAccess::getFileName(const ::pid_t pid, const int fd, std::string &val) {
// Given a process id and a file descriptor number
// return full name of the open file.
// NOTE: For sockets, the name will be of the format "socket:[nnnnnnn]"
return FsAccess::readSymLink(fullFdPath(pid, fd), val);
}
::pid_t ProcfsAccess::myProcessId() {
return ::getpid();
}
// Sysfs Access
const std::string SysfsAccess::drmPath = "/sys/class/drm/";
const std::string SysfsAccess::devicesPath = "device/drm/";
const std::string SysfsAccess::primaryDevName = "card";
const std::string SysfsAccess::drmDriverDevNodeDir = "/dev/dri/";
const std::string SysfsAccess::intelGpuBindEntry = "/sys/bus/pci/drivers/i915/bind";
const std::string SysfsAccess::intelGpuUnbindEntry = "/sys/bus/pci/drivers/i915/unbind";
std::string SysfsAccess::fullPath(const std::string file) {
// Prepend sysfs directory path for this device
return std::string(dirname + file);
}
SysfsAccess::SysfsAccess(const std::string dev) {
// dev could be either /dev/dri/cardX or /dev/dri/renderDX
std::string fileName = FsAccess::getBaseName(dev);
std::string devicesDir = drmPath + fileName + std::string("/") + devicesPath;
FsAccess::listDirectory(devicesDir, deviceNames);
for (auto &&next : deviceNames) {
if (!next.compare(0, primaryDevName.length(), primaryDevName)) {
dirname = drmPath + next + std::string("/");
break;
}
}
}
SysfsAccess *SysfsAccess::create(const std::string dev) {
return new SysfsAccess(dev);
}
ze_result_t SysfsAccess::canRead(const std::string file) {
// Prepend sysfs directory path and call the base canRead
return FsAccess::canRead(fullPath(file));
}
ze_result_t SysfsAccess::canWrite(const std::string file) {
// Prepend sysfs directory path and call the base canWrite
return FsAccess::canWrite(fullPath(file));
}
ze_result_t SysfsAccess::getFileMode(const std::string file, ::mode_t &mode) {
// Prepend sysfs directory path and call the base getFileMode
return FsAccess::getFileMode(fullPath(file), mode);
}
ze_result_t SysfsAccess::read(const std::string file, std::string &val) {
// Prepend sysfs directory path and call the base read
return FsAccess::read(fullPath(file).c_str(), val);
}
ze_result_t SysfsAccess::read(const std::string file, int &val) {
std::string str;
ze_result_t result;
result = FsAccess::read(fullPath(file), str);
if (ZE_RESULT_SUCCESS != result) {
return result;
}
std::istringstream stream(str);
stream >> val;
if (stream.fail()) {
return ZE_RESULT_ERROR_UNKNOWN;
}
return ZE_RESULT_SUCCESS;
}
ze_result_t SysfsAccess::read(const std::string file, uint32_t &val) {
std::string str;
ze_result_t result;
result = FsAccess::read(fullPath(file), str);
if (ZE_RESULT_SUCCESS != result) {
return result;
}
std::istringstream stream(str);
stream >> val;
if (stream.fail()) {
return ZE_RESULT_ERROR_UNKNOWN;
}
return ZE_RESULT_SUCCESS;
}
ze_result_t SysfsAccess::read(const std::string file, double &val) {
std::string str;
ze_result_t result;
result = FsAccess::read(fullPath(file), str);
if (ZE_RESULT_SUCCESS != result) {
return result;
}
std::istringstream stream(str);
stream >> val;
if (stream.fail()) {
return ZE_RESULT_ERROR_UNKNOWN;
}
return ZE_RESULT_SUCCESS;
}
ze_result_t SysfsAccess::read(const std::string file, uint64_t &val) {
std::string str;
ze_result_t result;
result = FsAccess::read(fullPath(file), str);
if (ZE_RESULT_SUCCESS != result) {
return result;
}
std::istringstream stream(str);
stream >> val;
if (stream.fail()) {
return ZE_RESULT_ERROR_UNKNOWN;
}
return ZE_RESULT_SUCCESS;
}
ze_result_t SysfsAccess::read(const std::string file, std::vector<std::string> &val) {
// Prepend sysfs directory path and call the base read
return FsAccess::read(fullPath(file), val);
}
ze_result_t SysfsAccess::write(const std::string file, const std::string val) {
// Prepend sysfs directory path and call the base write
return FsAccess::write(fullPath(file).c_str(), val);
}
ze_result_t SysfsAccess::write(const std::string file, const int val) {
std::ostringstream stream;
stream << val;
if (stream.fail()) {
return ZE_RESULT_ERROR_UNKNOWN;
}
return FsAccess::write(fullPath(file), stream.str());
}
ze_result_t SysfsAccess::write(const std::string file, const double val) {
std::ostringstream stream;
stream << val;
if (stream.fail()) {
return ZE_RESULT_ERROR_UNKNOWN;
}
return FsAccess::write(fullPath(file), stream.str());
}
ze_result_t SysfsAccess::write(const std::string file, const uint64_t val) {
std::ostringstream stream;
stream << val;
if (stream.fail()) {
return ZE_RESULT_ERROR_UNKNOWN;
}
return FsAccess::write(fullPath(file), stream.str());
}
ze_result_t SysfsAccess::scanDirEntries(const std::string path, std::vector<std::string> &list) {
list.clear();
return FsAccess::listDirectory(fullPath(path).c_str(), list);
}
ze_result_t SysfsAccess::readSymLink(const std::string path, std::string &val) {
// Prepend sysfs directory path and call the base readSymLink
return FsAccess::readSymLink(fullPath(path).c_str(), val);
}
ze_result_t SysfsAccess::getRealPath(const std::string path, std::string &val) {
// Prepend sysfs directory path and call the base getRealPath
return FsAccess::getRealPath(fullPath(path).c_str(), val);
}
ze_result_t SysfsAccess::bindDevice(std::string device) {
return FsAccess::write(intelGpuBindEntry, device);
}
ze_result_t SysfsAccess::unbindDevice(std::string device) {
return FsAccess::write(intelGpuUnbindEntry, device);
}
bool SysfsAccess::fileExists(const std::string file) {
// Prepend sysfs directory path and call the base fileExists
return FsAccess::fileExists(fullPath(file).c_str());
}
ze_bool_t SysfsAccess::isMyDeviceFile(const std::string dev) {
// dev is a full pathname.
if (getDirName(dev).compare(drmDriverDevNodeDir)) {
for (auto &&next : deviceNames) {
if (!getBaseName(dev).compare(next)) {
return true;
}
}
}
return false;
}
} // namespace L0