mirror of
https://github.com/systemd/systemd
synced 2024-07-21 10:17:21 +00:00
Merge pull request #7284 from poettering/cgroup-delegate-mask
add a concept of delegating cgroups per unit while enabling specific controllers
This commit is contained in:
commit
f38326f21a
6
TODO
6
TODO
|
@ -66,10 +66,16 @@ Features:
|
||||||
* In journalctl add a way how "-o verbose" and suchlike can be tweaked to show
|
* In journalctl add a way how "-o verbose" and suchlike can be tweaked to show
|
||||||
only a specific set of properties
|
only a specific set of properties
|
||||||
|
|
||||||
|
* beef up pam_systemd to take unit file settings such as cgroups properties as
|
||||||
|
parameters
|
||||||
|
|
||||||
* export UID ranges nspawns's --private-user and DynamicUser= uses in
|
* export UID ranges nspawns's --private-user and DynamicUser= uses in
|
||||||
the systemd.pc pkg-config file, the same way we already expose the system
|
the systemd.pc pkg-config file, the same way we already expose the system
|
||||||
user boundary there
|
user boundary there
|
||||||
|
|
||||||
|
* a new "systemd-analyze security" tool outputting a checklist of security
|
||||||
|
features a service does and does not implement
|
||||||
|
|
||||||
* Whenever we check a UID against the system UID range, also check for the
|
* Whenever we check a UID against the system UID range, also check for the
|
||||||
dynamic UID range
|
dynamic UID range
|
||||||
|
|
||||||
|
|
|
@ -711,13 +711,30 @@
|
||||||
<term><varname>Delegate=</varname></term>
|
<term><varname>Delegate=</varname></term>
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>Turns on delegation of further resource control
|
<para>Turns on delegation of further resource control partitioning to processes of the unit. Units where this
|
||||||
partitioning to processes of the unit. For unprivileged
|
is enabled may create and manage their own private subhierarchy of control groups below the control group of
|
||||||
services (i.e. those using the <varname>User=</varname>
|
the unit itself. For unprivileged services (i.e. those using the <varname>User=</varname> setting) the unit's
|
||||||
setting), this allows processes to create a subhierarchy
|
control group will be made accessible to the relevant user. When enabled the service manager will refrain
|
||||||
beneath its control group path. For privileged services and
|
from manipulating control groups or moving processes below the unit's control group, so that a clear concept
|
||||||
scopes, this ensures the processes will have all control
|
of ownership is established: the control group tree above the unit's control group (i.e. towards the root
|
||||||
group controllers enabled.</para>
|
control group) is owned and managed by the service manager of the host, while the control group tree below
|
||||||
|
the unit's control group is owned and managed by the unit itself. Takes either a boolean argument or a list
|
||||||
|
of control group controller names. If true, delegation is turned on, and all supported controllers are
|
||||||
|
enabled for the unit, making them available to the unit's processes for management. If false, delegation is
|
||||||
|
turned off entirely (and no additional controllers are enabled). If set to a list of controllers, delegation
|
||||||
|
is turned on, and the specified controllers are enabled for the unit. Note that assigning the empty string
|
||||||
|
will enable delegation, but not enable any additional controllers. Defaults to false.</para>
|
||||||
|
|
||||||
|
<para>Note that controller delegation to less privileged code is only safe on the unified control group
|
||||||
|
hierarchy. Accordingly, access to the specified controllers will not be granted to unprivileged services on
|
||||||
|
the legacy hierarchy, even when requested.</para>
|
||||||
|
|
||||||
|
<para>The following controller names may be specified: <option>cpu</option>, <option>cpuacct</option>,
|
||||||
|
<option>io</option>, <option>blkio</option>, <option>memory</option>, <option>devices</option>,
|
||||||
|
<option>pids</option>. Not all of these controllers are available on all kernels however, and some are
|
||||||
|
specific to the unified hierarchy while others are specific to the legacy hierarchy. Also note that the
|
||||||
|
kernel might support further controllers, which aren't covered here yet as delegation is either not supported
|
||||||
|
at all for them or not defined cleanly.</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
|
@ -2244,10 +2244,10 @@ int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root)
|
||||||
}
|
}
|
||||||
|
|
||||||
int cg_mask_to_string(CGroupMask mask, char **ret) {
|
int cg_mask_to_string(CGroupMask mask, char **ret) {
|
||||||
const char *controllers[_CGROUP_CONTROLLER_MAX + 1];
|
_cleanup_free_ char *s = NULL;
|
||||||
|
size_t n = 0, allocated = 0;
|
||||||
|
bool space = false;
|
||||||
CGroupController c;
|
CGroupController c;
|
||||||
int i = 0;
|
|
||||||
char *s;
|
|
||||||
|
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
|
@ -2257,19 +2257,32 @@ int cg_mask_to_string(CGroupMask mask, char **ret) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
|
for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
|
||||||
|
const char *k;
|
||||||
|
size_t l;
|
||||||
|
|
||||||
if (!(mask & CGROUP_CONTROLLER_TO_MASK(c)))
|
if (!(mask & CGROUP_CONTROLLER_TO_MASK(c)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
controllers[i++] = cgroup_controller_to_string(c);
|
k = cgroup_controller_to_string(c);
|
||||||
controllers[i] = NULL;
|
l = strlen(k);
|
||||||
|
|
||||||
|
if (!GREEDY_REALLOC(s, allocated, n + space + l + 1))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (space)
|
||||||
|
s[n] = ' ';
|
||||||
|
memcpy(s + n + space, k, l);
|
||||||
|
n += space + l;
|
||||||
|
|
||||||
|
space = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
s = strv_join((char **)controllers, NULL);
|
assert(s);
|
||||||
if (!s)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
|
s[n] = 0;
|
||||||
*ret = s;
|
*ret = s;
|
||||||
|
s = NULL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,11 +34,11 @@
|
||||||
/* An enum of well known cgroup controllers */
|
/* An enum of well known cgroup controllers */
|
||||||
typedef enum CGroupController {
|
typedef enum CGroupController {
|
||||||
CGROUP_CONTROLLER_CPU,
|
CGROUP_CONTROLLER_CPU,
|
||||||
CGROUP_CONTROLLER_CPUACCT,
|
CGROUP_CONTROLLER_CPUACCT, /* v1 only */
|
||||||
CGROUP_CONTROLLER_IO,
|
CGROUP_CONTROLLER_IO, /* v2 only */
|
||||||
CGROUP_CONTROLLER_BLKIO,
|
CGROUP_CONTROLLER_BLKIO, /* v1 only */
|
||||||
CGROUP_CONTROLLER_MEMORY,
|
CGROUP_CONTROLLER_MEMORY,
|
||||||
CGROUP_CONTROLLER_DEVICES,
|
CGROUP_CONTROLLER_DEVICES, /* v1 only */
|
||||||
CGROUP_CONTROLLER_PIDS,
|
CGROUP_CONTROLLER_PIDS,
|
||||||
_CGROUP_CONTROLLER_MAX,
|
_CGROUP_CONTROLLER_MAX,
|
||||||
_CGROUP_CONTROLLER_INVALID = -1,
|
_CGROUP_CONTROLLER_INVALID = -1,
|
||||||
|
|
|
@ -1527,9 +1527,7 @@ int mkdtemp_malloc(const char *template, char **ret) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void funlockfilep(FILE **f) {
|
DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile);
|
||||||
funlockfile(*f);
|
|
||||||
}
|
|
||||||
|
|
||||||
int read_line(FILE *f, size_t limit, char **ret) {
|
int read_line(FILE *f, size_t limit, char **ret) {
|
||||||
_cleanup_free_ char *buffer = NULL;
|
_cleanup_free_ char *buffer = NULL;
|
||||||
|
|
|
@ -278,6 +278,9 @@ char *strjoin_real(const char *x, ...) {
|
||||||
char *strstrip(char *s) {
|
char *strstrip(char *s) {
|
||||||
char *e;
|
char *e;
|
||||||
|
|
||||||
|
if (!s)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
/* Drops trailing whitespace. Modifies the string in
|
/* Drops trailing whitespace. Modifies the string in
|
||||||
* place. Returns pointer to first non-space character */
|
* place. Returns pointer to first non-space character */
|
||||||
|
|
||||||
|
@ -295,7 +298,13 @@ char *strstrip(char *s) {
|
||||||
char *delete_chars(char *s, const char *bad) {
|
char *delete_chars(char *s, const char *bad) {
|
||||||
char *f, *t;
|
char *f, *t;
|
||||||
|
|
||||||
/* Drops all whitespace, regardless where in the string */
|
/* Drops all specified bad characters, regardless where in the string */
|
||||||
|
|
||||||
|
if (!s)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!bad)
|
||||||
|
bad = WHITESPACE;
|
||||||
|
|
||||||
for (f = s, t = s; *f; f++) {
|
for (f = s, t = s; *f; f++) {
|
||||||
if (strchr(bad, *f))
|
if (strchr(bad, *f))
|
||||||
|
@ -309,6 +318,26 @@ char *delete_chars(char *s, const char *bad) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *delete_trailing_chars(char *s, const char *bad) {
|
||||||
|
char *p, *c = s;
|
||||||
|
|
||||||
|
/* Drops all specified bad characters, at the end of the string */
|
||||||
|
|
||||||
|
if (!s)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!bad)
|
||||||
|
bad = WHITESPACE;
|
||||||
|
|
||||||
|
for (p = s; *p; p++)
|
||||||
|
if (!strchr(bad, *p))
|
||||||
|
c = p + 1;
|
||||||
|
|
||||||
|
*c = 0;
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
char *truncate_nl(char *s) {
|
char *truncate_nl(char *s) {
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
|
|
|
@ -133,8 +133,20 @@ char *strjoin_real(const char *x, ...) _sentinel_;
|
||||||
|
|
||||||
char *strstrip(char *s);
|
char *strstrip(char *s);
|
||||||
char *delete_chars(char *s, const char *bad);
|
char *delete_chars(char *s, const char *bad);
|
||||||
|
char *delete_trailing_chars(char *s, const char *bad);
|
||||||
char *truncate_nl(char *s);
|
char *truncate_nl(char *s);
|
||||||
|
|
||||||
|
static inline char *skip_leading_chars(const char *s, const char *bad) {
|
||||||
|
|
||||||
|
if (!s)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!bad)
|
||||||
|
bad = WHITESPACE;
|
||||||
|
|
||||||
|
return (char*) s + strspn(s, bad);
|
||||||
|
}
|
||||||
|
|
||||||
char ascii_tolower(char x);
|
char ascii_tolower(char x);
|
||||||
char *ascii_strlower(char *s);
|
char *ascii_strlower(char *s);
|
||||||
char *ascii_strlower_n(char *s, size_t n);
|
char *ascii_strlower_n(char *s, size_t n);
|
||||||
|
|
|
@ -382,19 +382,14 @@ int unit_name_path_escape(const char *f, char **ret) {
|
||||||
if (STR_IN_SET(p, "/", ""))
|
if (STR_IN_SET(p, "/", ""))
|
||||||
s = strdup("-");
|
s = strdup("-");
|
||||||
else {
|
else {
|
||||||
char *e;
|
|
||||||
|
|
||||||
if (!path_is_safe(p))
|
if (!path_is_safe(p))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Truncate trailing slashes */
|
/* Truncate trailing slashes */
|
||||||
e = endswith(p, "/");
|
delete_trailing_chars(p, "/");
|
||||||
if (e)
|
|
||||||
*e = 0;
|
|
||||||
|
|
||||||
/* Truncate leading slashes */
|
/* Truncate leading slashes */
|
||||||
if (p[0] == '/')
|
p = skip_leading_chars(p, "/");
|
||||||
p++;
|
|
||||||
|
|
||||||
s = unit_name_escape(p);
|
s = unit_name_escape(p);
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,6 +209,16 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
|
||||||
prefix, cgroup_device_policy_to_string(c->device_policy),
|
prefix, cgroup_device_policy_to_string(c->device_policy),
|
||||||
prefix, yes_no(c->delegate));
|
prefix, yes_no(c->delegate));
|
||||||
|
|
||||||
|
if (c->delegate) {
|
||||||
|
_cleanup_free_ char *t = NULL;
|
||||||
|
|
||||||
|
(void) cg_mask_to_string(c->delegate_controllers, &t);
|
||||||
|
|
||||||
|
fprintf(f, "%sDelegateController=%s\n",
|
||||||
|
prefix,
|
||||||
|
strempty(t));
|
||||||
|
}
|
||||||
|
|
||||||
LIST_FOREACH(device_allow, a, c->device_allow)
|
LIST_FOREACH(device_allow, a, c->device_allow)
|
||||||
fprintf(f,
|
fprintf(f,
|
||||||
"%sDeviceAllow=%s %s%s%s\n",
|
"%sDeviceAllow=%s %s%s%s\n",
|
||||||
|
@ -1062,37 +1072,47 @@ CGroupMask unit_get_own_mask(Unit *u) {
|
||||||
if (!c)
|
if (!c)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* If delegation is turned on, then turn on all cgroups,
|
return cgroup_context_get_mask(c);
|
||||||
* unless we are on the legacy hierarchy and the process we
|
}
|
||||||
* fork into it is known to drop privileges, and hence
|
|
||||||
* shouldn't get access to the controllers.
|
|
||||||
*
|
|
||||||
* Note that on the unified hierarchy it is safe to delegate
|
|
||||||
* controllers to unprivileged services. */
|
|
||||||
|
|
||||||
if (c->delegate) {
|
CGroupMask unit_get_delegate_mask(Unit *u) {
|
||||||
|
CGroupContext *c;
|
||||||
|
|
||||||
|
/* If delegation is turned on, then turn on selected controllers, unless we are on the legacy hierarchy and the
|
||||||
|
* process we fork into is known to drop privileges, and hence shouldn't get access to the controllers.
|
||||||
|
*
|
||||||
|
* Note that on the unified hierarchy it is safe to delegate controllers to unprivileged services. */
|
||||||
|
|
||||||
|
if (u->type == UNIT_SLICE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
c = unit_get_cgroup_context(u);
|
||||||
|
if (!c)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!c->delegate)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (cg_all_unified() <= 0) {
|
||||||
ExecContext *e;
|
ExecContext *e;
|
||||||
|
|
||||||
e = unit_get_exec_context(u);
|
e = unit_get_exec_context(u);
|
||||||
if (!e ||
|
if (e && !exec_context_maintains_privileges(e))
|
||||||
exec_context_maintains_privileges(e) ||
|
return 0;
|
||||||
cg_all_unified() > 0)
|
|
||||||
return _CGROUP_MASK_ALL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cgroup_context_get_mask(c);
|
return c->delegate_controllers;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGroupMask unit_get_members_mask(Unit *u) {
|
CGroupMask unit_get_members_mask(Unit *u) {
|
||||||
assert(u);
|
assert(u);
|
||||||
|
|
||||||
/* Returns the mask of controllers all of the unit's children
|
/* Returns the mask of controllers all of the unit's children require, merged */
|
||||||
* require, merged */
|
|
||||||
|
|
||||||
if (u->cgroup_members_mask_valid)
|
if (u->cgroup_members_mask_valid)
|
||||||
return u->cgroup_members_mask;
|
return u->cgroup_members_mask;
|
||||||
|
|
||||||
u->cgroup_members_mask = 0;
|
u->cgroup_members_mask = unit_get_delegate_mask(u);
|
||||||
|
|
||||||
if (u->type == UNIT_SLICE) {
|
if (u->type == UNIT_SLICE) {
|
||||||
void *v;
|
void *v;
|
||||||
|
@ -1107,9 +1127,7 @@ CGroupMask unit_get_members_mask(Unit *u) {
|
||||||
if (UNIT_DEREF(member->slice) != u)
|
if (UNIT_DEREF(member->slice) != u)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
u->cgroup_members_mask |=
|
u->cgroup_members_mask |= unit_get_subtree_mask(member); /* note that this calls ourselves again, for the children */
|
||||||
unit_get_own_mask(member) |
|
|
||||||
unit_get_members_mask(member);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1127,7 +1145,7 @@ CGroupMask unit_get_siblings_mask(Unit *u) {
|
||||||
if (UNIT_ISSET(u->slice))
|
if (UNIT_ISSET(u->slice))
|
||||||
return unit_get_members_mask(UNIT_DEREF(u->slice));
|
return unit_get_members_mask(UNIT_DEREF(u->slice));
|
||||||
|
|
||||||
return unit_get_own_mask(u) | unit_get_members_mask(u);
|
return unit_get_subtree_mask(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
CGroupMask unit_get_subtree_mask(Unit *u) {
|
CGroupMask unit_get_subtree_mask(Unit *u) {
|
||||||
|
@ -1946,11 +1964,9 @@ int manager_setup_cgroup(Manager *m) {
|
||||||
if (e)
|
if (e)
|
||||||
*e = 0;
|
*e = 0;
|
||||||
|
|
||||||
/* And make sure to store away the root value without trailing
|
/* And make sure to store away the root value without trailing slash, even for the root dir, so that we can
|
||||||
* slash, even for the root dir, so that we can easily prepend
|
* easily prepend it everywhere. */
|
||||||
* it everywhere. */
|
delete_trailing_chars(m->cgroup_root, "/");
|
||||||
while ((e = endswith(m->cgroup_root, "/")))
|
|
||||||
*e = 0;
|
|
||||||
|
|
||||||
/* 2. Show data */
|
/* 2. Show data */
|
||||||
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, NULL, &path);
|
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, NULL, &path);
|
||||||
|
|
|
@ -126,6 +126,7 @@ struct CGroupContext {
|
||||||
uint64_t tasks_max;
|
uint64_t tasks_max;
|
||||||
|
|
||||||
bool delegate;
|
bool delegate;
|
||||||
|
CGroupMask delegate_controllers;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Used when querying IP accounting data */
|
/* Used when querying IP accounting data */
|
||||||
|
@ -153,8 +154,9 @@ void cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODe
|
||||||
void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockIODeviceBandwidth *b);
|
void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockIODeviceBandwidth *b);
|
||||||
|
|
||||||
CGroupMask unit_get_own_mask(Unit *u);
|
CGroupMask unit_get_own_mask(Unit *u);
|
||||||
CGroupMask unit_get_siblings_mask(Unit *u);
|
CGroupMask unit_get_delegate_mask(Unit *u);
|
||||||
CGroupMask unit_get_members_mask(Unit *u);
|
CGroupMask unit_get_members_mask(Unit *u);
|
||||||
|
CGroupMask unit_get_siblings_mask(Unit *u);
|
||||||
CGroupMask unit_get_subtree_mask(Unit *u);
|
CGroupMask unit_get_subtree_mask(Unit *u);
|
||||||
|
|
||||||
CGroupMask unit_get_target_mask(Unit *u);
|
CGroupMask unit_get_target_mask(Unit *u);
|
||||||
|
|
|
@ -32,6 +32,42 @@
|
||||||
|
|
||||||
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy);
|
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy);
|
||||||
|
|
||||||
|
static int property_get_delegate_controllers(
|
||||||
|
sd_bus *bus,
|
||||||
|
const char *path,
|
||||||
|
const char *interface,
|
||||||
|
const char *property,
|
||||||
|
sd_bus_message *reply,
|
||||||
|
void *userdata,
|
||||||
|
sd_bus_error *error) {
|
||||||
|
|
||||||
|
CGroupContext *c = userdata;
|
||||||
|
CGroupController cc;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(bus);
|
||||||
|
assert(reply);
|
||||||
|
assert(c);
|
||||||
|
|
||||||
|
if (!c->delegate)
|
||||||
|
return sd_bus_message_append(reply, "as", 0);
|
||||||
|
|
||||||
|
r = sd_bus_message_open_container(reply, 'a', "s");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
for (cc = 0; cc < _CGROUP_CONTROLLER_MAX; cc++) {
|
||||||
|
if ((c->delegate_controllers & CGROUP_CONTROLLER_TO_MASK(cc)) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
r = sd_bus_message_append(reply, "s", cgroup_controller_to_string(cc));
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sd_bus_message_close_container(reply);
|
||||||
|
}
|
||||||
|
|
||||||
static int property_get_io_device_weight(
|
static int property_get_io_device_weight(
|
||||||
sd_bus *bus,
|
sd_bus *bus,
|
||||||
const char *path,
|
const char *path,
|
||||||
|
@ -255,6 +291,7 @@ static int property_get_ip_address_access(
|
||||||
const sd_bus_vtable bus_cgroup_vtable[] = {
|
const sd_bus_vtable bus_cgroup_vtable[] = {
|
||||||
SD_BUS_VTABLE_START(0),
|
SD_BUS_VTABLE_START(0),
|
||||||
SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool, offsetof(CGroupContext, delegate), 0),
|
SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool, offsetof(CGroupContext, delegate), 0),
|
||||||
|
SD_BUS_PROPERTY("DelegateControllers", "as", property_get_delegate_controllers, 0, 0),
|
||||||
SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0),
|
SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0),
|
||||||
SD_BUS_PROPERTY("CPUWeight", "t", NULL, offsetof(CGroupContext, cpu_weight), 0),
|
SD_BUS_PROPERTY("CPUWeight", "t", NULL, offsetof(CGroupContext, cpu_weight), 0),
|
||||||
SD_BUS_PROPERTY("StartupCPUWeight", "t", NULL, offsetof(CGroupContext, startup_cpu_weight), 0),
|
SD_BUS_PROPERTY("StartupCPUWeight", "t", NULL, offsetof(CGroupContext, startup_cpu_weight), 0),
|
||||||
|
@ -315,9 +352,54 @@ static int bus_cgroup_set_transient_property(
|
||||||
|
|
||||||
if (mode != UNIT_CHECK) {
|
if (mode != UNIT_CHECK) {
|
||||||
c->delegate = b;
|
c->delegate = b;
|
||||||
|
c->delegate_controllers = b ? _CGROUP_MASK_ALL : 0;
|
||||||
|
|
||||||
unit_write_drop_in_private(u, mode, name, b ? "Delegate=yes" : "Delegate=no");
|
unit_write_drop_in_private(u, mode, name, b ? "Delegate=yes" : "Delegate=no");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
} else if (streq(name, "DelegateControllers")) {
|
||||||
|
CGroupMask mask = 0;
|
||||||
|
|
||||||
|
r = sd_bus_message_enter_container(message, 'a', "s");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
CGroupController cc;
|
||||||
|
const char *t;
|
||||||
|
|
||||||
|
r = sd_bus_message_read(message, "s", &t);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
cc = cgroup_controller_from_string(t);
|
||||||
|
if (cc < 0)
|
||||||
|
return sd_bus_error_set_errnof(error, EINVAL, "Unknown cgroup contoller '%s'", t);
|
||||||
|
|
||||||
|
mask |= CGROUP_CONTROLLER_TO_MASK(cc);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sd_bus_message_exit_container(message);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (mode != UNIT_CHECK) {
|
||||||
|
_cleanup_free_ char *t = NULL;
|
||||||
|
|
||||||
|
r = cg_mask_to_string(mask, &t);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
c->delegate = true;
|
||||||
|
c->delegate_controllers |= mask;
|
||||||
|
|
||||||
|
unit_write_drop_in_private_format(u, mode, name, "Delegate=%s", t);
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,8 +117,8 @@ static int process_deps(Unit *u, UnitDependency dependency, const char *dir_suff
|
||||||
|
|
||||||
r = unit_add_dependency_by_name(u, dependency, entry, *p, true, UNIT_DEPENDENCY_FILE);
|
r = unit_add_dependency_by_name(u, dependency, entry, *p, true, UNIT_DEPENDENCY_FILE);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_unit_error_errno(u, r, "cannot add %s dependency on %s, ignoring: %m",
|
log_unit_warning_errno(u, r, "Cannot add %s dependency on %s, ignoring: %m",
|
||||||
unit_dependency_to_string(dependency), entry);
|
unit_dependency_to_string(dependency), entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -154,12 +154,11 @@ int unit_load_dropin(Unit *u) {
|
||||||
return log_oom();
|
return log_oom();
|
||||||
}
|
}
|
||||||
|
|
||||||
STRV_FOREACH(f, u->dropin_paths) {
|
STRV_FOREACH(f, u->dropin_paths)
|
||||||
config_parse(u->id, *f, NULL,
|
(void) config_parse(u->id, *f, NULL,
|
||||||
UNIT_VTABLE(u)->sections,
|
UNIT_VTABLE(u)->sections,
|
||||||
config_item_perf_lookup, load_fragment_gperf_lookup,
|
config_item_perf_lookup, load_fragment_gperf_lookup,
|
||||||
false, false, false, u);
|
0, u);
|
||||||
}
|
|
||||||
|
|
||||||
u->dropin_mtime = now(CLOCK_REALTIME);
|
u->dropin_mtime = now(CLOCK_REALTIME);
|
||||||
|
|
||||||
|
|
|
@ -174,7 +174,7 @@ $1.BlockIOReadBandwidth, config_parse_blockio_bandwidth, 0,
|
||||||
$1.BlockIOWriteBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)
|
$1.BlockIOWriteBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)
|
||||||
$1.TasksAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.tasks_accounting)
|
$1.TasksAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.tasks_accounting)
|
||||||
$1.TasksMax, config_parse_tasks_max, 0, offsetof($1, cgroup_context.tasks_max)
|
$1.TasksMax, config_parse_tasks_max, 0, offsetof($1, cgroup_context.tasks_max)
|
||||||
$1.Delegate, config_parse_bool, 0, offsetof($1, cgroup_context.delegate)
|
$1.Delegate, config_parse_delegate, 0, offsetof($1, cgroup_context)
|
||||||
$1.IPAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.ip_accounting)
|
$1.IPAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.ip_accounting)
|
||||||
$1.IPAddressAllow, config_parse_ip_address_access, 0, offsetof($1, cgroup_context.ip_address_allow)
|
$1.IPAddressAllow, config_parse_ip_address_access, 0, offsetof($1, cgroup_context.ip_address_allow)
|
||||||
$1.IPAddressDeny, config_parse_ip_address_access, 0, offsetof($1, cgroup_context.ip_address_deny)
|
$1.IPAddressDeny, config_parse_ip_address_access, 0, offsetof($1, cgroup_context.ip_address_deny)
|
||||||
|
|
|
@ -3202,6 +3202,67 @@ int config_parse_tasks_max(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int config_parse_delegate(
|
||||||
|
const char *unit,
|
||||||
|
const char *filename,
|
||||||
|
unsigned line,
|
||||||
|
const char *section,
|
||||||
|
unsigned section_line,
|
||||||
|
const char *lvalue,
|
||||||
|
int ltype,
|
||||||
|
const char *rvalue,
|
||||||
|
void *data,
|
||||||
|
void *userdata) {
|
||||||
|
|
||||||
|
CGroupContext *c = data;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
/* We either accept a boolean value, which may be used to turn on delegation for all controllers, or turn it
|
||||||
|
* off for all. Or it takes a list of controller names, in which case we add the specified controllers to the
|
||||||
|
* mask to delegate. */
|
||||||
|
|
||||||
|
r = parse_boolean(rvalue);
|
||||||
|
if (r < 0) {
|
||||||
|
const char *p = rvalue;
|
||||||
|
CGroupMask mask = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
_cleanup_free_ char *word = NULL;
|
||||||
|
CGroupController cc;
|
||||||
|
|
||||||
|
r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
|
if (r == -ENOMEM)
|
||||||
|
return log_oom();
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
cc = cgroup_controller_from_string(word);
|
||||||
|
if (cc < 0) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid controller name '%s', ignoring", rvalue);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
mask |= CGROUP_CONTROLLER_TO_MASK(cc);
|
||||||
|
}
|
||||||
|
|
||||||
|
c->delegate = true;
|
||||||
|
c->delegate_controllers |= mask;
|
||||||
|
|
||||||
|
} else if (r > 0) {
|
||||||
|
c->delegate = true;
|
||||||
|
c->delegate_controllers = _CGROUP_MASK_ALL;
|
||||||
|
} else {
|
||||||
|
c->delegate = false;
|
||||||
|
c->delegate_controllers = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int config_parse_device_allow(
|
int config_parse_device_allow(
|
||||||
const char *unit,
|
const char *unit,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
|
@ -4450,7 +4511,7 @@ static int load_from_path(Unit *u, const char *path) {
|
||||||
r = config_parse(u->id, filename, f,
|
r = config_parse(u->id, filename, f,
|
||||||
UNIT_VTABLE(u)->sections,
|
UNIT_VTABLE(u)->sections,
|
||||||
config_item_perf_lookup, load_fragment_gperf_lookup,
|
config_item_perf_lookup, load_fragment_gperf_lookup,
|
||||||
false, true, false, u);
|
CONFIG_PARSE_ALLOW_INCLUDE, u);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,7 @@ int config_parse_cpu_weight(const char *unit, const char *filename, unsigned lin
|
||||||
int config_parse_cpu_shares(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
int config_parse_cpu_shares(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||||
int config_parse_memory_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
int config_parse_memory_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||||
int config_parse_tasks_max(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
int config_parse_tasks_max(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||||
|
int config_parse_delegate(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||||
int config_parse_device_policy(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
int config_parse_device_policy(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||||
int config_parse_device_allow(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
int config_parse_device_allow(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||||
int config_parse_io_weight(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
int config_parse_io_weight(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||||
|
|
|
@ -768,7 +768,7 @@ static int parse_config_file(void) {
|
||||||
CONF_PATHS_NULSTR("systemd/system.conf.d") :
|
CONF_PATHS_NULSTR("systemd/system.conf.d") :
|
||||||
CONF_PATHS_NULSTR("systemd/user.conf.d");
|
CONF_PATHS_NULSTR("systemd/user.conf.d");
|
||||||
|
|
||||||
config_parse_many_nulstr(fn, conf_dirs_nulstr, "Manager\0", config_item_table_lookup, items, false, NULL);
|
(void) config_parse_many_nulstr(fn, conf_dirs_nulstr, "Manager\0", config_item_table_lookup, items, CONFIG_PARSE_WARN, NULL);
|
||||||
|
|
||||||
/* Traditionally "0" was used to turn off the default unit timeouts. Fix this up so that we used USEC_INFINITY
|
/* Traditionally "0" was used to turn off the default unit timeouts. Fix this up so that we used USEC_INFINITY
|
||||||
* like everywhere else. */
|
* like everywhere else. */
|
||||||
|
|
|
@ -1152,10 +1152,6 @@ int setup_namespace(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to set up the new root directory before mounting anything there */
|
|
||||||
if (root)
|
|
||||||
(void) base_filesystem_create(root, UID_INVALID, GID_INVALID);
|
|
||||||
|
|
||||||
if (root_image) {
|
if (root_image) {
|
||||||
/* A root image is specified, mount it to the right place */
|
/* A root image is specified, mount it to the right place */
|
||||||
r = dissected_image_mount(dissected_image, root, dissect_image_flags);
|
r = dissected_image_mount(dissected_image, root, dissect_image_flags);
|
||||||
|
@ -1192,6 +1188,10 @@ int setup_namespace(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Try to set up the new root directory before mounting anything else there. */
|
||||||
|
if (root_image || root_directory)
|
||||||
|
(void) base_filesystem_create(root, UID_INVALID, GID_INVALID);
|
||||||
|
|
||||||
if (n_mounts > 0) {
|
if (n_mounts > 0) {
|
||||||
_cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
|
_cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
|
||||||
char **blacklist;
|
char **blacklist;
|
||||||
|
|
|
@ -1057,8 +1057,9 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
|
||||||
timespan[FORMAT_TIMESPAN_MAX];
|
timespan[FORMAT_TIMESPAN_MAX];
|
||||||
Unit *following;
|
Unit *following;
|
||||||
_cleanup_set_free_ Set *following_set = NULL;
|
_cleanup_set_free_ Set *following_set = NULL;
|
||||||
int r;
|
|
||||||
const char *n;
|
const char *n;
|
||||||
|
CGroupMask m;
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(u);
|
assert(u);
|
||||||
assert(u->type >= 0);
|
assert(u->type >= 0);
|
||||||
|
@ -1105,11 +1106,23 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
|
||||||
if (u->cgroup_realized_mask != 0) {
|
if (u->cgroup_realized_mask != 0) {
|
||||||
_cleanup_free_ char *s = NULL;
|
_cleanup_free_ char *s = NULL;
|
||||||
(void) cg_mask_to_string(u->cgroup_realized_mask, &s);
|
(void) cg_mask_to_string(u->cgroup_realized_mask, &s);
|
||||||
fprintf(f, "%s\tCGroup mask: %s\n", prefix, strnull(s));
|
fprintf(f, "%s\tCGroup realized mask: %s\n", prefix, strnull(s));
|
||||||
}
|
}
|
||||||
if (u->cgroup_members_mask != 0) {
|
if (u->cgroup_enabled_mask != 0) {
|
||||||
_cleanup_free_ char *s = NULL;
|
_cleanup_free_ char *s = NULL;
|
||||||
(void) cg_mask_to_string(u->cgroup_members_mask, &s);
|
(void) cg_mask_to_string(u->cgroup_enabled_mask, &s);
|
||||||
|
fprintf(f, "%s\tCGroup enabled mask: %s\n", prefix, strnull(s));
|
||||||
|
}
|
||||||
|
m = unit_get_own_mask(u);
|
||||||
|
if (m != 0) {
|
||||||
|
_cleanup_free_ char *s = NULL;
|
||||||
|
(void) cg_mask_to_string(m, &s);
|
||||||
|
fprintf(f, "%s\tCGroup own mask: %s\n", prefix, strnull(s));
|
||||||
|
}
|
||||||
|
m = unit_get_members_mask(u);
|
||||||
|
if (m != 0) {
|
||||||
|
_cleanup_free_ char *s = NULL;
|
||||||
|
(void) cg_mask_to_string(m, &s);
|
||||||
fprintf(f, "%s\tCGroup members mask: %s\n", prefix, strnull(s));
|
fprintf(f, "%s\tCGroup members mask: %s\n", prefix, strnull(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -147,7 +147,7 @@ static int parse_config(void) {
|
||||||
CONF_PATHS_NULSTR("systemd/coredump.conf.d"),
|
CONF_PATHS_NULSTR("systemd/coredump.conf.d"),
|
||||||
"Coredump\0",
|
"Coredump\0",
|
||||||
config_item_table_lookup, items,
|
config_item_table_lookup, items,
|
||||||
false, NULL);
|
CONFIG_PARSE_WARN, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t storage_size_max(void) {
|
static inline uint64_t storage_size_max(void) {
|
||||||
|
|
|
@ -1254,7 +1254,7 @@ static int parse_config(void) {
|
||||||
return config_parse_many_nulstr(PKGSYSCONFDIR "/journal-remote.conf",
|
return config_parse_many_nulstr(PKGSYSCONFDIR "/journal-remote.conf",
|
||||||
CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"),
|
CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"),
|
||||||
"Remote\0", config_item_table_lookup, items,
|
"Remote\0", config_item_table_lookup, items,
|
||||||
false, NULL);
|
CONFIG_PARSE_WARN, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void help(void) {
|
static void help(void) {
|
||||||
|
|
|
@ -543,7 +543,7 @@ static int parse_config(void) {
|
||||||
return config_parse_many_nulstr(PKGSYSCONFDIR "/journal-upload.conf",
|
return config_parse_many_nulstr(PKGSYSCONFDIR "/journal-upload.conf",
|
||||||
CONF_PATHS_NULSTR("systemd/journal-upload.conf.d"),
|
CONF_PATHS_NULSTR("systemd/journal-upload.conf.d"),
|
||||||
"Upload\0", config_item_table_lookup, items,
|
"Upload\0", config_item_table_lookup, items,
|
||||||
false, NULL);
|
CONFIG_PARSE_WARN, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void help(void) {
|
static void help(void) {
|
||||||
|
|
|
@ -1398,7 +1398,7 @@ static int server_parse_config_file(Server *s) {
|
||||||
CONF_PATHS_NULSTR("systemd/journald.conf.d"),
|
CONF_PATHS_NULSTR("systemd/journald.conf.d"),
|
||||||
"Journal\0",
|
"Journal\0",
|
||||||
config_item_perf_lookup, journald_gperf_lookup,
|
config_item_perf_lookup, journald_gperf_lookup,
|
||||||
false, s);
|
CONFIG_PARSE_WARN, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int server_dispatch_sync(sd_event_source *es, usec_t t, void *userdata) {
|
static int server_dispatch_sync(sd_event_source *es, usec_t t, void *userdata) {
|
||||||
|
|
|
@ -138,7 +138,6 @@ int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_expor
|
||||||
#define UDEV_ALLOWED_CHARS_INPUT "/ $%?,"
|
#define UDEV_ALLOWED_CHARS_INPUT "/ $%?,"
|
||||||
int util_log_priority(const char *priority);
|
int util_log_priority(const char *priority);
|
||||||
size_t util_path_encode(const char *src, char *dest, size_t size);
|
size_t util_path_encode(const char *src, char *dest, size_t size);
|
||||||
void util_remove_trailing_chars(char *path, char c);
|
|
||||||
int util_replace_whitespace(const char *str, char *to, size_t len);
|
int util_replace_whitespace(const char *str, char *to, size_t len);
|
||||||
int util_replace_chars(char *str, const char *white);
|
int util_replace_chars(char *str, const char *white);
|
||||||
unsigned int util_string_hash32(const char *key);
|
unsigned int util_string_hash32(const char *key);
|
||||||
|
|
|
@ -150,17 +150,6 @@ size_t util_path_encode(const char *src, char *dest, size_t size)
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
void util_remove_trailing_chars(char *path, char c)
|
|
||||||
{
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
if (path == NULL)
|
|
||||||
return;
|
|
||||||
len = strlen(path);
|
|
||||||
while (len > 0 && path[len-1] == c)
|
|
||||||
path[--len] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy from 'str' to 'to', while removing all leading and trailing whitespace,
|
* Copy from 'str' to 'to', while removing all leading and trailing whitespace,
|
||||||
* and replacing each run of consecutive whitespace with a single underscore.
|
* and replacing each run of consecutive whitespace with a single underscore.
|
||||||
|
|
|
@ -1072,7 +1072,7 @@ static int manager_parse_config_file(Manager *m) {
|
||||||
CONF_PATHS_NULSTR("systemd/logind.conf.d"),
|
CONF_PATHS_NULSTR("systemd/logind.conf.d"),
|
||||||
"Login\0",
|
"Login\0",
|
||||||
config_item_perf_lookup, logind_gperf_lookup,
|
config_item_perf_lookup, logind_gperf_lookup,
|
||||||
false, m);
|
CONFIG_PARSE_WARN, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int manager_dispatch_reload_signal(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
|
static int manager_dispatch_reload_signal(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
|
||||||
|
|
|
@ -630,7 +630,7 @@ static int netdev_load_one(Manager *manager, const char *filename) {
|
||||||
r = config_parse_many(filename, network_dirs, dropin_dirname,
|
r = config_parse_many(filename, network_dirs, dropin_dirname,
|
||||||
"Match\0NetDev\0",
|
"Match\0NetDev\0",
|
||||||
config_item_perf_lookup, network_netdev_gperf_lookup,
|
config_item_perf_lookup, network_netdev_gperf_lookup,
|
||||||
true, netdev_raw);
|
CONFIG_PARSE_WARN, netdev_raw);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -671,7 +671,7 @@ static int netdev_load_one(Manager *manager, const char *filename) {
|
||||||
r = config_parse(NULL, filename, file,
|
r = config_parse(NULL, filename, file,
|
||||||
NETDEV_VTABLE(netdev)->sections,
|
NETDEV_VTABLE(netdev)->sections,
|
||||||
config_item_perf_lookup, network_netdev_gperf_lookup,
|
config_item_perf_lookup, network_netdev_gperf_lookup,
|
||||||
false, false, false, netdev);
|
CONFIG_PARSE_WARN, netdev);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ int manager_parse_config_file(Manager *m) {
|
||||||
CONF_PATHS_NULSTR("systemd/networkd.conf.d"),
|
CONF_PATHS_NULSTR("systemd/networkd.conf.d"),
|
||||||
"DHCP\0",
|
"DHCP\0",
|
||||||
config_item_perf_lookup, networkd_gperf_lookup,
|
config_item_perf_lookup, networkd_gperf_lookup,
|
||||||
false, m);
|
CONFIG_PARSE_WARN, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* const duid_type_table[_DUID_TYPE_MAX] = {
|
static const char* const duid_type_table[_DUID_TYPE_MAX] = {
|
||||||
|
|
|
@ -280,7 +280,7 @@ static int network_load_one(Manager *manager, const char *filename) {
|
||||||
"IPv6PrefixDelegation\0"
|
"IPv6PrefixDelegation\0"
|
||||||
"IPv6Prefix\0",
|
"IPv6Prefix\0",
|
||||||
config_item_perf_lookup, network_network_gperf_lookup,
|
config_item_perf_lookup, network_network_gperf_lookup,
|
||||||
false, network);
|
CONFIG_PARSE_WARN, network);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -59,9 +59,7 @@ int settings_load(FILE *f, const char *path, Settings **ret) {
|
||||||
"Network\0"
|
"Network\0"
|
||||||
"Files\0",
|
"Files\0",
|
||||||
config_item_perf_lookup, nspawn_gperf_lookup,
|
config_item_perf_lookup, nspawn_gperf_lookup,
|
||||||
false,
|
CONFIG_PARSE_WARN,
|
||||||
false,
|
|
||||||
true,
|
|
||||||
s);
|
s);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
|
@ -236,7 +236,7 @@ int manager_parse_config_file(Manager *m) {
|
||||||
CONF_PATHS_NULSTR("systemd/resolved.conf.d"),
|
CONF_PATHS_NULSTR("systemd/resolved.conf.d"),
|
||||||
"Resolve\0",
|
"Resolve\0",
|
||||||
config_item_perf_lookup, resolved_gperf_lookup,
|
config_item_perf_lookup, resolved_gperf_lookup,
|
||||||
false, m);
|
CONFIG_PARSE_WARN, m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -183,6 +183,51 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
|
||||||
|
|
||||||
r = sd_bus_message_append(m, "sv", field, "t", bytes);
|
r = sd_bus_message_append(m, "sv", field, "t", bytes);
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
|
} else if (streq(field, "Delegate")) {
|
||||||
|
|
||||||
|
r = parse_boolean(eq);
|
||||||
|
if (r < 0) {
|
||||||
|
const char *p = eq;
|
||||||
|
|
||||||
|
r = sd_bus_message_append(m, "s", "DelegateControllers");
|
||||||
|
if (r < 0)
|
||||||
|
goto finish;
|
||||||
|
|
||||||
|
r = sd_bus_message_open_container(m, 'v', "as");
|
||||||
|
if (r < 0)
|
||||||
|
goto finish;
|
||||||
|
|
||||||
|
r = sd_bus_message_open_container(m, 'a', "s");
|
||||||
|
if (r < 0)
|
||||||
|
goto finish;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
_cleanup_free_ char *word = NULL;
|
||||||
|
|
||||||
|
r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
|
if (r == -ENOMEM)
|
||||||
|
return log_oom();
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Invalid syntax: %s", eq);
|
||||||
|
|
||||||
|
r = sd_bus_message_append(m, "s", word);
|
||||||
|
if (r < 0)
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sd_bus_message_close_container(m);
|
||||||
|
if (r < 0)
|
||||||
|
goto finish;
|
||||||
|
|
||||||
|
r = sd_bus_message_close_container(m);
|
||||||
|
} else
|
||||||
|
r = sd_bus_message_append(m, "sv", "Delegate", "b", r);
|
||||||
|
|
||||||
|
goto finish;
|
||||||
|
|
||||||
} else if (streq(field, "TasksMax")) {
|
} else if (streq(field, "TasksMax")) {
|
||||||
uint64_t t;
|
uint64_t t;
|
||||||
|
|
||||||
|
@ -238,7 +283,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
|
||||||
"TasksAccounting", "IPAccounting", "SendSIGHUP", "SendSIGKILL", "WakeSystem",
|
"TasksAccounting", "IPAccounting", "SendSIGHUP", "SendSIGKILL", "WakeSystem",
|
||||||
"DefaultDependencies", "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate",
|
"DefaultDependencies", "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate",
|
||||||
"RemainAfterExit", "PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers",
|
"RemainAfterExit", "PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers",
|
||||||
"NoNewPrivileges", "SyslogLevelPrefix", "Delegate", "RemainAfterElapse",
|
"NoNewPrivileges", "SyslogLevelPrefix", "RemainAfterElapse",
|
||||||
"MemoryDenyWriteExecute", "RestrictRealtime", "DynamicUser", "RemoveIPC",
|
"MemoryDenyWriteExecute", "RestrictRealtime", "DynamicUser", "RemoveIPC",
|
||||||
"ProtectKernelTunables", "ProtectKernelModules", "ProtectControlGroups", "MountAPIVFS",
|
"ProtectKernelTunables", "ProtectKernelModules", "ProtectControlGroups", "MountAPIVFS",
|
||||||
"CPUSchedulingResetOnFork", "LockPersonality")) {
|
"CPUSchedulingResetOnFork", "LockPersonality")) {
|
||||||
|
|
|
@ -121,17 +121,18 @@ int config_item_perf_lookup(
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Run the user supplied parser for an assignment */
|
/* Run the user supplied parser for an assignment */
|
||||||
static int next_assignment(const char *unit,
|
static int next_assignment(
|
||||||
const char *filename,
|
const char *unit,
|
||||||
unsigned line,
|
const char *filename,
|
||||||
ConfigItemLookup lookup,
|
unsigned line,
|
||||||
const void *table,
|
ConfigItemLookup lookup,
|
||||||
const char *section,
|
const void *table,
|
||||||
unsigned section_line,
|
const char *section,
|
||||||
const char *lvalue,
|
unsigned section_line,
|
||||||
const char *rvalue,
|
const char *lvalue,
|
||||||
bool relaxed,
|
const char *rvalue,
|
||||||
void *userdata) {
|
ConfigParseFlags flags,
|
||||||
|
void *userdata) {
|
||||||
|
|
||||||
ConfigParserCallback func = NULL;
|
ConfigParserCallback func = NULL;
|
||||||
int ltype = 0;
|
int ltype = 0;
|
||||||
|
@ -157,26 +158,26 @@ static int next_assignment(const char *unit,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Warn about unknown non-extension fields. */
|
/* Warn about unknown non-extension fields. */
|
||||||
if (!relaxed && !startswith(lvalue, "X-"))
|
if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(lvalue, "X-"))
|
||||||
log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s'", lvalue, section);
|
log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s'", lvalue, section);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse a variable assignment line */
|
/* Parse a variable assignment line */
|
||||||
static int parse_line(const char* unit,
|
static int parse_line(
|
||||||
const char *filename,
|
const char* unit,
|
||||||
unsigned line,
|
const char *filename,
|
||||||
const char *sections,
|
unsigned line,
|
||||||
ConfigItemLookup lookup,
|
const char *sections,
|
||||||
const void *table,
|
ConfigItemLookup lookup,
|
||||||
bool relaxed,
|
const void *table,
|
||||||
bool allow_include,
|
ConfigParseFlags flags,
|
||||||
char **section,
|
char **section,
|
||||||
unsigned *section_line,
|
unsigned *section_line,
|
||||||
bool *section_ignored,
|
bool *section_ignored,
|
||||||
char *l,
|
char *l,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
char *e;
|
char *e;
|
||||||
|
|
||||||
|
@ -186,7 +187,6 @@ static int parse_line(const char* unit,
|
||||||
assert(l);
|
assert(l);
|
||||||
|
|
||||||
l = strstrip(l);
|
l = strstrip(l);
|
||||||
|
|
||||||
if (!*l)
|
if (!*l)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -205,7 +205,7 @@ static int parse_line(const char* unit,
|
||||||
*
|
*
|
||||||
* Support for them should be eventually removed. */
|
* Support for them should be eventually removed. */
|
||||||
|
|
||||||
if (!allow_include) {
|
if (!(flags & CONFIG_PARSE_ALLOW_INCLUDE)) {
|
||||||
log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
|
log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -214,7 +214,7 @@ static int parse_line(const char* unit,
|
||||||
if (!fn)
|
if (!fn)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, userdata);
|
return config_parse(unit, fn, NULL, sections, lookup, table, flags, userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*l == '[') {
|
if (*l == '[') {
|
||||||
|
@ -235,7 +235,7 @@ static int parse_line(const char* unit,
|
||||||
|
|
||||||
if (sections && !nulstr_contains(sections, n)) {
|
if (sections && !nulstr_contains(sections, n)) {
|
||||||
|
|
||||||
if (!relaxed && !startswith(n, "X-"))
|
if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(n, "X-"))
|
||||||
log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
|
log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
|
||||||
|
|
||||||
free(n);
|
free(n);
|
||||||
|
@ -254,7 +254,7 @@ static int parse_line(const char* unit,
|
||||||
|
|
||||||
if (sections && !*section) {
|
if (sections && !*section) {
|
||||||
|
|
||||||
if (!relaxed && !*section_ignored)
|
if (!(flags & CONFIG_PARSE_RELAXED) && !*section_ignored)
|
||||||
log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
|
log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -278,7 +278,7 @@ static int parse_line(const char* unit,
|
||||||
*section_line,
|
*section_line,
|
||||||
strstrip(l),
|
strstrip(l),
|
||||||
strstrip(e),
|
strstrip(e),
|
||||||
relaxed,
|
flags,
|
||||||
userdata);
|
userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,15 +289,13 @@ int config_parse(const char *unit,
|
||||||
const char *sections,
|
const char *sections,
|
||||||
ConfigItemLookup lookup,
|
ConfigItemLookup lookup,
|
||||||
const void *table,
|
const void *table,
|
||||||
bool relaxed,
|
ConfigParseFlags flags,
|
||||||
bool allow_include,
|
|
||||||
bool warn,
|
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
_cleanup_free_ char *section = NULL, *continuation = NULL;
|
_cleanup_free_ char *section = NULL, *continuation = NULL;
|
||||||
_cleanup_fclose_ FILE *ours = NULL;
|
_cleanup_fclose_ FILE *ours = NULL;
|
||||||
unsigned line = 0, section_line = 0;
|
unsigned line = 0, section_line = 0;
|
||||||
bool section_ignored = false, allow_bom = true;
|
bool section_ignored = false;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(filename);
|
assert(filename);
|
||||||
|
@ -308,7 +306,7 @@ int config_parse(const char *unit,
|
||||||
if (!f) {
|
if (!f) {
|
||||||
/* Only log on request, except for ENOENT,
|
/* Only log on request, except for ENOENT,
|
||||||
* since we return 0 to the caller. */
|
* since we return 0 to the caller. */
|
||||||
if (warn || errno == ENOENT)
|
if ((flags & CONFIG_PARSE_WARN) || errno == ENOENT)
|
||||||
log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
|
log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
|
||||||
"Failed to open configuration file '%s': %m", filename);
|
"Failed to open configuration file '%s': %m", filename);
|
||||||
return errno == ENOENT ? 0 : -errno;
|
return errno == ENOENT ? 0 : -errno;
|
||||||
|
@ -319,52 +317,50 @@ int config_parse(const char *unit,
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
_cleanup_free_ char *buf = NULL;
|
_cleanup_free_ char *buf = NULL;
|
||||||
char *l, *p, *c = NULL, *e;
|
|
||||||
bool escaped = false;
|
bool escaped = false;
|
||||||
|
char *l, *p, *e;
|
||||||
|
|
||||||
r = read_line(f, LONG_LINE_MAX, &buf);
|
r = read_line(f, LONG_LINE_MAX, &buf);
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
break;
|
break;
|
||||||
if (r == -ENOBUFS) {
|
if (r == -ENOBUFS) {
|
||||||
if (warn)
|
if (flags & CONFIG_PARSE_WARN)
|
||||||
log_error_errno(r, "%s:%u: Line too long", filename, line);
|
log_error_errno(r, "%s:%u: Line too long", filename, line);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
if (warn)
|
if (CONFIG_PARSE_WARN)
|
||||||
log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line);
|
log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
l = buf;
|
l = buf;
|
||||||
if (allow_bom) {
|
if (!(flags & CONFIG_PARSE_REFUSE_BOM)) {
|
||||||
char *q;
|
char *q;
|
||||||
|
|
||||||
q = startswith(buf, UTF8_BYTE_ORDER_MARK);
|
q = startswith(buf, UTF8_BYTE_ORDER_MARK);
|
||||||
if (q) {
|
if (q) {
|
||||||
l = q;
|
l = q;
|
||||||
allow_bom = false;
|
flags |= CONFIG_PARSE_REFUSE_BOM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (continuation) {
|
if (continuation) {
|
||||||
if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) {
|
if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) {
|
||||||
if (warn)
|
if (flags & CONFIG_PARSE_WARN)
|
||||||
log_error("%s:%u: Continuation line too long", filename, line);
|
log_error("%s:%u: Continuation line too long", filename, line);
|
||||||
return -ENOBUFS;
|
return -ENOBUFS;
|
||||||
}
|
}
|
||||||
|
|
||||||
c = strappend(continuation, l);
|
if (!strextend(&continuation, l, NULL)) {
|
||||||
if (!c) {
|
if (flags & CONFIG_PARSE_WARN)
|
||||||
if (warn)
|
|
||||||
log_oom();
|
log_oom();
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
continuation = mfree(continuation);
|
p = continuation;
|
||||||
p = c;
|
|
||||||
} else
|
} else
|
||||||
p = l;
|
p = l;
|
||||||
|
|
||||||
|
@ -378,12 +374,10 @@ int config_parse(const char *unit,
|
||||||
if (escaped) {
|
if (escaped) {
|
||||||
*(e-1) = ' ';
|
*(e-1) = ' ';
|
||||||
|
|
||||||
if (c)
|
if (!continuation) {
|
||||||
continuation = c;
|
|
||||||
else {
|
|
||||||
continuation = strdup(l);
|
continuation = strdup(l);
|
||||||
if (!continuation) {
|
if (!continuation) {
|
||||||
if (warn)
|
if (flags & CONFIG_PARSE_WARN)
|
||||||
log_oom();
|
log_oom();
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
@ -398,20 +392,20 @@ int config_parse(const char *unit,
|
||||||
sections,
|
sections,
|
||||||
lookup,
|
lookup,
|
||||||
table,
|
table,
|
||||||
relaxed,
|
flags,
|
||||||
allow_include,
|
|
||||||
§ion,
|
§ion,
|
||||||
§ion_line,
|
§ion_line,
|
||||||
§ion_ignored,
|
§ion_ignored,
|
||||||
p,
|
p,
|
||||||
userdata);
|
userdata);
|
||||||
free(c);
|
|
||||||
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
if (warn)
|
if (flags & CONFIG_PARSE_WARN)
|
||||||
log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
|
log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
continuation = mfree(continuation);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -423,20 +417,20 @@ static int config_parse_many_files(
|
||||||
const char *sections,
|
const char *sections,
|
||||||
ConfigItemLookup lookup,
|
ConfigItemLookup lookup,
|
||||||
const void *table,
|
const void *table,
|
||||||
bool relaxed,
|
ConfigParseFlags flags,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
char **fn;
|
char **fn;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (conf_file) {
|
if (conf_file) {
|
||||||
r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata);
|
r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
STRV_FOREACH(fn, files) {
|
STRV_FOREACH(fn, files) {
|
||||||
r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata);
|
r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -451,7 +445,7 @@ int config_parse_many_nulstr(
|
||||||
const char *sections,
|
const char *sections,
|
||||||
ConfigItemLookup lookup,
|
ConfigItemLookup lookup,
|
||||||
const void *table,
|
const void *table,
|
||||||
bool relaxed,
|
ConfigParseFlags flags,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
_cleanup_strv_free_ char **files = NULL;
|
_cleanup_strv_free_ char **files = NULL;
|
||||||
|
@ -461,8 +455,7 @@ int config_parse_many_nulstr(
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
return config_parse_many_files(conf_file, files,
|
return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
|
||||||
sections, lookup, table, relaxed, userdata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse each config file in the directories specified as strv. */
|
/* Parse each config file in the directories specified as strv. */
|
||||||
|
@ -473,7 +466,7 @@ int config_parse_many(
|
||||||
const char *sections,
|
const char *sections,
|
||||||
ConfigItemLookup lookup,
|
ConfigItemLookup lookup,
|
||||||
const void *table,
|
const void *table,
|
||||||
bool relaxed,
|
ConfigParseFlags flags,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
_cleanup_strv_free_ char **dropin_dirs = NULL;
|
_cleanup_strv_free_ char **dropin_dirs = NULL;
|
||||||
|
@ -490,8 +483,7 @@ int config_parse_many(
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
return config_parse_many_files(conf_file, files,
|
return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
|
||||||
sections, lookup, table, relaxed, userdata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DEFINE_PARSER(type, vartype, conv_func) \
|
#define DEFINE_PARSER(type, vartype, conv_func) \
|
||||||
|
@ -567,16 +559,17 @@ int config_parse_iec_size(const char* unit,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int config_parse_si_size(const char* unit,
|
int config_parse_si_size(
|
||||||
const char *filename,
|
const char* unit,
|
||||||
unsigned line,
|
const char *filename,
|
||||||
const char *section,
|
unsigned line,
|
||||||
unsigned section_line,
|
const char *section,
|
||||||
const char *lvalue,
|
unsigned section_line,
|
||||||
int ltype,
|
const char *lvalue,
|
||||||
const char *rvalue,
|
int ltype,
|
||||||
void *data,
|
const char *rvalue,
|
||||||
void *userdata) {
|
void *data,
|
||||||
|
void *userdata) {
|
||||||
|
|
||||||
size_t *sz = data;
|
size_t *sz = data;
|
||||||
uint64_t v;
|
uint64_t v;
|
||||||
|
@ -597,16 +590,17 @@ int config_parse_si_size(const char* unit,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int config_parse_iec_uint64(const char* unit,
|
int config_parse_iec_uint64(
|
||||||
const char *filename,
|
const char* unit,
|
||||||
unsigned line,
|
const char *filename,
|
||||||
const char *section,
|
unsigned line,
|
||||||
unsigned section_line,
|
const char *section,
|
||||||
const char *lvalue,
|
unsigned section_line,
|
||||||
int ltype,
|
const char *lvalue,
|
||||||
const char *rvalue,
|
int ltype,
|
||||||
void *data,
|
const char *rvalue,
|
||||||
void *userdata) {
|
void *data,
|
||||||
|
void *userdata) {
|
||||||
|
|
||||||
uint64_t *bytes = data;
|
uint64_t *bytes = data;
|
||||||
int r;
|
int r;
|
||||||
|
|
|
@ -29,8 +29,14 @@
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
|
||||||
/* An abstract parser for simple, line based, shallow configuration
|
/* An abstract parser for simple, line based, shallow configuration files consisting of variable assignments only. */
|
||||||
* files consisting of variable assignments only. */
|
|
||||||
|
typedef enum ConfigParseFlags {
|
||||||
|
CONFIG_PARSE_RELAXED = 1U << 0,
|
||||||
|
CONFIG_PARSE_ALLOW_INCLUDE = 1U << 1,
|
||||||
|
CONFIG_PARSE_WARN = 1U << 2,
|
||||||
|
CONFIG_PARSE_REFUSE_BOM = 1U << 3,
|
||||||
|
} ConfigParseFlags;
|
||||||
|
|
||||||
/* Prototype for a parser for a specific configuration setting */
|
/* Prototype for a parser for a specific configuration setting */
|
||||||
typedef int (*ConfigParserCallback)(const char *unit,
|
typedef int (*ConfigParserCallback)(const char *unit,
|
||||||
|
@ -91,9 +97,7 @@ int config_parse(
|
||||||
const char *sections, /* nulstr */
|
const char *sections, /* nulstr */
|
||||||
ConfigItemLookup lookup,
|
ConfigItemLookup lookup,
|
||||||
const void *table,
|
const void *table,
|
||||||
bool relaxed,
|
ConfigParseFlags flags,
|
||||||
bool allow_include,
|
|
||||||
bool warn,
|
|
||||||
void *userdata);
|
void *userdata);
|
||||||
|
|
||||||
int config_parse_many_nulstr(
|
int config_parse_many_nulstr(
|
||||||
|
@ -102,7 +106,7 @@ int config_parse_many_nulstr(
|
||||||
const char *sections, /* nulstr */
|
const char *sections, /* nulstr */
|
||||||
ConfigItemLookup lookup,
|
ConfigItemLookup lookup,
|
||||||
const void *table,
|
const void *table,
|
||||||
bool relaxed,
|
ConfigParseFlags flags,
|
||||||
void *userdata);
|
void *userdata);
|
||||||
|
|
||||||
int config_parse_many(
|
int config_parse_many(
|
||||||
|
@ -112,7 +116,7 @@ int config_parse_many(
|
||||||
const char *sections, /* nulstr */
|
const char *sections, /* nulstr */
|
||||||
ConfigItemLookup lookup,
|
ConfigItemLookup lookup,
|
||||||
const void *table,
|
const void *table,
|
||||||
bool relaxed,
|
ConfigParseFlags flags,
|
||||||
void *userdata);
|
void *userdata);
|
||||||
|
|
||||||
/* Generic parsers */
|
/* Generic parsers */
|
||||||
|
|
|
@ -1308,7 +1308,7 @@ static int unit_file_load(
|
||||||
r = config_parse(info->name, path, f,
|
r = config_parse(info->name, path, f,
|
||||||
NULL,
|
NULL,
|
||||||
config_item_table_lookup, items,
|
config_item_table_lookup, items,
|
||||||
true, true, false, info);
|
CONFIG_PARSE_RELAXED|CONFIG_PARSE_ALLOW_INCLUDE, info);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to parse %s: %m", info->name);
|
return log_debug_errno(r, "Failed to parse %s: %m", info->name);
|
||||||
|
|
||||||
|
|
|
@ -58,10 +58,10 @@ int parse_sleep_config(const char *verb, char ***_modes, char ***_states) {
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
config_parse_many_nulstr(PKGSYSCONFDIR "/sleep.conf",
|
(void) config_parse_many_nulstr(PKGSYSCONFDIR "/sleep.conf",
|
||||||
CONF_PATHS_NULSTR("systemd/sleep.conf.d"),
|
CONF_PATHS_NULSTR("systemd/sleep.conf.d"),
|
||||||
"Sleep\0", config_item_table_lookup, items,
|
"Sleep\0", config_item_table_lookup, items,
|
||||||
false, NULL);
|
CONFIG_PARSE_WARN, NULL);
|
||||||
|
|
||||||
if (streq(verb, "suspend")) {
|
if (streq(verb, "suspend")) {
|
||||||
/* empty by default */
|
/* empty by default */
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "manager.h"
|
#include "manager.h"
|
||||||
#include "rm-rf.h"
|
#include "rm-rf.h"
|
||||||
|
#include "string-util.h"
|
||||||
#include "test-helper.h"
|
#include "test-helper.h"
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
#include "unit.h"
|
#include "unit.h"
|
||||||
|
@ -117,10 +118,38 @@ static int test_cgroup_mask(void) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_cg_mask_to_string_one(CGroupMask mask, const char *t) {
|
||||||
|
_cleanup_free_ char *b = NULL;
|
||||||
|
|
||||||
|
assert_se(cg_mask_to_string(mask, &b) >= 0);
|
||||||
|
assert_se(streq_ptr(b, t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_cg_mask_to_string(void) {
|
||||||
|
test_cg_mask_to_string_one(0, NULL);
|
||||||
|
test_cg_mask_to_string_one(_CGROUP_MASK_ALL, "cpu cpuacct io blkio memory devices pids");
|
||||||
|
test_cg_mask_to_string_one(CGROUP_MASK_CPU, "cpu");
|
||||||
|
test_cg_mask_to_string_one(CGROUP_MASK_CPUACCT, "cpuacct");
|
||||||
|
test_cg_mask_to_string_one(CGROUP_MASK_IO, "io");
|
||||||
|
test_cg_mask_to_string_one(CGROUP_MASK_BLKIO, "blkio");
|
||||||
|
test_cg_mask_to_string_one(CGROUP_MASK_MEMORY, "memory");
|
||||||
|
test_cg_mask_to_string_one(CGROUP_MASK_DEVICES, "devices");
|
||||||
|
test_cg_mask_to_string_one(CGROUP_MASK_PIDS, "pids");
|
||||||
|
test_cg_mask_to_string_one(CGROUP_MASK_CPU|CGROUP_MASK_CPUACCT, "cpu cpuacct");
|
||||||
|
test_cg_mask_to_string_one(CGROUP_MASK_CPU|CGROUP_MASK_PIDS, "cpu pids");
|
||||||
|
test_cg_mask_to_string_one(CGROUP_MASK_CPUACCT|CGROUP_MASK_PIDS, "cpuacct pids");
|
||||||
|
test_cg_mask_to_string_one(CGROUP_MASK_DEVICES|CGROUP_MASK_PIDS, "devices pids");
|
||||||
|
test_cg_mask_to_string_one(CGROUP_MASK_IO|CGROUP_MASK_BLKIO, "io blkio");
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
|
log_parse_environment();
|
||||||
|
log_open();
|
||||||
|
|
||||||
TEST_REQ_RUNNING_SYSTEMD(rc = test_cgroup_mask());
|
TEST_REQ_RUNNING_SYSTEMD(rc = test_cgroup_mask());
|
||||||
|
test_cg_mask_to_string();
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -311,7 +311,7 @@ static void test_config_parse(unsigned i, const char *s) {
|
||||||
r = config_parse(NULL, name, f,
|
r = config_parse(NULL, name, f,
|
||||||
"Section\0",
|
"Section\0",
|
||||||
config_item_table_lookup, items,
|
config_item_table_lookup, items,
|
||||||
false, false, true, NULL);
|
CONFIG_PARSE_WARN, NULL);
|
||||||
|
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 0 ... 3:
|
case 0 ... 3:
|
||||||
|
|
|
@ -288,11 +288,47 @@ static void test_endswith_no_case(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_delete_chars(void) {
|
static void test_delete_chars(void) {
|
||||||
char *r;
|
char *s, input[] = " hello, waldo. abc";
|
||||||
char input[] = " hello, waldo. abc";
|
|
||||||
|
|
||||||
r = delete_chars(input, WHITESPACE);
|
s = delete_chars(input, WHITESPACE);
|
||||||
assert_se(streq(r, "hello,waldo.abc"));
|
assert_se(streq(s, "hello,waldo.abc"));
|
||||||
|
assert_se(s == input);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_delete_trailing_chars(void) {
|
||||||
|
|
||||||
|
char *s,
|
||||||
|
input1[] = " \n \r k \n \r ",
|
||||||
|
input2[] = "kkkkthiskkkiskkkaktestkkk",
|
||||||
|
input3[] = "abcdef";
|
||||||
|
|
||||||
|
s = delete_trailing_chars(input1, WHITESPACE);
|
||||||
|
assert_se(streq(s, " \n \r k"));
|
||||||
|
assert_se(s == input1);
|
||||||
|
|
||||||
|
s = delete_trailing_chars(input2, "kt");
|
||||||
|
assert_se(streq(s, "kkkkthiskkkiskkkaktes"));
|
||||||
|
assert_se(s == input2);
|
||||||
|
|
||||||
|
s = delete_trailing_chars(input3, WHITESPACE);
|
||||||
|
assert_se(streq(s, "abcdef"));
|
||||||
|
assert_se(s == input3);
|
||||||
|
|
||||||
|
s = delete_trailing_chars(input3, "fe");
|
||||||
|
assert_se(streq(s, "abcd"));
|
||||||
|
assert_se(s == input3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_skip_leading_chars(void) {
|
||||||
|
char input1[] = " \n \r k \n \r ",
|
||||||
|
input2[] = "kkkkthiskkkiskkkaktestkkk",
|
||||||
|
input3[] = "abcdef";
|
||||||
|
|
||||||
|
assert_se(streq(skip_leading_chars(input1, WHITESPACE), "k \n \r "));
|
||||||
|
assert_se(streq(skip_leading_chars(input2, "k"), "thiskkkiskkkaktestkkk"));
|
||||||
|
assert_se(streq(skip_leading_chars(input2, "tk"), "hiskkkiskkkaktestkkk"));
|
||||||
|
assert_se(streq(skip_leading_chars(input3, WHITESPACE), "abcdef"));
|
||||||
|
assert_se(streq(skip_leading_chars(input3, "bcaef"), "def"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_in_charset(void) {
|
static void test_in_charset(void) {
|
||||||
|
@ -361,6 +397,8 @@ int main(int argc, char *argv[]) {
|
||||||
test_endswith();
|
test_endswith();
|
||||||
test_endswith_no_case();
|
test_endswith_no_case();
|
||||||
test_delete_chars();
|
test_delete_chars();
|
||||||
|
test_delete_trailing_chars();
|
||||||
|
test_skip_leading_chars();
|
||||||
test_in_charset();
|
test_in_charset();
|
||||||
test_split_pair();
|
test_split_pair();
|
||||||
test_first_word();
|
test_first_word();
|
||||||
|
|
|
@ -114,7 +114,7 @@ int manager_parse_config_file(Manager *m) {
|
||||||
CONF_PATHS_NULSTR("systemd/timesyncd.conf.d"),
|
CONF_PATHS_NULSTR("systemd/timesyncd.conf.d"),
|
||||||
"Time\0",
|
"Time\0",
|
||||||
config_item_perf_lookup, timesyncd_gperf_lookup,
|
config_item_perf_lookup, timesyncd_gperf_lookup,
|
||||||
false, m);
|
CONFIG_PARSE_WARN, m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -310,7 +310,7 @@ static int parse_password(const char *filename, char **wall) {
|
||||||
r = config_parse(NULL, filename, NULL,
|
r = config_parse(NULL, filename, NULL,
|
||||||
NULL,
|
NULL,
|
||||||
config_item_table_lookup, items,
|
config_item_table_lookup, items,
|
||||||
true, false, true, NULL);
|
CONFIG_PARSE_RELAXED|CONFIG_PARSE_WARN, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -175,7 +175,7 @@ static int load_link(link_config_ctx *ctx, const char *filename) {
|
||||||
r = config_parse(NULL, filename, file,
|
r = config_parse(NULL, filename, file,
|
||||||
"Match\0Link\0Ethernet\0",
|
"Match\0Link\0Ethernet\0",
|
||||||
config_item_perf_lookup, link_config_gperf_lookup,
|
config_item_perf_lookup, link_config_gperf_lookup,
|
||||||
false, false, true, link);
|
CONFIG_PARSE_WARN, link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
else
|
else
|
||||||
|
|
|
@ -1967,7 +1967,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
|
||||||
} else {
|
} else {
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
util_remove_trailing_chars(result, '\n');
|
delete_trailing_chars(result, "\n");
|
||||||
if (IN_SET(esc, ESCAPE_UNSET, ESCAPE_REPLACE)) {
|
if (IN_SET(esc, ESCAPE_UNSET, ESCAPE_REPLACE)) {
|
||||||
count = util_replace_chars(result, UDEV_ALLOWED_CHARS_INPUT);
|
count = util_replace_chars(result, UDEV_ALLOWED_CHARS_INPUT);
|
||||||
if (count > 0)
|
if (count > 0)
|
||||||
|
|
|
@ -85,7 +85,7 @@ static int adm_builtin(struct udev *udev, int argc, char *argv[]) {
|
||||||
strscpyl(filename, sizeof(filename), "/sys", syspath, NULL);
|
strscpyl(filename, sizeof(filename), "/sys", syspath, NULL);
|
||||||
else
|
else
|
||||||
strscpy(filename, sizeof(filename), syspath);
|
strscpy(filename, sizeof(filename), syspath);
|
||||||
util_remove_trailing_chars(filename, '/');
|
delete_trailing_chars(filename, "/");
|
||||||
|
|
||||||
dev = udev_device_new_from_syspath(udev, filename);
|
dev = udev_device_new_from_syspath(udev, filename);
|
||||||
if (dev == NULL) {
|
if (dev == NULL) {
|
||||||
|
|
|
@ -116,7 +116,7 @@ static int adm_test(struct udev *udev, int argc, char *argv[]) {
|
||||||
strscpyl(filename, sizeof(filename), "/sys", syspath, NULL);
|
strscpyl(filename, sizeof(filename), "/sys", syspath, NULL);
|
||||||
else
|
else
|
||||||
strscpy(filename, sizeof(filename), syspath);
|
strscpy(filename, sizeof(filename), syspath);
|
||||||
util_remove_trailing_chars(filename, '/');
|
delete_trailing_chars(filename, "/");
|
||||||
|
|
||||||
dev = udev_device_new_from_synthetic_event(udev, filename, action);
|
dev = udev_device_new_from_synthetic_event(udev, filename, action);
|
||||||
if (dev == NULL) {
|
if (dev == NULL) {
|
||||||
|
|
Loading…
Reference in a new issue