blob: 4efb1413c7dad19ad5a329c27af0c27b05a63634 [file] [log] [blame]
Austin Schuhc979f7c2024-03-02 16:49:20 -08001#include <sys/statvfs.h>
2
3#include "absl/strings/str_split.h"
4#include "gflags/gflags.h"
5
6#include "aos/events/shm_event_loop.h"
7#include "aos/init.h"
8#include "aos/util/filesystem_generated.h"
9
10DEFINE_string(config, "aos_config.json", "File path of aos configuration");
11
12namespace aos::util {
13namespace {
14std::optional<std::string> ReadShortFile(std::string_view file_name) {
15 // Open as input and seek to end immediately.
16 std::ifstream file(std::string(file_name), std::ios_base::in);
17 if (!file.good()) {
18 VLOG(1) << "Can't read " << file_name;
19 return std::nullopt;
20 }
21 const size_t kMaxLineLength = 4096;
22 char buffer[kMaxLineLength];
23 file.read(buffer, kMaxLineLength);
24 if (!file.eof()) {
25 return std::nullopt;
26 }
27 return std::string(buffer, file.gcount());
28}
29} // namespace
30
31// Periodically sends out the Filesystems message with filesystem utilization
32// info.
33class FilesystemMonitor {
34 public:
35 FilesystemMonitor(aos::EventLoop *event_loop)
36 : event_loop_(event_loop),
37 sender_(event_loop_->MakeSender<FilesystemStatus>("/aos")) {
38 periodic_timer_ =
39 event_loop_->AddTimer([this]() { PublishFilesystemStatus(); });
40 event_loop_->OnRun([this]() {
41 periodic_timer_->Schedule(event_loop_->monotonic_now(),
42 std::chrono::seconds(5));
43 });
44 }
45
46 private:
47 void PublishFilesystemStatus() {
48 aos::Sender<FilesystemStatus>::Builder builder = sender_.MakeBuilder();
49
50 std::optional<std::string> contents = ReadShortFile("/proc/self/mountinfo");
51
52 CHECK(contents.has_value());
53
54 std::vector<flatbuffers::Offset<Filesystem>> filesystems;
55
56 // Iterate through /proc/self/mounts to find all the filesystems.
57 for (std::string_view line :
58 absl::StrSplit(std::string_view(contents->c_str(), contents->size()),
59 '\n', absl::SkipWhitespace())) {
60 // See https://www.kernel.org/doc/Documentation/filesystems/proc.txt for
61 // the format.
62 std::vector<std::string_view> elements =
63 absl::StrSplit(line, ' ', absl::SkipWhitespace());
64
65 // First thing after - is the filesystem type.
66 size_t i = 6;
67 while (elements[i] != "-") {
68 ++i;
69 CHECK_LT(i + 1, elements.size());
70 }
71
72 // Mount point is the 4th element.
73 std::string mount_point(elements[4]);
74 std::string_view type = elements[i + 1];
75
76 // Ignore filesystems without reasonable types.
77 if (type != "ext2" && type != "xfs" && type != "vfat" && type != "ext3" &&
78 type != "ext4" && type != "tmpfs" && type != "devtmpfs") {
79 continue;
80 }
81 VLOG(1) << mount_point << ", type " << type;
82
83 struct statvfs info;
84
85 PCHECK(statvfs(mount_point.c_str(), &info) == 0);
86
87 VLOG(1) << "overall size: " << info.f_frsize * info.f_blocks << ", free "
88 << info.f_bfree * info.f_bsize << ", inodes " << info.f_files
89 << ", free " << info.f_ffree;
90
91 flatbuffers::Offset<flatbuffers::String> path_offset =
92 builder.fbb()->CreateString(mount_point);
93 flatbuffers::Offset<flatbuffers::String> type_offset =
94 builder.fbb()->CreateString(type);
95 Filesystem::Builder filesystem_builder =
96 builder.MakeBuilder<Filesystem>();
97 filesystem_builder.add_path(path_offset);
98 filesystem_builder.add_type(type_offset);
99 filesystem_builder.add_overall_space(info.f_frsize * info.f_blocks);
100 filesystem_builder.add_free_space(info.f_bfree * info.f_bsize);
101 filesystem_builder.add_overall_inodes(info.f_files);
102 filesystem_builder.add_free_inodes(info.f_ffree);
103
104 filesystems.emplace_back(filesystem_builder.Finish());
105 }
106
107 flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Filesystem>>>
108 filesystems_offset = builder.fbb()->CreateVector(filesystems);
109
110 FilesystemStatus::Builder filesystem_status_builder =
111 builder.MakeBuilder<FilesystemStatus>();
112
113 filesystem_status_builder.add_filesystems(filesystems_offset);
114
115 (void)builder.Send(filesystem_status_builder.Finish());
116 }
117
118 aos::EventLoop *event_loop_;
119
120 aos::Sender<FilesystemStatus> sender_;
121
122 aos::TimerHandler *periodic_timer_;
123};
124
125} // namespace aos::util
126
127int main(int argc, char **argv) {
128 aos::InitGoogle(&argc, &argv);
129
130 aos::FlatbufferDetachedBuffer<aos::Configuration> config =
131 aos::configuration::ReadConfig(FLAGS_config);
132
133 aos::ShmEventLoop shm_event_loop(&config.message());
134
135 aos::util::FilesystemMonitor filesystem_monitor(&shm_event_loop);
136
137 shm_event_loop.Run();
138
139 return 0;
140}