You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
197 lines
7.6 KiB
197 lines
7.6 KiB
2 years ago
|
From 516fc73142e803a7a6cbd126c338e1c3c73d6843 Mon Sep 17 00:00:00 2001
|
||
|
From: Jan Macku <jamacku@redhat.com>
|
||
|
Date: Fri, 21 Jan 2022 12:10:45 +0100
|
||
|
Subject: [PATCH] sysctl: if options are prefixed with "-" ignore write errors
|
||
|
|
||
|
(cherry picked from commit dec02d6e1993d420a0a94c7fec294605df55e88e)
|
||
|
|
||
|
Resolves: #2037807
|
||
|
---
|
||
|
src/sysctl/sysctl.c | 115 ++++++++++++++++++++++++++++++--------------
|
||
|
1 file changed, 80 insertions(+), 35 deletions(-)
|
||
|
|
||
|
diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c
|
||
|
index 0151f7dabe..7b0528877c 100644
|
||
|
--- a/src/sysctl/sysctl.c
|
||
|
+++ b/src/sysctl/sysctl.c
|
||
|
@@ -26,25 +26,71 @@ static char **arg_prefixes = NULL;
|
||
|
static bool arg_cat_config = false;
|
||
|
static bool arg_no_pager = false;
|
||
|
|
||
|
+typedef struct Option {
|
||
|
+ char *key;
|
||
|
+ char *value;
|
||
|
+ bool ignore_failure;
|
||
|
+} Option;
|
||
|
+
|
||
|
+static Option *option_free(Option *o) {
|
||
|
+ if (!o)
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ free(o->key);
|
||
|
+ free(o->value);
|
||
|
+
|
||
|
+ return mfree(o);
|
||
|
+}
|
||
|
+
|
||
|
+DEFINE_TRIVIAL_CLEANUP_FUNC(Option*, option_free);
|
||
|
+DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(option_hash_ops, char, string_hash_func, string_compare_func, Option, option_free);
|
||
|
+
|
||
|
+static Option *option_new(
|
||
|
+ const char *key,
|
||
|
+ const char *value,
|
||
|
+ bool ignore_failure) {
|
||
|
+
|
||
|
+ _cleanup_(option_freep) Option *o = NULL;
|
||
|
+
|
||
|
+ assert(key);
|
||
|
+ assert(value);
|
||
|
+
|
||
|
+ o = new(Option, 1);
|
||
|
+ if (!o)
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ *o = (Option) {
|
||
|
+ .key = strdup(key),
|
||
|
+ .value = strdup(value),
|
||
|
+ .ignore_failure = ignore_failure,
|
||
|
+ };
|
||
|
+
|
||
|
+ if (!o->key || !o->value)
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ return TAKE_PTR(o);
|
||
|
+}
|
||
|
+
|
||
|
static int apply_all(OrderedHashmap *sysctl_options) {
|
||
|
- char *property, *value;
|
||
|
+ Option *option;
|
||
|
Iterator i;
|
||
|
int r = 0;
|
||
|
|
||
|
- ORDERED_HASHMAP_FOREACH_KEY(value, property, sysctl_options, i) {
|
||
|
+ ORDERED_HASHMAP_FOREACH(option, sysctl_options, i) {
|
||
|
int k;
|
||
|
|
||
|
- k = sysctl_write(property, value);
|
||
|
+ k = sysctl_write(option->key, option->value);
|
||
|
if (k < 0) {
|
||
|
- /* If the sysctl is not available in the kernel or we are running with reduced privileges and
|
||
|
- * cannot write it, then log about the issue at LOG_NOTICE level, and proceed without
|
||
|
- * failing. (EROFS is treated as a permission problem here, since that's how container managers
|
||
|
- * usually protected their sysctls.) In all other cases log an error and make the tool fail. */
|
||
|
-
|
||
|
- if (IN_SET(k, -EPERM, -EACCES, -EROFS, -ENOENT))
|
||
|
- log_notice_errno(k, "Couldn't write '%s' to '%s', ignoring: %m", value, property);
|
||
|
+ /* If the sysctl is not available in the kernel or we are running with reduced
|
||
|
+ * privileges and cannot write it, then log about the issue at LOG_NOTICE level, and
|
||
|
+ * proceed without failing. (EROFS is treated as a permission problem here, since
|
||
|
+ * that's how container managers usually protected their sysctls.) In all other cases
|
||
|
+ * log an error and make the tool fail. */
|
||
|
+
|
||
|
+ if (IN_SET(k, -EPERM, -EACCES, -EROFS, -ENOENT) || option->ignore_failure)
|
||
|
+ log_notice_errno(k, "Couldn't write '%s' to '%s', ignoring: %m", option->value, option->key);
|
||
|
else {
|
||
|
- log_error_errno(k, "Couldn't write '%s' to '%s': %m", value, property);
|
||
|
+ log_error_errno(k, "Couldn't write '%s' to '%s': %m", option->value, option->key);
|
||
|
if (r == 0)
|
||
|
r = k;
|
||
|
}
|
||
|
@@ -90,9 +136,11 @@ static int parse_file(OrderedHashmap *sysctl_options, const char *path, bool ign
|
||
|
|
||
|
log_debug("Parsing %s", path);
|
||
|
for (;;) {
|
||
|
- char *p, *value, *new_value, *property, *existing;
|
||
|
+ _cleanup_(option_freep) Option *new_option = NULL;
|
||
|
_cleanup_free_ char *l = NULL;
|
||
|
- void *v;
|
||
|
+ bool ignore_failure;
|
||
|
+ Option *existing;
|
||
|
+ char *p, *value;
|
||
|
int k;
|
||
|
|
||
|
k = read_line(f, LONG_LINE_MAX, &l);
|
||
|
@@ -122,39 +170,37 @@ static int parse_file(OrderedHashmap *sysctl_options, const char *path, bool ign
|
||
|
*value = 0;
|
||
|
value++;
|
||
|
|
||
|
- p = sysctl_normalize(strstrip(p));
|
||
|
+ p = strstrip(p);
|
||
|
+ ignore_failure = p[0] == '-';
|
||
|
+ if (ignore_failure)
|
||
|
+ p++;
|
||
|
+
|
||
|
+ p = sysctl_normalize(p);
|
||
|
value = strstrip(value);
|
||
|
|
||
|
if (!test_prefix(p))
|
||
|
continue;
|
||
|
|
||
|
- existing = ordered_hashmap_get2(sysctl_options, p, &v);
|
||
|
+ existing = ordered_hashmap_get(sysctl_options, p);
|
||
|
if (existing) {
|
||
|
- if (streq(value, existing))
|
||
|
+ if (streq(value, existing->value)) {
|
||
|
+ existing->ignore_failure = existing->ignore_failure || ignore_failure;
|
||
|
continue;
|
||
|
+ }
|
||
|
|
||
|
log_debug("Overwriting earlier assignment of %s at '%s:%u'.", p, path, c);
|
||
|
- free(ordered_hashmap_remove(sysctl_options, p));
|
||
|
- free(v);
|
||
|
+ option_free(ordered_hashmap_remove(sysctl_options, p));
|
||
|
}
|
||
|
|
||
|
- property = strdup(p);
|
||
|
- if (!property)
|
||
|
+ new_option = option_new(p, value, ignore_failure);
|
||
|
+ if (!new_option)
|
||
|
return log_oom();
|
||
|
|
||
|
- new_value = strdup(value);
|
||
|
- if (!new_value) {
|
||
|
- free(property);
|
||
|
- return log_oom();
|
||
|
- }
|
||
|
+ k = ordered_hashmap_put(sysctl_options, new_option->key, new_option);
|
||
|
+ if (k < 0)
|
||
|
+ return log_error_errno(k, "Failed to add sysctl variable %s to hashmap: %m", p);
|
||
|
|
||
|
- k = ordered_hashmap_put(sysctl_options, property, new_value);
|
||
|
- if (k < 0) {
|
||
|
- log_error_errno(k, "Failed to add sysctl variable %s to hashmap: %m", property);
|
||
|
- free(property);
|
||
|
- free(new_value);
|
||
|
- return k;
|
||
|
- }
|
||
|
+ TAKE_PTR(new_option);
|
||
|
}
|
||
|
|
||
|
return r;
|
||
|
@@ -251,7 +297,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||
|
}
|
||
|
|
||
|
int main(int argc, char *argv[]) {
|
||
|
- OrderedHashmap *sysctl_options = NULL;
|
||
|
+ _cleanup_(ordered_hashmap_freep) OrderedHashmap *sysctl_options = NULL;
|
||
|
int r = 0, k;
|
||
|
|
||
|
r = parse_argv(argc, argv);
|
||
|
@@ -264,7 +310,7 @@ int main(int argc, char *argv[]) {
|
||
|
|
||
|
umask(0022);
|
||
|
|
||
|
- sysctl_options = ordered_hashmap_new(&path_hash_ops);
|
||
|
+ sysctl_options = ordered_hashmap_new(&option_hash_ops);
|
||
|
if (!sysctl_options) {
|
||
|
r = log_oom();
|
||
|
goto finish;
|
||
|
@@ -311,7 +357,6 @@ int main(int argc, char *argv[]) {
|
||
|
finish:
|
||
|
pager_close();
|
||
|
|
||
|
- ordered_hashmap_free_free_free(sysctl_options);
|
||
|
strv_free(arg_prefixes);
|
||
|
|
||
|
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|