2021-09-21 19:27:42 +00:00
|
|
|
#include "modules/fs.hpp"
|
|
|
|
|
2016-11-13 05:09:51 +00:00
|
|
|
#include <sys/statvfs.h>
|
2021-09-21 19:27:42 +00:00
|
|
|
|
2017-01-12 22:31:52 +00:00
|
|
|
#include <fstream>
|
2022-03-02 13:58:47 +00:00
|
|
|
#include <utility>
|
2016-11-20 22:04:31 +00:00
|
|
|
|
2016-11-19 14:49:03 +00:00
|
|
|
#include "drawtypes/label.hpp"
|
|
|
|
#include "drawtypes/progressbar.hpp"
|
|
|
|
#include "drawtypes/ramp.hpp"
|
2021-09-21 19:27:42 +00:00
|
|
|
#include "modules/meta/base.inl"
|
2016-11-13 05:09:51 +00:00
|
|
|
#include "utils/math.hpp"
|
|
|
|
#include "utils/string.hpp"
|
|
|
|
|
2016-11-19 05:22:44 +00:00
|
|
|
POLYBAR_NS
|
2016-11-13 05:09:51 +00:00
|
|
|
|
2017-01-12 22:31:52 +00:00
|
|
|
// Columns in /proc/self/mountinfo
|
|
|
|
#define MOUNTINFO_DIR 4
|
|
|
|
#define MOUNTINFO_TYPE 7
|
|
|
|
#define MOUNTINFO_FSNAME 8
|
|
|
|
|
2016-11-13 05:09:51 +00:00
|
|
|
namespace modules {
|
2016-11-20 22:04:31 +00:00
|
|
|
template class module<fs_module>;
|
|
|
|
|
2016-11-13 05:09:51 +00:00
|
|
|
/**
|
|
|
|
* Bootstrap the module by reading config values and
|
|
|
|
* setting up required components
|
|
|
|
*/
|
2016-12-21 07:00:09 +00:00
|
|
|
fs_module::fs_module(const bar_settings& bar, string name_) : timer_module<fs_module>(bar, move(name_)) {
|
2022-05-02 10:54:03 +00:00
|
|
|
m_mountpoints = m_conf.get_list(name(), "mount", {});
|
|
|
|
if (m_mountpoints.empty()) {
|
|
|
|
m_log.info("%s: No mountpoints specified, using fallback \"/\"", name());
|
|
|
|
m_mountpoints.emplace_back("/");
|
|
|
|
}
|
2016-12-30 21:44:28 +00:00
|
|
|
m_remove_unmounted = m_conf.get(name(), "remove-unmounted", m_remove_unmounted);
|
2020-12-02 14:55:13 +00:00
|
|
|
m_perc_used_warn = m_conf.get(name(), "warn-percentage", 90);
|
2016-12-30 21:44:28 +00:00
|
|
|
m_fixed = m_conf.get(name(), "fixed-values", m_fixed);
|
|
|
|
m_spacing = m_conf.get(name(), "spacing", m_spacing);
|
2020-12-05 21:58:38 +00:00
|
|
|
set_interval(30s);
|
2016-11-13 05:09:51 +00:00
|
|
|
|
|
|
|
// Add formats and elements
|
|
|
|
m_formatter->add(
|
|
|
|
FORMAT_MOUNTED, TAG_LABEL_MOUNTED, {TAG_LABEL_MOUNTED, TAG_BAR_FREE, TAG_BAR_USED, TAG_RAMP_CAPACITY});
|
2020-12-02 14:55:13 +00:00
|
|
|
m_formatter->add_optional(FORMAT_WARN, {TAG_LABEL_WARN, TAG_BAR_FREE, TAG_BAR_USED, TAG_RAMP_CAPACITY});
|
2016-11-13 05:40:35 +00:00
|
|
|
m_formatter->add(FORMAT_UNMOUNTED, TAG_LABEL_UNMOUNTED, {TAG_LABEL_UNMOUNTED});
|
2016-11-13 05:09:51 +00:00
|
|
|
|
2016-11-25 12:55:15 +00:00
|
|
|
if (m_formatter->has(TAG_LABEL_MOUNTED)) {
|
2017-01-13 19:03:08 +00:00
|
|
|
m_labelmounted = load_optional_label(m_conf, name(), TAG_LABEL_MOUNTED, "%mountpoint% %percentage_free%%");
|
2016-11-25 12:55:15 +00:00
|
|
|
}
|
2020-12-02 14:55:13 +00:00
|
|
|
if (m_formatter->has(TAG_LABEL_WARN)) {
|
|
|
|
m_labelwarn = load_optional_label(m_conf, name(), TAG_LABEL_WARN, "%mountpoint% %percentage_free%%");
|
|
|
|
}
|
2016-11-25 12:55:15 +00:00
|
|
|
if (m_formatter->has(TAG_LABEL_UNMOUNTED)) {
|
2016-11-13 05:09:51 +00:00
|
|
|
m_labelunmounted = load_optional_label(m_conf, name(), TAG_LABEL_UNMOUNTED, "%mountpoint% is not mounted");
|
2016-11-25 12:55:15 +00:00
|
|
|
}
|
|
|
|
if (m_formatter->has(TAG_BAR_FREE)) {
|
2016-11-13 05:09:51 +00:00
|
|
|
m_barfree = load_progressbar(m_bar, m_conf, name(), TAG_BAR_FREE);
|
2016-11-25 12:55:15 +00:00
|
|
|
}
|
|
|
|
if (m_formatter->has(TAG_BAR_USED)) {
|
2016-11-13 05:09:51 +00:00
|
|
|
m_barused = load_progressbar(m_bar, m_conf, name(), TAG_BAR_USED);
|
2016-11-25 12:55:15 +00:00
|
|
|
}
|
|
|
|
if (m_formatter->has(TAG_RAMP_CAPACITY)) {
|
2016-11-13 05:09:51 +00:00
|
|
|
m_rampcapacity = load_ramp(m_conf, name(), TAG_RAMP_CAPACITY);
|
2016-11-25 12:55:15 +00:00
|
|
|
}
|
2016-12-30 21:44:28 +00:00
|
|
|
|
|
|
|
// Warn about "unreachable" format tag
|
|
|
|
if (m_formatter->has(TAG_LABEL_UNMOUNTED) && m_remove_unmounted) {
|
|
|
|
m_log.warn("%s: Defined format tag \"%s\" will never be used (reason: `remove-unmounted = true`)", name(),
|
2019-05-16 00:42:29 +00:00
|
|
|
string{TAG_LABEL_UNMOUNTED});
|
2016-12-30 21:44:28 +00:00
|
|
|
}
|
2016-11-13 05:09:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-01-12 22:31:52 +00:00
|
|
|
* Update mountpoints
|
2016-11-13 05:09:51 +00:00
|
|
|
*/
|
|
|
|
bool fs_module::update() {
|
2016-11-13 07:50:00 +00:00
|
|
|
m_mounts.clear();
|
2016-11-13 05:09:51 +00:00
|
|
|
|
2017-01-12 22:31:52 +00:00
|
|
|
vector<vector<string>> mountinfo;
|
|
|
|
std::ifstream filestream("/proc/self/mountinfo");
|
|
|
|
string line;
|
2017-01-08 19:42:35 +00:00
|
|
|
|
2017-01-12 22:31:52 +00:00
|
|
|
// Get details for mounted filesystems
|
|
|
|
while (std::getline(filestream, line)) {
|
|
|
|
auto cols = string_util::split(line, ' ');
|
|
|
|
if (std::find(m_mountpoints.begin(), m_mountpoints.end(), cols[MOUNTINFO_DIR]) != m_mountpoints.end()) {
|
|
|
|
mountinfo.emplace_back(move(cols));
|
2016-11-13 05:09:51 +00:00
|
|
|
}
|
2017-01-12 22:31:52 +00:00
|
|
|
}
|
2016-11-13 05:09:51 +00:00
|
|
|
|
2017-01-12 22:31:52 +00:00
|
|
|
// Get data for defined mountpoints
|
|
|
|
for (auto&& mountpoint : m_mountpoints) {
|
2021-09-21 19:27:42 +00:00
|
|
|
auto details = std::find_if(mountinfo.begin(), mountinfo.end(),
|
|
|
|
[&](const vector<string>& m) { return m.size() > 4 && m[MOUNTINFO_DIR] == mountpoint; });
|
2016-11-13 05:09:51 +00:00
|
|
|
|
2021-02-15 22:32:56 +00:00
|
|
|
m_mounts.emplace_back(std::make_unique<fs_mount>(mountpoint, details != mountinfo.end()));
|
2017-01-12 22:31:52 +00:00
|
|
|
struct statvfs buffer {};
|
|
|
|
|
|
|
|
if (!m_mounts.back()->mounted) {
|
|
|
|
m_log.warn("%s: Mountpoint %s is not mounted", name(), mountpoint);
|
|
|
|
} else if (statvfs(mountpoint.c_str(), &buffer) == -1) {
|
|
|
|
m_log.err("%s: Failed to query filesystem (statvfs() error: %s)", name(), strerror(errno));
|
|
|
|
} else {
|
|
|
|
auto& mount = m_mounts.back();
|
|
|
|
mount->mountpoint = details->at(MOUNTINFO_DIR);
|
|
|
|
mount->type = details->at(MOUNTINFO_TYPE);
|
|
|
|
mount->fsname = details->at(MOUNTINFO_FSNAME);
|
2016-11-13 05:09:51 +00:00
|
|
|
|
2020-02-21 14:39:39 +00:00
|
|
|
// see: https://en.cppreference.com/w/cpp/filesystem/space
|
2019-03-18 17:16:42 +00:00
|
|
|
mount->bytes_total = static_cast<uint64_t>(buffer.f_frsize) * static_cast<uint64_t>(buffer.f_blocks);
|
|
|
|
mount->bytes_free = static_cast<uint64_t>(buffer.f_frsize) * static_cast<uint64_t>(buffer.f_bfree);
|
2017-09-07 00:06:55 +00:00
|
|
|
mount->bytes_used = mount->bytes_total - mount->bytes_free;
|
2019-03-18 17:16:42 +00:00
|
|
|
mount->bytes_avail = static_cast<uint64_t>(buffer.f_frsize) * static_cast<uint64_t>(buffer.f_bavail);
|
2017-01-12 22:31:52 +00:00
|
|
|
|
2021-02-15 22:32:56 +00:00
|
|
|
mount->percentage_free =
|
|
|
|
math_util::percentage<double>(mount->bytes_avail, mount->bytes_used + mount->bytes_avail);
|
|
|
|
mount->percentage_used =
|
|
|
|
math_util::percentage<double>(mount->bytes_used, mount->bytes_used + mount->bytes_avail);
|
2016-11-13 05:09:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-30 21:44:28 +00:00
|
|
|
if (m_remove_unmounted) {
|
2021-02-15 22:32:56 +00:00
|
|
|
auto new_end =
|
|
|
|
std::stable_partition(m_mounts.begin(), m_mounts.end(), [](const auto& mount) { return mount->mounted; });
|
|
|
|
|
|
|
|
for (auto it = new_end; it < m_mounts.end(); ++it) {
|
|
|
|
m_log.info("%s: Removing mountpoint \"%s\" (reason: `remove-unmounted = true`)", name(), (*it)->mountpoint);
|
|
|
|
m_mountpoints.erase(
|
|
|
|
std::remove(m_mountpoints.begin(), m_mountpoints.end(), (*it)->mountpoint), m_mountpoints.end());
|
2016-12-30 21:44:28 +00:00
|
|
|
}
|
2021-02-15 22:32:56 +00:00
|
|
|
|
|
|
|
m_mounts.erase(new_end, m_mounts.end());
|
2016-12-30 21:44:28 +00:00
|
|
|
}
|
|
|
|
|
2016-11-13 05:09:51 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate the module output
|
|
|
|
*/
|
|
|
|
string fs_module::get_output() {
|
|
|
|
string output;
|
|
|
|
|
2016-12-30 21:44:28 +00:00
|
|
|
for (m_index = 0_z; m_index < m_mounts.size(); ++m_index) {
|
2021-07-10 20:08:49 +00:00
|
|
|
string mount_output = timer_module::get_output();
|
|
|
|
/*
|
|
|
|
* Add spacing before the mountpoint, but only if the mountpoint contents
|
|
|
|
* are not empty and there is already other content in the module.
|
|
|
|
*/
|
|
|
|
if (!output.empty() && !mount_output.empty()) {
|
Add units support (POINT, PIXEL, SPACE) (#2578)
* add units support (POINT, PIXEL, SPACE) for polybar
- add a size_with_unit struct
- add a geometry_format_values struct
- move dpi initialisation from renderer.cpp to bar.cpp
- add a string to size_with_unit converter
- add point support (with pt)
- add pixel support (with px)
* Fix unit test compilation
* clang-format
* Better names
The old names didn't really capture the purpose of the structs and
function.
space_type -> spacing_type
space_size -> spacing_val
size_type -> extent_type
geometry -> extent_val
geometry_format_values -> percentage_with_offset
* Remove parse_size_with_unit
No longer needed. The convert<spacing_val> function in config.cpp
already does all the work for us and always setting the type to pixel
was wrong.
In addition, line-size should not be of type spacing_val but extent_val.
* Cleanup
I tried to address most of my comments on the old PR
* Fix renderer width calculation
We can't just blindly add the x difference to the width because for
example the width should increase if x < width and the increase keeps
x < width.
Similarly, we can't just add the offset to the width.
* Rename geom_format_to_pixels to percentage_with_offset_to_pixel
* Cleanup
* Apply suggested changes from Patrick on GitHub
Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
* Update src/components/bar.cpp
Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
* Update src/components/config.cpp
Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
* Update src/components/builder.cpp
Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
* Update src/components/builder.cpp
Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
* config: Use stod for parsing percentage
* Use stof instead of strtof
* units: Fix test edge cases
* Remove unnecessary clang-format toggle
* Use percentage_with_offset for margin-{top,bottom}
* Support negative extent values
* Rename unit to units and create a cpp file
* Move percentage_with_offset_to_pixel unit test to units
* Add unit tests for units_utils
* Clarify when and how negative spacing/extent is allowed
Negative spacing is never allowed and produces a config error.
Extents allow negative values in theory, but only a few use-cases accept
it.
Only the extent value used for the `%{O}` tag and the offset value in
percentage_with_offset can be negative. Everything else is capped below
at 0.
The final pixel value of percentage_with_offset also caps below at 0.
* Fix parsing errors not being caught in config
* Print a proper error message for uncaught exceptions
* Cleanup module::get_output
All changes preserve the existing semantics
* Stop using remove_trailing_space in module::get_output
Instead, we first check if the current tag is built, and only if it is,
the spacing is prepended.
* Remove unused imports
* Restore old behavior
If there are two tags and the second one isn't built (module::build
returns false), the space in between them is removed.
For example in the mpd module:
format-online = <toggle> <label-song> foo
If mpd is not running, the mpd module will return false when trying to
build the `<label-song>` tag. If we don't remove the space between
`<toggle>` and `<label-song>`, we end up with two spaces between
`<toggle>` and `foo`.
This change is to match the old behavior where at least one trailing
space character was removed from the builder.
* Add changelog entry
* Remove unused setting
* Use percentage with offset for tray-offset
Co-authored-by: Jérôme BOULMIER <jerome.boulmier@outlook.fr>
Co-authored-by: Joe Groocock <github@frebib.net>
2022-02-20 20:08:57 +00:00
|
|
|
m_builder->spacing(m_spacing);
|
2021-07-10 20:08:49 +00:00
|
|
|
output += m_builder->flush();
|
2016-11-25 12:55:15 +00:00
|
|
|
}
|
2021-07-10 20:08:49 +00:00
|
|
|
output += mount_output;
|
2016-11-13 05:09:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return output;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Select format based on fs state
|
|
|
|
*/
|
|
|
|
string fs_module::get_format() const {
|
2020-12-02 14:55:13 +00:00
|
|
|
if (!m_mounts[m_index]->mounted) {
|
|
|
|
return FORMAT_UNMOUNTED;
|
|
|
|
}
|
|
|
|
if (m_mounts[m_index]->percentage_used >= m_perc_used_warn && m_formatter->has_format(FORMAT_WARN)) {
|
|
|
|
return FORMAT_WARN;
|
|
|
|
}
|
|
|
|
return FORMAT_MOUNTED;
|
2016-11-13 05:09:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Output content using configured format tags
|
|
|
|
*/
|
2016-11-25 12:55:15 +00:00
|
|
|
bool fs_module::build(builder* builder, const string& tag) const {
|
2016-11-13 07:50:00 +00:00
|
|
|
auto& mount = m_mounts[m_index];
|
2016-11-13 05:09:51 +00:00
|
|
|
|
2020-12-12 02:18:54 +00:00
|
|
|
auto replace_tokens = [&](const label_t& label) {
|
|
|
|
label->reset_tokens();
|
|
|
|
label->replace_token("%mountpoint%", mount->mountpoint);
|
|
|
|
label->replace_token("%type%", mount->type);
|
|
|
|
label->replace_token("%fsname%", mount->fsname);
|
|
|
|
label->replace_token("%percentage_free%", to_string(mount->percentage_free));
|
|
|
|
label->replace_token("%percentage_used%", to_string(mount->percentage_used));
|
|
|
|
label->replace_token(
|
|
|
|
"%total%", string_util::filesize(mount->bytes_total, m_fixed ? 2 : 0, m_fixed, m_bar.locale));
|
2021-09-21 19:27:42 +00:00
|
|
|
label->replace_token("%free%", string_util::filesize(mount->bytes_avail, m_fixed ? 2 : 0, m_fixed, m_bar.locale));
|
|
|
|
label->replace_token("%used%", string_util::filesize(mount->bytes_used, m_fixed ? 2 : 0, m_fixed, m_bar.locale));
|
2020-12-12 02:18:54 +00:00
|
|
|
};
|
|
|
|
|
2016-11-13 05:09:51 +00:00
|
|
|
if (tag == TAG_BAR_FREE) {
|
2016-11-13 07:50:00 +00:00
|
|
|
builder->node(m_barfree->output(mount->percentage_free));
|
2016-11-13 05:09:51 +00:00
|
|
|
} else if (tag == TAG_BAR_USED) {
|
2016-11-13 07:50:00 +00:00
|
|
|
builder->node(m_barused->output(mount->percentage_used));
|
2016-11-13 05:09:51 +00:00
|
|
|
} else if (tag == TAG_RAMP_CAPACITY) {
|
2020-12-02 14:55:13 +00:00
|
|
|
builder->node(m_rampcapacity->get_by_percentage_with_borders(mount->percentage_free, 0, m_perc_used_warn));
|
2016-11-13 05:40:35 +00:00
|
|
|
} else if (tag == TAG_LABEL_MOUNTED) {
|
2020-12-12 02:18:54 +00:00
|
|
|
replace_tokens(m_labelmounted);
|
2016-11-13 07:50:00 +00:00
|
|
|
builder->node(m_labelmounted);
|
2020-12-02 14:55:13 +00:00
|
|
|
} else if (tag == TAG_LABEL_WARN) {
|
2020-12-12 02:18:54 +00:00
|
|
|
replace_tokens(m_labelwarn);
|
2020-12-02 14:55:13 +00:00
|
|
|
builder->node(m_labelwarn);
|
2016-11-13 05:40:35 +00:00
|
|
|
} else if (tag == TAG_LABEL_UNMOUNTED) {
|
2020-12-12 02:18:54 +00:00
|
|
|
m_labelunmounted->reset_tokens();
|
|
|
|
m_labelunmounted->replace_token("%mountpoint%", mount->mountpoint);
|
2016-11-13 05:40:35 +00:00
|
|
|
builder->node(m_labelunmounted);
|
2016-11-13 05:09:51 +00:00
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2022-03-02 13:58:47 +00:00
|
|
|
} // namespace modules
|
2016-11-13 05:09:51 +00:00
|
|
|
|
2016-11-19 05:22:44 +00:00
|
|
|
POLYBAR_NS_END
|