1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 14:18:12 +00:00

sysctl: Allow showing or setting multiple variables

The `-w` option is enforced when setting variables.
This commit is contained in:
SeekingBlues 2021-10-16 18:18:38 -04:00 committed by Andreas Kling
parent 3d174e3ad2
commit 638f39fbc1
2 changed files with 81 additions and 67 deletions

View file

@ -5,7 +5,7 @@ sysctl - configure kernel parameters at runtime
## Synopsis ## Synopsis
```**sh ```**sh
# sysctl [-a] [variable[=value]] # sysctl [-a] [-w] [variable[=value]...]
``` ```
## Description ## Description
@ -16,12 +16,13 @@ Available parameters are listed under /proc/sys/.
## Options ## Options
* `-a`: Display all kernel parameters and associated values * `-a`: Display all kernel parameters and associated values.
* `-w`: Set kernel parameters to the specified values.
## Arguments ## Arguments
* `variable`: Retrieve the specified parameter * `variable`: Retrieve the specified parameter.
* `variable=value`: Set the specified parameter to the specified value * `variable=value`: Set the specified parameter to the specified value. The option `-w` has to be specified.
## Files ## Files
@ -43,8 +44,10 @@ ubsan_is_deadly = 1
``` ```
Set `ubsan_is_deadly` parameter to zero (disabled): Set `ubsan_is_deadly` parameter to zero (disabled):
(Note: This requires root privileges)
```sh ```sh
# sysctl ubsan_is_deadly=0 # su
ubsan_is_deadly = 1 -> 0 # sysctl -w ubsan_is_deadly=0
ubsan_is_deadly: 1 -> 0
``` ```

View file

@ -4,48 +4,76 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <AK/ByteBuffer.h>
#include <AK/String.h>
#include <AK/StringBuilder.h>
#include <LibCore/ArgsParser.h> #include <LibCore/ArgsParser.h>
#include <LibCore/DirIterator.h> #include <LibCore/DirIterator.h>
#include <LibCore/File.h> #include <LibCore/File.h>
static String read_var(const String& name) static bool s_set_variable = false;
static String get_variable(StringView const& name)
{ {
StringBuilder builder; auto path = String::formatted("/proc/sys/{}", name);
builder.append("/proc/sys/"); auto file = Core::File::construct(path);
builder.append(name); if (!file->open(Core::OpenMode::ReadOnly)) {
auto path = builder.to_string(); warnln("Failed to open {}: {}", path, file->error_string());
auto f = Core::File::construct(path); return {};
if (!f->open(Core::OpenMode::ReadOnly)) {
warnln("Failed to open {}: {}", f->name(), f->error_string());
exit(1);
} }
const auto& b = f->read_all(); auto buffer = file->read_all();
if (f->error() < 0) { if (file->error() < 0) {
warnln("Failed to read: {}", f->error_string()); warnln("Failed to read {}: {}", path, file->error_string());
exit(1); return {};
} }
return String((const char*)b.data(), b.size(), Chomp); return { (char const*)buffer.data(), buffer.size(), Chomp };
} }
static void write_var(const String& name, const String& value) static bool read_variable(StringView const& name)
{ {
StringBuilder builder; auto value = get_variable(name);
builder.append("/proc/sys/"); if (value.is_null())
builder.append(name); return false;
auto path = builder.to_string(); outln("{} = {}", name, value);
auto f = Core::File::construct(path); return true;
if (!f->open(Core::OpenMode::WriteOnly)) { }
warnln("Failed to open: {}", f->error_string());
exit(1); static bool write_variable(StringView const& name, StringView const& value)
{
auto old_value = get_variable(name);
if (old_value.is_null())
return false;
auto path = String::formatted("/proc/sys/{}", name);
auto file = Core::File::construct(path);
if (!file->open(Core::OpenMode::WriteOnly)) {
warnln("Failed to open {}: {}", path, file->error_string());
return false;
} }
f->write(value); if (!file->write(value)) {
if (f->error() < 0) { warnln("Failed to write {}: {}", path, file->error_string());
warnln("Failed to write: {}", f->error_string()); return false;
exit(1);
} }
outln("{}: {} -> {}", name, old_value, value);
return true;
}
static int handle_variables(Vector<String> const& variables)
{
bool success = false;
for (auto const& variable : variables) {
auto maybe_index = variable.find('=');
if (!maybe_index.has_value()) {
success = read_variable(variable);
continue;
}
auto equal_index = maybe_index.release_value();
auto name = variable.substring_view(0, equal_index);
auto value = variable.substring_view(equal_index + 1, variable.length() - equal_index - 1);
if (name.is_empty())
warnln("Malformed setting '{}'", variable);
else if (!s_set_variable)
warnln("Must specify '-w' to set variables");
else
success = write_variable(name, value);
}
return success ? 0 : 1;
} }
static int handle_show_all() static int handle_show_all()
@ -56,52 +84,35 @@ static int handle_show_all()
return 1; return 1;
} }
bool success = false;
while (di.has_next()) { while (di.has_next()) {
String variable_name = di.next_path(); auto name = di.next_path();
outln("{} = {}", variable_name, read_var(variable_name)); success = read_variable(name);
} }
return 0; return success ? 0 : 1;
}
static int handle_var(const String& var)
{
String spec(var.characters(), Chomp);
auto parts = spec.split('=');
String variable_name = parts[0];
bool is_write = parts.size() > 1;
if (!is_write) {
outln("{} = {}", variable_name, read_var(variable_name));
return 0;
}
out("{} = {}", variable_name, read_var(variable_name));
write_var(variable_name, parts[1]);
outln(" -> {}", read_var(variable_name));
return 0;
} }
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
bool show_all = false; bool show_all = false;
const char* var = nullptr; Vector<String> variables;
Core::ArgsParser args_parser; Core::ArgsParser args_parser;
args_parser.set_general_help( args_parser.set_general_help("Show or modify system-internal values. This requires root, and can crash your system.");
"Show or modify system-internal values. This requires root, and can crash your system."); args_parser.add_option(show_all, "Show all variables", "all", 'a');
args_parser.add_option(show_all, "Show all variables", nullptr, 'a'); args_parser.add_option(s_set_variable, "Set variables", "write", 'w');
args_parser.add_positional_argument(var, "variable[=value]", "variable", Core::ArgsParser::Required::No); args_parser.add_positional_argument(variables, "variable[=value]", "variables", Core::ArgsParser::Required::No);
args_parser.parse(argc, argv); args_parser.parse(argc, argv);
if (var == nullptr) { if (!show_all && variables.is_empty()) {
// Not supplied; assume `-a`. args_parser.print_usage(stdout, argv[0]);
show_all = true; return 1;
} }
if (show_all) { if (show_all) {
// Ignore `var`, even if it was supplied. Just like the real procps does. // Ignore `variables`, even if they are supplied. Just like the real procps does.
return handle_show_all(); return handle_show_all();
} }
return handle_var(var); return handle_variables(variables);
} }