blob: d8a2f8bf7a7e916cdeb28f607d2823279596cd3a [file] [log] [blame]
// Copyright 2021 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "spaced/disk_usage_impl.h"
#include <algorithm>
#include <memory>
#include <optional>
#include <string>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/posix/eintr_wrapper.h>
#include <base/strings/string_util.h>
#include <rootdev/rootdev.h>
namespace spaced {
DiskUsageUtilImpl::DiskUsageUtilImpl(const base::FilePath& rootdev,
std::optional<brillo::Thinpool> thinpool)
: rootdev_(rootdev), thinpool_(thinpool) {}
int DiskUsageUtilImpl::StatVFS(const base::FilePath& path, struct statvfs* st) {
return HANDLE_EINTR(statvfs(path.value().c_str(), st));
}
int64_t DiskUsageUtilImpl::GetFreeDiskSpace(const base::FilePath& path) {
// Use statvfs() to get the free space for the given path.
struct statvfs stat;
if (StatVFS(path, &stat) != 0) {
PLOG(ERROR) << "Failed to run statvfs() on " << path;
return -1;
}
int64_t free_disk_space = static_cast<int64_t>(stat.f_bavail) * stat.f_frsize;
return free_disk_space;
}
int64_t DiskUsageUtilImpl::GetTotalDiskSpace(const base::FilePath& path) {
// Use statvfs() to get the total space for the given path.
struct statvfs stat;
if (StatVFS(path, &stat) != 0) {
PLOG(ERROR) << "Failed to run statvfs() on " << path;
return -1;
}
int64_t total_disk_space =
static_cast<int64_t>(stat.f_blocks) * stat.f_frsize;
int64_t thinpool_total_space;
if (thinpool_ && thinpool_->IsValid() &&
thinpool_->GetTotalSpace(&thinpool_total_space)) {
total_disk_space = std::min(total_disk_space, thinpool_total_space);
}
return total_disk_space;
}
int64_t DiskUsageUtilImpl::GetBlockDeviceSize(const base::FilePath& device) {
base::ScopedFD fd(HANDLE_EINTR(
open(device.value().c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
if (!fd.is_valid()) {
PLOG(ERROR) << "open " << device.value();
return -1;
}
int64_t size;
if (ioctl(fd.get(), BLKGETSIZE64, &size)) {
PLOG(ERROR) << "ioctl(BLKGETSIZE): " << device.value();
return -1;
}
return size;
}
int64_t DiskUsageUtilImpl::GetRootDeviceSize() {
if (rootdev_.empty()) {
LOG(WARNING) << "Failed to get root device";
return -1;
}
return GetBlockDeviceSize(rootdev_);
}
} // namespace spaced