blob: 4c0818594acb4889c74c178aacb5542b91425124 [file] [log] [blame] [edit]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "swap_management/status.h"
#include "swap_management/utils.h"
#include <fcntl.h>
#include <limits>
#include <utility>
#include <absl/strings/numbers.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/rand_util.h>
#include <base/strings/string_number_conversions.h>
#include <brillo/files/file_util.h>
#include <brillo/process/process.h>
#include <sys/mount.h>
namespace swap_management {
Utils* Utils::Get() {
return *GetSingleton<Utils>();
}
void Utils::OverrideForTesting(Utils* util) {
[[maybe_unused]] static bool is_overridden = []() -> bool {
if (*GetSingleton<Utils>())
delete *GetSingleton<Utils>();
return true;
}();
*GetSingleton<Utils>() = util;
}
// Helper function to run binary.
// On success, store stdout in |output| and return absl::OkStatus()
// On failure, return corresponding absl error based on errno and append stderr.
absl::Status Utils::RunProcessHelper(const std::vector<std::string>& commands,
std::string* output) {
if (commands.empty())
return absl::InvalidArgumentError("Empty input for RunProcessHelper.");
brillo::ProcessImpl process;
for (auto& com : commands)
process.AddArg(com);
process.RedirectOutputToMemory(true);
if (process.Run() != EXIT_SUCCESS)
return ErrnoToStatus(errno, process.GetOutputString(STDOUT_FILENO));
*output = process.GetOutputString(STDOUT_FILENO);
return absl::OkStatus();
}
// Same as the previous one, but log stdout instead of send it back.
absl::Status Utils::RunProcessHelper(const std::vector<std::string>& commands) {
std::string output;
absl::Status status = absl::OkStatus();
status = RunProcessHelper(commands, &output);
if (!status.ok())
return status;
if (!output.empty())
LOG(INFO) << commands[0] << ": " << output;
return absl::OkStatus();
}
absl::Status Utils::WriteFile(const base::FilePath& path,
const std::string& data) {
if (!base::WriteFile(path, data))
return ErrnoToStatus(errno, "Failed to write " + path.value());
return absl::OkStatus();
}
absl::Status Utils::ReadFileToStringWithMaxSize(const base::FilePath& path,
std::string* contents,
size_t max_size) {
if (!base::ReadFileToStringWithMaxSize(path, contents, max_size))
return ErrnoToStatus(errno, "Failed to read " + path.value());
return absl::OkStatus();
}
absl::Status Utils::ReadFileToString(const base::FilePath& path,
std::string* contents) {
return ReadFileToStringWithMaxSize(path, contents,
std::numeric_limits<size_t>::max());
}
absl::Status Utils::DeleteFile(const base::FilePath& path) {
if (!brillo::DeleteFile(path))
return ErrnoToStatus(errno, "Failed to delete " + path.value());
return absl::OkStatus();
}
absl::Status Utils::PathExists(const base::FilePath& path) {
if (!base::PathExists(path))
return ErrnoToStatus(errno, path.value() + " does not exist.");
return absl::OkStatus();
}
// Extend file at |path| to the size |size|.
absl::Status Utils::Fallocate(const base::FilePath& path, size_t size) {
absl::Status status = absl::OkStatus();
base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_WRITE);
if (HANDLE_EINTR(fallocate(file.GetPlatformFile(), 0, 0,
static_cast<off_t>(size))) == -1)
status = ErrnoToStatus(errno, "Can not extend " + path.value() +
" to size " + std::to_string(size));
file.Close();
return status;
}
absl::Status Utils::CreateDirectory(const base::FilePath& path) {
if (!base::CreateDirectory(path))
return ErrnoToStatus(errno, "Can not create " + path.value());
return absl::OkStatus();
}
absl::Status Utils::SetPosixFilePermissions(const base::FilePath& path,
int mode) {
if (!base::SetPosixFilePermissions(path, mode))
return ErrnoToStatus(errno, "Failed to set permission for " + path.value() +
" to " + std::to_string(mode));
return absl::OkStatus();
}
absl::Status Utils::Mount(const std::string& source,
const std::string& target,
const std::string& fs_type,
uint64_t mount_flags,
const std::string& data) {
if (mount(source.c_str(), target.c_str(), fs_type.c_str(), mount_flags,
data.c_str()) == -1)
return ErrnoToStatus(errno, "Failed to mount " + target);
return absl::OkStatus();
}
absl::Status Utils::Umount(const std::string& target) {
if (umount(target.c_str()) == -1)
return ErrnoToStatus(errno, "Failed to umount " + target);
return absl::OkStatus();
}
absl::StatusOr<struct statfs> Utils::GetStatfs(const std::string& path) {
struct statfs sf = {};
if (statfs(path.c_str(), &sf) == -1)
return ErrnoToStatus(errno, "Failed to read statfs for " + path);
return std::move(sf);
}
absl::StatusOr<std::string> Utils::GenerateRandHex(size_t size) {
std::string random_bytes = base::RandBytesAsString(size);
if (random_bytes.size() != size)
return ErrnoToStatus(errno, " Failed to generate random hex with size" +
std::to_string(size));
return base::HexEncode(random_bytes.data(), random_bytes.size());
}
absl::StatusOr<base::SystemMemoryInfoKB> Utils::GetSystemMemoryInfo() {
base::SystemMemoryInfoKB meminfo;
if (!base::GetSystemMemoryInfo(&meminfo))
return absl::NotFoundError("Could not get MemTotal in /proc/meminfo");
return std::move(meminfo);
}
// Round up multiple will round the first argument |number| up to the next
// multiple of the second argument |alignment|.
uint64_t Utils::RoundupMultiple(uint64_t number, uint64_t alignment) {
return ((number + (alignment - 1)) / alignment) * alignment;
}
absl::StatusOr<bool> Utils::SimpleAtob(const std::string& str) {
bool output;
if (!absl::SimpleAtob(str, &output))
return absl::InvalidArgumentError("Failed to convert " + str +
" to boolean.");
return output;
}
const base::FilePath ScopedFilePathTraits::InvalidValue() {
return base::FilePath();
}
void ScopedFilePathTraits::Free(const base::FilePath path) {
absl::Status status = Utils::Get()->DeleteFile(path);
LOG_IF(ERROR, !status.ok()) << status;
}
absl::StatusOr<double> Utils::SimpleAtod(const std::string& str) {
double output;
if (!absl::SimpleAtod(str, &output))
return absl::InvalidArgumentError("Failed to convert " + str +
" to double.");
return output;
}
} // namespace swap_management