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