sysctl: if options are prefixed with "-" ignore write errors

This commit is contained in:
Lennart Poettering 2019-07-26 09:17:01 +02:00
parent 2de30233f7
commit dec02d6e19
1 changed files with 79 additions and 33 deletions

View File

@ -30,25 +30,71 @@ static PagerFlags arg_pager_flags = 0;
STATIC_DESTRUCTOR_REGISTER(arg_prefixes, strv_freep);
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 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 (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;
}
@ -94,9 +140,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);
@ -125,39 +173,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;
@ -264,7 +310,7 @@ static int parse_argv(int argc, char *argv[]) {
}
static int run(int argc, char *argv[]) {
_cleanup_(ordered_hashmap_free_free_freep) OrderedHashmap *sysctl_options = NULL;
_cleanup_(ordered_hashmap_freep) OrderedHashmap *sysctl_options = NULL;
int r, k;
r = parse_argv(argc, argv);
@ -275,7 +321,7 @@ static int run(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)
return log_oom();