summaryrefslogtreecommitdiff
path: root/src/core/load-fragment.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/load-fragment.c')
-rw-r--r--src/core/load-fragment.c435
1 files changed, 280 insertions, 155 deletions
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 15fabe860..57c8156fd 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -51,6 +51,7 @@
#include "path-util.h"
#include "syscall-list.h"
#include "env-util.h"
+#include "cgroup.h"
#ifndef HAVE_SYSV_COMPAT
int config_parse_warn_compat(const char *unit,
@@ -996,58 +997,6 @@ int config_parse_limit(const char *unit,
return 0;
}
-int config_parse_unit_cgroup(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Unit *u = userdata;
- char *w;
- size_t l;
- char *state;
-
- if (isempty(rvalue)) {
- /* An empty assignment resets the list */
- cgroup_bonding_free_list(u->cgroup_bondings, false);
- u->cgroup_bondings = NULL;
- return 0;
- }
-
- FOREACH_WORD_QUOTED(w, l, rvalue, state) {
- _cleanup_free_ char *t = NULL, *k = NULL, *ku = NULL;
- int r;
-
- t = strndup(w, l);
- if (!t)
- return log_oom();
-
- k = unit_full_printf(u, t);
- if (!k)
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to resolve unit specifiers on %s. Ignoring.",
- t);
-
- ku = cunescape(k ? k : t);
- if (!ku)
- return log_oom();
-
- r = unit_add_cgroup_from_text(u, ku, true, NULL);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse cgroup value %s, ignoring: %s",
- k, rvalue);
- return 0;
- }
- }
-
- return 0;
-}
-
#ifdef HAVE_SYSV_COMPAT
int config_parse_sysv_priority(const char *unit,
const char *filename,
@@ -1793,108 +1742,6 @@ int config_parse_unit_condition_null(const char *unit,
DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
-int config_parse_unit_cgroup_attr(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Unit *u = data;
- size_t a, b;
- _cleanup_free_ char *n = NULL, *v = NULL;
- const CGroupSemantics *s;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- /* Empty assignment clears the list */
- cgroup_attribute_free_list(u->cgroup_attributes);
- u->cgroup_attributes = NULL;
- return 0;
- }
-
- a = strcspn(rvalue, WHITESPACE);
- b = strspn(rvalue + a, WHITESPACE);
- if (a <= 0 || b <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse cgroup attribute value, ignoring: %s",
- rvalue);
- return 0;
- }
-
- n = strndup(rvalue, a);
- if (!n)
- return log_oom();
-
- r = cgroup_semantics_find(NULL, n, rvalue + a + b, &v, &s);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse cgroup attribute value, ignoring: %s",
- rvalue);
- return 0;
- }
-
- r = unit_add_cgroup_attribute(u, s, NULL, n, v ? v : rvalue + a + b, NULL);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to add cgroup attribute value, ignoring: %s", rvalue);
- return 0;
- }
-
- return 0;
-}
-
-int config_parse_unit_cgroup_attr_pretty(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Unit *u = data;
- _cleanup_free_ char *v = NULL;
- const CGroupSemantics *s;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- r = cgroup_semantics_find(NULL, lvalue, rvalue, &v, &s);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse cgroup attribute value, ignoring: %s",
- rvalue);
- return 0;
- } else if (r == 0) {
- log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
- "Unknown or unsupported cgroup attribute %s, ignoring: %s",
- lvalue, rvalue);
- return 0;
- }
-
- r = unit_add_cgroup_attribute(u, s, NULL, NULL, v, NULL);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to add cgroup attribute value, ignoring: %s", rvalue);
- return 0;
- }
-
- return 0;
-}
-
int config_parse_unit_requires_mounts_for(const char *unit,
const char *filename,
unsigned line,
@@ -2104,6 +1951,285 @@ int config_parse_unit_slice(
return 0;
}
+DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
+
+int config_parse_cpu_shares(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ CGroupContext *c = data;
+ unsigned long lu;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ c->cpu_shares = 1024;
+ return 0;
+ }
+
+ r = safe_atolu(rvalue, &lu);
+ if (r < 0 || lu <= 0) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "CPU shares '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+
+ c->cpu_shares = lu;
+ return 0;
+}
+
+int config_parse_memory_limit(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ CGroupContext *c = data;
+ uint64_t *limit;
+ off_t bytes;
+ int r;
+
+ limit = streq(lvalue, "MemoryLimit") ? &c->memory_limit : &c->memory_soft_limit;
+
+ if (isempty(rvalue)) {
+ *limit = (uint64_t) -1;
+ return 0;
+ }
+
+ assert_cc(sizeof(uint64_t) == sizeof(off_t));
+
+ r = parse_bytes(rvalue, &bytes);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Memory limit '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+
+ *limit = (uint64_t) bytes;
+ return 0;
+}
+
+int config_parse_device_allow(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_free_ char *path = NULL;
+ CGroupContext *c = data;
+ CGroupDeviceAllow *a;
+ const char *m;
+ size_t n;
+
+ if (isempty(rvalue)) {
+ while (c->device_allow)
+ cgroup_context_free_device_allow(c, c->device_allow);
+
+ return 0;
+ }
+
+ n = strcspn(rvalue, WHITESPACE);
+ path = strndup(rvalue, n);
+ if (!path)
+ return log_oom();
+
+ if (!path_startswith(path, "/dev")) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Invalid device node path '%s'. Ignoring.", path);
+ return 0;
+ }
+
+ m = rvalue + n + strspn(rvalue + n, WHITESPACE);
+ if (isempty(m))
+ m = "rwm";
+
+ if (!in_charset(m, "rwm")) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Invalid device rights '%s'. Ignoring.", m);
+ return 0;
+ }
+
+ a = new0(CGroupDeviceAllow, 1);
+ if (!a)
+ return log_oom();
+
+ a->path = path;
+ path = NULL;
+ a->r = !!strchr(m, 'r');
+ a->w = !!strchr(m, 'w');
+ a->m = !!strchr(m, 'm');
+
+ LIST_PREPEND(CGroupDeviceAllow, device_allow, c->device_allow, a);
+ return 0;
+}
+
+int config_parse_blockio_weight(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_free_ char *path = NULL;
+ CGroupContext *c = data;
+ unsigned long lu;
+ const char *weight;
+ size_t n;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ c->blockio_weight = 1000;
+
+ while (c->blockio_device_weights)
+ cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
+
+ return 0;
+ }
+
+ n = strcspn(rvalue, WHITESPACE);
+ weight = rvalue + n;
+ if (*weight) {
+ /* Two params, first device name, then weight */
+ path = strndup(rvalue, n);
+ if (!path)
+ return log_oom();
+
+ if (!path_startswith(path, "/dev")) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Invalid device node path '%s'. Ignoring.", path);
+ return 0;
+ }
+
+ weight += strspn(weight, WHITESPACE);
+ } else
+ /* One param, only weight */
+ weight = rvalue;
+
+ r = safe_atolu(weight, &lu);
+ if (r < 0 || lu < 10 || lu > 1000) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Block IO weight '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+
+ if (!path)
+ c->blockio_weight = lu;
+ else {
+ CGroupBlockIODeviceWeight *w;
+
+ w = new0(CGroupBlockIODeviceWeight, 1);
+ if (!w)
+ return log_oom();
+
+ w->path = path;
+ path = NULL;
+
+ w->weight = lu;
+
+ LIST_PREPEND(CGroupBlockIODeviceWeight, device_weights, c->blockio_device_weights, w);
+ }
+
+ return 0;
+}
+
+int config_parse_blockio_bandwidth(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_free_ char *path = NULL;
+ CGroupBlockIODeviceBandwidth *b;
+ CGroupContext *c = data;
+ const char *bandwidth;
+ off_t bytes;
+ size_t n;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ while (c->blockio_device_bandwidths)
+ cgroup_context_free_blockio_device_bandwidth(c, c->blockio_device_bandwidths);
+
+ return 0;
+ }
+
+ n = strcspn(rvalue, WHITESPACE);
+ bandwidth = rvalue + n;
+ bandwidth += strspn(bandwidth, WHITESPACE);
+
+ if (!*bandwidth) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Expected space separated pair of device node and bandwidth. Ignoring.");
+ return 0;
+ }
+
+ path = strndup(rvalue, n);
+ if (!path)
+ return log_oom();
+
+ if (!path_startswith(path, "/dev")) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Invalid device node path '%s'. Ignoring.", path);
+ return 0;
+ }
+
+ r = parse_bytes(bandwidth, &bytes);
+ if (r < 0 || bytes <= 0) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+
+ b = new0(CGroupBlockIODeviceBandwidth, 1);
+ if (!b)
+ return log_oom();
+
+ b->path = path;
+ path = NULL;
+ b->bandwidth = (uint64_t) bytes;
+
+ LIST_PREPEND(CGroupBlockIODeviceBandwidth, device_bandwidths, c->blockio_device_bandwidths, b);
+
+ return 0;
+}
+
#define FOLLOW_MAX 8
static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
@@ -2463,7 +2589,6 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_exec_secure_bits, "SECUREBITS" },
{ config_parse_bounding_set, "BOUNDINGSET" },
{ config_parse_limit, "LIMIT" },
- { config_parse_unit_cgroup, "CGROUP [...]" },
{ config_parse_unit_deps, "UNIT [...]" },
{ config_parse_exec, "PATH [ARGUMENT [...]]" },
{ config_parse_service_type, "SERVICETYPE" },