From c9f620bfec8f11d431dfed3cfa0de97bc0ab77b2 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 19 May 2018 23:59:02 +0900 Subject: [PATCH] core: support unit specifiers in IODeviceWeight= and friends --- TODO | 2 - src/core/load-fragment.c | 254 ++++++++++++++++++++++----------------- 2 files changed, 141 insertions(+), 115 deletions(-) diff --git a/TODO b/TODO index 5a0117260e..32838a4f25 100644 --- a/TODO +++ b/TODO @@ -329,8 +329,6 @@ Features: * rework fopen_temporary() to make use of open_tmpfile_linkable() (problem: the kernel doesn't support linkat() that replaces existing files, currently) -* check if DeviceAllow= should split first, resolve specifiers later - * transient units: don't bother with actually setting unit properties, we reload the unit file anyway diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index f02b6c0c9c..b9b23bb278 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3421,11 +3421,10 @@ int config_parse_device_allow( void *data, void *userdata) { - _cleanup_free_ char *path = NULL, *t = NULL; + _cleanup_free_ char *path = NULL, *resolved = NULL; CGroupContext *c = data; CGroupDeviceAllow *a; - const char *m = NULL; - size_t n; + const char *p = rvalue; int r; if (isempty(rvalue)) { @@ -3435,32 +3434,35 @@ int config_parse_device_allow( return 0; } - r = unit_full_printf(userdata, rvalue, &t); + r = extract_first_word(&p, &path, NULL, EXTRACT_QUOTES); + if (r == -ENOMEM) + return log_oom(); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to resolve specifiers in %s, ignoring: %m", - rvalue); + "Invalid syntax, ignoring: %s", rvalue); + return 0; + } + if (r == 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Failed to extract device path and rights from '%s', ignoring.", rvalue); return 0; } - n = strcspn(t, WHITESPACE); - - path = strndup(t, n); - if (!path) - return log_oom(); - - if (!is_deviceallow_pattern(path) && - !path_startswith(path, "/run/systemd/inaccessible/")) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path); + r = unit_full_printf(userdata, path, &resolved); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to resolve unit specifiers in '%s', ignoring: %m", path); return 0; } - m = t + n + strspn(t + n, WHITESPACE); - if (isempty(m)) - m = "rwm"; + if (!is_deviceallow_pattern(resolved) && + !path_startswith(resolved, "/run/systemd/inaccessible/")) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s', ignoring.", resolved); + return 0; + } - if (!in_charset(m, "rwm")) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device rights '%s'. Ignoring.", m); + if (!isempty(p) && !in_charset(p, "rwm")) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device rights '%s', ignoring.", p); return 0; } @@ -3468,10 +3470,10 @@ int config_parse_device_allow( if (!a) return log_oom(); - a->path = TAKE_PTR(path); - a->r = !!strchr(m, 'r'); - a->w = !!strchr(m, 'w'); - a->m = !!strchr(m, 'm'); + a->path = TAKE_PTR(resolved); + a->r = isempty(p) || !!strchr(p, 'r'); + a->w = isempty(p) || !!strchr(p, 'w'); + a->m = isempty(p) || !!strchr(p, 'm'); LIST_PREPEND(device_allow, c->device_allow, a); return 0; @@ -3517,12 +3519,11 @@ int config_parse_io_device_weight( void *data, void *userdata) { - _cleanup_free_ char *path = NULL; + _cleanup_free_ char *path = NULL, *resolved = NULL; CGroupIODeviceWeight *w; CGroupContext *c = data; - const char *weight; + const char *p = rvalue; uint64_t u; - size_t n; int r; assert(filename); @@ -3536,28 +3537,36 @@ int config_parse_io_device_weight( return 0; } - n = strcspn(rvalue, WHITESPACE); - weight = rvalue + n; - weight += strspn(weight, WHITESPACE); - - if (isempty(weight)) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring."); - return 0; - } - - path = strndup(rvalue, n); - if (!path) + r = extract_first_word(&p, &path, NULL, EXTRACT_QUOTES); + if (r == -ENOMEM) return log_oom(); - - if (!path_startswith(path, "/dev") && - !path_startswith(path, "/run/systemd/inaccessible/")) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid syntax, ignoring: %s", rvalue); + return 0; + } + if (r == 0 || isempty(p)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Failed to extract device path and weight from '%s', ignoring.", rvalue); return 0; } - r = cg_weight_parse(weight, &u); + r = unit_full_printf(userdata, path, &resolved); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", weight); + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to resolve unit specifiers in '%s', ignoring: %m", path); + return 0; + } + + if (!path_startswith(resolved, "/dev") && + !path_startswith(resolved, "/run/systemd/inaccessible/")) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s', ignoring.", resolved); + return 0; + } + + r = cg_weight_parse(p, &u); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid, ignoring: %m", p); return 0; } @@ -3567,8 +3576,7 @@ int config_parse_io_device_weight( if (!w) return log_oom(); - w->path = TAKE_PTR(path); - + w->path = TAKE_PTR(resolved); w->weight = u; LIST_PREPEND(device_weights, c->io_device_weights, w); @@ -3587,13 +3595,12 @@ int config_parse_io_limit( void *data, void *userdata) { - _cleanup_free_ char *path = NULL; + _cleanup_free_ char *path = NULL, *resolved = NULL; CGroupIODeviceLimit *l = NULL, *t; CGroupContext *c = data; CGroupIOLimitType type; - const char *limit; + const char *p = rvalue; uint64_t num; - size_t n; int r; assert(filename); @@ -3609,37 +3616,45 @@ int config_parse_io_limit( return 0; } - n = strcspn(rvalue, WHITESPACE); - limit = rvalue + n; - limit += strspn(limit, WHITESPACE); - - if (!*limit) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring."); - return 0; - } - - path = strndup(rvalue, n); - if (!path) + r = extract_first_word(&p, &path, NULL, EXTRACT_QUOTES); + if (r == -ENOMEM) return log_oom(); - - if (!path_startswith(path, "/dev") && - !path_startswith(path, "/run/systemd/inaccessible/")) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid syntax, ignoring: %s", rvalue); + return 0; + } + if (r == 0 || isempty(p)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Failed to extract device node and bandwidth from '%s', ignoring.", rvalue); return 0; } - if (streq("infinity", limit)) { + r = unit_full_printf(userdata, path, &resolved); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to resolve unit specifiers in '%s', ignoring: %m", path); + return 0; + } + + if (!path_startswith(resolved, "/dev") && + !path_startswith(resolved, "/run/systemd/inaccessible/")) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s', ignoring.", resolved); + return 0; + } + + if (streq("infinity", p)) { num = CGROUP_LIMIT_MAX; } else { - r = parse_size(limit, 1000, &num); + r = parse_size(p, 1000, &num); if (r < 0 || num <= 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "IO Limit '%s' invalid. Ignoring.", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid IO limit '%s', ignoring.", p); return 0; } } LIST_FOREACH(device_limits, t, c->io_device_limits) { - if (path_equal(path, t->path)) { + if (path_equal(resolved, t->path)) { l = t; break; } @@ -3652,7 +3667,7 @@ int config_parse_io_limit( if (!l) return log_oom(); - l->path = TAKE_PTR(path); + l->path = TAKE_PTR(resolved); for (ttype = 0; ttype < _CGROUP_IO_LIMIT_TYPE_MAX; ttype++) l->limits[ttype] = cgroup_io_limit_defaults[ttype]; @@ -3704,12 +3719,11 @@ int config_parse_blockio_device_weight( void *data, void *userdata) { - _cleanup_free_ char *path = NULL; + _cleanup_free_ char *path = NULL, *resolved = NULL; CGroupBlockIODeviceWeight *w; CGroupContext *c = data; - const char *weight; + const char *p = rvalue; uint64_t u; - size_t n; int r; assert(filename); @@ -3723,28 +3737,36 @@ int config_parse_blockio_device_weight( return 0; } - n = strcspn(rvalue, WHITESPACE); - weight = rvalue + n; - weight += strspn(weight, WHITESPACE); - - if (isempty(weight)) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring."); - return 0; - } - - path = strndup(rvalue, n); - if (!path) + r = extract_first_word(&p, &path, NULL, EXTRACT_QUOTES); + if (r == -ENOMEM) return log_oom(); - - if (!path_startswith(path, "/dev") && - !path_startswith(path, "/run/systemd/inaccessible/")) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid syntax, ignoring: %s", rvalue); + return 0; + } + if (r == 0 || isempty(p)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Failed to extract device node and weight from '%s', ignoring.", rvalue); return 0; } - r = cg_blkio_weight_parse(weight, &u); + r = unit_full_printf(userdata, path, &resolved); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", weight); + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to resolve unit specifiers in '%s', ignoring: %m", path); + return 0; + } + + if (!path_startswith(resolved, "/dev") && + !path_startswith(resolved, "/run/systemd/inaccessible/")) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", resolved); + return 0; + } + + r = cg_blkio_weight_parse(p, &u); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Invalid block IO weight '%s', ignoring: %m", p); return 0; } @@ -3754,8 +3776,7 @@ int config_parse_blockio_device_weight( if (!w) return log_oom(); - w->path = TAKE_PTR(path); - + w->path = TAKE_PTR(resolved); w->weight = u; LIST_PREPEND(device_weights, c->blockio_device_weights, w); @@ -3774,13 +3795,12 @@ int config_parse_blockio_bandwidth( void *data, void *userdata) { - _cleanup_free_ char *path = NULL; + _cleanup_free_ char *path = NULL, *resolved = NULL; CGroupBlockIODeviceBandwidth *b = NULL, *t; CGroupContext *c = data; - const char *bandwidth; + const char *p = rvalue; uint64_t bytes; bool read; - size_t n; int r; assert(filename); @@ -3797,33 +3817,41 @@ int config_parse_blockio_bandwidth( return 0; } - n = strcspn(rvalue, WHITESPACE); - bandwidth = rvalue + n; - bandwidth += strspn(bandwidth, WHITESPACE); - - if (!*bandwidth) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring."); - return 0; - } - - path = strndup(rvalue, n); - if (!path) + r = extract_first_word(&p, &path, NULL, EXTRACT_QUOTES); + if (r == -ENOMEM) return log_oom(); - - if (!path_startswith(path, "/dev") && - !path_startswith(path, "/run/systemd/inaccessible/")) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid syntax, ignoring: %s", rvalue); + return 0; + } + if (r == 0 || isempty(p)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Failed to extract device node and bandwidth from '%s', ignoring.", rvalue); return 0; } - r = parse_size(bandwidth, 1000, &bytes); + r = unit_full_printf(userdata, path, &resolved); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to resolve unit specifiers in '%s', ignoring: %m", path); + return 0; + } + + if (!path_startswith(resolved, "/dev") && + !path_startswith(resolved, "/run/systemd/inaccessible/")) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s', ignoring.", resolved); + return 0; + } + + r = parse_size(p, 1000, &bytes); if (r < 0 || bytes <= 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Invalid Block IO Bandwidth '%s', ignoring.", p); return 0; } LIST_FOREACH(device_bandwidths, t, c->blockio_device_bandwidths) { - if (path_equal(path, t->path)) { + if (path_equal(resolved, t->path)) { b = t; break; } @@ -3834,7 +3862,7 @@ int config_parse_blockio_bandwidth( if (!b) return log_oom(); - b->path = TAKE_PTR(path); + b->path = TAKE_PTR(resolved); b->rbps = CGROUP_LIMIT_MAX; b->wbps = CGROUP_LIMIT_MAX;