summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2018-06-22 13:38:31 +0200
committerMichael Biebl <biebl@debian.org>2018-06-22 13:38:31 +0200
commitb012e92123bdc9fa10c2f079ec5bd9313b23e21a (patch)
tree94b74f04796e0da187092db7c2487aaf30f0faf1 /src/core
parent98393f852f2f66a74f7370aa63c07b26d610343c (diff)
downloadsystemd-b012e92123bdc9fa10c2f079ec5bd9313b23e21a.tar.gz
New upstream version 239
Diffstat (limited to 'src/core')
-rw-r--r--src/core/all-units.h14
-rw-r--r--src/core/audit-fd.c19
-rw-r--r--src/core/audit-fd.h19
-rw-r--r--src/core/automount.c32
-rw-r--r--src/core/automount.h21
-rw-r--r--src/core/bpf-firewall.c32
-rw-r--r--src/core/bpf-firewall.h18
-rw-r--r--src/core/cgroup.c165
-rw-r--r--src/core/cgroup.h22
-rw-r--r--src/core/chown-recursive.c18
-rw-r--r--src/core/chown-recursive.h19
-rw-r--r--src/core/dbus-automount.c18
-rw-r--r--src/core/dbus-automount.h21
-rw-r--r--src/core/dbus-cgroup.c184
-rw-r--r--src/core/dbus-cgroup.h21
-rw-r--r--src/core/dbus-device.c18
-rw-r--r--src/core/dbus-device.h21
-rw-r--r--src/core/dbus-execute.c392
-rw-r--r--src/core/dbus-execute.h20
-rw-r--r--src/core/dbus-job.c21
-rw-r--r--src/core/dbus-job.h20
-rw-r--r--src/core/dbus-kill.c18
-rw-r--r--src/core/dbus-kill.h20
-rw-r--r--src/core/dbus-manager.c340
-rw-r--r--src/core/dbus-manager.h19
-rw-r--r--src/core/dbus-mount.c101
-rw-r--r--src/core/dbus-mount.h20
-rw-r--r--src/core/dbus-path.c45
-rw-r--r--src/core/dbus-path.h20
-rw-r--r--src/core/dbus-scope.c18
-rw-r--r--src/core/dbus-scope.h21
-rw-r--r--src/core/dbus-service.c27
-rw-r--r--src/core/dbus-service.h20
-rw-r--r--src/core/dbus-slice.c18
-rw-r--r--src/core/dbus-slice.h20
-rw-r--r--src/core/dbus-socket.c55
-rw-r--r--src/core/dbus-socket.h20
-rw-r--r--src/core/dbus-swap.c74
-rw-r--r--src/core/dbus-swap.h19
-rw-r--r--src/core/dbus-target.c18
-rw-r--r--src/core/dbus-target.h21
-rw-r--r--src/core/dbus-timer.c46
-rw-r--r--src/core/dbus-timer.h20
-rw-r--r--src/core/dbus-unit.c316
-rw-r--r--src/core/dbus-unit.h23
-rw-r--r--src/core/dbus-util.c38
-rw-r--r--src/core/dbus-util.h123
-rw-r--r--src/core/dbus.c95
-rw-r--r--src/core/dbus.h21
-rw-r--r--src/core/device.c545
-rw-r--r--src/core/device.h46
-rw-r--r--src/core/dynamic-user.c31
-rw-r--r--src/core/dynamic-user.h20
-rw-r--r--src/core/emergency-action.c18
-rw-r--r--src/core/emergency-action.h18
-rw-r--r--src/core/execute.c351
-rw-r--r--src/core/execute.h56
-rw-r--r--src/core/hostname-setup.c18
-rw-r--r--src/core/hostname-setup.h19
-rw-r--r--src/core/ima-setup.c20
-rw-r--r--src/core/ima-setup.h20
-rw-r--r--src/core/ip-address-access.c18
-rw-r--r--src/core/ip-address-access.h21
-rw-r--r--src/core/job.c88
-rw-r--r--src/core/job.h22
-rw-r--r--src/core/kill.c18
-rw-r--r--src/core/kill.h19
-rw-r--r--src/core/killall.c18
-rw-r--r--src/core/killall.h19
-rw-r--r--src/core/kmod-setup.c18
-rw-r--r--src/core/kmod-setup.h19
-rw-r--r--src/core/load-dropin.c47
-rw-r--r--src/core/load-dropin.h21
-rw-r--r--src/core/load-fragment-gperf.gperf.m459
-rw-r--r--src/core/load-fragment.c1516
-rw-r--r--src/core/load-fragment.h215
-rw-r--r--src/core/locale-setup.c25
-rw-r--r--src/core/locale-setup.h19
-rw-r--r--src/core/loopback-setup.c18
-rw-r--r--src/core/loopback-setup.h19
-rw-r--r--src/core/machine-id-setup.c18
-rw-r--r--src/core/machine-id-setup.h19
-rw-r--r--src/core/macros.systemd.in52
-rw-r--r--src/core/main.c342
-rw-r--r--src/core/manager.c646
-rw-r--r--src/core/manager.h58
-rw-r--r--src/core/meson.build20
-rw-r--r--src/core/mount-setup.c107
-rw-r--r--src/core/mount-setup.h19
-rw-r--r--src/core/mount.c60
-rw-r--r--src/core/mount.h22
-rw-r--r--src/core/namespace.c368
-rw-r--r--src/core/namespace.h33
-rw-r--r--src/core/org.freedesktop.systemd1.conf12
-rw-r--r--src/core/org.freedesktop.systemd1.policy.in1
-rw-r--r--src/core/path.c24
-rw-r--r--src/core/path.h21
-rw-r--r--src/core/scope.c59
-rw-r--r--src/core/scope.h21
-rw-r--r--src/core/selinux-access.c17
-rw-r--r--src/core/selinux-access.h17
-rw-r--r--src/core/selinux-setup.c24
-rw-r--r--src/core/selinux-setup.h19
-rw-r--r--src/core/service.c135
-rw-r--r--src/core/service.h25
-rw-r--r--src/core/show-status.c18
-rw-r--r--src/core/show-status.h19
-rw-r--r--src/core/shutdown.c62
-rw-r--r--src/core/slice.c28
-rw-r--r--src/core/slice.h21
-rw-r--r--src/core/smack-setup.c17
-rw-r--r--src/core/smack-setup.h17
-rw-r--r--src/core/socket.c171
-rw-r--r--src/core/socket.h25
-rw-r--r--src/core/swap.c66
-rw-r--r--src/core/swap.h21
-rw-r--r--src/core/system.conf.in1
-rw-r--r--src/core/target.c20
-rw-r--r--src/core/target.h21
-rw-r--r--src/core/timer.c35
-rw-r--r--src/core/timer.h22
-rw-r--r--src/core/transaction.c31
-rw-r--r--src/core/transaction.h19
-rw-r--r--src/core/triggers.systemd.in29
-rw-r--r--src/core/umount.c425
-rw-r--r--src/core/umount.h37
-rw-r--r--src/core/unit-printf.c108
-rw-r--r--src/core/unit-printf.h19
-rw-r--r--src/core/unit.c311
-rw-r--r--src/core/unit.h113
130 files changed, 3846 insertions, 6021 deletions
diff --git a/src/core/all-units.h b/src/core/all-units.h
new file mode 100644
index 0000000000..ed8350ebe0
--- /dev/null
+++ b/src/core/all-units.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "unit.h"
+
+#include "automount.h"
+#include "device.h"
+#include "path.h"
+#include "scope.h"
+#include "service.h"
+#include "slice.h"
+#include "socket.h"
+#include "swap.h"
+#include "target.h"
+#include "timer.h"
diff --git a/src/core/audit-fd.c b/src/core/audit-fd.c
index 60e79035af..fdef433923 100644
--- a/src/core/audit-fd.c
+++ b/src/core/audit-fd.c
@@ -1,23 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2012 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include <errno.h>
diff --git a/src/core/audit-fd.h b/src/core/audit-fd.h
index 43f4f193d8..8c1e471b96 100644
--- a/src/core/audit-fd.h
+++ b/src/core/audit-fd.h
@@ -1,24 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2012 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
int get_audit_fd(void);
void close_audit_fd(void);
diff --git a/src/core/automount.c b/src/core/automount.c
index 01a6ff806e..1b96a52c00 100644
--- a/src/core/automount.c
+++ b/src/core/automount.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
#include <fcntl.h>
@@ -185,16 +167,16 @@ static int automount_verify(Automount *a) {
if (path_equal(a->where, "/")) {
log_unit_error(UNIT(a), "Cannot have an automount unit for the root directory. Refusing.");
- return -EINVAL;
+ return -ENOEXEC;
}
r = unit_name_from_path(a->where, ".automount", &e);
if (r < 0)
- return log_unit_error(UNIT(a), "Failed to generate unit name from path: %m");
+ return log_unit_error_errno(UNIT(a), r, "Failed to generate unit name from path: %m");
if (!unit_has_name(UNIT(a), e)) {
log_unit_error(UNIT(a), "Where= setting doesn't match unit name. Refusing.");
- return -EINVAL;
+ return -ENOEXEC;
}
return 0;
@@ -212,7 +194,7 @@ static int automount_set_where(Automount *a) {
if (r < 0)
return r;
- path_kill_slashes(a->where);
+ path_simplify(a->where, false);
return 1;
}
@@ -265,7 +247,7 @@ static void automount_set_state(Automount *a, AutomountState state) {
if (state != old_state)
log_unit_debug(UNIT(a), "Changed %s -> %s", automount_state_to_string(old_state), automount_state_to_string(state));
- unit_notify(UNIT(a), state_translation_table[old_state], state_translation_table[state], true);
+ unit_notify(UNIT(a), state_translation_table[old_state], state_translation_table[state], 0);
}
static int automount_coldplug(Unit *u) {
@@ -346,7 +328,7 @@ static int open_dev_autofs(Manager *m) {
if (m->dev_autofs_fd >= 0)
return m->dev_autofs_fd;
- label_fix("/dev/autofs", false, false);
+ (void) label_fix("/dev/autofs", 0);
m->dev_autofs_fd = open("/dev/autofs", O_CLOEXEC|O_RDONLY);
if (m->dev_autofs_fd < 0)
@@ -429,7 +411,7 @@ static int autofs_set_timeout(int dev_autofs_fd, int ioctl_fd, usec_t usec) {
param.timeout.timeout = 0;
else
/* Convert to seconds, rounding up. */
- param.timeout.timeout = (usec + USEC_PER_SEC - 1) / USEC_PER_SEC;
+ param.timeout.timeout = DIV_ROUND_UP(usec, USEC_PER_SEC);
if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_TIMEOUT, &param) < 0)
return -errno;
diff --git a/src/core/automount.h b/src/core/automount.h
index b8be4d316e..21dd1c0774 100644
--- a/src/core/automount.h
+++ b/src/core/automount.h
@@ -1,25 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
typedef struct Automount Automount;
#include "unit.h"
@@ -58,3 +39,5 @@ extern const UnitVTable automount_vtable;
const char* automount_result_to_string(AutomountResult i) _const_;
AutomountResult automount_result_from_string(const char *s) _pure_;
+
+DEFINE_CAST(AUTOMOUNT, Automount);
diff --git a/src/core/bpf-firewall.c b/src/core/bpf-firewall.c
index 48666f64a2..8b66ef73dc 100644
--- a/src/core/bpf-firewall.c
+++ b/src/core/bpf-firewall.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2016 Daniel Mack
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <arpa/inet.h>
#include <assert.h>
@@ -311,8 +293,7 @@ static int bpf_firewall_compile_bpf(
return r;
} while (false);
- *ret = p;
- p = NULL;
+ *ret = TAKE_PTR(p);
return 0;
}
@@ -705,13 +686,14 @@ int bpf_firewall_supported(void) {
1,
BPF_F_NO_PREALLOC);
if (fd < 0) {
- log_debug_errno(r, "Can't allocate BPF LPM TRIE map, BPF firewalling is not supported: %m");
+ log_debug_errno(fd, "Can't allocate BPF LPM TRIE map, BPF firewalling is not supported: %m");
return supported = BPF_FIREWALL_UNSUPPORTED;
}
safe_close(fd);
- if (bpf_program_new(BPF_PROG_TYPE_CGROUP_SKB, &program) < 0) {
+ r = bpf_program_new(BPF_PROG_TYPE_CGROUP_SKB, &program);
+ if (r < 0) {
log_debug_errno(r, "Can't allocate CGROUP SKB BPF program, BPF firewalling is not supported: %m");
return supported = BPF_FIREWALL_UNSUPPORTED;
}
@@ -742,8 +724,7 @@ int bpf_firewall_supported(void) {
.attach_bpf_fd = -1,
};
- r = bpf(BPF_PROG_ATTACH, &attr, sizeof(attr));
- if (r < 0) {
+ if (bpf(BPF_PROG_ATTACH, &attr, sizeof(attr)) < 0) {
if (errno != EBADF) {
log_debug_errno(errno, "Didn't get EBADF from BPF_PROG_ATTACH, BPF firewalling is not supported: %m");
return supported = BPF_FIREWALL_UNSUPPORTED;
@@ -767,8 +748,7 @@ int bpf_firewall_supported(void) {
.attach_flags = BPF_F_ALLOW_MULTI,
};
- r = bpf(BPF_PROG_ATTACH, &attr, sizeof(attr));
- if (r < 0) {
+ if (bpf(BPF_PROG_ATTACH, &attr, sizeof(attr)) < 0) {
if (errno == EBADF) {
log_debug_errno(errno, "Got EBADF when using BPF_F_ALLOW_MULTI, which indicates it is supported. Yay!");
return supported = BPF_FIREWALL_SUPPORTED_WITH_MULTI;
diff --git a/src/core/bpf-firewall.h b/src/core/bpf-firewall.h
index a0658e3b86..e2d08a0fc8 100644
--- a/src/core/bpf-firewall.h
+++ b/src/core/bpf-firewall.h
@@ -1,24 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2016 Daniel Mack
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <inttypes.h>
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 3c0ff09639..bb02436203 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <fcntl.h>
#include <fnmatch.h>
@@ -24,6 +6,7 @@
#include "alloc-util.h"
#include "blockdev-util.h"
#include "bpf-firewall.h"
+#include "btrfs-util.h"
#include "bus-error.h"
#include "cgroup-util.h"
#include "cgroup.h"
@@ -53,7 +36,7 @@ bool manager_owns_root_cgroup(Manager *m) {
if (detect_container() > 0)
return false;
- return isempty(m->cgroup_root) || path_equal(m->cgroup_root, "/");
+ return empty_or_root(m->cgroup_root);
}
bool unit_has_root_cgroup(Unit *u) {
@@ -319,32 +302,36 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
}
}
-static int lookup_block_device(const char *p, dev_t *dev) {
+static int lookup_block_device(const char *p, dev_t *ret) {
struct stat st;
int r;
assert(p);
- assert(dev);
+ assert(ret);
- r = stat(p, &st);
- if (r < 0)
- return log_warning_errno(errno, "Couldn't stat device %s: %m", p);
+ if (stat(p, &st) < 0)
+ return log_warning_errno(errno, "Couldn't stat device '%s': %m", p);
if (S_ISBLK(st.st_mode))
- *dev = st.st_rdev;
- else if (major(st.st_dev) != 0) {
- /* If this is not a device node then find the block
- * device this file is stored on */
- *dev = st.st_dev;
-
- /* If this is a partition, try to get the originating
- * block device */
- (void) block_get_whole_disk(*dev, dev);
- } else {
- log_warning("%s is not a block device and file system block device cannot be determined or is not local.", p);
- return -ENODEV;
+ *ret = st.st_rdev;
+ else if (major(st.st_dev) != 0)
+ *ret = st.st_dev; /* If this is not a device node then use the block device this file is stored on */
+ else {
+ /* If this is btrfs, getting the backing block device is a bit harder */
+ r = btrfs_get_block_device(p, ret);
+ if (r < 0 && r != -ENOTTY)
+ return log_warning_errno(r, "Failed to determine block device backing btrfs file system '%s': %m", p);
+ if (r == -ENOTTY) {
+ log_warning("'%s' is not a block device node, and file system block device cannot be determined or is not local.", p);
+ return -ENODEV;
+ }
}
+ /* If this is a LUKS device, try to get the originating block device */
+ (void) block_get_originating(*ret, ret);
+
+ /* If this is a partition, try to get the originating block device */
+ (void) block_get_whole_disk(*ret, ret);
return 0;
}
@@ -632,26 +619,22 @@ static void cgroup_apply_blkio_device_weight(Unit *u, const char *dev_path, uint
"Failed to set blkio.weight_device: %m");
}
-static unsigned cgroup_apply_io_device_limit(Unit *u, const char *dev_path, uint64_t *limits) {
+static void cgroup_apply_io_device_limit(Unit *u, const char *dev_path, uint64_t *limits) {
char limit_bufs[_CGROUP_IO_LIMIT_TYPE_MAX][DECIMAL_STR_MAX(uint64_t)];
char buf[DECIMAL_STR_MAX(dev_t)*2+2+(6+DECIMAL_STR_MAX(uint64_t)+1)*4];
CGroupIOLimitType type;
dev_t dev;
- unsigned n = 0;
int r;
r = lookup_block_device(dev_path, &dev);
if (r < 0)
- return 0;
+ return;
- for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++) {
- if (limits[type] != cgroup_io_limit_defaults[type]) {
+ for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
+ if (limits[type] != cgroup_io_limit_defaults[type])
xsprintf(limit_bufs[type], "%" PRIu64, limits[type]);
- n++;
- } else {
+ else
xsprintf(limit_bufs[type], "%s", limits[type] == CGROUP_LIMIT_MAX ? "max" : "0");
- }
- }
xsprintf(buf, "%u:%u rbps=%s wbps=%s riops=%s wiops=%s\n", major(dev), minor(dev),
limit_bufs[CGROUP_IO_RBPS_MAX], limit_bufs[CGROUP_IO_WBPS_MAX],
@@ -660,36 +643,28 @@ static unsigned cgroup_apply_io_device_limit(Unit *u, const char *dev_path, uint
if (r < 0)
log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set io.max: %m");
- return n;
}
-static unsigned cgroup_apply_blkio_device_limit(Unit *u, const char *dev_path, uint64_t rbps, uint64_t wbps) {
+static void cgroup_apply_blkio_device_limit(Unit *u, const char *dev_path, uint64_t rbps, uint64_t wbps) {
char buf[DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1];
dev_t dev;
- unsigned n = 0;
int r;
r = lookup_block_device(dev_path, &dev);
if (r < 0)
- return 0;
+ return;
- if (rbps != CGROUP_LIMIT_MAX)
- n++;
sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), rbps);
r = cg_set_attribute("blkio", u->cgroup_path, "blkio.throttle.read_bps_device", buf);
if (r < 0)
log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set blkio.throttle.read_bps_device: %m");
- if (wbps != CGROUP_LIMIT_MAX)
- n++;
sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), wbps);
r = cg_set_attribute("blkio", u->cgroup_path, "blkio.throttle.write_bps_device", buf);
if (r < 0)
log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set blkio.throttle.write_bps_device: %m");
-
- return n;
}
static bool cgroup_context_has_unified_memory_config(CGroupContext *c) {
@@ -840,16 +815,15 @@ static void cgroup_context_apply(
/* Apply limits and free ones without config. */
if (has_io) {
- CGroupIODeviceLimit *l, *next;
+ CGroupIODeviceLimit *l;
+
+ LIST_FOREACH(device_limits, l, c->io_device_limits)
+ cgroup_apply_io_device_limit(u, l->path, l->limits);
- LIST_FOREACH_SAFE(device_limits, l, next, c->io_device_limits) {
- if (!cgroup_apply_io_device_limit(u, l->path, l->limits))
- cgroup_context_free_io_device_limit(c, l);
- }
} else if (has_blockio) {
- CGroupBlockIODeviceBandwidth *b, *next;
+ CGroupBlockIODeviceBandwidth *b;
- LIST_FOREACH_SAFE(device_bandwidths, b, next, c->blockio_device_bandwidths) {
+ LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
uint64_t limits[_CGROUP_IO_LIMIT_TYPE_MAX];
CGroupIOLimitType type;
@@ -862,8 +836,7 @@ static void cgroup_context_apply(
log_cgroup_compat(u, "Applying BlockIO{Read|Write}Bandwidth %" PRIu64 " %" PRIu64 " as IO{Read|Write}BandwidthMax for %s",
b->rbps, b->wbps, b->path);
- if (!cgroup_apply_io_device_limit(u, b->path, limits))
- cgroup_context_free_blockio_device_bandwidth(c, b);
+ cgroup_apply_io_device_limit(u, b->path, limits);
}
}
}
@@ -917,21 +890,19 @@ static void cgroup_context_apply(
/* Apply limits and free ones without config. */
if (has_io) {
- CGroupIODeviceLimit *l, *next;
+ CGroupIODeviceLimit *l;
- LIST_FOREACH_SAFE(device_limits, l, next, c->io_device_limits) {
+ LIST_FOREACH(device_limits, l, c->io_device_limits) {
log_cgroup_compat(u, "Applying IO{Read|Write}Bandwidth %" PRIu64 " %" PRIu64 " as BlockIO{Read|Write}BandwidthMax for %s",
l->limits[CGROUP_IO_RBPS_MAX], l->limits[CGROUP_IO_WBPS_MAX], l->path);
- if (!cgroup_apply_blkio_device_limit(u, l->path, l->limits[CGROUP_IO_RBPS_MAX], l->limits[CGROUP_IO_WBPS_MAX]))
- cgroup_context_free_io_device_limit(c, l);
+ cgroup_apply_blkio_device_limit(u, l->path, l->limits[CGROUP_IO_RBPS_MAX], l->limits[CGROUP_IO_WBPS_MAX]);
}
} else if (has_blockio) {
- CGroupBlockIODeviceBandwidth *b, *next;
+ CGroupBlockIODeviceBandwidth *b;
- LIST_FOREACH_SAFE(device_bandwidths, b, next, c->blockio_device_bandwidths)
- if (!cgroup_apply_blkio_device_limit(u, b->path, b->rbps, b->wbps))
- cgroup_context_free_blockio_device_bandwidth(c, b);
+ LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths)
+ cgroup_apply_blkio_device_limit(u, b->path, b->rbps, b->wbps);
}
}
@@ -1318,7 +1289,7 @@ const char *unit_get_realized_cgroup_path(Unit *u, CGroupMask mask) {
if (u->cgroup_path &&
u->cgroup_realized &&
- (u->cgroup_realized_mask & mask) == mask)
+ FLAGS_SET(u->cgroup_realized_mask, mask))
return u->cgroup_path;
u = UNIT_DEREF(u->slice);
@@ -1381,8 +1352,7 @@ int unit_set_cgroup_path(Unit *u, const char *path) {
unit_release_cgroup(u);
- u->cgroup_path = p;
- p = NULL;
+ u->cgroup_path = TAKE_PTR(p);
return 1;
}
@@ -1469,6 +1439,7 @@ static int unit_create_cgroup(
CGroupContext *c;
int r;
+ bool created;
assert(u);
@@ -1485,14 +1456,20 @@ static int unit_create_cgroup(
r = cg_create_everywhere(u->manager->cgroup_supported, target_mask, u->cgroup_path);
if (r < 0)
return log_unit_error_errno(u, r, "Failed to create cgroup %s: %m", u->cgroup_path);
+ created = !!r;
/* Start watching it */
(void) unit_watch_cgroup(u);
- /* Enable all controllers we need */
- r = cg_enable_everywhere(u->manager->cgroup_supported, enable_mask, u->cgroup_path);
- if (r < 0)
- log_unit_warning_errno(u, r, "Failed to enable controllers on cgroup %s, ignoring: %m", u->cgroup_path);
+ /* Preserve enabled controllers in delegated units, adjust others. */
+ if (created || !unit_cgroup_delegate(u)) {
+
+ /* Enable all controllers we need */
+ r = cg_enable_everywhere(u->manager->cgroup_supported, enable_mask, u->cgroup_path);
+ if (r < 0)
+ log_unit_warning_errno(u, r, "Failed to enable controllers on cgroup %s, ignoring: %m",
+ u->cgroup_path);
+ }
/* Keep track that this is now realized */
u->cgroup_realized = true;
@@ -1535,7 +1512,7 @@ static int unit_attach_pid_to_cgroup_via_bus(Unit *u, pid_t pid, const char *suf
return -EINVAL;
pp = strjoina("/", pp, suffix_path);
- path_kill_slashes(pp);
+ path_simplify(pp, false);
r = sd_bus_call_method(u->manager->system_bus,
"org.freedesktop.systemd1",
@@ -1706,7 +1683,6 @@ static void unit_remove_from_cgroup_realize_queue(Unit *u) {
u->in_cgroup_realize_queue = false;
}
-
/* Check if necessary controllers and attributes for a unit are in place.
*
* If so, do nothing.
@@ -2057,7 +2033,7 @@ static int on_cgroup_empty_event(sd_event_source *s, void *userdata) {
/* More stuff queued, let's make sure we remain enabled */
r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT);
if (r < 0)
- log_debug_errno(r, "Failed to reenable cgroup empty event source: %m");
+ log_debug_errno(r, "Failed to reenable cgroup empty event source, ignoring: %m");
}
unit_add_to_gc_queue(u);
@@ -2272,19 +2248,20 @@ int manager_setup_cgroup(Manager *m) {
/* 5. Make sure we are in the special "init.scope" unit in the root slice. */
scope_path = strjoina(m->cgroup_root, "/" SPECIAL_INIT_SCOPE);
r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, scope_path, 0);
- if (r < 0)
- return log_error_errno(r, "Failed to create %s control group: %m", scope_path);
+ if (r >= 0) {
+ /* Also, move all other userspace processes remaining in the root cgroup into that scope. */
+ r = cg_migrate(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, SYSTEMD_CGROUP_CONTROLLER, scope_path, 0);
+ if (r < 0)
+ log_warning_errno(r, "Couldn't move remaining userspace processes, ignoring: %m");
- /* Also, move all other userspace processes remaining in the root cgroup into that scope. */
- r = cg_migrate(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, SYSTEMD_CGROUP_CONTROLLER, scope_path, 0);
- if (r < 0)
- log_warning_errno(r, "Couldn't move remaining userspace processes, ignoring: %m");
+ /* 6. And pin it, so that it cannot be unmounted */
+ safe_close(m->pin_cgroupfs_fd);
+ m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK);
+ if (m->pin_cgroupfs_fd < 0)
+ return log_error_errno(errno, "Failed to open pin file: %m");
- /* 6. And pin it, so that it cannot be unmounted */
- safe_close(m->pin_cgroupfs_fd);
- m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK);
- if (m->pin_cgroupfs_fd < 0)
- return log_error_errno(errno, "Failed to open pin file: %m");
+ } else if (r < 0 && !m->test_run_flags)
+ return log_error_errno(r, "Failed to create %s control group: %m", scope_path);
/* 7. Always enable hierarchical support if it exists... */
if (!all_unified && m->test_run_flags == 0)
@@ -2305,7 +2282,7 @@ void manager_shutdown_cgroup(Manager *m, bool delete) {
/* We can't really delete the group, since we are in it. But
* let's trim it. */
- if (delete && m->cgroup_root)
+ if (delete && m->cgroup_root && m->test_run_flags != MANAGER_TEST_RUN_MINIMAL)
(void) cg_trim(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, false);
m->cgroup_empty_event_source = sd_event_source_unref(m->cgroup_empty_event_source);
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index ae5f1c7647..2d2ff6fc3c 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -1,25 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include <stdbool.h>
#include "cgroup-util.h"
@@ -140,7 +121,8 @@ typedef enum CGroupIPAccountingMetric {
_CGROUP_IP_ACCOUNTING_METRIC_INVALID = -1,
} CGroupIPAccountingMetric;
-#include "unit.h"
+typedef struct Unit Unit;
+typedef struct Manager Manager;
void cgroup_context_init(CGroupContext *c);
void cgroup_context_done(CGroupContext *c);
diff --git a/src/core/chown-recursive.c b/src/core/chown-recursive.c
index f021f03a06..c4794501c2 100644
--- a/src/core/chown-recursive.c
+++ b/src/core/chown-recursive.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2017 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <sys/types.h>
#include <sys/stat.h>
diff --git a/src/core/chown-recursive.h b/src/core/chown-recursive.h
index 7540a8db59..f3fa40a656 100644
--- a/src/core/chown-recursive.h
+++ b/src/core/chown-recursive.h
@@ -1,25 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2017 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include <sys/types.h>
int path_chown_recursive(const char *path, uid_t uid, gid_t gid);
diff --git a/src/core/dbus-automount.c b/src/core/dbus-automount.c
index 113d352a43..bd6e6a9dde 100644
--- a/src/core/dbus-automount.c
+++ b/src/core/dbus-automount.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include "automount.h"
#include "bus-util.h"
diff --git a/src/core/dbus-automount.h b/src/core/dbus-automount.h
index 378119410c..3e165b0566 100644
--- a/src/core/dbus-automount.h
+++ b/src/core/dbus-automount.h
@@ -1,25 +1,10 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
+#include "sd-bus.h"
+#include "sd-bus-vtable.h"
+#include "unit.h"
extern const sd_bus_vtable bus_automount_vtable[];
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index f480664613..540bc77aed 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <arpa/inet.h>
#include <stdio_ext.h>
@@ -389,7 +371,7 @@ static int bus_cgroup_set_transient_property(
cc = cgroup_controller_from_string(t);
if (cc < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown cgroup contoller '%s'", t);
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown cgroup controller '%s'", t);
mask |= CGROUP_CONTROLLER_TO_MASK(cc);
}
@@ -446,14 +428,129 @@ static int bus_cgroup_set_boolean(
return 1;
}
-static BUS_DEFINE_SET_CGROUP_WEIGHT(cpu_weight, CGROUP_MASK_CPU, CGROUP_WEIGHT_IS_OK, CGROUP_WEIGHT_INVALID,);
-static BUS_DEFINE_SET_CGROUP_WEIGHT(cpu_shares, CGROUP_MASK_CPU, CGROUP_CPU_SHARES_IS_OK, CGROUP_CPU_SHARES_INVALID,);
-static BUS_DEFINE_SET_CGROUP_WEIGHT(io_weight, CGROUP_MASK_IO, CGROUP_WEIGHT_IS_OK, CGROUP_WEIGHT_INVALID,);
-static BUS_DEFINE_SET_CGROUP_WEIGHT(blockio_weight, CGROUP_MASK_BLKIO, CGROUP_BLKIO_WEIGHT_IS_OK, CGROUP_BLKIO_WEIGHT_INVALID,);
-static BUS_DEFINE_SET_CGROUP_WEIGHT(memory, CGROUP_MASK_MEMORY, , CGROUP_LIMIT_MAX, "infinity");
-static BUS_DEFINE_SET_CGROUP_WEIGHT(tasks_max, CGROUP_MASK_PIDS, , (uint64_t) -1, "infinity");
-static BUS_DEFINE_SET_CGROUP_SCALE(memory, CGROUP_MASK_MEMORY, physical_memory_scale);
-static BUS_DEFINE_SET_CGROUP_SCALE(tasks_max, CGROUP_MASK_PIDS, system_tasks_max_scale);
+#define BUS_DEFINE_SET_CGROUP_WEIGHT(function, mask, check, val) \
+ static int bus_cgroup_set_##function( \
+ Unit *u, \
+ const char *name, \
+ uint64_t *p, \
+ sd_bus_message *message, \
+ UnitWriteFlags flags, \
+ sd_bus_error *error) { \
+ \
+ uint64_t v; \
+ int r; \
+ \
+ assert(p); \
+ \
+ r = sd_bus_message_read(message, "t", &v); \
+ if (r < 0) \
+ return r; \
+ \
+ if (!check(v)) \
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, \
+ "Value specified in %s is out of range", name); \
+ \
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) { \
+ *p = v; \
+ unit_invalidate_cgroup(u, (mask)); \
+ \
+ if (v == (val)) \
+ unit_write_settingf(u, flags, name, \
+ "%s=", name); \
+ else \
+ unit_write_settingf(u, flags, name, \
+ "%s=%" PRIu64, name, v); \
+ } \
+ \
+ return 1; \
+ }
+
+#define BUS_DEFINE_SET_CGROUP_LIMIT(function, mask, scale, minimum) \
+ static int bus_cgroup_set_##function( \
+ Unit *u, \
+ const char *name, \
+ uint64_t *p, \
+ sd_bus_message *message, \
+ UnitWriteFlags flags, \
+ sd_bus_error *error) { \
+ \
+ uint64_t v; \
+ int r; \
+ \
+ assert(p); \
+ \
+ r = sd_bus_message_read(message, "t", &v); \
+ if (r < 0) \
+ return r; \
+ \
+ if (v < minimum) \
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, \
+ "Value specified in %s is out of range", name); \
+ \
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) { \
+ *p = v; \
+ unit_invalidate_cgroup(u, (mask)); \
+ \
+ if (v == CGROUP_LIMIT_MAX) \
+ unit_write_settingf(u, flags, name, \
+ "%s=infinity", name); \
+ else \
+ unit_write_settingf(u, flags, name, \
+ "%s=%" PRIu64, name, v); \
+ } \
+ \
+ return 1; \
+ } \
+ static int bus_cgroup_set_##function##_scale( \
+ Unit *u, \
+ const char *name, \
+ uint64_t *p, \
+ sd_bus_message *message, \
+ UnitWriteFlags flags, \
+ sd_bus_error *error) { \
+ \
+ uint64_t v; \
+ uint32_t raw; \
+ int r; \
+ \
+ assert(p); \
+ \
+ r = sd_bus_message_read(message, "u", &raw); \
+ if (r < 0) \
+ return r; \
+ \
+ v = scale(raw, UINT32_MAX); \
+ if (v < minimum || v >= UINT64_MAX) \
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, \
+ "Value specified in %s is out of range", name); \
+ \
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) { \
+ const char *e; \
+ \
+ *p = v; \
+ unit_invalidate_cgroup(u, (mask)); \
+ \
+ /* Chop off suffix */ \
+ assert_se(e = endswith(name, "Scale")); \
+ name = strndupa(name, e - name); \
+ \
+ unit_write_settingf(u, flags, name, "%s=%" PRIu32 "%%", name, \
+ (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX))); \
+ } \
+ \
+ return 1; \
+ }
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wtype-limits"
+BUS_DEFINE_SET_CGROUP_WEIGHT(cpu_weight, CGROUP_MASK_CPU, CGROUP_WEIGHT_IS_OK, CGROUP_WEIGHT_INVALID);
+BUS_DEFINE_SET_CGROUP_WEIGHT(cpu_shares, CGROUP_MASK_CPU, CGROUP_CPU_SHARES_IS_OK, CGROUP_CPU_SHARES_INVALID);
+BUS_DEFINE_SET_CGROUP_WEIGHT(io_weight, CGROUP_MASK_IO, CGROUP_WEIGHT_IS_OK, CGROUP_WEIGHT_INVALID);
+BUS_DEFINE_SET_CGROUP_WEIGHT(blockio_weight, CGROUP_MASK_BLKIO, CGROUP_BLKIO_WEIGHT_IS_OK, CGROUP_BLKIO_WEIGHT_INVALID);
+BUS_DEFINE_SET_CGROUP_LIMIT(memory, CGROUP_MASK_MEMORY, physical_memory_scale, 1);
+BUS_DEFINE_SET_CGROUP_LIMIT(swap, CGROUP_MASK_MEMORY, physical_memory_scale, 0);
+BUS_DEFINE_SET_CGROUP_LIMIT(tasks_max, CGROUP_MASK_PIDS, system_tasks_max_scale, 1);
+#pragma GCC diagnostic pop
int bus_cgroup_set_property(
Unit *u,
@@ -516,7 +613,7 @@ int bus_cgroup_set_property(
return bus_cgroup_set_memory(u, name, &c->memory_high, message, flags, error);
if (streq(name, "MemorySwapMax"))
- return bus_cgroup_set_memory(u, name, &c->memory_swap_max, message, flags, error);
+ return bus_cgroup_set_swap(u, name, &c->memory_swap_max, message, flags, error);
if (streq(name, "MemoryMax"))
return bus_cgroup_set_memory(u, name, &c->memory_max, message, flags, error);
@@ -531,7 +628,7 @@ int bus_cgroup_set_property(
return bus_cgroup_set_memory_scale(u, name, &c->memory_high, message, flags, error);
if (streq(name, "MemorySwapMaxScale"))
- return bus_cgroup_set_memory_scale(u, name, &c->memory_swap_max, message, flags, error);
+ return bus_cgroup_set_swap_scale(u, name, &c->memory_swap_max, message, flags, error);
if (streq(name, "MemoryMaxScale"))
return bus_cgroup_set_memory_scale(u, name, &c->memory_max, message, flags, error);
@@ -585,9 +682,8 @@ int bus_cgroup_set_property(
while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
- if (!path_startswith(path, "/dev") &&
- !path_startswith(path, "/run/systemd/inaccessible/"))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s specified in %s= is not a device file in /dev", name, path);
+ if (!path_is_normalized(path))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
CGroupIODeviceLimit *a = NULL, *b;
@@ -673,9 +769,8 @@ int bus_cgroup_set_property(
while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
- if (!path_startswith(path, "/dev") &&
- !path_startswith(path, "/run/systemd/inaccessible/"))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s specified in %s= is not a device file in /dev", name, path);
+ if (!path_is_normalized(path))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
if (!CGROUP_WEIGHT_IS_OK(weight) || weight == CGROUP_WEIGHT_INVALID)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "IODeviceWeight= value out of range");
@@ -759,9 +854,8 @@ int bus_cgroup_set_property(
while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
- if (!path_startswith(path, "/dev") &&
- !path_startswith(path, "/run/systemd/inaccessible/"))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s specified in %s= is not a device file in /dev", name, path);
+ if (!path_is_normalized(path))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
CGroupBlockIODeviceBandwidth *a = NULL, *b;
@@ -859,9 +953,8 @@ int bus_cgroup_set_property(
while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
- if (!path_startswith(path, "/dev") &&
- !path_startswith(path, "/run/systemd/inaccessible/"))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s specified in %s= is not a device file in /dev", name, path);
+ if (!path_is_normalized(path))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight) || weight == CGROUP_BLKIO_WEIGHT_INVALID)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "BlockIODeviceWeight= out of range");
@@ -961,15 +1054,12 @@ int bus_cgroup_set_property(
while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
- if ((!is_deviceallow_pattern(path) &&
- !path_startswith(path, "/run/systemd/inaccessible/")) ||
- strpbrk(path, WHITESPACE))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires device node");
+ if (!valid_device_allow_pattern(path) || strpbrk(path, WHITESPACE))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires device node or pattern");
if (isempty(rwm))
rwm = "rwm";
-
- if (!in_charset(rwm, "rwm"))
+ else if (!in_charset(rwm, "rwm"))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires combination of rwm flags");
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
diff --git a/src/core/dbus-cgroup.h b/src/core/dbus-cgroup.h
index 0588370aa5..188baa99e9 100644
--- a/src/core/dbus-cgroup.h
+++ b/src/core/dbus-cgroup.h
@@ -1,27 +1,10 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include "sd-bus.h"
+#include "sd-bus-vtable.h"
+#include "unit.h"
#include "cgroup.h"
extern const sd_bus_vtable bus_cgroup_vtable[];
diff --git a/src/core/dbus-device.c b/src/core/dbus-device.c
index fbb60d821e..6cf7f58e02 100644
--- a/src/core/dbus-device.c
+++ b/src/core/dbus-device.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include "dbus-device.h"
#include "device.h"
diff --git a/src/core/dbus-device.h b/src/core/dbus-device.h
index c8098708f4..077a2bf128 100644
--- a/src/core/dbus-device.h
+++ b/src/core/dbus-device.h
@@ -1,25 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "unit.h"
+#include "sd-bus-vtable.h"
extern const sd_bus_vtable bus_device_vtable[];
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 635213a866..c44970c10c 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -1,23 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
+#include <sys/mount.h>
#include <sys/prctl.h>
#include <stdio_ext.h>
@@ -63,13 +46,18 @@
BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutput);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_input, exec_input, ExecInput);
-
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_preserve_mode, exec_preserve_mode, ExecPreserveMode);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_keyring_mode, exec_keyring_mode, ExecKeyringMode);
-
-static BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_protect_home, protect_home, ProtectHome);
-static BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_protect_system, protect_system, ProtectSystem);
+static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_protect_home, protect_home, ProtectHome);
+static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_protect_system, protect_system, ProtectSystem);
+static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_personality, personality, unsigned long);
+static BUS_DEFINE_PROPERTY_GET(property_get_ioprio, "i", ExecContext, exec_context_get_effective_ioprio);
+static BUS_DEFINE_PROPERTY_GET2(property_get_ioprio_class, "i", ExecContext, exec_context_get_effective_ioprio, IOPRIO_PRIO_CLASS);
+static BUS_DEFINE_PROPERTY_GET2(property_get_ioprio_priority, "i", ExecContext, exec_context_get_effective_ioprio, IOPRIO_PRIO_DATA);
+static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_empty_string, "s", NULL);
+static BUS_DEFINE_PROPERTY_GET_REF(property_get_syslog_level, "i", int, LOG_PRI);
+static BUS_DEFINE_PROPERTY_GET_REF(property_get_syslog_facility, "i", int, LOG_FAC);
static int property_get_environment_files(
sd_bus *bus,
@@ -112,7 +100,6 @@ static int property_get_oom_score_adjust(
void *userdata,
sd_bus_error *error) {
-
ExecContext *c = userdata;
int32_t n;
@@ -142,7 +129,6 @@ static int property_get_nice(
void *userdata,
sd_bus_error *error) {
-
ExecContext *c = userdata;
int32_t n;
@@ -162,63 +148,6 @@ static int property_get_nice(
return sd_bus_message_append(reply, "i", n);
}
-static int property_get_ioprio(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
-
- ExecContext *c = userdata;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- return sd_bus_message_append(reply, "i", exec_context_get_effective_ioprio(c));
-}
-
-static int property_get_ioprio_class(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
-
- ExecContext *c = userdata;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- return sd_bus_message_append(reply, "i", IOPRIO_PRIO_CLASS(exec_context_get_effective_ioprio(c)));
-}
-
-static int property_get_ioprio_priority(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
-
- ExecContext *c = userdata;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- return sd_bus_message_append(reply, "i", IOPRIO_PRIO_DATA(exec_context_get_effective_ioprio(c)));
-}
-
static int property_get_cpu_sched_policy(
sd_bus *bus,
const char *path,
@@ -291,10 +220,7 @@ static int property_get_cpu_affinity(
assert(reply);
assert(c);
- if (c->cpuset)
- return sd_bus_message_append_array(reply, 'y', c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus));
- else
- return sd_bus_message_append_array(reply, 'y', NULL, 0);
+ return sd_bus_message_append_array(reply, 'y', c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus));
}
static int property_get_timer_slack_nsec(
@@ -321,57 +247,6 @@ static int property_get_timer_slack_nsec(
return sd_bus_message_append(reply, "t", u);
}
-static int property_get_capability_bounding_set(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- ExecContext *c = userdata;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- return sd_bus_message_append(reply, "t", c->capability_bounding_set);
-}
-
-static int property_get_ambient_capabilities(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- ExecContext *c = userdata;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- return sd_bus_message_append(reply, "t", c->capability_ambient_set);
-}
-
-static int property_get_empty_string(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- assert(bus);
- assert(reply);
-
- return sd_bus_message_append(reply, "s", "");
-}
-
static int property_get_syscall_filter(
sd_bus *bus,
const char *path,
@@ -424,10 +299,8 @@ static int property_get_syscall_filter(
if (r < 0)
return -ENOMEM;
}
- } else {
- s = name;
- name = NULL;
- }
+ } else
+ s = TAKE_PTR(name);
r = strv_consume(&l, s);
if (r < 0)
@@ -489,24 +362,6 @@ static int property_get_syscall_archs(
return 0;
}
-static int property_get_syscall_errno(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- ExecContext *c = userdata;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- return sd_bus_message_append(reply, "i", (int32_t) c->syscall_errno);
-}
-
static int property_get_selinux_context(
sd_bus *bus,
const char *path,
@@ -561,24 +416,6 @@ static int property_get_smack_process_label(
return sd_bus_message_append(reply, "(bs)", c->smack_process_label_ignore, c->smack_process_label);
}
-static int property_get_personality(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- ExecContext *c = userdata;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- return sd_bus_message_append(reply, "s", personality_to_string(c->personality));
-}
-
static int property_get_address_families(
sd_bus *bus,
const char *path,
@@ -654,42 +491,6 @@ static int property_get_working_directory(
return sd_bus_message_append(reply, "s", wd);
}
-static int property_get_syslog_level(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- ExecContext *c = userdata;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- return sd_bus_message_append(reply, "i", LOG_PRI(c->syslog_priority));
-}
-
-static int property_get_syslog_facility(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- ExecContext *c = userdata;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- return sd_bus_message_append(reply, "i", LOG_FAC(c->syslog_priority));
-}
-
static int property_get_stdio_fdname(
sd_bus *bus,
const char *path,
@@ -757,7 +558,7 @@ static int property_get_bind_paths(
assert(property);
assert(reply);
- ro = !!strstr(property, "ReadOnly");
+ ro = strstr(property, "ReadOnly");
r = sd_bus_message_open_container(reply, 'a', "(ssbt)");
if (r < 0)
@@ -914,13 +715,13 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("SyslogPriority", "i", bus_property_get_int, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SyslogIdentifier", "s", NULL, offsetof(ExecContext, syslog_identifier), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SyslogLevelPrefix", "b", bus_property_get_bool, offsetof(ExecContext, syslog_level_prefix), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("SyslogLevel", "i", property_get_syslog_level, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("SyslogFacility", "i", property_get_syslog_facility, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("SyslogLevel", "i", property_get_syslog_level, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("SyslogFacility", "i", property_get_syslog_facility, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("LogLevelMax", "i", bus_property_get_int, offsetof(ExecContext, log_level_max), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("LogExtraFields", "aay", property_get_log_extra_fields, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("AmbientCapabilities", "t", property_get_ambient_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("CapabilityBoundingSet", "t", NULL, offsetof(ExecContext, capability_bounding_set), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("AmbientCapabilities", "t", NULL, offsetof(ExecContext, capability_ambient_set), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("User", "s", NULL, offsetof(ExecContext, user), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DynamicUser", "b", bus_property_get_bool, offsetof(ExecContext, dynamic_user), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -938,8 +739,9 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("ProtectControlGroups", "b", bus_property_get_bool, offsetof(ExecContext, protect_control_groups), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PrivateUsers", "b", bus_property_get_bool, offsetof(ExecContext, private_users), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("ProtectHome", "s", bus_property_get_protect_home, offsetof(ExecContext, protect_home), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("ProtectSystem", "s", bus_property_get_protect_system, offsetof(ExecContext, protect_system), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("PrivateMounts", "b", bus_property_get_bool, offsetof(ExecContext, private_mounts), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("ProtectHome", "s", property_get_protect_home, offsetof(ExecContext, protect_home), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("ProtectSystem", "s", property_get_protect_system, offsetof(ExecContext, protect_system), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SameProcessGroup", "b", bus_property_get_bool, offsetof(ExecContext, same_pgrp), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("UtmpIdentifier", "s", NULL, offsetof(ExecContext, utmp_id), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("UtmpMode", "s", property_get_exec_utmp_mode, offsetof(ExecContext, utmp_mode), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -950,8 +752,8 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("NoNewPrivileges", "b", bus_property_get_bool, offsetof(ExecContext, no_new_privileges), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SystemCallFilter", "(bas)", property_get_syscall_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SystemCallArchitectures", "as", property_get_syscall_archs, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("SystemCallErrorNumber", "i", property_get_syscall_errno, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Personality", "s", property_get_personality, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("SystemCallErrorNumber", "i", bus_property_get_int, offsetof(ExecContext, syscall_errno), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Personality", "s", property_get_personality, offsetof(ExecContext, personality), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("LockPersonality", "b", bus_property_get_bool, offsetof(ExecContext, lock_personality), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RestrictAddressFamilies", "(bas)", property_get_address_families, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RuntimeDirectoryPreserve", "s", property_get_exec_preserve_mode, offsetof(ExecContext, runtime_directory_preserve_mode), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -1125,12 +927,11 @@ int bus_set_transient_exec_command(
return -ENOMEM;
}
- c->argv = argv;
- argv = NULL;
+ c->argv = TAKE_PTR(argv);
c->flags = b ? EXEC_COMMAND_IGNORE_FAILURE : 0;
- path_kill_slashes(c->path);
+ path_simplify(c->path, false);
exec_command_append_list(exec_command, c);
}
@@ -1219,15 +1020,15 @@ static BUS_DEFINE_SET_TRANSIENT_IS_VALID(nice, "i", int32_t, int, "%" PRIi32, ni
static BUS_DEFINE_SET_TRANSIENT_PARSE(std_input, ExecInput, exec_input_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(std_output, ExecOutput, exec_output_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(utmp_mode, ExecUtmpMode, exec_utmp_mode_from_string);
-static BUS_DEFINE_SET_TRANSIENT_PARSE(protect_system, ProtectSystem, parse_protect_system_or_bool);
-static BUS_DEFINE_SET_TRANSIENT_PARSE(protect_home, ProtectHome, parse_protect_home_or_bool);
+static BUS_DEFINE_SET_TRANSIENT_PARSE(protect_system, ProtectSystem, protect_system_from_string);
+static BUS_DEFINE_SET_TRANSIENT_PARSE(protect_home, ProtectHome, protect_home_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(keyring_mode, ExecKeyringMode, exec_keyring_mode_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(preserve_mode, ExecPreserveMode, exec_preserve_mode_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE_PTR(personality, unsigned long, parse_personality);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(secure_bits, "i", int32_t, int, "%" PRIi32, secure_bits_to_string_alloc_with_check);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(capability, "t", uint64_t, uint64_t, "%" PRIu64, capability_set_to_string_alloc);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(sched_policy, "i", int32_t, int, "%" PRIi32, sched_policy_to_string_alloc_with_check);
-static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(namespace_flag, "t", uint64_t, unsigned long, "%" PRIu64, namespace_flag_to_string_many_with_check);
+static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(namespace_flag, "t", uint64_t, unsigned long, "%" PRIu64, namespace_flags_to_string);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING(mount_flags, "t", uint64_t, unsigned long, "%" PRIu64, mount_propagation_flags_to_string_with_check);
int bus_exec_context_set_transient_property(
@@ -1238,8 +1039,8 @@ int bus_exec_context_set_transient_property(
UnitWriteFlags flags,
sd_bus_error *error) {
- const char *soft = NULL;
- int r, ri;
+ const char *suffix;
+ int r;
assert(u);
assert(c);
@@ -1305,6 +1106,9 @@ int bus_exec_context_set_transient_property(
if (streq(name, "PrivateDevices"))
return bus_set_transient_bool(u, name, &c->private_devices, message, flags, error);
+ if (streq(name, "PrivateMounts"))
+ return bus_set_transient_bool(u, name, &c->private_mounts, message, flags, error);
+
if (streq(name, "PrivateNetwork"))
return bus_set_transient_bool(u, name, &c->private_network, message, flags, error);
@@ -2043,9 +1847,7 @@ int bus_exec_context_set_transient_property(
if (!e)
return -ENOMEM;
- strv_free(c->environment);
- c->environment = e;
-
+ strv_free_and_replace(c->environment, e);
unit_write_settingf(u, flags, name, "Environment=%s", joined);
}
}
@@ -2079,9 +1881,7 @@ int bus_exec_context_set_transient_property(
if (!e)
return -ENOMEM;
- strv_free(c->unset_environment);
- c->unset_environment = e;
-
+ strv_free_and_replace(c->unset_environment, e);
unit_write_settingf(u, flags, name, "UnsetEnvironment=%s", joined);
}
}
@@ -2250,7 +2050,7 @@ int bus_exec_context_set_transient_property(
if (!path_is_absolute(i + offset))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name);
- path_kill_slashes(i + offset);
+ path_simplify(i + offset, false);
}
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
@@ -2290,8 +2090,14 @@ int bus_exec_context_set_transient_property(
return r;
STRV_FOREACH(p, l) {
- if (!path_is_normalized(*p) || path_is_absolute(*p))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= path is not valid: %s", name, *p);
+ if (!path_is_normalized(*p))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= path is not normalized: %s", name, *p);
+
+ if (path_is_absolute(*p))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= path is absolute: %s", name, *p);
+
+ if (path_startswith(*p, "private"))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= path can't be 'private': %s", name, *p);
}
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
@@ -2464,73 +2270,77 @@ int bus_exec_context_set_transient_property(
}
return 1;
- }
- ri = rlimit_from_string(name);
- if (ri < 0) {
- soft = endswith(name, "Soft");
- if (soft) {
- const char *n;
+ } else if ((suffix = startswith(name, "Limit"))) {
+ const char *soft = NULL;
+ int ri;
- n = strndupa(name, soft - name);
- ri = rlimit_from_string(n);
- if (ri >= 0)
- name = n;
+ ri = rlimit_from_string(suffix);
+ if (ri < 0) {
+ soft = endswith(suffix, "Soft");
+ if (soft) {
+ const char *n;
+ n = strndupa(suffix, soft - suffix);
+ ri = rlimit_from_string(n);
+ if (ri >= 0)
+ name = strjoina("Limit", n);
+ }
}
- }
- if (ri >= 0) {
- uint64_t rl;
- rlim_t x;
+ if (ri >= 0) {
+ uint64_t rl;
+ rlim_t x;
- r = sd_bus_message_read(message, "t", &rl);
- if (r < 0)
- return r;
-
- if (rl == (uint64_t) -1)
- x = RLIM_INFINITY;
- else {
- x = (rlim_t) rl;
-
- if ((uint64_t) x != rl)
- return -ERANGE;
- }
-
- if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
- _cleanup_free_ char *f = NULL;
- struct rlimit nl;
-
- if (c->rlimit[ri]) {
- nl = *c->rlimit[ri];
-
- if (soft)
- nl.rlim_cur = x;
- else
- nl.rlim_max = x;
- } else
- /* When the resource limit is not initialized yet, then assign the value to both fields */
- nl = (struct rlimit) {
- .rlim_cur = x,
- .rlim_max = x,
- };
-
- r = rlimit_format(&nl, &f);
+ r = sd_bus_message_read(message, "t", &rl);
if (r < 0)
return r;
- if (c->rlimit[ri])
- *c->rlimit[ri] = nl;
+ if (rl == (uint64_t) -1)
+ x = RLIM_INFINITY;
else {
- c->rlimit[ri] = newdup(struct rlimit, &nl, 1);
- if (!c->rlimit[ri])
- return -ENOMEM;
+ x = (rlim_t) rl;
+
+ if ((uint64_t) x != rl)
+ return -ERANGE;
}
- unit_write_settingf(u, flags, name, "%s=%s", name, f);
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ _cleanup_free_ char *f = NULL;
+ struct rlimit nl;
+
+ if (c->rlimit[ri]) {
+ nl = *c->rlimit[ri];
+
+ if (soft)
+ nl.rlim_cur = x;
+ else
+ nl.rlim_max = x;
+ } else
+ /* When the resource limit is not initialized yet, then assign the value to both fields */
+ nl = (struct rlimit) {
+ .rlim_cur = x,
+ .rlim_max = x,
+ };
+
+ r = rlimit_format(&nl, &f);
+ if (r < 0)
+ return r;
+
+ if (c->rlimit[ri])
+ *c->rlimit[ri] = nl;
+ else {
+ c->rlimit[ri] = newdup(struct rlimit, &nl, 1);
+ if (!c->rlimit[ri])
+ return -ENOMEM;
+ }
+
+ unit_write_settingf(u, flags, name, "%s=%s", name, f);
+ }
+
+ return 1;
}
- return 1;
}
return 0;
diff --git a/src/core/dbus-execute.h b/src/core/dbus-execute.h
index 4d9b368f81..84051700ab 100644
--- a/src/core/dbus-execute.h
+++ b/src/core/dbus-execute.h
@@ -1,26 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include "sd-bus.h"
+#include "sd-bus-vtable.h"
#include "execute.h"
diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c
index 0802fc9773..5551c56d0e 100644
--- a/src/core/dbus-job.c
+++ b/src/core/dbus-job.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include "sd-bus.h"
@@ -274,8 +256,7 @@ int bus_job_coldplug_bus_track(Job *j) {
assert(j);
- deserialized_clients = j->deserialized_clients;
- j->deserialized_clients = NULL;
+ deserialized_clients = TAKE_PTR(j->deserialized_clients);
if (strv_isempty(deserialized_clients))
return 0;
diff --git a/src/core/dbus-job.h b/src/core/dbus-job.h
index 65d87814a6..3cc60f22ee 100644
--- a/src/core/dbus-job.h
+++ b/src/core/dbus-job.h
@@ -1,26 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include "sd-bus.h"
+#include "sd-bus-vtable.h"
#include "job.h"
diff --git a/src/core/dbus-kill.c b/src/core/dbus-kill.c
index 53d0aad63b..028e7ec1c1 100644
--- a/src/core/dbus-kill.c
+++ b/src/core/dbus-kill.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2012 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include "bus-util.h"
#include "dbus-kill.h"
diff --git a/src/core/dbus-kill.h b/src/core/dbus-kill.h
index 1df3b37c65..8192e94fbb 100644
--- a/src/core/dbus-kill.h
+++ b/src/core/dbus-kill.h
@@ -1,26 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2012 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include "sd-bus.h"
+#include "sd-bus-vtable.h"
#include "kill.h"
#include "unit.h"
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 889779d548..4ed68af1e0 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
#include <sys/prctl.h>
@@ -39,6 +21,7 @@
#include "fs-util.h"
#include "install.h"
#include "log.h"
+#include "os-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "selinux-access.h"
@@ -59,35 +42,14 @@ static UnitFileFlags unit_file_bools_to_flags(bool runtime, bool force) {
(force ? UNIT_FILE_FORCE : 0);
}
-static int property_get_version(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- assert(bus);
- assert(reply);
-
- return sd_bus_message_append(reply, "s", PACKAGE_VERSION);
-}
-
-static int property_get_features(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- assert(bus);
- assert(reply);
-
- return sd_bus_message_append(reply, "s", SYSTEMD_FEATURES);
-}
+static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_version, "s", PACKAGE_VERSION);
+static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_features, "s", SYSTEMD_FEATURES);
+static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_architecture, "s", architecture_to_string(uname_architecture()));
+static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_log_target, "s", log_target_to_string(log_get_target()));
+static BUS_DEFINE_PROPERTY_GET2(property_get_system_state, "s", Manager, manager_state, manager_state_to_string);
+static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_timer_slack_nsec, "t", (uint64_t) prctl(PR_GET_TIMERSLACK));
+static BUS_DEFINE_PROPERTY_GET_REF(property_get_hashmap_size, "u", Hashmap *, hashmap_size);
+static BUS_DEFINE_PROPERTY_GET_REF(property_get_set_size, "u", Set *, set_size);
static int property_get_virtualization(
sd_bus *bus,
@@ -112,22 +74,7 @@ static int property_get_virtualization(
return sd_bus_message_append(
reply, "s",
- v == VIRTUALIZATION_NONE ? "" : virtualization_to_string(v));
-}
-
-static int property_get_architecture(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- assert(bus);
- assert(reply);
-
- return sd_bus_message_append(reply, "s", architecture_to_string(uname_architecture()));
+ v == VIRTUALIZATION_NONE ? NULL : virtualization_to_string(v));
}
static int property_get_tainted(
@@ -153,21 +100,6 @@ static int property_get_tainted(
return sd_bus_message_append(reply, "s", s);
}
-static int property_get_log_target(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- assert(bus);
- assert(reply);
-
- return sd_bus_message_append(reply, "s", log_target_to_string(log_get_target()));
-}
-
static int property_set_log_target(
sd_bus *bus,
const char *path,
@@ -177,6 +109,7 @@ static int property_set_log_target(
void *userdata,
sd_bus_error *error) {
+ Manager *m = userdata;
const char *t;
int r;
@@ -187,7 +120,19 @@ static int property_set_log_target(
if (r < 0)
return r;
- return log_set_target_from_string(t);
+ if (isempty(t))
+ manager_restore_original_log_target(m);
+ else {
+ LogTarget target;
+
+ target = log_target_from_string(t);
+ if (target < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid log target '%s'", t);
+
+ manager_override_log_target(m, target);
+ }
+
+ return 0;
}
static int property_get_log_level(
@@ -221,6 +166,7 @@ static int property_set_log_level(
void *userdata,
sd_bus_error *error) {
+ Manager *m = userdata;
const char *t;
int r;
@@ -231,64 +177,19 @@ static int property_set_log_level(
if (r < 0)
return r;
- r = log_set_max_level_from_string(t);
- if (r == 0)
- log_info("Setting log level to %s.", t);
- return r;
-}
-
-static int property_get_n_names(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Manager *m = userdata;
-
- assert(bus);
- assert(reply);
- assert(m);
-
- return sd_bus_message_append(reply, "u", (uint32_t) hashmap_size(m->units));
-}
-
-static int property_get_n_failed_units(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Manager *m = userdata;
-
- assert(bus);
- assert(reply);
- assert(m);
-
- return sd_bus_message_append(reply, "u", (uint32_t) set_size(m->failed_units));
-}
-
-static int property_get_n_jobs(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
+ if (isempty(t))
+ manager_restore_original_log_level(m);
+ else {
+ int level;
- Manager *m = userdata;
+ level = log_level_from_string(t);
+ if (level < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid log level '%s'", t);
- assert(bus);
- assert(reply);
- assert(m);
+ manager_override_log_level(m, level);
+ }
- return sd_bus_message_append(reply, "u", (uint32_t) hashmap_size(m->jobs));
+ return 0;
}
static int property_get_progress(
@@ -315,7 +216,7 @@ static int property_get_progress(
return sd_bus_message_append(reply, "d", d);
}
-static int property_get_system_state(
+static int property_get_show_status(
sd_bus *bus,
const char *path,
const char *interface,
@@ -325,12 +226,14 @@ static int property_get_system_state(
sd_bus_error *error) {
Manager *m = userdata;
+ int b;
assert(bus);
assert(reply);
assert(m);
- return sd_bus_message_append(reply, "s", manager_state_to_string(manager_state(m)));
+ b = m->show_status > 0;
+ return sd_bus_message_append_basic(reply, 'b', &b);
}
static int property_set_runtime_watchdog(
@@ -357,21 +260,6 @@ static int property_set_runtime_watchdog(
return watchdog_set_timeout(t);
}
-static int property_get_timer_slack_nsec(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- assert(bus);
- assert(reply);
-
- return sd_bus_message_append(reply, "t", (uint64_t) prctl(PR_GET_TIMERSLACK));
-}
-
static int bus_get_unit_by_name(Manager *m, sd_bus_message *message, const char *name, Unit **ret_unit, sd_bus_error *error) {
Unit *u;
int r;
@@ -557,6 +445,32 @@ static int method_get_unit_by_invocation_id(sd_bus_message *message, void *userd
return sd_bus_reply_method_return(message, "o", path);
}
+static int method_get_unit_by_control_group(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ _cleanup_free_ char *path = NULL;
+ Manager *m = userdata;
+ const char *cgroup;
+ Unit *u;
+ int r;
+
+ r = sd_bus_message_read(message, "s", &cgroup);
+ if (r < 0)
+ return r;
+
+ u = manager_get_unit_by_cgroup(m, cgroup);
+ if (!u)
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Control group '%s' is not valid or not managed by this instance", cgroup);
+
+ r = mac_selinux_unit_access_check(u, message, "status", error);
+ if (r < 0)
+ return r;
+
+ path = unit_dbus_path(u);
+ if (!path)
+ return -ENOMEM;
+
+ return sd_bus_reply_method_return(message, "o", path);
+}
+
static int method_load_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *path = NULL;
Manager *m = userdata;
@@ -714,7 +628,7 @@ static int method_set_unit_properties(sd_bus_message *message, void *userdata, s
if (r < 0)
return r;
- r = bus_unit_check_load_state(u, error);
+ r = bus_unit_validate_load_state(u, error);
if (r < 0)
return r;
@@ -738,7 +652,7 @@ static int method_ref_unit(sd_bus_message *message, void *userdata, sd_bus_error
if (r < 0)
return r;
- r = bus_unit_check_load_state(u, error);
+ r = bus_unit_validate_load_state(u, error);
if (r < 0)
return r;
@@ -762,7 +676,7 @@ static int method_unref_unit(sd_bus_message *message, void *userdata, sd_bus_err
if (r < 0)
return r;
- r = bus_unit_check_load_state(u, error);
+ r = bus_unit_validate_load_state(u, error);
if (r < 0)
return r;
@@ -1308,7 +1222,7 @@ static int method_unsubscribe(sd_bus_message *message, void *userdata, sd_bus_er
return sd_bus_reply_method_return(message, NULL);
}
-static int method_dump(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int dump_impl(sd_bus_message *message, void *userdata, sd_bus_error *error, int (*reply)(sd_bus_message *, char *)) {
_cleanup_free_ char *dump = NULL;
Manager *m = userdata;
int r;
@@ -1326,9 +1240,31 @@ static int method_dump(sd_bus_message *message, void *userdata, sd_bus_error *er
if (r < 0)
return r;
+ return reply(message, dump);
+}
+
+static int reply_dump(sd_bus_message *message, char *dump) {
return sd_bus_reply_method_return(message, "s", dump);
}
+static int method_dump(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return dump_impl(message, userdata, error, reply_dump);
+}
+
+static int reply_dump_by_fd(sd_bus_message *message, char *dump) {
+ _cleanup_close_ int fd = -1;
+
+ fd = acquire_data_fd(dump, strlen(dump), 0);
+ if (fd < 0)
+ return fd;
+
+ return sd_bus_reply_method_return(message, "h", fd);
+}
+
+static int method_dump_by_fd(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return dump_impl(message, userdata, error, reply_dump_by_fd);
+}
+
static int method_refuse_snapshot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Support for snapshots has been removed.");
}
@@ -1546,7 +1482,7 @@ static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_er
if (available < RELOAD_DISK_SPACE_MIN) {
char fb_available[FORMAT_BYTES_MAX], fb_need[FORMAT_BYTES_MAX];
- log_warning("Dangerously low amount of free space on /run/systemd, root switching operation might not complete successfuly. "
+ log_warning("Dangerously low amount of free space on /run/systemd, root switching operation might not complete successfully. "
"Currently, %s are free, but %s are suggested. Proceeding anyway.",
format_bytes(fb_available, sizeof(fb_available), available),
format_bytes(fb_need, sizeof(fb_need), RELOAD_DISK_SPACE_MIN));
@@ -1583,7 +1519,7 @@ static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_er
if (!path_is_absolute(init))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path to init binary '%s' not absolute.", init);
- r = chase_symlinks(init, root, CHASE_PREFIX_ROOT, &chased);
+ r = chase_symlinks(init, root, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &chased);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Could not resolve init executable %s: %m", init);
@@ -1798,6 +1734,50 @@ static int method_lookup_dynamic_user_by_uid(sd_bus_message *message, void *user
return sd_bus_reply_method_return(message, "s", name);
}
+static int method_get_dynamic_users(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ Manager *m = userdata;
+ DynamicUser *d;
+ Iterator i;
+ int r;
+
+ assert(message);
+ assert(m);
+
+ assert_cc(sizeof(uid_t) == sizeof(uint32_t));
+
+ if (!MANAGER_IS_SYSTEM(m))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Dynamic users are only supported in the system instance.");
+
+ r = sd_bus_message_new_method_return(message, &reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(reply, 'a', "(us)");
+ if (r < 0)
+ return r;
+
+ HASHMAP_FOREACH(d, m->dynamic_users, i) {
+ uid_t uid;
+
+ r = dynamic_user_current(d, &uid);
+ if (r == -EAGAIN) /* not realized yet? */
+ continue;
+ if (r < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Failed to lookup a dynamic user.");
+
+ r = sd_bus_message_append(reply, "(us)", uid, d->name);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return r;
+
+ return sd_bus_send(NULL, reply, NULL);
+}
+
static int list_unit_files_by_patterns(sd_bus_message *message, void *userdata, sd_bus_error *error, char **states, char **patterns) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
Manager *m = userdata;
@@ -1941,9 +1921,10 @@ static int install_error(
sd_bus_error *error,
int c,
UnitFileChange *changes,
- unsigned n_changes) {
+ size_t n_changes) {
+
+ size_t i;
int r;
- unsigned i;
for (i = 0; i < n_changes; i++)
@@ -1999,12 +1980,12 @@ static int reply_unit_file_changes_and_free(
sd_bus_message *message,
int carries_install_info,
UnitFileChange *changes,
- unsigned n_changes,
+ size_t n_changes,
sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
bool bad = false, good = false;
- unsigned i;
+ size_t i;
int r;
if (unit_file_changes_have_modification(changes, n_changes)) {
@@ -2065,13 +2046,13 @@ fail:
static int method_enable_unit_files_generic(
sd_bus_message *message,
Manager *m,
- int (*call)(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes),
+ int (*call)(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, size_t *n_changes),
bool carries_install_info,
sd_bus_error *error) {
_cleanup_strv_free_ char **l = NULL;
UnitFileChange *changes = NULL;
- unsigned n_changes = 0;
+ size_t n_changes = 0;
UnitFileFlags flags;
int runtime, force, r;
@@ -2113,7 +2094,7 @@ static int method_link_unit_files(sd_bus_message *message, void *userdata, sd_bu
return method_enable_unit_files_generic(message, userdata, unit_file_link, false, error);
}
-static int unit_file_preset_without_mode(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes) {
+static int unit_file_preset_without_mode(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, size_t *n_changes) {
return unit_file_preset(scope, flags, root_dir, files, UNIT_FILE_PRESET_FULL, changes, n_changes);
}
@@ -2129,7 +2110,7 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use
_cleanup_strv_free_ char **l = NULL;
UnitFileChange *changes = NULL;
- unsigned n_changes = 0;
+ size_t n_changes = 0;
Manager *m = userdata;
UnitFilePresetMode mm;
int runtime, force, r;
@@ -2173,12 +2154,12 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use
static int method_disable_unit_files_generic(
sd_bus_message *message,
Manager *m,
- int (*call)(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes),
+ int (*call)(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, size_t *n_changes),
sd_bus_error *error) {
_cleanup_strv_free_ char **l = NULL;
UnitFileChange *changes = NULL;
- unsigned n_changes = 0;
+ size_t n_changes = 0;
int r, runtime;
assert(message);
@@ -2216,7 +2197,7 @@ static int method_unmask_unit_files(sd_bus_message *message, void *userdata, sd_
static int method_revert_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_strv_free_ char **l = NULL;
UnitFileChange *changes = NULL;
- unsigned n_changes = 0;
+ size_t n_changes = 0;
Manager *m = userdata;
int r;
@@ -2242,7 +2223,7 @@ static int method_revert_unit_files(sd_bus_message *message, void *userdata, sd_
static int method_set_default_target(sd_bus_message *message, void *userdata, sd_bus_error *error) {
UnitFileChange *changes = NULL;
- unsigned n_changes = 0;
+ size_t n_changes = 0;
Manager *m = userdata;
const char *name;
int force, r;
@@ -2273,7 +2254,7 @@ static int method_set_default_target(sd_bus_message *message, void *userdata, sd
static int method_preset_all_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
UnitFileChange *changes = NULL;
- unsigned n_changes = 0;
+ size_t n_changes = 0;
Manager *m = userdata;
UnitFilePresetMode mm;
const char *mode;
@@ -2318,7 +2299,7 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd
_cleanup_strv_free_ char **l = NULL;
Manager *m = userdata;
UnitFileChange *changes = NULL;
- unsigned n_changes = 0;
+ size_t n_changes = 0;
int runtime, force, r;
char *target, *type;
UnitDependency dep;
@@ -2357,7 +2338,7 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd
static int method_get_unit_file_links(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
UnitFileChange *changes = NULL;
- unsigned n_changes = 0, i;
+ size_t n_changes = 0, i;
UnitFileFlags flags;
const char *name;
char **p;
@@ -2439,15 +2420,15 @@ const sd_bus_vtable bus_manager_vtable[] = {
BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadFinishTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_UNITS_LOAD_FINISH]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_WRITABLE_PROPERTY("LogLevel", "s", property_get_log_level, property_set_log_level, 0, 0),
SD_BUS_WRITABLE_PROPERTY("LogTarget", "s", property_get_log_target, property_set_log_target, 0, 0),
- SD_BUS_PROPERTY("NNames", "u", property_get_n_names, 0, 0),
- SD_BUS_PROPERTY("NFailedUnits", "u", property_get_n_failed_units, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("NJobs", "u", property_get_n_jobs, 0, 0),
+ SD_BUS_PROPERTY("NNames", "u", property_get_hashmap_size, offsetof(Manager, units), 0),
+ SD_BUS_PROPERTY("NFailedUnits", "u", property_get_set_size, offsetof(Manager, failed_units), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("NJobs", "u", property_get_hashmap_size, offsetof(Manager, jobs), 0),
SD_BUS_PROPERTY("NInstalledJobs", "u", bus_property_get_unsigned, offsetof(Manager, n_installed_jobs), 0),
SD_BUS_PROPERTY("NFailedJobs", "u", bus_property_get_unsigned, offsetof(Manager, n_failed_jobs), 0),
SD_BUS_PROPERTY("Progress", "d", property_get_progress, 0, 0),
SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(Manager, environment), 0),
SD_BUS_PROPERTY("ConfirmSpawn", "b", bus_property_get_bool, offsetof(Manager, confirm_spawn), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("ShowStatus", "b", bus_property_get_bool, offsetof(Manager, show_status), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("ShowStatus", "b", property_get_show_status, 0, 0),
SD_BUS_PROPERTY("UnitPath", "as", NULL, offsetof(Manager, lookup_paths.search_path), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultStandardOutput", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultStandardError", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -2508,6 +2489,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetUnitByPID", "u", "o", method_get_unit_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetUnitByInvocationID", "ay", "o", method_get_unit_by_invocation_id, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("GetUnitByControlGroup", "s", "o", method_get_unit_by_control_group, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("LoadUnit", "s", "o", method_load_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("StartUnit", "ss", "o", method_start_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("StartUnitReplace", "sss", "o", method_start_unit_replace, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -2539,8 +2521,9 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_METHOD("Subscribe", NULL, NULL, method_subscribe, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Unsubscribe", NULL, NULL, method_unsubscribe, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Dump", NULL, "s", method_dump, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("CreateSnapshot", "sb", "o", method_refuse_snapshot, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("RemoveSnapshot", "s", NULL, method_refuse_snapshot, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("DumpByFileDescriptor", NULL, "h", method_dump_by_fd, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("CreateSnapshot", "sb", "o", method_refuse_snapshot, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_HIDDEN),
+ SD_BUS_METHOD("RemoveSnapshot", "s", NULL, method_refuse_snapshot, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_HIDDEN),
SD_BUS_METHOD("Reload", NULL, NULL, method_reload, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Reexecute", NULL, NULL, method_reexecute, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Exit", NULL, NULL, method_exit, 0),
@@ -2572,6 +2555,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_METHOD("SetExitCode", "y", NULL, method_set_exit_code, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("LookupDynamicUserByName", "s", "u", method_lookup_dynamic_user_by_name, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("LookupDynamicUserByUID", "u", "s", method_lookup_dynamic_user_by_uid, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("GetDynamicUsers", NULL, "a(us)", method_get_dynamic_users, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_SIGNAL("UnitNew", "so", 0),
SD_BUS_SIGNAL("UnitRemoved", "so", 0),
diff --git a/src/core/dbus-manager.h b/src/core/dbus-manager.h
index 1a6090f0f5..d0306adc70 100644
--- a/src/core/dbus-manager.h
+++ b/src/core/dbus-manager.h
@@ -1,24 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
+#include "sd-bus-vtable.h"
#include "manager.h"
diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c
index 9e52f55fa5..3f98d3ecf0 100644
--- a/src/core/dbus-mount.c
+++ b/src/core/dbus-mount.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include "bus-util.h"
#include "dbus-cgroup.h"
@@ -28,78 +10,33 @@
#include "string-util.h"
#include "unit.h"
-static int property_get_what(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Mount *m = userdata;
- const char *d = NULL;
-
- assert(bus);
- assert(reply);
- assert(m);
-
+static const char *mount_get_what(const Mount *m) {
if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.what)
- d = m->parameters_proc_self_mountinfo.what;
- else if (m->from_fragment && m->parameters_fragment.what)
- d = m->parameters_fragment.what;
-
- return sd_bus_message_append(reply, "s", d);
+ return m->parameters_proc_self_mountinfo.what;
+ if (m->from_fragment && m->parameters_fragment.what)
+ return m->parameters_fragment.what;
+ return NULL;
}
-static int property_get_options(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Mount *m = userdata;
- const char *d = NULL;
-
- assert(bus);
- assert(reply);
- assert(m);
-
+static const char *mount_get_options(const Mount *m) {
if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.options)
- d = m->parameters_proc_self_mountinfo.options;
- else if (m->from_fragment && m->parameters_fragment.options)
- d = m->parameters_fragment.options;
-
- return sd_bus_message_append(reply, "s", d);
+ return m->parameters_proc_self_mountinfo.options;
+ if (m->from_fragment && m->parameters_fragment.options)
+ return m->parameters_fragment.options;
+ return NULL;
}
-static int property_get_type(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- const char *fstype = NULL;
- Mount *m = userdata;
-
- assert(bus);
- assert(reply);
- assert(m);
-
+static const char *mount_get_fstype(const Mount *m) {
if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.fstype)
- fstype = m->parameters_proc_self_mountinfo.fstype;
+ return m->parameters_proc_self_mountinfo.fstype;
else if (m->from_fragment && m->parameters_fragment.fstype)
- fstype = m->parameters_fragment.fstype;
-
- return sd_bus_message_append(reply, "s", fstype);
+ return m->parameters_fragment.fstype;
+ return NULL;
}
+static BUS_DEFINE_PROPERTY_GET(property_get_what, "s", Mount, mount_get_what);
+static BUS_DEFINE_PROPERTY_GET(property_get_options, "s", Mount, mount_get_options);
+static BUS_DEFINE_PROPERTY_GET(property_get_type, "s", Mount, mount_get_fstype);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, mount_result, MountResult);
const sd_bus_vtable bus_mount_vtable[] = {
@@ -115,8 +52,8 @@ const sd_bus_vtable bus_mount_vtable[] = {
SD_BUS_PROPERTY("LazyUnmount", "b", bus_property_get_bool, offsetof(Mount, lazy_unmount), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ForceUnmount", "b", bus_property_get_bool, offsetof(Mount, force_unmount), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Mount, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("UID", "u", NULL, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("GID", "u", NULL, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("UID", "u", bus_property_get_uid, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("GID", "u", bus_property_get_gid, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
BUS_EXEC_COMMAND_VTABLE("ExecMount", offsetof(Mount, exec_command[MOUNT_EXEC_MOUNT]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_VTABLE("ExecUnmount", offsetof(Mount, exec_command[MOUNT_EXEC_UNMOUNT]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_VTABLE("ExecRemount", offsetof(Mount, exec_command[MOUNT_EXEC_REMOUNT]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
diff --git a/src/core/dbus-mount.h b/src/core/dbus-mount.h
index 5d5e1f679f..f7112a9f02 100644
--- a/src/core/dbus-mount.h
+++ b/src/core/dbus-mount.h
@@ -1,26 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include "sd-bus.h"
+#include "sd-bus-vtable.h"
#include "unit.h"
diff --git a/src/core/dbus-path.c b/src/core/dbus-path.c
index b3f502f4c9..1a97d62486 100644
--- a/src/core/dbus-path.c
+++ b/src/core/dbus-path.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include "alloc-util.h"
#include "bus-util.h"
@@ -60,29 +42,9 @@ static int property_get_paths(
return sd_bus_message_close_container(reply);
}
-static int property_get_unit(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Unit *p = userdata, *trigger;
-
- assert(bus);
- assert(reply);
- assert(p);
-
- trigger = UNIT_TRIGGER(p);
-
- return sd_bus_message_append(reply, "s", trigger ? trigger->id : "");
-}
-
const sd_bus_vtable bus_path_vtable[] = {
SD_BUS_VTABLE_START(0),
- SD_BUS_PROPERTY("Unit", "s", property_get_unit, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Unit", "s", bus_property_get_triggered_unit, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Paths", "a(ss)", property_get_paths, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MakeDirectory", "b", bus_property_get_bool, offsetof(Path, make_directory), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Path, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -141,13 +103,14 @@ static int bus_path_set_transient_property(
if (!k)
return -ENOMEM;
+ path_simplify(k, false);
+
s = new0(PathSpec, 1);
if (!s)
return -ENOMEM;
s->unit = u;
- s->path = path_kill_slashes(k);
- k = NULL;
+ s->path = TAKE_PTR(k);
s->type = t;
s->inotify_fd = -1;
diff --git a/src/core/dbus-path.h b/src/core/dbus-path.h
index ccd88c7f86..ad42b23662 100644
--- a/src/core/dbus-path.h
+++ b/src/core/dbus-path.h
@@ -1,26 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include "sd-bus.h"
+#include "sd-bus-vtable.h"
#include "unit.h"
diff --git a/src/core/dbus-scope.c b/src/core/dbus-scope.c
index 4d9ced81de..6725f62794 100644
--- a/src/core/dbus-scope.c
+++ b/src/core/dbus-scope.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include "alloc-util.h"
#include "bus-common-errors.h"
diff --git a/src/core/dbus-scope.h b/src/core/dbus-scope.h
index aa604897eb..7c080dbcf7 100644
--- a/src/core/dbus-scope.h
+++ b/src/core/dbus-scope.h
@@ -1,27 +1,10 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include "sd-bus.h"
+#include "sd-bus-vtable.h"
+#include "scope.h"
#include "unit.h"
extern const sd_bus_vtable bus_scope_vtable[];
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
index 6de905b69c..1b4c98c7d2 100644
--- a/src/core/dbus-service.c
+++ b/src/core/dbus-service.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <stdio_ext.h>
@@ -136,12 +118,12 @@ const sd_bus_vtable bus_service_vtable[] = {
SD_BUS_PROPERTY("FileDescriptorStoreMax", "u", bus_property_get_unsigned, offsetof(Service, n_fd_store_max), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("NFileDescriptorStore", "u", bus_property_get_unsigned, offsetof(Service, n_fd_store), 0),
SD_BUS_PROPERTY("StatusText", "s", NULL, offsetof(Service, status_text), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("StatusErrno", "i", NULL, offsetof(Service, status_errno), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("StatusErrno", "i", bus_property_get_int, offsetof(Service, status_errno), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Service, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("USBFunctionDescriptors", "s", NULL, offsetof(Service, usb_function_descriptors), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("USBFunctionStrings", "s", NULL, offsetof(Service, usb_function_strings), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("UID", "u", NULL, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("GID", "u", NULL, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("UID", "u", bus_property_get_uid, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("GID", "u", bus_property_get_gid, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("NRestarts", "u", bus_property_get_unsigned, offsetof(Service, n_restarts), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
BUS_EXEC_STATUS_VTABLE("ExecMain", offsetof(Service, main_exec_status), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
@@ -354,7 +336,8 @@ static int bus_service_set_transient_property(
if (streq(name, "SuccessExitStatus"))
return bus_set_transient_exit_status(u, name, &s->success_status, message, flags, error);
- if ((ci = service_exec_command_from_string(name)) >= 0)
+ ci = service_exec_command_from_string(name);
+ if (ci >= 0)
return bus_set_transient_exec_command(u, name, &s->exec_command[ci], message, flags, error);
if (streq(name, "StandardInputFileDescriptor"))
diff --git a/src/core/dbus-service.h b/src/core/dbus-service.h
index 2da29ec601..22d2b887b4 100644
--- a/src/core/dbus-service.h
+++ b/src/core/dbus-service.h
@@ -1,26 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include "sd-bus.h"
+#include "sd-bus-vtable.h"
#include "unit.h"
diff --git a/src/core/dbus-slice.c b/src/core/dbus-slice.c
index fa2ff72151..722a5688a5 100644
--- a/src/core/dbus-slice.c
+++ b/src/core/dbus-slice.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include "dbus-cgroup.h"
#include "dbus-slice.h"
diff --git a/src/core/dbus-slice.h b/src/core/dbus-slice.h
index 0c21919ad1..88cc48c808 100644
--- a/src/core/dbus-slice.h
+++ b/src/core/dbus-slice.h
@@ -1,26 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include "sd-bus.h"
+#include "sd-bus-vtable.h"
#include "unit.h"
diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
index 035651f213..913cc74918 100644
--- a/src/core/dbus-socket.c
+++ b/src/core/dbus-socket.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include "alloc-util.h"
#include "bus-util.h"
@@ -36,6 +18,7 @@
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, socket_result, SocketResult);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_bind_ipv6_only, socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
+static BUS_DEFINE_PROPERTY_GET(property_get_fdname, "s", Socket, socket_fdname);
static int property_get_listen(
sd_bus *bus,
@@ -46,7 +29,6 @@ static int property_get_listen(
void *userdata,
sd_bus_error *error) {
-
Socket *s = SOCKET(userdata);
SocketPort *p;
int r;
@@ -92,25 +74,6 @@ static int property_get_listen(
return sd_bus_message_close_container(reply);
}
-
-static int property_get_fdname(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Socket *s = SOCKET(userdata);
-
- assert(bus);
- assert(reply);
- assert(s);
-
- return sd_bus_message_append(reply, "s", socket_fdname(s));
-}
-
const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("BindIPv6Only", "s", property_get_bind_ipv6_only, offsetof(Socket, bind_ipv6_only), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -157,12 +120,13 @@ const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Socket, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("NConnections", "u", bus_property_get_unsigned, offsetof(Socket, n_connections), 0),
SD_BUS_PROPERTY("NAccepted", "u", bus_property_get_unsigned, offsetof(Socket, n_accepted), 0),
+ SD_BUS_PROPERTY("NRefused", "u", bus_property_get_unsigned, offsetof(Socket, n_refused), 0),
SD_BUS_PROPERTY("FileDescriptorName", "s", property_get_fdname, 0, 0),
SD_BUS_PROPERTY("SocketProtocol", "i", bus_property_get_int, offsetof(Socket, socket_protocol), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TriggerLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Socket, trigger_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TriggerLimitBurst", "u", bus_property_get_unsigned, offsetof(Socket, trigger_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("UID", "u", NULL, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("GID", "u", NULL, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("UID", "u", bus_property_get_uid, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("GID", "u", bus_property_get_gid, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPre", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
@@ -174,7 +138,10 @@ static inline bool check_size_t_truncation(uint64_t t) {
return (size_t) t == t;
}
-static inline const char* socket_protocol_to_name_supported(int32_t i) {
+static inline const char* supported_socket_protocol_to_string(int32_t i) {
+ if (i == IPPROTO_IP)
+ return "";
+
if (!IN_SET(i, IPPROTO_UDPLITE, IPPROTO_SCTP))
return NULL;
@@ -184,11 +151,11 @@ static inline const char* socket_protocol_to_name_supported(int32_t i) {
static BUS_DEFINE_SET_TRANSIENT(int, "i", int32_t, int, "%" PRIi32);
static BUS_DEFINE_SET_TRANSIENT(message_queue, "x", int64_t, long, "%" PRIi64);
static BUS_DEFINE_SET_TRANSIENT_IS_VALID(size_t_check_truncation, "t", uint64_t, size_t, "%" PRIu64, check_size_t_truncation);
-static BUS_DEFINE_SET_TRANSIENT_PARSE(bind_ipv6_only, SocketAddressBindIPv6Only, parse_socket_address_bind_ipv6_only_or_bool);
+static BUS_DEFINE_SET_TRANSIENT_PARSE(bind_ipv6_only, SocketAddressBindIPv6Only, socket_address_bind_ipv6_only_or_bool_from_string);
static BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(fdname, fdname_is_valid);
static BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(ifname, ifname_valid);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(ip_tos, "i", int32_t, int, "%" PRIi32, ip_tos_to_string_alloc);
-static BUS_DEFINE_SET_TRANSIENT_TO_STRING(socket_protocol, "i", int32_t, int, "%" PRIi32, socket_protocol_to_name_supported);
+static BUS_DEFINE_SET_TRANSIENT_TO_STRING(socket_protocol, "i", int32_t, int, "%" PRIi32, supported_socket_protocol_to_string);
static int bus_socket_set_transient_property(
Socket *s,
@@ -394,7 +361,7 @@ static int bus_socket_set_transient_property(
if (p->type != SOCKET_SOCKET) {
p->path = strdup(a);
- path_kill_slashes(p->path);
+ path_simplify(p->path, false);
} else if (streq(t, "Netlink")) {
r = socket_address_parse_netlink(&p->address, a);
diff --git a/src/core/dbus-socket.h b/src/core/dbus-socket.h
index e6db2d0772..9aa8133d18 100644
--- a/src/core/dbus-socket.h
+++ b/src/core/dbus-socket.h
@@ -1,26 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include "sd-bus.h"
+#include "sd-bus-vtable.h"
#include "unit.h"
diff --git a/src/core/dbus-swap.c b/src/core/dbus-swap.c
index 795aaa94fe..b272d10113 100644
--- a/src/core/dbus-swap.c
+++ b/src/core/dbus-swap.c
@@ -1,22 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
- Copyright 2010 Maarten Lankhorst
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ Copyright © 2010 Maarten Lankhorst
***/
#include "bus-util.h"
@@ -27,54 +11,22 @@
#include "swap.h"
#include "unit.h"
-static int property_get_priority(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Swap *s = SWAP(userdata);
- int p;
-
- assert(bus);
- assert(reply);
- assert(s);
-
+static int swap_get_priority(Swap *s) {
if (s->from_proc_swaps)
- p = s->parameters_proc_swaps.priority;
- else if (s->from_fragment)
- p = s->parameters_fragment.priority;
- else
- p = -1;
-
- return sd_bus_message_append(reply, "i", p);
+ return s->parameters_proc_swaps.priority;
+ if (s->from_fragment)
+ return s->parameters_fragment.priority;
+ return -1;
}
-static int property_get_options(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Swap *s = SWAP(userdata);
- const char *options = NULL;
-
- assert(bus);
- assert(reply);
- assert(s);
-
+static const char *swap_get_options(Swap *s) {
if (s->from_fragment)
- options = s->parameters_fragment.options;
-
- return sd_bus_message_append(reply, "s", options);
+ return s->parameters_fragment.options;
+ return NULL;
}
+static BUS_DEFINE_PROPERTY_GET(property_get_priority, "i", Swap, swap_get_priority);
+static BUS_DEFINE_PROPERTY_GET(property_get_options, "s", Swap, swap_get_options);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, swap_result, SwapResult);
const sd_bus_vtable bus_swap_vtable[] = {
@@ -85,8 +37,8 @@ const sd_bus_vtable bus_swap_vtable[] = {
SD_BUS_PROPERTY("TimeoutUSec", "t", bus_property_get_usec, offsetof(Swap, timeout_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Swap, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Swap, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("UID", "u", NULL, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("GID", "u", NULL, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("UID", "u", bus_property_get_uid, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("GID", "u", bus_property_get_gid, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
BUS_EXEC_COMMAND_VTABLE("ExecActivate", offsetof(Swap, exec_command[SWAP_EXEC_ACTIVATE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_VTABLE("ExecDeactivate", offsetof(Swap, exec_command[SWAP_EXEC_DEACTIVATE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
SD_BUS_VTABLE_END
diff --git a/src/core/dbus-swap.h b/src/core/dbus-swap.h
index 6cca7483d8..b114fe04c7 100644
--- a/src/core/dbus-swap.h
+++ b/src/core/dbus-swap.h
@@ -2,26 +2,11 @@
#pragma once
/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
- Copyright 2010 Maarten Lankhorst
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ Copyright © 2010 Maarten Lankhorst
***/
#include "sd-bus.h"
+#include "sd-bus-vtable.h"
#include "unit.h"
diff --git a/src/core/dbus-target.c b/src/core/dbus-target.c
index 7060b65c6e..ba50113641 100644
--- a/src/core/dbus-target.c
+++ b/src/core/dbus-target.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include "dbus-target.h"
#include "unit.h"
diff --git a/src/core/dbus-target.h b/src/core/dbus-target.h
index 7852917962..ad02a1db74 100644
--- a/src/core/dbus-target.h
+++ b/src/core/dbus-target.h
@@ -1,25 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "sd-bus.h"
+#include "sd-bus-vtable.h"
extern const sd_bus_vtable bus_target_vtable[];
diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c
index 1eedf217fe..b9d2f3d07e 100644
--- a/src/core/dbus-timer.c
+++ b/src/core/dbus-timer.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include "alloc-util.h"
#include "bus-util.h"
@@ -116,26 +98,6 @@ static int property_get_calendar_timers(
return sd_bus_message_close_container(reply);
}
-static int property_get_unit(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Unit *u = userdata, *trigger;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- trigger = UNIT_TRIGGER(u);
-
- return sd_bus_message_append(reply, "s", trigger ? trigger->id : "");
-}
-
static int property_get_next_elapse_monotonic(
sd_bus *bus,
const char *path,
@@ -158,7 +120,7 @@ static int property_get_next_elapse_monotonic(
const sd_bus_vtable bus_timer_vtable[] = {
SD_BUS_VTABLE_START(0),
- SD_BUS_PROPERTY("Unit", "s", property_get_unit, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Unit", "s", bus_property_get_triggered_unit, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TimersMonotonic", "a(stt)", property_get_monotonic_timers, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
SD_BUS_PROPERTY("TimersCalendar", "a(sst)", property_get_calendar_timers, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
SD_BUS_PROPERTY("NextElapseUSecRealtime", "t", bus_property_get_usec, offsetof(Timer, next_elapse_realtime), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
@@ -290,8 +252,7 @@ static int bus_timer_set_transient_property(
return -ENOMEM;
v->base = b;
- v->calendar_spec = c;
- c = NULL;
+ v->calendar_spec = TAKE_PTR(c);
LIST_PREPEND(value, t->values, v);
}
@@ -377,8 +338,7 @@ static int bus_timer_set_transient_property(
return -ENOMEM;
v->base = TIMER_CALENDAR;
- v->calendar_spec = c;
- c = NULL;
+ v->calendar_spec = TAKE_PTR(c);
LIST_PREPEND(value, t->values, v);
}
diff --git a/src/core/dbus-timer.h b/src/core/dbus-timer.h
index d810b048ee..bb126b22dc 100644
--- a/src/core/dbus-timer.h
+++ b/src/core/dbus-timer.h
@@ -1,26 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include "sd-bus.h"
+#include "sd-bus-vtable.h"
#include "unit.h"
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index 50a5ab9819..ae0410414e 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include "sd-bus.h"
@@ -42,10 +24,32 @@
#include "user-util.h"
#include "web-util.h"
+static bool unit_can_start_refuse_manual(Unit *u) {
+ return unit_can_start(u) && !u->refuse_manual_start;
+}
+
+static bool unit_can_stop_refuse_manual(Unit *u) {
+ return unit_can_stop(u) && !u->refuse_manual_stop;
+}
+
+static bool unit_can_isolate_refuse_manual(Unit *u) {
+ return unit_can_isolate(u) && !u->refuse_manual_start;
+}
+
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_collect_mode, collect_mode, CollectMode);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_emergency_action, emergency_action, EmergencyAction);
+static BUS_DEFINE_PROPERTY_GET(property_get_description, "s", Unit, unit_description);
+static BUS_DEFINE_PROPERTY_GET2(property_get_active_state, "s", Unit, unit_active_state, unit_active_state_to_string);
+static BUS_DEFINE_PROPERTY_GET(property_get_sub_state, "s", Unit, unit_sub_state_to_string);
+static BUS_DEFINE_PROPERTY_GET2(property_get_unit_file_state, "s", Unit, unit_get_unit_file_state, unit_file_state_to_string);
+static BUS_DEFINE_PROPERTY_GET(property_get_can_reload, "b", Unit, unit_can_reload);
+static BUS_DEFINE_PROPERTY_GET(property_get_can_start, "b", Unit, unit_can_start_refuse_manual);
+static BUS_DEFINE_PROPERTY_GET(property_get_can_stop, "b", Unit, unit_can_stop_refuse_manual);
+static BUS_DEFINE_PROPERTY_GET(property_get_can_isolate, "b", Unit, unit_can_isolate_refuse_manual);
+static BUS_DEFINE_PROPERTY_GET(property_get_need_daemon_reload, "b", Unit, unit_need_daemon_reload);
+static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_empty_strv, "as", 0);
static int property_get_names(
sd_bus *bus,
@@ -56,20 +60,20 @@ static int property_get_names(
void *userdata,
sd_bus_error *error) {
- Unit *u = userdata;
+ Set **s = userdata;
Iterator i;
const char *t;
int r;
assert(bus);
assert(reply);
- assert(u);
+ assert(s);
r = sd_bus_message_open_container(reply, 'a', "s");
if (r < 0)
return r;
- SET_FOREACH(t, u->names, i) {
+ SET_FOREACH(t, *s, i) {
r = sd_bus_message_append(reply, "s", t);
if (r < 0)
return r;
@@ -94,7 +98,7 @@ static int property_get_following(
assert(u);
f = unit_following(u);
- return sd_bus_message_append(reply, "s", f ? f->id : "");
+ return sd_bus_message_append(reply, "s", f ? f->id : NULL);
}
static int property_get_dependencies(
@@ -106,7 +110,7 @@ static int property_get_dependencies(
void *userdata,
sd_bus_error *error) {
- Hashmap *h = *(Hashmap**) userdata;
+ Hashmap **h = userdata;
Iterator j;
Unit *u;
void *v;
@@ -114,12 +118,13 @@ static int property_get_dependencies(
assert(bus);
assert(reply);
+ assert(h);
r = sd_bus_message_open_container(reply, 'a', "s");
if (r < 0)
return r;
- HASHMAP_FOREACH_KEY(v, u, h, j) {
+ HASHMAP_FOREACH_KEY(v, u, *h, j) {
r = sd_bus_message_append(reply, "s", u->id);
if (r < 0)
return r;
@@ -128,22 +133,6 @@ static int property_get_dependencies(
return sd_bus_message_close_container(reply);
}
-static int property_get_obsolete_dependencies(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- assert(bus);
- assert(reply);
-
- /* For dependency types we don't support anymore always return an empty array */
- return sd_bus_message_append(reply, "as", 0);
-}
-
static int property_get_requires_mounts_for(
sd_bus *bus,
const char *path,
@@ -153,7 +142,7 @@ static int property_get_requires_mounts_for(
void *userdata,
sd_bus_error *error) {
- Hashmap *h = *(Hashmap**) userdata;
+ Hashmap **h = userdata;
const char *p;
Iterator j;
void *v;
@@ -161,12 +150,13 @@ static int property_get_requires_mounts_for(
assert(bus);
assert(reply);
+ assert(h);
r = sd_bus_message_open_container(reply, 'a', "s");
if (r < 0)
return r;
- HASHMAP_FOREACH_KEY(v, p, h, j) {
+ HASHMAP_FOREACH_KEY(v, p, *h, j) {
r = sd_bus_message_append(reply, "s", p);
if (r < 0)
return r;
@@ -175,60 +165,6 @@ static int property_get_requires_mounts_for(
return sd_bus_message_close_container(reply);
}
-static int property_get_description(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Unit *u = userdata;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- return sd_bus_message_append(reply, "s", unit_description(u));
-}
-
-static int property_get_active_state(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Unit *u = userdata;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- return sd_bus_message_append(reply, "s", unit_active_state_to_string(unit_active_state(u)));
-}
-
-static int property_get_sub_state(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Unit *u = userdata;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- return sd_bus_message_append(reply, "s", unit_sub_state_to_string(u));
-}
-
static int property_get_unit_file_preset(
sd_bus *bus,
const char *path,
@@ -248,100 +184,10 @@ static int property_get_unit_file_preset(
r = unit_get_unit_file_preset(u);
return sd_bus_message_append(reply, "s",
- r < 0 ? "":
+ r < 0 ? NULL:
r > 0 ? "enabled" : "disabled");
}
-static int property_get_unit_file_state(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Unit *u = userdata;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- return sd_bus_message_append(reply, "s", unit_file_state_to_string(unit_get_unit_file_state(u)));
-}
-
-static int property_get_can_start(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Unit *u = userdata;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_start);
-}
-
-static int property_get_can_stop(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Unit *u = userdata;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- return sd_bus_message_append(reply, "b", unit_can_stop(u) && !u->refuse_manual_stop);
-}
-
-static int property_get_can_reload(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Unit *u = userdata;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- return sd_bus_message_append(reply, "b", unit_can_reload(u));
-}
-
-static int property_get_can_isolate(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Unit *u = userdata;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- return sd_bus_message_append(reply, "b", unit_can_isolate(u) && !u->refuse_manual_start);
-}
-
static int property_get_job(
sd_bus *bus,
const char *path,
@@ -352,38 +198,20 @@ static int property_get_job(
sd_bus_error *error) {
_cleanup_free_ char *p = NULL;
- Unit *u = userdata;
+ Job **j = userdata;
assert(bus);
assert(reply);
- assert(u);
+ assert(j);
- if (!u->job)
+ if (!*j)
return sd_bus_message_append(reply, "(uo)", 0, "/");
- p = job_dbus_path(u->job);
+ p = job_dbus_path(*j);
if (!p)
return -ENOMEM;
- return sd_bus_message_append(reply, "(uo)", u->job->id, p);
-}
-
-static int property_get_need_daemon_reload(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Unit *u = userdata;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- return sd_bus_message_append(reply, "b", unit_need_daemon_reload(u));
+ return sd_bus_message_append(reply, "(uo)", (*j)->id, p);
}
static int property_get_conditions(
@@ -439,15 +267,17 @@ static int property_get_load_error(
_cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL;
Unit *u = userdata;
+ int r;
assert(bus);
assert(reply);
assert(u);
- if (u->load_error != 0)
- sd_bus_error_set_errno(&e, u->load_error);
+ r = bus_unit_validate_load_state(u, &e);
+ if (r < 0)
+ return sd_bus_message_append(reply, "(ss)", e.name, e.message);
- return sd_bus_message_append(reply, "(ss)", e.name, e.message);
+ return sd_bus_message_append(reply, "(ss)", NULL, NULL);
}
static int bus_verify_manage_units_async_full(
@@ -735,7 +565,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Names", "as", property_get_names, offsetof(Unit, names), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0),
SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -777,7 +607,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("Job", "(uo)", property_get_job, offsetof(Unit, job), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -821,11 +651,12 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_METHOD("Ref", NULL, NULL, bus_unit_method_ref, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Unref", NULL, NULL, bus_unit_method_unref, SD_BUS_VTABLE_UNPRIVILEGED),
- /* Obsolete properties or obsolete alias names */
- SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
- SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
- SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
- SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
+ /* For dependency types we don't support anymore always return an empty array */
+ SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_empty_strv, 0, SD_BUS_VTABLE_HIDDEN),
+ SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_empty_strv, 0, SD_BUS_VTABLE_HIDDEN),
+ SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_empty_strv, 0, SD_BUS_VTABLE_HIDDEN),
+ SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_empty_strv, 0, SD_BUS_VTABLE_HIDDEN),
+ /* Obsolete alias names */
SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
SD_BUS_PROPERTY("StartLimitIntervalSec", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
SD_BUS_VTABLE_END
@@ -931,7 +762,7 @@ static int property_get_cgroup(
sd_bus_error *error) {
Unit *u = userdata;
- const char *t;
+ const char *t = NULL;
assert(bus);
assert(reply);
@@ -944,9 +775,7 @@ static int property_get_cgroup(
* other cases we report as-is. */
if (u->cgroup_path)
- t = isempty(u->cgroup_path) ? "/" : u->cgroup_path;
- else
- t = "";
+ t = empty_to_root(u->cgroup_path);
return sd_bus_message_append(reply, "s", t);
}
@@ -992,7 +821,7 @@ static int append_cgroup(sd_bus_message *reply, const char *p, Set *pids) {
assert(p);
r = cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, p, &f);
- if (r == ENOENT)
+ if (r == -ENOENT)
return 0;
if (r < 0)
return r;
@@ -1043,7 +872,7 @@ static int append_cgroup(sd_bus_message *reply, const char *p, Set *pids) {
int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- _cleanup_(set_freep) Set *pids = NULL;
+ _cleanup_set_free_ Set *pids = NULL;
Unit *u = userdata;
pid_t pid;
int r;
@@ -1130,7 +959,7 @@ static int property_get_ip_counter(
int bus_unit_method_attach_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
- _cleanup_(set_freep) Set *pids = NULL;
+ _cleanup_set_free_ Set *pids = NULL;
Unit *u = userdata;
const char *path;
int r;
@@ -1408,7 +1237,7 @@ int bus_unit_queue_job(
}
if (type == JOB_STOP &&
- (IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_ERROR)) &&
+ IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_ERROR, UNIT_BAD_SETTING) &&
unit_active_state(u) == UNIT_INACTIVE)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
@@ -1880,22 +1709,33 @@ int bus_unit_set_properties(
return n;
}
-int bus_unit_check_load_state(Unit *u, sd_bus_error *error) {
+int bus_unit_validate_load_state(Unit *u, sd_bus_error *error) {
assert(u);
- if (u->load_state == UNIT_LOADED)
- return 0;
+ /* Generates a pretty error if a unit isn't properly loaded. */
- /* Give a better description of the unit error when
- * possible. Note that in the case of UNIT_MASKED, load_error
- * is not set. */
- if (u->load_state == UNIT_MASKED)
- return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit %s is masked.", u->id);
+ switch (u->load_state) {
+
+ case UNIT_LOADED:
+ return 0;
- if (u->load_state == UNIT_NOT_FOUND)
+ case UNIT_NOT_FOUND:
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not found.", u->id);
- return sd_bus_error_set_errnof(error, u->load_error, "Unit %s is not loaded properly: %m.", u->id);
+ case UNIT_BAD_SETTING:
+ return sd_bus_error_setf(error, BUS_ERROR_BAD_UNIT_SETTING, "Unit %s has a bad unit file setting.", u->id);
+
+ case UNIT_ERROR: /* Only show .load_error in UNIT_ERROR state */
+ return sd_bus_error_set_errnof(error, u->load_error, "Unit %s failed to loaded properly: %m.", u->id);
+
+ case UNIT_MASKED:
+ return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit %s is masked.", u->id);
+
+ case UNIT_STUB:
+ case UNIT_MERGED:
+ default:
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unexpected load state of unit %s", u->id);
+ }
}
static int bus_unit_track_handler(sd_bus_track *t, void *userdata) {
diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h
index bb4e43f5ca..68eb621836 100644
--- a/src/core/dbus-unit.h
+++ b/src/core/dbus-unit.h
@@ -1,27 +1,10 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include "sd-bus.h"
+#include "sd-bus-vtable.h"
+#include "job.h"
#include "unit.h"
extern const sd_bus_vtable bus_unit_vtable[];
@@ -42,7 +25,7 @@ int bus_unit_method_ref(sd_bus_message *message, void *userdata, sd_bus_error *e
int bus_unit_method_unref(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error);
-int bus_unit_check_load_state(Unit *u, sd_bus_error *error);
+int bus_unit_validate_load_state(Unit *u, sd_bus_error *error);
int bus_unit_track_add_name(Unit *u, const char *name);
int bus_unit_track_add_sender(Unit *u, sd_bus_message *m);
diff --git a/src/core/dbus-util.c b/src/core/dbus-util.c
index 75bbd07604..f4fbb72cb9 100644
--- a/src/core/dbus-util.c
+++ b/src/core/dbus-util.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include "bus-util.h"
#include "dbus-util.h"
@@ -26,6 +8,26 @@
#include "user-util.h"
#include "unit.h"
+int bus_property_get_triggered_unit(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Unit *u = userdata, *trigger;
+
+ assert(bus);
+ assert(reply);
+ assert(u);
+
+ trigger = UNIT_TRIGGER(u);
+
+ return sd_bus_message_append(reply, "s", trigger ? trigger->id : NULL);
+}
+
BUS_DEFINE_SET_TRANSIENT(mode_t, "u", uint32_t, mode_t, "%040o");
BUS_DEFINE_SET_TRANSIENT(unsigned, "u", uint32_t, unsigned, "%" PRIu32);
BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(user, valid_user_group_name_or_id);
diff --git a/src/core/dbus-util.h b/src/core/dbus-util.h
index 8260298577..12b055e4ac 100644
--- a/src/core/dbus-util.h
+++ b/src/core/dbus-util.h
@@ -1,28 +1,12 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include "sd-bus.h"
+
#include "unit.h"
+int bus_property_get_triggered_unit(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
+
#define BUS_DEFINE_SET_TRANSIENT(function, bus_type, type, cast_type, fmt) \
int bus_set_transient_##function( \
Unit *u, \
@@ -48,8 +32,7 @@
} \
\
return 1; \
- } \
- struct __useless_struct_to_allow_trailing_semicolon__
+ }
#define BUS_DEFINE_SET_TRANSIENT_IS_VALID(function, bus_type, type, cast_type, fmt, check) \
int bus_set_transient_##function( \
@@ -80,8 +63,7 @@
} \
\
return 1; \
- } \
- struct __useless_struct_to_allow_trailing_semicolon__
+ }
#define BUS_DEFINE_SET_TRANSIENT_TO_STRING(function, bus_type, type, cast_type, fmt, to_string) \
int bus_set_transient_##function( \
@@ -114,8 +96,7 @@
} \
\
return 1; \
- } \
- struct __useless_struct_to_allow_trailing_semicolon__
+ }
#define BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(function, bus_type, type, cast_type, fmt, to_string) \
int bus_set_transient_##function( \
@@ -150,8 +131,7 @@
} \
\
return 1; \
- } \
- struct __useless_struct_to_allow_trailing_semicolon__
+ }
#define BUS_DEFINE_SET_TRANSIENT_PARSE(function, type, parse) \
int bus_set_transient_##function( \
@@ -184,8 +164,7 @@
} \
\
return 1; \
- } \
- struct __useless_struct_to_allow_trailing_semicolon__
+ }
#define BUS_DEFINE_SET_TRANSIENT_PARSE_PTR(function, type, parse) \
int bus_set_transient_##function( \
@@ -218,8 +197,7 @@
} \
\
return 1; \
- } \
- struct __useless_struct_to_allow_trailing_semicolon__
+ }
#define BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(function, check) \
int bus_set_transient_##function( \
@@ -253,88 +231,7 @@
} \
\
return 1; \
- } \
- struct __useless_struct_to_allow_trailing_semicolon__
-
-#define BUS_DEFINE_SET_CGROUP_WEIGHT(function, mask, check, val, str) \
- int bus_cgroup_set_##function( \
- Unit *u, \
- const char *name, \
- uint64_t *p, \
- sd_bus_message *message, \
- UnitWriteFlags flags, \
- sd_bus_error *error) { \
- \
- uint64_t v; \
- int r; \
- \
- assert(p); \
- \
- r = sd_bus_message_read(message, "t", &v); \
- if (r < 0) \
- return r; \
- \
- if (!check(v)) \
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, \
- "Value specified in %s is out of range", name); \
- \
- if (!UNIT_WRITE_FLAGS_NOOP(flags)) { \
- *p = v; \
- unit_invalidate_cgroup(u, (mask)); \
- \
- if (v == (val)) \
- unit_write_settingf(u, flags, name, \
- "%s=" str, name); \
- else \
- unit_write_settingf(u, flags, name, \
- "%s=%" PRIu64, name, v); \
- } \
- \
- return 1; \
- } \
- struct __useless_struct_to_allow_trailing_semicolon__
-
-#define BUS_DEFINE_SET_CGROUP_SCALE(function, mask, scale) \
- int bus_cgroup_set_##function##_scale( \
- Unit *u, \
- const char *name, \
- uint64_t *p, \
- sd_bus_message *message, \
- UnitWriteFlags flags, \
- sd_bus_error *error) { \
- \
- uint64_t v; \
- uint32_t raw; \
- int r; \
- \
- assert(p); \
- \
- r = sd_bus_message_read(message, "u", &raw); \
- if (r < 0) \
- return r; \
- \
- v = scale(raw, UINT32_MAX); \
- if (v <= 0 || v >= UINT64_MAX) \
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, \
- "Value specified in %s is out of range", name); \
- \
- if (!UNIT_WRITE_FLAGS_NOOP(flags)) { \
- const char *e; \
- \
- *p = v; \
- unit_invalidate_cgroup(u, (mask)); \
- \
- /* Chop off suffix */ \
- assert_se(e = endswith(name, "Scale")); \
- name = strndupa(name, e - name); \
- \
- unit_write_settingf(u, flags, name, "%s=%" PRIu32 "%%", name, \
- (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX))); \
- } \
- \
- return 1; \
- } \
- struct __useless_struct_to_allow_trailing_semicolon__
+ }
int bus_set_transient_mode_t(Unit *u, const char *name, mode_t *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
int bus_set_transient_unsigned(Unit *u, const char *name, unsigned *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
diff --git a/src/core/dbus.c b/src/core/dbus.c
index 56b43adcda..bf5917696e 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
#include <sys/epoll.h>
@@ -29,11 +11,22 @@
#include "bus-error.h"
#include "bus-internal.h"
#include "bus-util.h"
+#include "dbus-automount.h"
#include "dbus-cgroup.h"
+#include "dbus-device.h"
#include "dbus-execute.h"
#include "dbus-job.h"
#include "dbus-kill.h"
#include "dbus-manager.h"
+#include "dbus-mount.h"
+#include "dbus-path.h"
+#include "dbus-scope.h"
+#include "dbus-service.h"
+#include "dbus-slice.h"
+#include "dbus-socket.h"
+#include "dbus-swap.h"
+#include "dbus-target.h"
+#include "dbus-timer.h"
#include "dbus-unit.h"
#include "dbus.h"
#include "fd-util.h"
@@ -43,6 +36,7 @@
#include "mkdir.h"
#include "process-util.h"
#include "selinux-access.h"
+#include "service.h"
#include "special.h"
#include "string-util.h"
#include "strv.h"
@@ -242,7 +236,6 @@ static int mac_selinux_filter(sd_bus_message *message, void *userdata, sd_bus_er
path = sd_bus_message_get_path(message);
if (object_path_startswith("/org/freedesktop/systemd1", path)) {
-
r = mac_selinux_access_check(message, verb, error);
if (r < 0)
return r;
@@ -270,7 +263,6 @@ static int mac_selinux_filter(sd_bus_message *message, void *userdata, sd_bus_er
else
manager_load_unit_from_dbus_path(m, path, NULL, &u);
}
-
if (!u)
return 0;
@@ -501,8 +493,7 @@ static int bus_job_enumerate(sd_bus *bus, const char *path, void *userdata, char
assert(hashmap_size(m->jobs) == k);
- *nodes = l;
- l = NULL;
+ *nodes = TAKE_PTR(l);
return k;
}
@@ -526,8 +517,7 @@ static int bus_unit_enumerate(sd_bus *bus, const char *path, void *userdata, cha
k++;
}
- *nodes = l;
- l = NULL;
+ *nodes = TAKE_PTR(l);
return k;
}
@@ -897,9 +887,9 @@ int bus_init_api(Manager *m) {
bus = sd_bus_ref(m->system_bus);
else {
if (MANAGER_IS_SYSTEM(m))
- r = sd_bus_open_system(&bus);
+ r = sd_bus_open_system_with_description(&bus, "bus-api-system");
else
- r = sd_bus_open_user(&bus);
+ r = sd_bus_open_user_with_description(&bus, "bus-api-user");
if (r < 0)
return log_error_errno(r, "Failed to connect to API bus: %m");
@@ -916,8 +906,7 @@ int bus_init_api(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to set up API bus: %m");
- m->api_bus = bus;
- bus = NULL;
+ m->api_bus = TAKE_PTR(bus);
r = manager_enqueue_sync_bus_names(m);
if (r < 0)
@@ -961,7 +950,7 @@ int bus_init_system(Manager *m) {
if (MANAGER_IS_SYSTEM(m) && m->api_bus)
bus = sd_bus_ref(m->api_bus);
else {
- r = sd_bus_open_system(&bus);
+ r = sd_bus_open_system_with_description(&bus, "bus-system");
if (r < 0)
return log_error_errno(r, "Failed to connect to system bus: %m");
@@ -978,8 +967,7 @@ int bus_init_system(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to set up system bus: %m");
- m->system_bus = bus;
- bus = NULL;
+ m->system_bus = TAKE_PTR(bus);
return 0;
}
@@ -1105,17 +1093,11 @@ static void destroy_bus(Manager *m, sd_bus **bus) {
}
void bus_done_api(Manager *m) {
- assert(m);
-
- if (m->api_bus)
- destroy_bus(m, &m->api_bus);
+ destroy_bus(m, &m->api_bus);
}
void bus_done_system(Manager *m) {
- assert(m);
-
- if (m->system_bus)
- destroy_bus(m, &m->system_bus);
+ destroy_bus(m, &m->system_bus);
}
void bus_done_private(Manager *m) {
@@ -1310,3 +1292,38 @@ uint64_t manager_bus_n_queued_write(Manager *m) {
return c;
}
+
+static void vtable_dump_bus_properties(FILE *f, const sd_bus_vtable *table) {
+ const sd_bus_vtable *i;
+
+ for (i = table; i->type != _SD_BUS_VTABLE_END; i++) {
+ if (!IN_SET(i->type, _SD_BUS_VTABLE_PROPERTY, _SD_BUS_VTABLE_WRITABLE_PROPERTY) ||
+ (i->flags & (SD_BUS_VTABLE_DEPRECATED | SD_BUS_VTABLE_HIDDEN)) != 0)
+ continue;
+
+ fprintf(f, "%s\n", i->x.property.member);
+ }
+}
+
+void dump_bus_properties(FILE *f) {
+ assert(f);
+
+ vtable_dump_bus_properties(f, bus_automount_vtable);
+ vtable_dump_bus_properties(f, bus_cgroup_vtable);
+ vtable_dump_bus_properties(f, bus_device_vtable);
+ vtable_dump_bus_properties(f, bus_exec_vtable);
+ vtable_dump_bus_properties(f, bus_job_vtable);
+ vtable_dump_bus_properties(f, bus_kill_vtable);
+ vtable_dump_bus_properties(f, bus_manager_vtable);
+ vtable_dump_bus_properties(f, bus_mount_vtable);
+ vtable_dump_bus_properties(f, bus_path_vtable);
+ vtable_dump_bus_properties(f, bus_scope_vtable);
+ vtable_dump_bus_properties(f, bus_service_vtable);
+ vtable_dump_bus_properties(f, bus_slice_vtable);
+ vtable_dump_bus_properties(f, bus_socket_vtable);
+ vtable_dump_bus_properties(f, bus_swap_vtable);
+ vtable_dump_bus_properties(f, bus_target_vtable);
+ vtable_dump_bus_properties(f, bus_timer_vtable);
+ vtable_dump_bus_properties(f, bus_unit_vtable);
+ vtable_dump_bus_properties(f, bus_unit_cgroup_vtable);
+}
diff --git a/src/core/dbus.h b/src/core/dbus.h
index 702bc48ae1..382a96da7d 100644
--- a/src/core/dbus.h
+++ b/src/core/dbus.h
@@ -1,24 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
+#include "sd-bus.h"
#include "manager.h"
@@ -50,3 +33,5 @@ int bus_verify_set_environment_async(Manager *m, sd_bus_message *call, sd_bus_er
int bus_forward_agent_released(Manager *m, const char *path);
uint64_t manager_bus_n_queued_write(Manager *m);
+
+void dump_bus_properties(FILE *f);
diff --git a/src/core/device.c b/src/core/device.c
index b0dd469fd1..a2d00a0fbe 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
#include <sys/epoll.h>
@@ -24,6 +6,7 @@
#include "libudev.h"
#include "alloc-util.h"
+#include "bus-error.h"
#include "dbus-device.h"
#include "device.h"
#include "log.h"
@@ -43,6 +26,7 @@ static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
};
static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
+static void device_update_found_one(Device *d, DeviceFound found, DeviceFound mask);
static void device_unset_sysfs(Device *d) {
Hashmap *devices;
@@ -68,8 +52,8 @@ static void device_unset_sysfs(Device *d) {
}
static int device_set_sysfs(Device *d, const char *sysfs) {
+ _cleanup_free_ char *copy = NULL;
Device *first;
- char *copy;
int r;
assert(d);
@@ -93,12 +77,10 @@ static int device_set_sysfs(Device *d, const char *sysfs) {
r = hashmap_replace(UNIT(d)->manager->devices_by_sysfs, copy, first);
if (r < 0) {
LIST_REMOVE(same_sysfs, first, d);
- free(copy);
return r;
}
- d->sysfs = copy;
-
+ d->sysfs = TAKE_PTR(copy);
return 0;
}
@@ -116,6 +98,8 @@ static void device_init(Unit *u) {
u->job_running_timeout = u->manager->default_timeout_start_usec;
u->ignore_on_isolate = true;
+
+ d->deserialized_state = _DEVICE_STATE_INVALID;
}
static void device_done(Unit *u) {
@@ -124,6 +108,7 @@ static void device_done(Unit *u) {
assert(d);
device_unset_sysfs(d);
+ d->wants_property = strv_free(d->wants_property);
}
static void device_set_state(Device *d, DeviceState state) {
@@ -133,10 +118,13 @@ static void device_set_state(Device *d, DeviceState state) {
old_state = d->state;
d->state = state;
+ if (state == DEVICE_DEAD)
+ device_unset_sysfs(d);
+
if (state != old_state)
log_unit_debug(UNIT(d), "Changed %s -> %s", device_state_to_string(old_state), device_state_to_string(state));
- unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state], true);
+ unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state], 0);
}
static int device_coldplug(Unit *u) {
@@ -145,19 +133,93 @@ static int device_coldplug(Unit *u) {
assert(d);
assert(d->state == DEVICE_DEAD);
- if (d->found & DEVICE_FOUND_UDEV)
- /* If udev says the device is around, it's around */
- device_set_state(d, DEVICE_PLUGGED);
- else if (d->found != DEVICE_NOT_FOUND && d->deserialized_state != DEVICE_PLUGGED)
- /* If a device is found in /proc/self/mountinfo or
- * /proc/swaps, and was not yet announced via udev,
- * it's "tentatively" around. */
- device_set_state(d, DEVICE_TENTATIVE);
+ /* First, let's put the deserialized state and found mask into effect, if we have it. */
+
+ if (d->deserialized_state < 0 ||
+ (d->deserialized_state == d->state &&
+ d->deserialized_found == d->found))
+ return 0;
+
+ d->found = d->deserialized_found;
+ device_set_state(d, d->deserialized_state);
+ return 0;
+}
+
+static void device_catchup(Unit *u) {
+ Device *d = DEVICE(u);
+
+ assert(d);
+
+ /* Second, let's update the state with the enumerated state if it's different */
+ if (d->enumerated_found == d->found)
+ return;
+
+ device_update_found_one(d, d->enumerated_found, DEVICE_FOUND_MASK);
+}
+
+static const struct {
+ DeviceFound flag;
+ const char *name;
+} device_found_map[] = {
+ { DEVICE_FOUND_UDEV, "found-udev" },
+ { DEVICE_FOUND_MOUNT, "found-mount" },
+ { DEVICE_FOUND_SWAP, "found-swap" },
+};
+
+static int device_found_to_string_many(DeviceFound flags, char **ret) {
+ _cleanup_free_ char *s = NULL;
+ unsigned i;
+
+ assert(ret);
+
+ for (i = 0; i < ELEMENTSOF(device_found_map); i++) {
+ if (!FLAGS_SET(flags, device_found_map[i].flag))
+ continue;
+
+ if (!strextend_with_separator(&s, ",", device_found_map[i].name, NULL))
+ return -ENOMEM;
+ }
+
+ *ret = TAKE_PTR(s);
return 0;
}
+static int device_found_from_string_many(const char *name, DeviceFound *ret) {
+ DeviceFound flags = 0;
+ int r;
+
+ assert(ret);
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+ DeviceFound f = 0;
+ unsigned i;
+
+ r = extract_first_word(&name, &word, ",", 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ for (i = 0; i < ELEMENTSOF(device_found_map); i++)
+ if (streq(word, device_found_map[i].name)) {
+ f = device_found_map[i].flag;
+ break;
+ }
+
+ if (f == 0)
+ return -EINVAL;
+
+ flags |= f;
+ }
+
+ *ret = flags;
+ return 0;
+}
+
static int device_serialize(Unit *u, FILE *f, FDSet *fds) {
+ _cleanup_free_ char *s = NULL;
Device *d = DEVICE(u);
assert(u);
@@ -166,11 +228,15 @@ static int device_serialize(Unit *u, FILE *f, FDSet *fds) {
unit_serialize_item(u, f, "state", device_state_to_string(d->state));
+ if (device_found_to_string_many(d->found, &s) >= 0)
+ unit_serialize_item(u, f, "found", s);
+
return 0;
}
static int device_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
Device *d = DEVICE(u);
+ int r;
assert(u);
assert(key);
@@ -182,9 +248,15 @@ static int device_deserialize_item(Unit *u, const char *key, const char *value,
state = device_state_from_string(value);
if (state < 0)
- log_unit_debug(u, "Failed to parse state value: %s", value);
+ log_unit_debug(u, "Failed to parse state value, ignoring: %s", value);
else
d->deserialized_state = state;
+
+ } else if (streq(key, "found")) {
+ r = device_found_from_string_many(value, &d->deserialized_found);
+ if (r < 0)
+ log_unit_debug_errno(u, r, "Failed to parse found value, ignoring: %s", value);
+
} else
log_unit_debug(u, "Unknown serialization key: %s", key);
@@ -193,14 +265,27 @@ static int device_deserialize_item(Unit *u, const char *key, const char *value,
static void device_dump(Unit *u, FILE *f, const char *prefix) {
Device *d = DEVICE(u);
+ _cleanup_free_ char *s = NULL;
assert(d);
+ (void) device_found_to_string_many(d->found, &s);
+
fprintf(f,
"%sDevice State: %s\n"
- "%sSysfs Path: %s\n",
+ "%sSysfs Path: %s\n"
+ "%sFound: %s\n",
prefix, device_state_to_string(d->state),
- prefix, strna(d->sysfs));
+ prefix, strna(d->sysfs),
+ prefix, strna(s));
+
+ if (!strv_isempty(d->wants_property)) {
+ char **i;
+
+ STRV_FOREACH(i, d->wants_property)
+ fprintf(f, "%sudev SYSTEMD_WANTS: %s\n",
+ prefix, *i);
+ }
}
_pure_ static UnitActiveState device_active_state(Unit *u) {
@@ -241,26 +326,27 @@ static int device_update_description(Unit *u, struct udev_device *dev, const cha
_cleanup_free_ char *j;
j = strjoin(model, " ", label);
- if (j)
- r = unit_set_description(u, j);
- else
- r = -ENOMEM;
+ if (!j)
+ return log_oom();
+
+ r = unit_set_description(u, j);
} else
r = unit_set_description(u, model);
} else
r = unit_set_description(u, path);
-
if (r < 0)
- log_unit_error_errno(u, r, "Failed to set device description: %m");
+ return log_unit_error_errno(u, r, "Failed to set device description: %m");
- return r;
+ return 0;
}
static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
+ _cleanup_strv_free_ char **added = NULL;
const char *wants, *property;
+ Device *d = DEVICE(u);
int r;
- assert(u);
+ assert(d);
assert(dev);
property = MANAGER_IS_USER(u->manager) ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS";
@@ -274,21 +360,21 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
r = extract_first_word(&wants, &word, NULL, EXTRACT_QUOTES);
if (r == 0)
- return 0;
+ break;
if (r == -ENOMEM)
return log_oom();
if (r < 0)
return log_unit_error_errno(u, r, "Failed to parse property %s with value %s: %m", property, wants);
- if (unit_name_is_valid(word, UNIT_NAME_TEMPLATE) && DEVICE(u)->sysfs) {
+ if (unit_name_is_valid(word, UNIT_NAME_TEMPLATE) && d->sysfs) {
_cleanup_free_ char *escaped = NULL;
/* If the unit name is specified as template, then automatically fill in the sysfs path of the
* device as instance name, properly escaped. */
- r = unit_name_path_escape(DEVICE(u)->sysfs, &escaped);
+ r = unit_name_path_escape(d->sysfs, &escaped);
if (r < 0)
- return log_unit_error_errno(u, r, "Failed to escape %s: %m", DEVICE(u)->sysfs);
+ return log_unit_error_errno(u, r, "Failed to escape %s: %m", d->sysfs);
r = unit_name_replace_instance(word, escaped, &k);
if (r < 0)
@@ -296,7 +382,7 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
} else {
/* If this is not a template, then let's mangle it so, that it becomes a valid unit name. */
- r = unit_name_mangle(word, UNIT_NAME_NOGLOB, &k);
+ r = unit_name_mangle(word, UNIT_NAME_MANGLE_WARN, &k);
if (r < 0)
return log_unit_error_errno(u, r, "Failed to mangle unit name \"%s\": %m", word);
}
@@ -304,7 +390,43 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
r = unit_add_dependency_by_name(u, UNIT_WANTS, k, NULL, true, UNIT_DEPENDENCY_UDEV);
if (r < 0)
return log_unit_error_errno(u, r, "Failed to add Wants= dependency: %m");
+
+ r = strv_push(&added, k);
+ if (r < 0)
+ return log_oom();
+
+ k = NULL;
}
+
+ if (d->state != DEVICE_DEAD) {
+ char **i;
+
+ /* So here's a special hack, to compensate for the fact that the udev database's reload cycles are not
+ * synchronized with our own reload cycles: when we detect that the SYSTEMD_WANTS property of a device
+ * changes while the device unit is already up, let's manually trigger any new units listed in it not
+ * seen before. This typically appens during the boot-time switch root transition, as udev devices
+ * will generally already be up in the initrd, but SYSTEMD_WANTS properties get then added through udev
+ * rules only available on the host system, and thus only when the initial udev coldplug trigger runs.
+ *
+ * We do this only if the device has been up already when we parse this, as otherwise the usual
+ * dependency logic that is run from the dead → plugged transition will trigger these deps. */
+
+ STRV_FOREACH(i, added) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+
+ if (strv_contains(d->wants_property, *i)) /* Was this unit already listed before? */
+ continue;
+
+ r = manager_add_job_by_name(u->manager, JOB_START, *i, JOB_FAIL, &error, NULL);
+ if (r < 0)
+ log_unit_warning_errno(u, r, "Failed to enqueue SYSTEMD_WANTS= job, ignoring: %s", bus_error_message(&error, r));
+ }
+ }
+
+ strv_free(d->wants_property);
+ d->wants_property = TAKE_PTR(added);
+
+ return 0;
}
static bool device_is_bound_by_mounts(Device *d, struct udev_device *dev) {
@@ -327,7 +449,7 @@ static bool device_is_bound_by_mounts(Device *d, struct udev_device *dev) {
return d->bind_mounts;
}
-static int device_upgrade_mount_deps(Unit *u) {
+static void device_upgrade_mount_deps(Unit *u) {
Unit *other;
Iterator i;
void *v;
@@ -341,9 +463,8 @@ static int device_upgrade_mount_deps(Unit *u) {
r = unit_add_dependency(other, UNIT_BINDS_TO, u, true, UNIT_DEPENDENCY_UDEV);
if (r < 0)
- return r;
+ log_unit_warning_errno(u, r, "Failed to add BindsTo= dependency between device and mount unit, ignoring: %m");
}
- return 0;
}
static int device_setup_unit(Manager *m, struct udev_device *dev, const char *path, bool main) {
@@ -358,8 +479,10 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa
if (dev) {
sysfs = udev_device_get_syspath(dev);
- if (!sysfs)
+ if (!sysfs) {
+ log_debug("Couldn't get syspath from udev device, ignoring.");
return 0;
+ }
}
r = unit_name_from_path(path, ".device", &e);
@@ -368,17 +491,21 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa
u = manager_get_unit(m, e);
if (u) {
- /* The device unit can still be present even if the device was unplugged: a mount unit can reference it hence
- * preventing the GC to have garbaged it. That's desired since the device unit may have a dependency on the
- * mount unit which was added during the loading of the later. */
- if (dev && DEVICE(u)->state == DEVICE_PLUGGED) {
-
- /* This unit is in plugged state: we're sure it's attached to a device. */
- if (!path_equal(DEVICE(u)->sysfs, sysfs)) {
- log_unit_debug(u, "Dev %s appeared twice with different sysfs paths %s and %s",
- e, DEVICE(u)->sysfs, sysfs);
- return -EEXIST;
- }
+ /* The device unit can still be present even if the device was unplugged: a mount unit can reference it
+ * hence preventing the GC to have garbaged it. That's desired since the device unit may have a
+ * dependency on the mount unit which was added during the loading of the later. When the device is
+ * plugged the sysfs might not be initialized yet, as we serialize the device's state but do not
+ * serialize the sysfs path across reloads/reexecs. Hence, when coming back from a reload/restart we
+ * might have the state valid, but not the sysfs path. Hence, let's filter out conflicting devices, but
+ * let's accept devices in any state with no sysfs path set. */
+
+ if (DEVICE(u)->state == DEVICE_PLUGGED &&
+ DEVICE(u)->sysfs &&
+ sysfs &&
+ !path_equal(DEVICE(u)->sysfs, sysfs)) {
+ log_unit_debug(u, "Device %s appeared twice with different sysfs paths %s and %s, ignoring the latter.",
+ e, DEVICE(u)->sysfs, sysfs);
+ return -EEXIST;
}
delete = false;
@@ -390,24 +517,26 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa
delete = true;
r = unit_new_for_name(m, sizeof(Device), e, &u);
- if (r < 0)
+ if (r < 0) {
+ log_error_errno(r, "Failed to allocate device unit %s: %m", e);
goto fail;
+ }
unit_add_to_load_queue(u);
}
- /* If this was created via some dependency and has not
- * actually been seen yet ->sysfs will not be
+ /* If this was created via some dependency and has not actually been seen yet ->sysfs will not be
* initialized. Hence initialize it if necessary. */
if (sysfs) {
r = device_set_sysfs(DEVICE(u), sysfs);
- if (r < 0)
+ if (r < 0) {
+ log_error_errno(r, "Failed to set sysfs path %s for device unit %s: %m", sysfs, e);
goto fail;
+ }
(void) device_update_description(u, dev, path);
- /* The additional systemd udev properties we only interpret
- * for the main object */
+ /* The additional systemd udev properties we only interpret for the main object */
if (main)
(void) device_add_udev_wants(u, dev);
}
@@ -419,13 +548,11 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa
device_upgrade_mount_deps(u);
/* Note that this won't dispatch the load queue, the caller has to do that if needed and appropriate */
-
unit_add_to_dbus_queue(u);
+
return 0;
fail:
- log_unit_warning_errno(u, r, "Failed to set up device unit: %m");
-
if (delete)
unit_free(u);
@@ -462,8 +589,7 @@ static int device_process_new(Manager *m, struct udev_device *dev) {
/* Don't bother with the /dev/block links */
p = udev_list_entry_get_name(item);
- if (path_startswith(p, "/dev/block/") ||
- path_startswith(p, "/dev/char/"))
+ if (PATH_STARTSWITH_SET(p, "/dev/block/", "/dev/char/"))
continue;
/* Verify that the symlink in the FS actually belongs
@@ -489,76 +615,81 @@ static int device_process_new(Manager *m, struct udev_device *dev) {
r = extract_first_word(&alias, &word, NULL, EXTRACT_QUOTES);
if (r == 0)
- return 0;
+ break;
if (r == -ENOMEM)
return log_oom();
if (r < 0)
return log_warning_errno(r, "Failed to add parse SYSTEMD_ALIAS for %s: %m", sysfs);
- if (path_is_absolute(word))
- (void) device_setup_unit(m, dev, word, false);
- else
+ if (!path_is_absolute(word))
log_warning("SYSTEMD_ALIAS for %s is not an absolute path, ignoring: %s", sysfs, word);
+ else if (!path_is_normalized(word))
+ log_warning("SYSTEMD_ALIAS for %s is not a normalized path, ignoring: %s", sysfs, word);
+ else
+ (void) device_setup_unit(m, dev, word, false);
}
-}
-static void device_update_found_one(Device *d, bool add, DeviceFound found, bool now) {
- DeviceFound n, previous;
+ return 0;
+}
+static void device_found_changed(Device *d, DeviceFound previous, DeviceFound now) {
assert(d);
- n = add ? (d->found | found) : (d->found & ~found);
- if (n == d->found)
- return;
-
- previous = d->found;
- d->found = n;
-
- if (!now)
- return;
-
/* Didn't exist before, but does now? if so, generate a new invocation ID for it */
- if (previous == DEVICE_NOT_FOUND && d->found != DEVICE_NOT_FOUND)
+ if (previous == DEVICE_NOT_FOUND && now != DEVICE_NOT_FOUND)
(void) unit_acquire_invocation_id(UNIT(d));
- if (d->found & DEVICE_FOUND_UDEV)
- /* When the device is known to udev we consider it
- * plugged. */
+ if (FLAGS_SET(now, DEVICE_FOUND_UDEV))
+ /* When the device is known to udev we consider it plugged. */
device_set_state(d, DEVICE_PLUGGED);
- else if (d->found != DEVICE_NOT_FOUND && (previous & DEVICE_FOUND_UDEV) == 0)
- /* If the device has not been seen by udev yet, but is
- * now referenced by the kernel, then we assume the
+ else if (now != DEVICE_NOT_FOUND && !FLAGS_SET(previous, DEVICE_FOUND_UDEV))
+ /* If the device has not been seen by udev yet, but is now referenced by the kernel, then we assume the
* kernel knows it now, and udev might soon too. */
device_set_state(d, DEVICE_TENTATIVE);
- else {
- /* If nobody sees the device, or if the device was
- * previously seen by udev and now is only referenced
- * from the kernel, then we consider the device is
- * gone, the kernel just hasn't noticed it yet. */
-
+ else
+ /* If nobody sees the device, or if the device was previously seen by udev and now is only referenced
+ * from the kernel, then we consider the device is gone, the kernel just hasn't noticed it yet. */
device_set_state(d, DEVICE_DEAD);
- device_unset_sysfs(d);
- }
+}
+
+static void device_update_found_one(Device *d, DeviceFound found, DeviceFound mask) {
+ assert(d);
+
+ if (MANAGER_IS_RUNNING(UNIT(d)->manager)) {
+ DeviceFound n, previous;
+
+ /* When we are already running, then apply the new mask right-away, and trigger state changes
+ * right-away */
+
+ n = (d->found & ~mask) | (found & mask);
+ if (n == d->found)
+ return;
+
+ previous = d->found;
+ d->found = n;
+ device_found_changed(d, previous, n);
+ } else
+ /* We aren't running yet, let's apply the new mask to the shadow variable instead, which we'll apply as
+ * soon as we catch-up with the state. */
+ d->enumerated_found = (d->enumerated_found & ~mask) | (found & mask);
}
-static int device_update_found_by_sysfs(Manager *m, const char *sysfs, bool add, DeviceFound found, bool now) {
+static void device_update_found_by_sysfs(Manager *m, const char *sysfs, DeviceFound found, DeviceFound mask) {
Device *d, *l, *n;
assert(m);
assert(sysfs);
- if (found == DEVICE_NOT_FOUND)
- return 0;
+ if (mask == 0)
+ return;
l = hashmap_get(m->devices_by_sysfs, sysfs);
LIST_FOREACH_SAFE(same_sysfs, d, n, l)
- device_update_found_one(d, add, found, now);
-
- return 0;
+ device_update_found_one(d, found, mask);
}
-static int device_update_found_by_name(Manager *m, const char *path, bool add, DeviceFound found, bool now) {
+static int device_update_found_by_name(Manager *m, const char *path, DeviceFound found, DeviceFound mask) {
_cleanup_free_ char *e = NULL;
Unit *u;
int r;
@@ -566,7 +697,7 @@ static int device_update_found_by_name(Manager *m, const char *path, bool add, D
assert(m);
assert(path);
- if (found == DEVICE_NOT_FOUND)
+ if (mask == 0)
return 0;
r = unit_name_from_path(path, ".device", &e);
@@ -577,7 +708,7 @@ static int device_update_found_by_name(Manager *m, const char *path, bool add, D
if (!u)
return 0;
- device_update_found_one(DEVICE(u), add, found, now);
+ device_update_found_one(DEVICE(u), found, mask);
return 0;
}
@@ -619,7 +750,7 @@ static Unit *device_following(Unit *u) {
static int device_following_set(Unit *u, Set **_set) {
Device *d = DEVICE(u), *other;
- Set *set;
+ _cleanup_set_free_ Set *set = NULL;
int r;
assert(d);
@@ -637,38 +768,29 @@ static int device_following_set(Unit *u, Set **_set) {
LIST_FOREACH_AFTER(same_sysfs, other, d) {
r = set_put(set, other);
if (r < 0)
- goto fail;
+ return r;
}
LIST_FOREACH_BEFORE(same_sysfs, other, d) {
r = set_put(set, other);
if (r < 0)
- goto fail;
+ return r;
}
- *_set = set;
+ *_set = TAKE_PTR(set);
return 1;
-
-fail:
- set_free(set);
- return r;
}
static void device_shutdown(Manager *m) {
assert(m);
m->udev_event_source = sd_event_source_unref(m->udev_event_source);
-
- if (m->udev_monitor) {
- udev_monitor_unref(m->udev_monitor);
- m->udev_monitor = NULL;
- }
-
+ m->udev_monitor = udev_monitor_unref(m->udev_monitor);
m->devices_by_sysfs = hashmap_free(m->devices_by_sysfs);
}
static void device_enumerate(Manager *m) {
- _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
+ _cleanup_(udev_enumerate_unrefp) struct udev_enumerate *e = NULL;
struct udev_list_entry *item = NULL, *first = NULL;
int r;
@@ -677,7 +799,7 @@ static void device_enumerate(Manager *m) {
if (!m->udev_monitor) {
m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
if (!m->udev_monitor) {
- log_oom();
+ log_error_errno(errno, "Failed to allocate udev monitor: %m");
goto fail;
}
@@ -709,7 +831,7 @@ static void device_enumerate(Manager *m) {
e = udev_enumerate_new(m->udev);
if (!e) {
- log_oom();
+ log_error_errno(errno, "Failed to alloacte udev enumerator: %m");
goto fail;
}
@@ -733,14 +855,20 @@ static void device_enumerate(Manager *m) {
first = udev_enumerate_get_list_entry(e);
udev_list_entry_foreach(item, first) {
- _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
+ _cleanup_(udev_device_unrefp) struct udev_device *dev = NULL;
const char *sysfs;
sysfs = udev_list_entry_get_name(item);
dev = udev_device_new_from_syspath(m->udev, sysfs);
if (!dev) {
- log_oom();
+ if (errno == ENOMEM) {
+ log_oom();
+ goto fail;
+ }
+
+ /* If we can't create a device, don't bother, it probably just disappeared. */
+ log_debug_errno(errno, "Failed to create udev device object for %s: %m", sysfs);
continue;
}
@@ -748,8 +876,7 @@ static void device_enumerate(Manager *m) {
continue;
(void) device_process_new(m, dev);
-
- device_update_found_by_sysfs(m, sysfs, true, DEVICE_FOUND_UDEV, false);
+ device_update_found_by_sysfs(m, sysfs, DEVICE_FOUND_UDEV, DEVICE_FOUND_UDEV);
}
return;
@@ -758,8 +885,26 @@ fail:
device_shutdown(m);
}
+static void device_propagate_reload_by_sysfs(Manager *m, const char *sysfs) {
+ Device *d, *l, *n;
+ int r;
+
+ assert(m);
+ assert(sysfs);
+
+ l = hashmap_get(m->devices_by_sysfs, sysfs);
+ LIST_FOREACH_SAFE(same_sysfs, d, n, l) {
+ if (d->state == DEVICE_DEAD)
+ continue;
+
+ r = manager_propagate_reload(m, UNIT(d), JOB_REPLACE, NULL);
+ if (r < 0)
+ log_warning_errno(r, "Failed to propagate reload, ignoring: %m");
+ }
+}
+
static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
- _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
+ _cleanup_(udev_device_unrefp) struct udev_device *dev = NULL;
Manager *m = userdata;
const char *action, *sysfs;
int r;
@@ -769,8 +914,8 @@ static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
if (revents != EPOLLIN) {
static RATELIMIT_DEFINE(limit, 10*USEC_PER_SEC, 5);
- if (!ratelimit_test(&limit))
- log_error_errno(errno, "Failed to get udev event: %m");
+ if (ratelimit_below(&limit))
+ log_warning("Failed to get udev event");
if (!(revents & EPOLLIN))
return 0;
}
@@ -795,20 +940,8 @@ static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
return 0;
}
- if (streq(action, "change")) {
- Unit *u;
- Device *d, *l, *n;
-
- l = hashmap_get(m->devices_by_sysfs, sysfs);
- LIST_FOREACH_SAFE(same_sysfs, d, n, l) {
- u = &d->meta;
- if (u && UNIT_VTABLE(u)->active_state(u) == UNIT_ACTIVE) {
- r = manager_propagate_reload(m, u, JOB_REPLACE, NULL);
- if (r < 0)
- log_error_errno(r, "Failed to propagate reload: %m");
- }
- }
- }
+ if (streq(action, "change"))
+ device_propagate_reload_by_sysfs(m, sysfs);
/* A change event can signal that a device is becoming ready, in particular if
* the device is using the SYSTEMD_READY logic in udev
@@ -816,12 +949,12 @@ static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
if (streq(action, "remove")) {
r = swap_process_device_remove(m, dev);
if (r < 0)
- log_error_errno(r, "Failed to process swap device remove event: %m");
+ log_warning_errno(r, "Failed to process swap device remove event, ignoring: %m");
/* If we get notified that a device was removed by
* udev, then it's completely gone, hence unset all
* found bits */
- device_update_found_by_sysfs(m, sysfs, false, DEVICE_FOUND_UDEV|DEVICE_FOUND_MOUNT|DEVICE_FOUND_SWAP, true);
+ device_update_found_by_sysfs(m, sysfs, 0, DEVICE_FOUND_UDEV|DEVICE_FOUND_MOUNT|DEVICE_FOUND_SWAP);
} else if (device_is_ready(dev)) {
@@ -829,19 +962,19 @@ static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
r = swap_process_device_new(m, dev);
if (r < 0)
- log_error_errno(r, "Failed to process swap device new event: %m");
+ log_warning_errno(r, "Failed to process swap device new event, ignoring: %m");
manager_dispatch_load_queue(m);
/* The device is found now, set the udev found bit */
- device_update_found_by_sysfs(m, sysfs, true, DEVICE_FOUND_UDEV, true);
+ device_update_found_by_sysfs(m, sysfs, DEVICE_FOUND_UDEV, DEVICE_FOUND_UDEV);
} else {
/* The device is nominally around, but not ready for
* us. Hence unset the udev bit, but leave the rest
* around. */
- device_update_found_by_sysfs(m, sysfs, false, DEVICE_FOUND_UDEV, true);
+ device_update_found_by_sysfs(m, sysfs, 0, DEVICE_FOUND_UDEV);
}
return 0;
@@ -859,61 +992,88 @@ static bool device_supported(void) {
return read_only <= 0;
}
-int device_found_node(Manager *m, const char *node, bool add, DeviceFound found, bool now) {
- _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
+static int validate_node(Manager *m, const char *node, struct udev_device **ret) {
struct stat st;
+ int r;
assert(m);
assert(node);
+ assert(ret);
- if (!device_supported())
- return 0;
+ /* Validates a device node that showed up in /proc/swaps or /proc/self/mountinfo if it makes sense for us to
+ * track. Note that this validator is fine within missing device nodes, but not with badly set up ones! */
- /* This is called whenever we find a device referenced in
- * /proc/swaps or /proc/self/mounts. Such a device might be
- * mounted/enabled at a time where udev has not finished
- * probing it yet, and we thus haven't learned about it
- * yet. In this case we will set the device unit to
- * "tentative" state. */
+ if (!path_startswith(node, "/dev")) {
+ *ret = NULL;
+ return 0; /* bad! */
+ }
- if (add) {
- if (!path_startswith(node, "/dev"))
- return 0;
+ if (stat(node, &st) < 0) {
+ if (errno != ENOENT)
+ return log_error_errno(errno, "Failed to stat() device node file %s: %m", node);
- /* We make an extra check here, if the device node
- * actually exists. If it's missing, then this is an
- * indication that device was unplugged but is still
- * referenced in /proc/swaps or
- * /proc/self/mountinfo. Note that this check doesn't
- * really cover all cases where a device might be gone
- * away, since drives that can have a medium inserted
- * will still have a device node even when the medium
- * is not there... */
+ *ret = NULL;
+ return 1; /* good! (though missing) */
- if (stat(node, &st) >= 0) {
- if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
- return 0;
+ } else {
+ _cleanup_(udev_device_unrefp) struct udev_device *dev = NULL;
+
+ r = udev_device_new_from_stat_rdev(m->udev, &st, &dev);
+ if (r == -ENOENT) {
+ *ret = NULL;
+ return 1; /* good! (though missing) */
+ } else if (r == -ENOTTY) {
+ *ret = NULL;
+ return 0; /* bad! (not a device node but some other kind of file system node) */
+ } else if (r < 0)
+ return log_error_errno(r, "Failed to get udev device from devnum %u:%u: %m", major(st.st_rdev), minor(st.st_rdev));
+
+ *ret = TAKE_PTR(dev);
+ return 1; /* good! */
+ }
+}
- dev = udev_device_new_from_devnum(m->udev, S_ISBLK(st.st_mode) ? 'b' : 'c', st.st_rdev);
- if (!dev && errno != ENOENT)
- return log_error_errno(errno, "Failed to get udev device from devnum %u:%u: %m", major(st.st_rdev), minor(st.st_rdev));
+void device_found_node(Manager *m, const char *node, DeviceFound found, DeviceFound mask) {
+ int r;
- } else if (errno != ENOENT)
- return log_error_errno(errno, "Failed to stat device node file %s: %m", node);
+ assert(m);
+ assert(node);
+
+ if (!device_supported())
+ return;
+
+ if (mask == 0)
+ return;
+
+ /* This is called whenever we find a device referenced in /proc/swaps or /proc/self/mounts. Such a device might
+ * be mounted/enabled at a time where udev has not finished probing it yet, and we thus haven't learned about
+ * it yet. In this case we will set the device unit to "tentative" state.
+ *
+ * This takes a pair of DeviceFound flags parameters. The 'mask' parameter is a bit mask that indicates which
+ * bits of 'found' to copy into the per-device DeviceFound flags field. Thus, this function may be used to set
+ * and unset individual bits in a single call, while merging partially with previous state. */
+
+ if ((found & mask) != 0) {
+ _cleanup_(udev_device_unrefp) struct udev_device *dev = NULL;
- /* If the device is known in the kernel and newly
- * appeared, then we'll create a device unit for it,
- * under the name referenced in /proc/swaps or
- * /proc/self/mountinfo. */
+ /* If the device is known in the kernel and newly appeared, then we'll create a device unit for it,
+ * under the name referenced in /proc/swaps or /proc/self/mountinfo. But first, let's validate if
+ * everything is alright with the device node. */
+
+ r = validate_node(m, node, &dev);
+ if (r <= 0)
+ return; /* Don't create a device unit for this if the device node is borked. */
(void) device_setup_unit(m, dev, node, false);
}
/* Update the device unit's state, should it exist */
- return device_update_found_by_name(m, node, add, found, now);
+ (void) device_update_found_by_name(m, node, found, mask);
}
bool device_shall_be_bound_by(Unit *device, Unit *u) {
+ assert(device);
+ assert(u);
if (u->type != UNIT_MOUNT)
return false;
@@ -935,6 +1095,7 @@ const UnitVTable device_vtable = {
.load = unit_load_fragment_and_dropin_optional,
.coldplug = device_coldplug,
+ .catchup = device_catchup,
.serialize = device_serialize,
.deserialize_item = device_deserialize_item,
diff --git a/src/core/device.h b/src/core/device.h
index a551e7748a..a119b33e57 100644
--- a/src/core/device.h
+++ b/src/core/device.h
@@ -1,51 +1,43 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
+#include "unit.h"
typedef struct Device Device;
+/* A mask specifying where we have seen the device currently. This is a bitmask because the device might show up
+ * asynchronously from each other at various places. For example, in very common case a device might already be mounted
+ * before udev finished probing it (think: a script setting up a loopback block device, formatting it and mounting it
+ * in quick succession). Hence we need to track precisely where it is already visible and where not. */
typedef enum DeviceFound {
- DEVICE_NOT_FOUND = 0,
- DEVICE_FOUND_UDEV = 1,
- DEVICE_FOUND_MOUNT = 2,
- DEVICE_FOUND_SWAP = 4,
+ DEVICE_NOT_FOUND = 0,
+ DEVICE_FOUND_UDEV = 1U << 1, /* The device has shown up in the udev database */
+ DEVICE_FOUND_MOUNT = 1U << 2, /* The device has shown up in /proc/self/mountinfo */
+ DEVICE_FOUND_SWAP = 1U << 3, /* The device has shown up in /proc/swaps */
+ DEVICE_FOUND_MASK = DEVICE_FOUND_UDEV|DEVICE_FOUND_MOUNT|DEVICE_FOUND_SWAP,
} DeviceFound;
struct Device {
Unit meta;
char *sysfs;
- DeviceFound found;
- /* In order to be able to distinguish dependencies on
- different device nodes we might end up creating multiple
- devices for the same sysfs path. We chain them up here. */
+ /* In order to be able to distinguish dependencies on different device nodes we might end up creating multiple
+ * devices for the same sysfs path. We chain them up here. */
LIST_FIELDS(struct Device, same_sysfs);
DeviceState state, deserialized_state;
+ DeviceFound found, deserialized_found, enumerated_found;
bool bind_mounts;
+
+ /* The SYSTEMD_WANTS udev property for this device the last time we saw it */
+ char **wants_property;
};
extern const UnitVTable device_vtable;
-int device_found_node(Manager *m, const char *node, bool add, DeviceFound found, bool now);
+void device_found_node(Manager *m, const char *node, DeviceFound found, DeviceFound mask);
bool device_shall_be_bound_by(Unit *device, Unit *u);
+
+DEFINE_CAST(DEVICE, Device);
diff --git a/src/core/dynamic-user.c b/src/core/dynamic-user.c
index 3da31bf870..7c5111ddf6 100644
--- a/src/core/dynamic-user.c
+++ b/src/core/dynamic-user.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2016 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <grp.h>
#include <pwd.h>
@@ -30,6 +12,7 @@
#include "io-util.h"
#include "parse-util.h"
#include "random-util.h"
+#include "socket-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "user-util.h"
@@ -319,10 +302,7 @@ static int pick_uid(char **suggested_paths, const char *name, uid_t *ret_uid) {
(void) make_uid_symlinks(candidate, name, true); /* also add direct lookup symlinks */
*ret_uid = candidate;
- r = lock_fd;
- lock_fd = -1;
-
- return r;
+ return TAKE_FD(lock_fd);
next:
;
@@ -354,7 +334,7 @@ static int dynamic_user_pop(DynamicUser *d, uid_t *ret_uid, int *ret_lock_fd) {
/* Read the UID and lock fd that is stored in the storage AF_UNIX socket. This should be called with the lock
* on the socket taken. */
- k = recvmsg(d->storage_socket[0], &mh, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_CMSG_CLOEXEC);
+ k = recvmsg(d->storage_socket[0], &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
if (k < 0)
return -errno;
@@ -563,7 +543,7 @@ static int dynamic_user_realize(
return 0;
}
-static int dynamic_user_current(DynamicUser *d, uid_t *ret) {
+int dynamic_user_current(DynamicUser *d, uid_t *ret) {
_cleanup_(unlockfp) int storage_socket0_lock = -1;
_cleanup_close_ int lock_fd = -1;
uid_t uid;
@@ -770,8 +750,7 @@ int dynamic_user_lookup_uid(Manager *m, uid_t uid, char **ret) {
if (check_uid != uid) /* lock file doesn't match our own idea */
return -ESRCH;
- *ret = user;
- user = NULL;
+ *ret = TAKE_PTR(user);
return 0;
}
diff --git a/src/core/dynamic-user.h b/src/core/dynamic-user.h
index b073c65837..791a8ba0ef 100644
--- a/src/core/dynamic-user.h
+++ b/src/core/dynamic-user.h
@@ -1,25 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2016 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
typedef struct DynamicUser DynamicUser;
typedef struct DynamicCreds {
@@ -48,6 +29,7 @@ int dynamic_user_serialize(Manager *m, FILE *f, FDSet *fds);
void dynamic_user_deserialize_one(Manager *m, const char *value, FDSet *fds);
void dynamic_user_vacuum(Manager *m, bool close_user);
+int dynamic_user_current(DynamicUser *d, uid_t *ret);
int dynamic_user_lookup_uid(Manager *m, uid_t uid, char **ret);
int dynamic_user_lookup_name(Manager *m, const char *name, uid_t *ret);
diff --git a/src/core/emergency-action.c b/src/core/emergency-action.c
index 3d37a986bc..76e1124cff 100644
--- a/src/core/emergency-action.c
+++ b/src/core/emergency-action.c
@@ -1,22 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
/***
- This file is part of systemd.
-
- Copyright 2014 Lennart Poettering
- Copyright 2012 Michael Olbrich
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ Copyright © 2012 Michael Olbrich
***/
#include <sys/reboot.h>
diff --git a/src/core/emergency-action.h b/src/core/emergency-action.h
index 4079e8499a..61791f176f 100644
--- a/src/core/emergency-action.h
+++ b/src/core/emergency-action.h
@@ -2,23 +2,7 @@
#pragma once
/***
- This file is part of systemd.
-
- Copyright 2014 Lennart Poettering
- Copyright 2012 Michael Olbrich
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ Copyright © 2012 Michael Olbrich
***/
typedef enum EmergencyAction {
diff --git a/src/core/execute.c b/src/core/execute.c
index 7292b815db..8ac69d1a0f 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
#include <fcntl.h>
@@ -99,6 +81,7 @@
#include "selinux-util.h"
#include "signal-util.h"
#include "smack-util.h"
+#include "socket-util.h"
#include "special.h"
#include "stat-util.h"
#include "string-table.h"
@@ -119,7 +102,7 @@
#define SNDBUF_SIZE (8*1024*1024)
-static int shift_fds(int fds[], unsigned n_fds) {
+static int shift_fds(int fds[], size_t n_fds) {
int start, restart_from;
if (n_fds <= 0)
@@ -164,8 +147,8 @@ static int shift_fds(int fds[], unsigned n_fds) {
return 0;
}
-static int flags_fds(const int fds[], unsigned n_storage_fds, unsigned n_socket_fds, bool nonblock) {
- unsigned i, n_fds;
+static int flags_fds(const int fds[], size_t n_storage_fds, size_t n_socket_fds, bool nonblock) {
+ size_t i, n_fds;
int r;
n_fds = n_storage_fds + n_socket_fds;
@@ -1126,7 +1109,7 @@ static int setup_pam(
gid_t gid,
const char *tty,
char ***env,
- int fds[], unsigned n_fds) {
+ int fds[], size_t n_fds) {
#if HAVE_PAM
@@ -1300,10 +1283,7 @@ static int setup_pam(
if (!barrier_place_and_sync(&barrier))
log_error("PAM initialization failed");
- strv_free(*env);
- *env = e;
-
- return 0;
+ return strv_free_and_replace(*env, e);
fail:
if (pam_code != PAM_SUCCESS) {
@@ -1609,7 +1589,7 @@ static int build_environment(
const Unit *u,
const ExecContext *c,
const ExecParameters *p,
- unsigned n_fds,
+ size_t n_fds,
const char *home,
const char *username,
const char *shell,
@@ -1618,7 +1598,7 @@ static int build_environment(
char ***ret) {
_cleanup_strv_free_ char **our_env = NULL;
- unsigned n_env = 0;
+ size_t n_env = 0;
char *x;
assert(u);
@@ -1636,7 +1616,7 @@ static int build_environment(
return -ENOMEM;
our_env[n_env++] = x;
- if (asprintf(&x, "LISTEN_FDS=%u", n_fds) < 0)
+ if (asprintf(&x, "LISTEN_FDS=%zu", n_fds) < 0)
return -ENOMEM;
our_env[n_env++] = x;
@@ -1733,8 +1713,7 @@ static int build_environment(
our_env[n_env++] = NULL;
assert(n_env <= 12);
- *ret = our_env;
- our_env = NULL;
+ *ret = TAKE_PTR(our_env);
return 0;
}
@@ -1758,13 +1737,11 @@ static int build_pass_environment(const ExecContext *c, char ***ret) {
if (!GREEDY_REALLOC(pass_env, n_bufsize, n_env + 2))
return -ENOMEM;
- pass_env[n_env++] = x;
+ pass_env[n_env++] = TAKE_PTR(x);
pass_env[n_env] = NULL;
- x = NULL;
}
- *ret = pass_env;
- pass_env = NULL;
+ *ret = TAKE_PTR(pass_env);
return 0;
}
@@ -1798,6 +1775,7 @@ static bool exec_needs_mount_namespace(
return true;
if (context->private_devices ||
+ context->private_mounts ||
context->protect_system != PROTECT_SYSTEM_NO ||
context->protect_home != PROTECT_HOME_NO ||
context->protect_kernel_tunables ||
@@ -1805,8 +1783,20 @@ static bool exec_needs_mount_namespace(
context->protect_control_groups)
return true;
- if (context->mount_apivfs && (context->root_image || context->root_directory))
- return true;
+ if (context->root_directory) {
+ ExecDirectoryType t;
+
+ if (context->mount_apivfs)
+ return true;
+
+ for (t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
+ if (!params->prefix[t])
+ continue;
+
+ if (!strv_isempty(context->directories[t].paths))
+ return true;
+ }
+ }
if (context->dynamic_user &&
(!strv_isempty(context->directories[EXEC_DIRECTORY_STATE].paths) ||
@@ -2051,7 +2041,7 @@ static int setup_exec_directory(
}
/* First set up private root if it doesn't exist yet, with access mode 0700 and owned by root:root */
- r = mkdir_safe_label(private_root, 0700, 0, 0, false);
+ r = mkdir_safe_label(private_root, 0700, 0, 0, MKDIR_WARN_MODE);
if (r < 0)
goto fail;
@@ -2107,10 +2097,10 @@ static int setup_exec_directory(
}
} else {
r = mkdir_label(p, context->directories[type].mode);
- if (r == -EEXIST)
- continue;
- if (r < 0)
+ if (r < 0 && r != -EEXIST)
goto fail;
+ if (r == -EEXIST && !context->dynamic_user)
+ continue;
}
/* Don't change the owner of the configuration directory, as in the common case it is not written to by
@@ -2168,12 +2158,12 @@ static int compile_bind_mounts(
const ExecContext *context,
const ExecParameters *params,
BindMount **ret_bind_mounts,
- unsigned *ret_n_bind_mounts,
+ size_t *ret_n_bind_mounts,
char ***ret_empty_directories) {
_cleanup_strv_free_ char **empty_directories = NULL;
BindMount *bind_mounts;
- unsigned n, h = 0, i;
+ size_t n, h = 0, i;
ExecDirectoryType t;
int r;
@@ -2238,7 +2228,8 @@ static int compile_bind_mounts(
continue;
if (context->dynamic_user &&
- !IN_SET(t, EXEC_DIRECTORY_RUNTIME, EXEC_DIRECTORY_CONFIGURATION)) {
+ !IN_SET(t, EXEC_DIRECTORY_RUNTIME, EXEC_DIRECTORY_CONFIGURATION) &&
+ !(context->root_directory || context->root_image)) {
char *private_root;
/* So this is for a dynamic user, and we need to make sure the process can access its own
@@ -2269,7 +2260,15 @@ static int compile_bind_mounts(
goto finish;
}
- d = strdup(s);
+ if (context->dynamic_user &&
+ !IN_SET(t, EXEC_DIRECTORY_RUNTIME, EXEC_DIRECTORY_CONFIGURATION) &&
+ (context->root_directory || context->root_image))
+ /* When RootDirectory= or RootImage= are set, then the symbolic link to the private
+ * directory is not created on the root directory. So, let's bind-mount the directory
+ * on the 'non-private' place. */
+ d = strjoin(params->prefix[t], "/", *suffix);
+ else
+ d = strdup(s);
if (!d) {
free(s);
r = -ENOMEM;
@@ -2290,9 +2289,7 @@ static int compile_bind_mounts(
*ret_bind_mounts = bind_mounts;
*ret_n_bind_mounts = n;
- *ret_empty_directories = empty_directories;
-
- empty_directories = NULL;
+ *ret_empty_directories = TAKE_PTR(empty_directories);
return (int) n;
@@ -2311,17 +2308,10 @@ static int apply_mount_namespace(
_cleanup_strv_free_ char **empty_directories = NULL;
char *tmp = NULL, *var = NULL;
const char *root_dir = NULL, *root_image = NULL;
- NamespaceInfo ns_info = {
- .ignore_protect_paths = false,
- .private_dev = context->private_devices,
- .protect_control_groups = context->protect_control_groups,
- .protect_kernel_tunables = context->protect_kernel_tunables,
- .protect_kernel_modules = context->protect_kernel_modules,
- .mount_apivfs = context->mount_apivfs,
- };
+ NamespaceInfo ns_info;
bool needs_sandboxing;
BindMount *bind_mounts = NULL;
- unsigned n_bind_mounts = 0;
+ size_t n_bind_mounts = 0;
int r;
assert(context);
@@ -2348,15 +2338,28 @@ static int apply_mount_namespace(
if (r < 0)
return r;
- /*
- * If DynamicUser=no and RootDirectory= is set then lets pass a relaxed
- * sandbox info, otherwise enforce it, don't ignore protected paths and
- * fail if we are enable to apply the sandbox inside the mount namespace.
- */
- if (!context->dynamic_user && root_dir)
- ns_info.ignore_protect_paths = true;
-
needs_sandboxing = (params->flags & EXEC_APPLY_SANDBOXING) && !(command->flags & EXEC_COMMAND_FULLY_PRIVILEGED);
+ if (needs_sandboxing)
+ ns_info = (NamespaceInfo) {
+ .ignore_protect_paths = false,
+ .private_dev = context->private_devices,
+ .protect_control_groups = context->protect_control_groups,
+ .protect_kernel_tunables = context->protect_kernel_tunables,
+ .protect_kernel_modules = context->protect_kernel_modules,
+ .mount_apivfs = context->mount_apivfs,
+ .private_mounts = context->private_mounts,
+ };
+ else if (!context->dynamic_user && root_dir)
+ /*
+ * If DynamicUser=no and RootDirectory= is set then lets pass a relaxed
+ * sandbox info, otherwise enforce it, don't ignore protected paths and
+ * fail if we are enable to apply the sandbox inside the mount namespace.
+ */
+ ns_info = (NamespaceInfo) {
+ .ignore_protect_paths = true,
+ };
+ else
+ ns_info = (NamespaceInfo) {};
r = setup_namespace(root_dir, root_image,
&ns_info, context->read_write_paths,
@@ -2438,7 +2441,9 @@ static int setup_keyring(
uid_t uid, gid_t gid) {
key_serial_t keyring;
- int r;
+ int r = 0;
+ uid_t saved_uid;
+ gid_t saved_gid;
assert(u);
assert(context);
@@ -2457,6 +2462,26 @@ static int setup_keyring(
if (context->keyring_mode == EXEC_KEYRING_INHERIT)
return 0;
+ /* Acquiring a reference to the user keyring is nasty. We briefly change identity in order to get things set up
+ * properly by the kernel. If we don't do that then we can't create it atomically, and that sucks for parallel
+ * execution. This mimics what pam_keyinit does, too. Setting up session keyring, to be owned by the right user
+ * & group is just as nasty as acquiring a reference to the user keyring. */
+
+ saved_uid = getuid();
+ saved_gid = getgid();
+
+ if (gid_is_valid(gid) && gid != saved_gid) {
+ if (setregid(gid, -1) < 0)
+ return log_unit_error_errno(u, errno, "Failed to change GID for user keyring: %m");
+ }
+
+ if (uid_is_valid(uid) && uid != saved_uid) {
+ if (setreuid(uid, -1) < 0) {
+ r = log_unit_error_errno(u, errno, "Failed to change UID for user keyring: %m");
+ goto out;
+ }
+ }
+
keyring = keyctl(KEYCTL_JOIN_SESSION_KEYRING, 0, 0, 0, 0);
if (keyring == -1) {
if (errno == ENOSYS)
@@ -2466,12 +2491,36 @@ static int setup_keyring(
else if (errno == EDQUOT)
log_unit_debug_errno(u, errno, "Out of kernel keyrings to allocate, ignoring.");
else
- return log_unit_error_errno(u, errno, "Setting up kernel keyring failed: %m");
+ r = log_unit_error_errno(u, errno, "Setting up kernel keyring failed: %m");
- return 0;
+ goto out;
+ }
+
+ /* When requested link the user keyring into the session keyring. */
+ if (context->keyring_mode == EXEC_KEYRING_SHARED) {
+
+ if (keyctl(KEYCTL_LINK,
+ KEY_SPEC_USER_KEYRING,
+ KEY_SPEC_SESSION_KEYRING, 0, 0) < 0) {
+ r = log_unit_error_errno(u, errno, "Failed to link user keyring into session keyring: %m");
+ goto out;
+ }
+ }
+
+ /* Restore uid/gid back */
+ if (uid_is_valid(uid) && uid != saved_uid) {
+ if (setreuid(saved_uid, -1) < 0) {
+ r = log_unit_error_errno(u, errno, "Failed to change UID back for user keyring: %m");
+ goto out;
+ }
}
- /* Populate they keyring with the invocation ID by default. */
+ if (gid_is_valid(gid) && gid != saved_gid) {
+ if (setregid(saved_gid, -1) < 0)
+ return log_unit_error_errno(u, errno, "Failed to change GID back for user keyring: %m");
+ }
+
+ /* Populate they keyring with the invocation ID by default, as original saved_uid. */
if (!sd_id128_is_null(u->invocation_id)) {
key_serial_t key;
@@ -2482,68 +2531,23 @@ static int setup_keyring(
if (keyctl(KEYCTL_SETPERM, key,
KEY_POS_VIEW|KEY_POS_READ|KEY_POS_SEARCH|
KEY_USR_VIEW|KEY_USR_READ|KEY_USR_SEARCH, 0, 0) < 0)
- return log_unit_error_errno(u, errno, "Failed to restrict invocation ID permission: %m");
+ r = log_unit_error_errno(u, errno, "Failed to restrict invocation ID permission: %m");
}
}
- /* And now, make the keyring owned by the service's user */
- if (uid_is_valid(uid) || gid_is_valid(gid))
- if (keyctl(KEYCTL_CHOWN, keyring, uid, gid, 0) < 0)
- return log_unit_error_errno(u, errno, "Failed to change ownership of session keyring: %m");
+out:
+ /* Revert back uid & gid for the the last time, and exit */
+ /* no extra logging, as only the first already reported error matters */
+ if (getuid() != saved_uid)
+ (void) setreuid(saved_uid, -1);
- /* When requested link the user keyring into the session keyring. */
- if (context->keyring_mode == EXEC_KEYRING_SHARED) {
- uid_t saved_uid;
- gid_t saved_gid;
+ if (getgid() != saved_gid)
+ (void) setregid(saved_gid, -1);
- /* Acquiring a reference to the user keyring is nasty. We briefly change identity in order to get things
- * set up properly by the kernel. If we don't do that then we can't create it atomically, and that
- * sucks for parallel execution. This mimics what pam_keyinit does, too.*/
-
- saved_uid = getuid();
- saved_gid = getgid();
-
- if (gid_is_valid(gid) && gid != saved_gid) {
- if (setregid(gid, -1) < 0)
- return log_unit_error_errno(u, errno, "Failed to change GID for user keyring: %m");
- }
-
- if (uid_is_valid(uid) && uid != saved_uid) {
- if (setreuid(uid, -1) < 0) {
- (void) setregid(saved_gid, -1);
- return log_unit_error_errno(u, errno, "Failed to change UID for user keyring: %m");
- }
- }
-
- if (keyctl(KEYCTL_LINK,
- KEY_SPEC_USER_KEYRING,
- KEY_SPEC_SESSION_KEYRING, 0, 0) < 0) {
-
- r = -errno;
-
- (void) setreuid(saved_uid, -1);
- (void) setregid(saved_gid, -1);
-
- return log_unit_error_errno(u, r, "Failed to link user keyring into session keyring: %m");
- }
-
- if (uid_is_valid(uid) && uid != saved_uid) {
- if (setreuid(saved_uid, -1) < 0) {
- (void) setregid(saved_gid, -1);
- return log_unit_error_errno(u, errno, "Failed to change UID back for user keyring: %m");
- }
- }
-
- if (gid_is_valid(gid) && gid != saved_gid) {
- if (setregid(saved_gid, -1) < 0)
- return log_unit_error_errno(u, errno, "Failed to change GID back for user keyring: %m");
- }
- }
-
- return 0;
+ return r;
}
-static void append_socket_pair(int *array, unsigned *n, const int pair[2]) {
+static void append_socket_pair(int *array, size_t *n, const int pair[2]) {
assert(array);
assert(n);
@@ -2562,9 +2566,9 @@ static int close_remaining_fds(
const DynamicCreds *dcreds,
int user_lookup_fd,
int socket_fd,
- int *fds, unsigned n_fds) {
+ int *fds, size_t n_fds) {
- unsigned n_dont_close = 0;
+ size_t n_dont_close = 0;
int dont_close[n_fds + 12];
assert(params);
@@ -2696,8 +2700,7 @@ static int compile_suggested_paths(const ExecContext *c, const ExecParameters *p
}
}
- *ret = list;
- list = NULL;
+ *ret = TAKE_PTR(list);
return 0;
}
@@ -2715,8 +2718,8 @@ static int exec_child(
int socket_fd,
int named_iofds[3],
int *fds,
- unsigned n_storage_fds,
- unsigned n_socket_fds,
+ size_t n_storage_fds,
+ size_t n_socket_fds,
char **files_env,
int user_lookup_fd,
int *exit_status) {
@@ -2744,8 +2747,8 @@ static int exec_child(
#endif
uid_t uid = UID_INVALID;
gid_t gid = GID_INVALID;
- int i, r, ngids = 0;
- unsigned n_fds;
+ int r, ngids = 0;
+ size_t n_fds;
ExecDirectoryType dt;
int secure_bits;
@@ -2933,15 +2936,9 @@ static int exec_child(
}
if (context->oom_score_adjust_set) {
- char t[DECIMAL_STR_MAX(context->oom_score_adjust)];
-
- /* When we can't make this change due to EPERM, then
- * let's silently skip over it. User namespaces
- * prohibit write access to this file, and we
- * shouldn't trip up over that. */
-
- sprintf(t, "%i", context->oom_score_adjust);
- r = write_string_file("/proc/self/oom_score_adj", t, 0);
+ /* When we can't make this change due to EPERM, then let's silently skip over it. User namespaces
+ * prohibit write access to this file, and we shouldn't trip up over that. */
+ r = set_oom_score_adjust(context->oom_score_adjust);
if (IN_SET(r, -EPERM, -EACCES))
log_unit_debug_errno(unit, r, "Failed to adjust OOM setting, assuming containerized execution, ignoring: %m");
else if (r < 0) {
@@ -3184,17 +3181,12 @@ static int exec_child(
if (needs_sandboxing) {
uint64_t bset;
+ int which_failed;
- for (i = 0; i < _RLIMIT_MAX; i++) {
-
- if (!context->rlimit[i])
- continue;
-
- r = setrlimit_closest(i, context->rlimit[i]);
- if (r < 0) {
- *exit_status = EXIT_LIMITS;
- return log_unit_error_errno(unit, r, "Failed to adjust resource limit %s: %m", rlimit_to_string(i));
- }
+ r = setrlimit_closest_all((const struct rlimit* const *) context->rlimit, &which_failed);
+ if (r < 0) {
+ *exit_status = EXIT_LIMITS;
+ return log_unit_error_errno(unit, r, "Failed to adjust resource limit RLIMIT_%s: %m", rlimit_to_string(which_failed));
}
/* Set the RTPRIO resource limit to 0, but only if nothing else was explicitly requested. */
@@ -3394,8 +3386,7 @@ static int exec_child(
return log_oom();
}
- strv_free(accum_env);
- accum_env = ee;
+ strv_free_and_replace(accum_env, ee);
}
final_argv = replace_env_argv(argv, accum_env);
@@ -3408,29 +3399,24 @@ static int exec_child(
_cleanup_free_ char *line;
line = exec_command_line(final_argv);
- if (line) {
+ if (line)
log_struct(LOG_DEBUG,
"EXECUTABLE=%s", command->path,
LOG_UNIT_MESSAGE(unit, "Executing: %s", line),
LOG_UNIT_ID(unit),
- LOG_UNIT_INVOCATION_ID(unit),
- NULL);
- }
+ LOG_UNIT_INVOCATION_ID(unit));
}
execve(command->path, final_argv, accum_env);
if (errno == ENOENT && (command->flags & EXEC_COMMAND_IGNORE_FAILURE)) {
-
log_struct_errno(LOG_INFO, errno,
"MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
LOG_UNIT_ID(unit),
LOG_UNIT_INVOCATION_ID(unit),
LOG_UNIT_MESSAGE(unit, "Executable %s missing, skipping: %m",
command->path),
- "EXECUTABLE=%s", command->path,
- NULL);
-
+ "EXECUTABLE=%s", command->path);
return 0;
}
@@ -3451,7 +3437,7 @@ int exec_spawn(Unit *unit,
_cleanup_strv_free_ char **files_env = NULL;
int *fds = NULL;
- unsigned n_storage_fds = 0, n_socket_fds = 0;
+ size_t n_storage_fds = 0, n_socket_fds = 0;
_cleanup_free_ char *line = NULL;
int socket_fd, r;
int named_iofds[3] = { -1, -1, -1 };
@@ -3504,8 +3490,7 @@ int exec_spawn(Unit *unit,
LOG_UNIT_MESSAGE(unit, "About to execute: %s", line),
"EXECUTABLE=%s", command->path,
LOG_UNIT_ID(unit),
- LOG_UNIT_INVOCATION_ID(unit),
- NULL);
+ LOG_UNIT_INVOCATION_ID(unit));
pid = fork();
if (pid < 0)
@@ -3530,7 +3515,7 @@ int exec_spawn(Unit *unit,
unit->manager->user_lookup_fds[1],
&exit_status);
- if (r < 0) {
+ if (r < 0)
log_struct_errno(LOG_ERR, r,
"MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
LOG_UNIT_ID(unit),
@@ -3538,9 +3523,7 @@ int exec_spawn(Unit *unit,
LOG_UNIT_MESSAGE(unit, "Failed at step %s spawning %s: %m",
exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD),
command->path),
- "EXECUTABLE=%s", command->path,
- NULL);
- }
+ "EXECUTABLE=%s", command->path);
_exit(exit_status);
}
@@ -3577,7 +3560,8 @@ void exec_context_init(ExecContext *c) {
for (i = 0; i < _EXEC_DIRECTORY_TYPE_MAX; i++)
c->directories[i].mode = 0755;
c->capability_bounding_set = CAP_ALL;
- c->restrict_namespaces = NAMESPACE_FLAGS_ALL;
+ assert_cc(NAMESPACE_FLAGS_INITIAL != NAMESPACE_FLAGS_ALL);
+ c->restrict_namespaces = NAMESPACE_FLAGS_INITIAL;
c->log_level_max = -1;
}
@@ -3592,8 +3576,7 @@ void exec_context_done(ExecContext *c) {
c->pass_environment = strv_free(c->pass_environment);
c->unset_environment = strv_free(c->unset_environment);
- for (l = 0; l < ELEMENTSOF(c->rlimit); l++)
- c->rlimit[l] = mfree(c->rlimit[l]);
+ rlimit_free_all(c->rlimit);
for (l = 0; l < 3; l++) {
c->stdio_fdname[l] = mfree(c->stdio_fdname[l]);
@@ -3676,8 +3659,8 @@ static void exec_command_done(ExecCommand *c) {
c->argv = strv_free(c->argv);
}
-void exec_command_done_array(ExecCommand *c, unsigned n) {
- unsigned i;
+void exec_command_done_array(ExecCommand *c, size_t n) {
+ size_t i;
for (i = 0; i < n; i++)
exec_command_done(c+i);
@@ -3695,8 +3678,8 @@ ExecCommand* exec_command_free_list(ExecCommand *c) {
return NULL;
}
-void exec_command_free_array(ExecCommand **c, unsigned n) {
- unsigned i;
+void exec_command_free_array(ExecCommand **c, size_t n) {
+ size_t i;
for (i = 0; i < n; i++)
c[i] = exec_command_free_list(c[i]);
@@ -3742,9 +3725,9 @@ const char* exec_context_fdname(const ExecContext *c, int fd_index) {
}
static int exec_context_named_iofds(const ExecContext *c, const ExecParameters *p, int named_iofds[3]) {
- unsigned i, targets;
+ size_t i, targets;
const char* stdio_fdname[3];
- unsigned n_fds;
+ size_t n_fds;
assert(c);
assert(p);
@@ -3993,9 +3976,9 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
for (i = 0; i < RLIM_NLIMITS; i++)
if (c->rlimit[i]) {
- fprintf(f, "%s%s: " RLIM_FMT "\n",
+ fprintf(f, "Limit%s%s: " RLIM_FMT "\n",
prefix, rlimit_to_string(i), c->rlimit[i]->rlim_max);
- fprintf(f, "%s%sSoft: " RLIM_FMT "\n",
+ fprintf(f, "Limit%s%sSoft: " RLIM_FMT "\n",
prefix, rlimit_to_string(i), c->rlimit[i]->rlim_cur);
}
@@ -4280,7 +4263,7 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
if (exec_context_restrict_namespaces_set(c)) {
_cleanup_free_ char *s = NULL;
- r = namespace_flag_to_string_many(c->restrict_namespaces, &s);
+ r = namespace_flags_to_string(c->restrict_namespaces, &s);
if (r >= 0)
fprintf(f, "%sRestrictNamespaces: %s\n",
prefix, s);
@@ -4507,10 +4490,7 @@ int exec_command_set(ExecCommand *c, const char *path, ...) {
free(c->path);
c->path = p;
- strv_free(c->argv);
- c->argv = l;
-
- return 0;
+ return strv_free_and_replace(c->argv, l);
}
int exec_command_append(ExecCommand *c, const char *path, ...) {
@@ -4857,12 +4837,11 @@ int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value,
} else
return 0;
-
/* If the object is newly created, then put it to the hashmap which manages ExecRuntime objects. */
if (rt_create) {
r = hashmap_put(u->manager->exec_runtime_by_id, rt_create->id, rt_create);
if (r < 0) {
- log_unit_debug_errno(u, r, "Failed to put runtime paramter to manager's storage: %m");
+ log_unit_debug_errno(u, r, "Failed to put runtime parameter to manager's storage: %m");
return 0;
}
diff --git a/src/core/execute.h b/src/core/execute.h
index a34cf0b873..77ffe82323 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -1,25 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
typedef struct ExecStatus ExecStatus;
typedef struct ExecCommand ExecCommand;
typedef struct ExecContext ExecContext;
@@ -218,9 +199,9 @@ struct ExecContext {
char **read_write_paths, **read_only_paths, **inaccessible_paths;
unsigned long mount_flags;
BindMount *bind_mounts;
- unsigned n_bind_mounts;
+ size_t n_bind_mounts;
TemporaryFileSystem *temporary_filesystems;
- unsigned n_temporary_filesystems;
+ size_t n_temporary_filesystems;
uint64_t capability_bounding_set;
uint64_t capability_ambient_set;
@@ -241,6 +222,7 @@ struct ExecContext {
bool private_network;
bool private_devices;
bool private_users;
+ bool private_mounts;
ProtectSystem protect_system;
ProtectHome protect_home;
bool protect_kernel_tunables;
@@ -292,20 +274,20 @@ static inline bool exec_context_restrict_namespaces_set(const ExecContext *c) {
}
typedef enum ExecFlags {
- EXEC_APPLY_SANDBOXING = 1U << 0,
- EXEC_APPLY_CHROOT = 1U << 1,
- EXEC_APPLY_TTY_STDIN = 1U << 2,
- EXEC_NEW_KEYRING = 1U << 3,
- EXEC_PASS_LOG_UNIT = 1U << 4, /* Whether to pass the unit name to the service's journal stream connection */
- EXEC_CHOWN_DIRECTORIES = 1U << 5, /* chown() the runtime/state/cache/log directories to the user we run as, under all conditions */
- EXEC_NSS_BYPASS_BUS = 1U << 6, /* Set the SYSTEMD_NSS_BYPASS_BUS environment variable, to disable nss-systemd for dbus */
- EXEC_CGROUP_DELEGATE = 1U << 7,
+ EXEC_APPLY_SANDBOXING = 1 << 0,
+ EXEC_APPLY_CHROOT = 1 << 1,
+ EXEC_APPLY_TTY_STDIN = 1 << 2,
+ EXEC_NEW_KEYRING = 1 << 3,
+ EXEC_PASS_LOG_UNIT = 1 << 4, /* Whether to pass the unit name to the service's journal stream connection */
+ EXEC_CHOWN_DIRECTORIES = 1 << 5, /* chown() the runtime/state/cache/log directories to the user we run as, under all conditions */
+ EXEC_NSS_BYPASS_BUS = 1 << 6, /* Set the SYSTEMD_NSS_BYPASS_BUS environment variable, to disable nss-systemd for dbus */
+ EXEC_CGROUP_DELEGATE = 1 << 7,
/* The following are not used by execute.c, but by consumers internally */
- EXEC_PASS_FDS = 1U << 8,
- EXEC_IS_CONTROL = 1U << 9,
- EXEC_SETENV_RESULT = 1U << 10,
- EXEC_SET_WATCHDOG = 1U << 11,
+ EXEC_PASS_FDS = 1 << 8,
+ EXEC_IS_CONTROL = 1 << 9,
+ EXEC_SETENV_RESULT = 1 << 10,
+ EXEC_SET_WATCHDOG = 1 << 11,
} ExecFlags;
struct ExecParameters {
@@ -314,8 +296,8 @@ struct ExecParameters {
int *fds;
char **fd_names;
- unsigned n_storage_fds;
- unsigned n_socket_fds;
+ size_t n_storage_fds;
+ size_t n_socket_fds;
ExecFlags flags;
bool selinux_context_net:1;
@@ -347,10 +329,10 @@ int exec_spawn(Unit *unit,
DynamicCreds *dynamic_creds,
pid_t *ret);
-void exec_command_done_array(ExecCommand *c, unsigned n);
+void exec_command_done_array(ExecCommand *c, size_t n);
ExecCommand* exec_command_free_list(ExecCommand *c);
-void exec_command_free_array(ExecCommand **c, unsigned n);
+void exec_command_free_array(ExecCommand **c, size_t n);
void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix);
void exec_command_append_list(ExecCommand **l, ExecCommand *e);
diff --git a/src/core/hostname-setup.c b/src/core/hostname-setup.c
index 19299918cc..83cce88131 100644
--- a/src/core/hostname-setup.c
+++ b/src/core/hostname-setup.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
#include <stdio.h>
diff --git a/src/core/hostname-setup.h b/src/core/hostname-setup.h
index 8bf8769859..dc7b9a6262 100644
--- a/src/core/hostname-setup.h
+++ b/src/core/hostname-setup.h
@@ -1,23 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
int hostname_setup(void);
diff --git a/src/core/ima-setup.c b/src/core/ima-setup.c
index 80319622ad..013d6c5de3 100644
--- a/src/core/ima-setup.c
+++ b/src/core/ima-setup.c
@@ -1,23 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
- Copyright (C) 2012 Roberto Sassu - Politecnico di Torino, Italy
- TORSEC group — http://security.polito.it
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ Copyright © 2012 Roberto Sassu - Politecnico di Torino, Italy
+ TORSEC group — http://security.polito.it
***/
#include <errno.h>
diff --git a/src/core/ima-setup.h b/src/core/ima-setup.h
index 1eae74bceb..cf478795a1 100644
--- a/src/core/ima-setup.h
+++ b/src/core/ima-setup.h
@@ -2,24 +2,8 @@
#pragma once
/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
- Copyright (C) 2012 Roberto Sassu - Politecnico di Torino, Italy
- TORSEC group — http://security.polito.it
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ Copyright © 2012 Roberto Sassu - Politecnico di Torino, Italy
+ TORSEC group — http://security.polito.it
***/
int ima_setup(void);
diff --git a/src/core/ip-address-access.c b/src/core/ip-address-access.c
index f10138c6de..1d431bb674 100644
--- a/src/core/ip-address-access.c
+++ b/src/core/ip-address-access.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2016 Daniel Mack
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <stdio.h>
#include <stdlib.h>
diff --git a/src/core/ip-address-access.h b/src/core/ip-address-access.h
index 536142e904..7babf19562 100644
--- a/src/core/ip-address-access.h
+++ b/src/core/ip-address-access.h
@@ -1,25 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2016 Daniel Mack
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
+#include "conf-parser.h"
#include "in-addr-util.h"
#include "list.h"
@@ -32,7 +15,7 @@ struct IPAddressAccessItem {
LIST_FIELDS(IPAddressAccessItem, items);
};
-int config_parse_ip_address_access(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);
+CONFIG_PARSER_PROTOTYPE(config_parse_ip_address_access);
IPAddressAccessItem* ip_address_access_free_all(IPAddressAccessItem *first);
diff --git a/src/core/job.c b/src/core/job.c
index 1b3534a7a6..734756b666 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
@@ -56,6 +38,7 @@ Job* job_new_raw(Unit *unit) {
j->manager = unit->manager;
j->unit = unit;
j->type = _JOB_TYPE_INVALID;
+ j->reloaded = false;
return j;
}
@@ -77,7 +60,7 @@ Job* job_new(Unit *unit, JobType type) {
return j;
}
-void job_free(Job *j) {
+void job_unlink(Job *j) {
assert(j);
assert(!j->installed);
assert(!j->transaction_prev);
@@ -85,16 +68,33 @@ void job_free(Job *j) {
assert(!j->subject_list);
assert(!j->object_list);
- if (j->in_run_queue)
+ if (j->in_run_queue) {
LIST_REMOVE(run_queue, j->manager->run_queue, j);
+ j->in_run_queue = false;
+ }
- if (j->in_dbus_queue)
+ if (j->in_dbus_queue) {
LIST_REMOVE(dbus_queue, j->manager->dbus_job_queue, j);
+ j->in_dbus_queue = false;
+ }
- if (j->in_gc_queue)
+ if (j->in_gc_queue) {
LIST_REMOVE(gc_queue, j->manager->gc_job_queue, j);
+ j->in_gc_queue = false;
+ }
+
+ j->timer_event_source = sd_event_source_unref(j->timer_event_source);
+}
+
+void job_free(Job *j) {
+ assert(j);
+ assert(!j->installed);
+ assert(!j->transaction_prev);
+ assert(!j->transaction_next);
+ assert(!j->subject_list);
+ assert(!j->object_list);
- sd_event_source_unref(j->timer_event_source);
+ job_unlink(j);
sd_bus_track_unref(j->bus_track);
strv_free(j->deserialized_clients);
@@ -254,6 +254,7 @@ int job_install_deserialized(Job *j) {
*pj = j;
j->installed = true;
+ j->reloaded = true;
if (j->state == JOB_RUNNING)
j->unit->manager->n_running_jobs++;
@@ -576,7 +577,6 @@ int job_run_and_invalidate(Job *j) {
job_set_state(j, JOB_RUNNING);
job_add_to_dbus_queue(j);
-
switch (j->type) {
case JOB_VERIFY_ACTIVE: {
@@ -626,6 +626,8 @@ int job_run_and_invalidate(Job *j) {
r = job_finish_and_invalidate(j, JOB_UNSUPPORTED, true, false);
else if (r == -ENOLINK)
r = job_finish_and_invalidate(j, JOB_DEPENDENCY, true, false);
+ else if (r == -ESTALE)
+ r = job_finish_and_invalidate(j, JOB_ONCE, true, false);
else if (r == -EAGAIN)
job_set_state(j, JOB_WAITING);
else if (r < 0)
@@ -645,6 +647,7 @@ _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobR
[JOB_ASSERT] = "Assertion failed for %s.",
[JOB_UNSUPPORTED] = "Starting of %s not supported.",
[JOB_COLLECTED] = "Unnecessary job for %s was removed.",
+ [JOB_ONCE] = "Unit %s has been started before and cannot be started again."
};
static const char *const generic_finished_stop_job[_JOB_RESULT_MAX] = {
[JOB_DONE] = "Stopped %s.",
@@ -704,6 +707,7 @@ static const struct {
[JOB_ASSERT] = { ANSI_HIGHLIGHT_YELLOW, "ASSERT" },
[JOB_UNSUPPORTED] = { ANSI_HIGHLIGHT_YELLOW, "UNSUPP" },
/* JOB_COLLECTED */
+ [JOB_ONCE] = { ANSI_HIGHLIGHT_RED, " ONCE " },
};
static void job_print_status_message(Unit *u, JobType t, JobResult result) {
@@ -761,6 +765,7 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
[JOB_ASSERT] = LOG_WARNING,
[JOB_UNSUPPORTED] = LOG_WARNING,
[JOB_COLLECTED] = LOG_INFO,
+ [JOB_ONCE] = LOG_ERR,
};
assert(u);
@@ -808,8 +813,7 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
"JOB_TYPE=%s", job_type_to_string(t),
"JOB_RESULT=%s", job_result_to_string(result),
LOG_UNIT_ID(u),
- LOG_UNIT_INVOCATION_ID(u),
- NULL);
+ LOG_UNIT_INVOCATION_ID(u));
return;
}
@@ -819,8 +823,7 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
"JOB_RESULT=%s", job_result_to_string(result),
LOG_UNIT_ID(u),
LOG_UNIT_INVOCATION_ID(u),
- mid,
- NULL);
+ mid);
}
static void job_emit_status_message(Unit *u, JobType t, JobResult result) {
@@ -853,6 +856,19 @@ static void job_fail_dependencies(Unit *u, UnitDependency d) {
}
}
+static int job_save_pending_finished_job(Job *j) {
+ int r;
+
+ assert(j);
+
+ r = set_ensure_allocated(&j->manager->pending_finished_jobs, NULL);
+ if (r < 0)
+ return r;
+
+ job_unlink(j);
+ return set_put(j->manager->pending_finished_jobs, j);
+}
+
int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool already) {
Unit *u;
Unit *other;
@@ -892,7 +908,11 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool alr
j->manager->n_failed_jobs++;
job_uninstall(j);
- job_free(j);
+ /* Keep jobs started before the reload to send singal later, free all others */
+ if (!MANAGER_IS_RELOADING(j->manager) ||
+ !j->reloaded ||
+ job_save_pending_finished_job(j) < 0)
+ job_free(j);
/* Fail depending jobs on failure */
if (result != JOB_DONE && recursive) {
@@ -916,8 +936,7 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool alr
LOG_UNIT_MESSAGE(u, "Job %s/%s failed with result '%s'.",
u->id,
job_type_to_string(t),
- job_result_to_string(result)),
- NULL);
+ job_result_to_string(result)));
unit_start_on_failure(u);
}
@@ -1439,8 +1458,7 @@ int job_get_before(Job *j, Job*** ret) {
n = sort_job_list(list, n);
- *ret = list;
- list = NULL;
+ *ret = TAKE_PTR(list);
return (int) n;
}
@@ -1489,8 +1507,7 @@ int job_get_after(Job *j, Job*** ret) {
n = sort_job_list(list, n);
- *ret = list;
- list = NULL;
+ *ret = TAKE_PTR(list);
return (int) n;
}
@@ -1539,6 +1556,7 @@ static const char* const job_result_table[_JOB_RESULT_MAX] = {
[JOB_ASSERT] = "assert",
[JOB_UNSUPPORTED] = "unsupported",
[JOB_COLLECTED] = "collected",
+ [JOB_ONCE] = "once",
};
DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult);
diff --git a/src/core/job.h b/src/core/job.h
index 2edb63169c..2f5f3f3989 100644
--- a/src/core/job.h
+++ b/src/core/job.h
@@ -1,25 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include <stdbool.h>
#include "sd-event.h"
@@ -109,6 +90,7 @@ enum JobResult {
JOB_ASSERT, /* Couldn't start a unit, because an assert didn't hold */
JOB_UNSUPPORTED, /* Couldn't start a unit, because the unit type is not supported on the system */
JOB_COLLECTED, /* Job was garbage collected, since nothing needed it anymore */
+ JOB_ONCE, /* Unit was started before, and hence can't be started again */
_JOB_RESULT_MAX,
_JOB_RESULT_INVALID = -1
};
@@ -174,10 +156,12 @@ struct Job {
bool irreversible:1;
bool in_gc_queue:1;
bool ref_by_private_bus:1;
+ bool reloaded:1;
};
Job* job_new(Unit *unit, JobType type);
Job* job_new_raw(Unit *unit);
+void job_unlink(Job *job);
void job_free(Job *job);
Job* job_install(Job *j);
int job_install_deserialized(Job *j);
diff --git a/src/core/kill.c b/src/core/kill.c
index 5dfcb780fa..929eebfe37 100644
--- a/src/core/kill.c
+++ b/src/core/kill.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2012 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include "kill.h"
#include "signal-util.h"
diff --git a/src/core/kill.h b/src/core/kill.h
index f0d6ec41e9..2d6aa943a6 100644
--- a/src/core/kill.h
+++ b/src/core/kill.h
@@ -1,25 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2012 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
typedef struct KillContext KillContext;
#include <stdbool.h>
diff --git a/src/core/killall.c b/src/core/killall.c
index daa9c4ea20..87d207fd3d 100644
--- a/src/core/killall.c
+++ b/src/core/killall.c
@@ -1,21 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
/***
- This file is part of systemd.
-
- Copyright 2010 ProFUSION embedded systems
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ Copyright © 2010 ProFUSION embedded systems
***/
#include <errno.h>
@@ -211,7 +196,6 @@ static int killall(int sig, Set *pids, bool send_sighup) {
make sure to only send this after SIGTERM so
that SIGTERM is always first in the queue. */
-
if (get_ctty_devnr(pid, NULL) >= 0)
/* it's OK if the process is gone, just ignore the result */
(void) kill(pid, SIGHUP);
diff --git a/src/core/killall.h b/src/core/killall.h
index 45e97ab594..cbd202651c 100644
--- a/src/core/killall.h
+++ b/src/core/killall.h
@@ -1,25 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2012 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include "time-util.h"
void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup, usec_t timeout);
diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c
index a2809d03f6..9251929558 100644
--- a/src/core/kmod-setup.c
+++ b/src/core/kmod-setup.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <ftw.h>
#include <string.h>
diff --git a/src/core/kmod-setup.h b/src/core/kmod-setup.h
index b5ea6b55a9..801c7bf699 100644
--- a/src/core/kmod-setup.h
+++ b/src/core/kmod-setup.h
@@ -1,23 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
int kmod_setup(void);
diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c
index 57ed686d1f..4b422cc54e 100644
--- a/src/core/load-dropin.c
+++ b/src/core/load-dropin.c
@@ -1,23 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include "conf-parser.h"
#include "fs-util.h"
@@ -31,26 +12,21 @@
#include "unit.h"
static int unit_name_compatible(const char *a, const char *b) {
- _cleanup_free_ char *prefix = NULL;
+ _cleanup_free_ char *template = NULL;
int r;
- /* the straightforward case: the symlink name matches the target */
+ /* The straightforward case: the symlink name matches the target */
if (streq(a, b))
return 1;
- r = unit_name_template(a, &prefix);
+ r = unit_name_template(a, &template);
if (r == -EINVAL)
- /* not a template */
- return 0;
+ return 0; /* Not a template */
if (r < 0)
- /* oom, or some other failure. Just skip the warning. */
- return r;
-
- /* an instance name points to a target that is just the template name */
- if (streq(prefix, b))
- return 1;
+ return r; /* OOM, or some other failure. Just skip the warning. */
- return 0;
+ /* An instance name points to a target that is just the template name */
+ return streq(template, b);
}
static int process_deps(Unit *u, UnitDependency dependency, const char *dir_suffix) {
@@ -69,8 +45,8 @@ static int process_deps(Unit *u, UnitDependency dependency, const char *dir_suff
return r;
STRV_FOREACH(p, paths) {
- const char *entry;
_cleanup_free_ char *target = NULL;
+ const char *entry;
entry = basename(*p);
@@ -146,10 +122,9 @@ int unit_load_dropin(Unit *u) {
if (r <= 0)
return 0;
- if (!u->dropin_paths) {
- u->dropin_paths = l;
- l = NULL;
- } else {
+ if (!u->dropin_paths)
+ u->dropin_paths = TAKE_PTR(l);
+ else {
r = strv_extend_strv(&u->dropin_paths, l, true);
if (r < 0)
return log_oom();
diff --git a/src/core/load-dropin.h b/src/core/load-dropin.h
index 4c8ab487b3..bb10a76338 100644
--- a/src/core/load-dropin.h
+++ b/src/core/load-dropin.h
@@ -1,31 +1,14 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include "dropin.h"
#include "unit.h"
/* Read service data supplementary drop-in directories */
static inline int unit_find_dropin_paths(Unit *u, char ***paths) {
+ assert(u);
+
return unit_file_find_dropin_conf_paths(NULL,
u->manager->lookup_paths.search_path,
u->manager->unit_path_cache,
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 5d90a7c054..15fb47838c 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -6,6 +6,8 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
#include "conf-parser.h"
#include "load-fragment.h"
#include "missing.h"
+
+#include "all-units.h"
%}
struct ConfigPerfItem;
%null_strings
@@ -57,11 +59,11 @@ $1.SyslogLevelPrefix, config_parse_bool, 0,
$1.LogLevelMax, config_parse_log_level, 0, offsetof($1, exec_context.log_level_max)
$1.LogExtraFields, config_parse_log_extra_fields, 0, offsetof($1, exec_context)
$1.Capabilities, config_parse_warn_compat, DISABLED_LEGACY, offsetof($1, exec_context)
-$1.SecureBits, config_parse_exec_secure_bits, 0, offsetof($1, exec_context)
+$1.SecureBits, config_parse_exec_secure_bits, 0, offsetof($1, exec_context.secure_bits)
$1.CapabilityBoundingSet, config_parse_capability_set, 0, offsetof($1, exec_context.capability_bounding_set)
$1.AmbientCapabilities, config_parse_capability_set, 0, offsetof($1, exec_context.capability_ambient_set)
$1.TimerSlackNSec, config_parse_nsec, 0, offsetof($1, exec_context.timer_slack_nsec)
-$1.NoNewPrivileges, config_parse_no_new_privileges, 0, offsetof($1, exec_context)
+$1.NoNewPrivileges, config_parse_bool, 0, offsetof($1, exec_context.no_new_privileges)
$1.KeyringMode, config_parse_exec_keyring_mode, 0, offsetof($1, exec_context.keyring_mode)
m4_ifdef(`HAVE_SECCOMP',
`$1.SystemCallFilter, config_parse_syscall_filter, 0, offsetof($1, exec_context)
@@ -80,22 +82,22 @@ $1.RestrictNamespaces, config_parse_warn_compat, DISABLED_CO
$1.RestrictRealtime, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.LockPersonality, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
-$1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit)
-$1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit)
-$1.LimitDATA, config_parse_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit)
-$1.LimitSTACK, config_parse_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit)
-$1.LimitCORE, config_parse_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit)
-$1.LimitRSS, config_parse_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit)
-$1.LimitNOFILE, config_parse_limit, RLIMIT_NOFILE, offsetof($1, exec_context.rlimit)
-$1.LimitAS, config_parse_limit, RLIMIT_AS, offsetof($1, exec_context.rlimit)
-$1.LimitNPROC, config_parse_limit, RLIMIT_NPROC, offsetof($1, exec_context.rlimit)
-$1.LimitMEMLOCK, config_parse_limit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit)
-$1.LimitLOCKS, config_parse_limit, RLIMIT_LOCKS, offsetof($1, exec_context.rlimit)
-$1.LimitSIGPENDING, config_parse_limit, RLIMIT_SIGPENDING, offsetof($1, exec_context.rlimit)
-$1.LimitMSGQUEUE, config_parse_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit)
-$1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit)
-$1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit)
-$1.LimitRTTIME, config_parse_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit)
+$1.LimitCPU, config_parse_rlimit, RLIMIT_CPU, offsetof($1, exec_context.rlimit)
+$1.LimitFSIZE, config_parse_rlimit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit)
+$1.LimitDATA, config_parse_rlimit, RLIMIT_DATA, offsetof($1, exec_context.rlimit)
+$1.LimitSTACK, config_parse_rlimit, RLIMIT_STACK, offsetof($1, exec_context.rlimit)
+$1.LimitCORE, config_parse_rlimit, RLIMIT_CORE, offsetof($1, exec_context.rlimit)
+$1.LimitRSS, config_parse_rlimit, RLIMIT_RSS, offsetof($1, exec_context.rlimit)
+$1.LimitNOFILE, config_parse_rlimit, RLIMIT_NOFILE, offsetof($1, exec_context.rlimit)
+$1.LimitAS, config_parse_rlimit, RLIMIT_AS, offsetof($1, exec_context.rlimit)
+$1.LimitNPROC, config_parse_rlimit, RLIMIT_NPROC, offsetof($1, exec_context.rlimit)
+$1.LimitMEMLOCK, config_parse_rlimit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit)
+$1.LimitLOCKS, config_parse_rlimit, RLIMIT_LOCKS, offsetof($1, exec_context.rlimit)
+$1.LimitSIGPENDING, config_parse_rlimit, RLIMIT_SIGPENDING, offsetof($1, exec_context.rlimit)
+$1.LimitMSGQUEUE, config_parse_rlimit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit)
+$1.LimitNICE, config_parse_rlimit, RLIMIT_NICE, offsetof($1, exec_context.rlimit)
+$1.LimitRTPRIO, config_parse_rlimit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit)
+$1.LimitRTTIME, config_parse_rlimit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit)
$1.ReadWriteDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_paths)
$1.ReadOnlyDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_paths)
$1.InaccessibleDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_paths)
@@ -112,9 +114,10 @@ $1.ProtectKernelModules, config_parse_bool, 0,
$1.ProtectControlGroups, config_parse_bool, 0, offsetof($1, exec_context.protect_control_groups)
$1.PrivateNetwork, config_parse_bool, 0, offsetof($1, exec_context.private_network)
$1.PrivateUsers, config_parse_bool, 0, offsetof($1, exec_context.private_users)
-$1.ProtectSystem, config_parse_protect_system, 0, offsetof($1, exec_context)
-$1.ProtectHome, config_parse_protect_home, 0, offsetof($1, exec_context)
-$1.MountFlags, config_parse_exec_mount_flags, 0, offsetof($1, exec_context)
+$1.PrivateMounts, config_parse_bool, 0, offsetof($1, exec_context.private_mounts)
+$1.ProtectSystem, config_parse_protect_system, 0, offsetof($1, exec_context.protect_system)
+$1.ProtectHome, config_parse_protect_home, 0, offsetof($1, exec_context.protect_home)
+$1.MountFlags, config_parse_exec_mount_flags, 0, offsetof($1, exec_context.mount_flags)
$1.MountAPIVFS, config_parse_bool, 0, offsetof($1, exec_context.mount_apivfs)
$1.Personality, config_parse_personality, 0, offsetof($1, exec_context.personality)
$1.RuntimeDirectoryPreserve, config_parse_runtime_preserve_mode, 0, offsetof($1, exec_context.runtime_directory_preserve_mode)
@@ -153,8 +156,8 @@ $1.KillSignal, config_parse_signal, 0,
m4_define(`CGROUP_CONTEXT_CONFIG_ITEMS',
`$1.Slice, config_parse_unit_slice, 0, 0
$1.CPUAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.cpu_accounting)
-$1.CPUWeight, config_parse_cpu_weight, 0, offsetof($1, cgroup_context.cpu_weight)
-$1.StartupCPUWeight, config_parse_cpu_weight, 0, offsetof($1, cgroup_context.startup_cpu_weight)
+$1.CPUWeight, config_parse_cg_weight, 0, offsetof($1, cgroup_context.cpu_weight)
+$1.StartupCPUWeight, config_parse_cg_weight, 0, offsetof($1, cgroup_context.startup_cpu_weight)
$1.CPUShares, config_parse_cpu_shares, 0, offsetof($1, cgroup_context.cpu_shares)
$1.StartupCPUShares, config_parse_cpu_shares, 0, offsetof($1, cgroup_context.startup_cpu_shares)
$1.CPUQuota, config_parse_cpu_quota, 0, offsetof($1, cgroup_context)
@@ -167,8 +170,8 @@ $1.MemoryLimit, config_parse_memory_limit, 0,
$1.DeviceAllow, config_parse_device_allow, 0, offsetof($1, cgroup_context)
$1.DevicePolicy, config_parse_device_policy, 0, offsetof($1, cgroup_context.device_policy)
$1.IOAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.io_accounting)
-$1.IOWeight, config_parse_io_weight, 0, offsetof($1, cgroup_context.io_weight)
-$1.StartupIOWeight, config_parse_io_weight, 0, offsetof($1, cgroup_context.startup_io_weight)
+$1.IOWeight, config_parse_cg_weight, 0, offsetof($1, cgroup_context.io_weight)
+$1.StartupIOWeight, config_parse_cg_weight, 0, offsetof($1, cgroup_context.startup_io_weight)
$1.IODeviceWeight, config_parse_io_device_weight, 0, offsetof($1, cgroup_context)
$1.IOReadBandwidthMax, config_parse_io_limit, 0, offsetof($1, cgroup_context)
$1.IOWriteBandwidthMax, config_parse_io_limit, 0, offsetof($1, cgroup_context)
@@ -289,7 +292,7 @@ Service.ExecStopPost, config_parse_exec, SERVICE_EXE
Service.RestartSec, config_parse_sec, 0, offsetof(Service, restart_usec)
Service.TimeoutSec, config_parse_service_timeout, 0, 0
Service.TimeoutStartSec, config_parse_service_timeout, 0, 0
-Service.TimeoutStopSec, config_parse_service_timeout, 0, 0
+Service.TimeoutStopSec, config_parse_sec_fix_0, 0, offsetof(Service, timeout_stop_usec)
Service.RuntimeMaxSec, config_parse_sec, 0, offsetof(Service, runtime_max_usec)
Service.WatchdogSec, config_parse_sec, 0, offsetof(Service, watchdog_usec)
m4_dnl The following five only exist for compatibility, they moved into Unit, see above
@@ -328,8 +331,8 @@ Socket.ListenNetlink, config_parse_socket_listen, SOCKET_SOCK
Socket.ListenSpecial, config_parse_socket_listen, SOCKET_SPECIAL, 0
Socket.ListenMessageQueue, config_parse_socket_listen, SOCKET_MQUEUE, 0
Socket.ListenUSBFunction, config_parse_socket_listen, SOCKET_USB_FUNCTION, 0
-Socket.SocketProtocol, config_parse_socket_protocol, 0, 0
-Socket.BindIPv6Only, config_parse_socket_bind, 0, 0,
+Socket.SocketProtocol, config_parse_socket_protocol, 0, offsetof(Socket, socket_protocol)
+Socket.BindIPv6Only, config_parse_socket_bind, 0, offsetof(Socket, bind_ipv6_only)
Socket.Backlog, config_parse_unsigned, 0, offsetof(Socket, backlog)
Socket.BindToDevice, config_parse_socket_bindtodevice, 0, 0
Socket.ExecStartPre, config_parse_exec, SOCKET_EXEC_START_PRE, offsetof(Socket, exec_command)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 1e3416c40b..d9a5094aa0 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -1,22 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
- Copyright 2012 Holger Hans Peter Freyther
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ Copyright © 2012 Holger Hans Peter Freyther
***/
#include <errno.h>
@@ -33,6 +17,7 @@
#include "af-list.h"
#include "alloc-util.h"
+#include "all-units.h"
#include "bus-error.h"
#include "bus-internal.h"
#include "bus-util.h"
@@ -57,7 +42,6 @@
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
-#include "rlimit-util.h"
#if HAVE_SECCOMP
#include "seccomp-util.h"
#endif
@@ -70,43 +54,45 @@
#include "strv.h"
#include "unit-name.h"
#include "unit-printf.h"
-#include "unit.h"
#include "user-util.h"
-#include "utf8.h"
#include "web-util.h"
-int config_parse_warn_compat(
- 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) {
- Disabled reason = ltype;
-
- switch(reason) {
- case DISABLED_CONFIGURATION:
- log_syntax(unit, LOG_DEBUG, filename, line, 0,
- "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
- break;
- case DISABLED_LEGACY:
- log_syntax(unit, LOG_INFO, filename, line, 0,
- "Support for option %s= has been removed and it is ignored", lvalue);
- break;
- case DISABLED_EXPERIMENTAL:
- log_syntax(unit, LOG_INFO, filename, line, 0,
- "Support for option %s= has not yet been enabled and it is ignored", lvalue);
- break;
- };
+static int supported_socket_protocol_from_string(const char *s) {
+ int r;
- return 0;
+ if (isempty(s))
+ return IPPROTO_IP;
+
+ r = socket_protocol_from_name(s);
+ if (r < 0)
+ return -EINVAL;
+ if (!IN_SET(r, IPPROTO_UDPLITE, IPPROTO_SCTP))
+ return -EPROTONOSUPPORT;
+
+ return r;
}
+DEFINE_CONFIG_PARSE(config_parse_socket_protocol, supported_socket_protocol_from_string, "Failed to parse socket protocol");
+DEFINE_CONFIG_PARSE(config_parse_exec_secure_bits, secure_bits_from_string, "Failed to parse secure bits");
DEFINE_CONFIG_PARSE_ENUM(config_parse_collect_mode, collect_mode, CollectMode, "Failed to parse garbage collection mode");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action, emergency_action, EmergencyAction, "Failed to parse failure action specifier");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_keyring_mode, exec_keyring_mode, ExecKeyringMode, "Failed to parse keyring mode");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode, "Failed to parse utmp mode");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_protect_home, protect_home, ProtectHome, "Failed to parse protect home value");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_protect_system, protect_system, ProtectSystem, "Failed to parse protect system value");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode, exec_preserve_mode, ExecPreserveMode, "Failed to parse runtime directory preserve mode");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_socket_bind, socket_address_bind_ipv6_only_or_bool, SocketAddressBindIPv6Only, "Failed to parse bind IPv6 only value");
+DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_ip_tos, ip_tos, int, -1, "Failed to parse IP TOS value");
+DEFINE_CONFIG_PARSE_PTR(config_parse_blockio_weight, cg_blkio_weight_parse, uint64_t, "Invalid block IO weight");
+DEFINE_CONFIG_PARSE_PTR(config_parse_cg_weight, cg_weight_parse, uint64_t, "Invalid weight");
+DEFINE_CONFIG_PARSE_PTR(config_parse_cpu_shares, cg_cpu_shares_parse, uint64_t, "Invalid CPU shares");
+DEFINE_CONFIG_PARSE_PTR(config_parse_exec_mount_flags, mount_propagation_flags_from_string, unsigned long, "Failed to parse mount flag");
int config_parse_unit_deps(
const char *unit,
@@ -145,7 +131,7 @@ int config_parse_unit_deps(
r = unit_name_printf(u, word, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", word);
continue;
}
@@ -198,7 +184,7 @@ int config_parse_unit_string_printf(
r = unit_full_printf(u, rvalue, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
return 0;
}
@@ -228,7 +214,7 @@ int config_parse_unit_strv_printf(
r = unit_full_printf(u, rvalue, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
return 0;
}
@@ -257,11 +243,19 @@ int config_parse_unit_path_printf(
assert(rvalue);
assert(u);
+ /* Let's not bother with anything that is too long */
+ if (strlen(rvalue) >= PATH_MAX) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "%s value too long%s.",
+ lvalue, fatal ? "" : ", ignoring");
+ return fatal ? -ENAMETOOLONG : 0;
+ }
+
r = unit_full_printf(u, rvalue, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to resolve unit specifiers on %s%s: %m",
- fatal ? "" : ", ignoring", rvalue);
+ "Failed to resolve unit specifiers in '%s'%s: %m",
+ rvalue, fatal ? "" : ", ignoring");
return fatal ? -ENOEXEC : 0;
}
@@ -312,22 +306,13 @@ int config_parse_unit_path_strv_printf(
r = unit_full_printf(u, word, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to resolve unit specifiers on \"%s\", ignoring: %m", word);
- return 0;
- }
-
- if (!utf8_is_valid(k)) {
- log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
+ "Failed to resolve unit specifiers in '%s', ignoring: %m", word);
return 0;
}
- if (!path_is_absolute(k)) {
- log_syntax(unit, LOG_ERR, filename, line, 0,
- "Symlink path is not absolute: %s", k);
+ r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
+ if (r < 0)
return 0;
- }
-
- path_kill_slashes(k);
r = strv_push(x, k);
if (r < 0)
@@ -370,47 +355,51 @@ int config_parse_socket_listen(const char *unit,
return log_oom();
if (ltype != SOCKET_SOCKET) {
+ _cleanup_free_ char *k = NULL;
- p->type = ltype;
- r = unit_full_printf(UNIT(s), rvalue, &p->path);
+ r = unit_full_printf(UNIT(s), rvalue, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
return 0;
}
- path_kill_slashes(p->path);
+ r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
+ if (r < 0)
+ return 0;
+
+ free_and_replace(p->path, k);
+ p->type = ltype;
} else if (streq(lvalue, "ListenNetlink")) {
_cleanup_free_ char *k = NULL;
- p->type = SOCKET_SOCKET;
r = unit_full_printf(UNIT(s), rvalue, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
return 0;
}
r = socket_address_parse_netlink(&p->address, k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value in '%s', ignoring: %m", k);
return 0;
}
+ p->type = SOCKET_SOCKET;
+
} else {
_cleanup_free_ char *k = NULL;
- p->type = SOCKET_SOCKET;
r = unit_full_printf(UNIT(s), rvalue, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
return 0;
}
r = socket_address_parse_and_warn(&p->address, k);
if (r < 0) {
if (r != -EAFNOSUPPORT)
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue);
-
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value in '%s', ignoring: %m", k);
return 0;
}
@@ -427,6 +416,8 @@ int config_parse_socket_listen(const char *unit,
log_syntax(unit, LOG_ERR, filename, line, 0, "Address family not supported, ignoring: %s", rvalue);
return 0;
}
+
+ p->type = SOCKET_SOCKET;
}
p->fd = -1;
@@ -442,72 +433,6 @@ int config_parse_socket_listen(const char *unit,
return 0;
}
-int config_parse_socket_protocol(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) {
- Socket *s;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- s = SOCKET(data);
-
- r = socket_protocol_from_name(rvalue);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid socket protocol, ignoring: %s", rvalue);
- return 0;
- } else if (!IN_SET(r, IPPROTO_UDPLITE, IPPROTO_SCTP)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Socket protocol not supported, ignoring: %s", rvalue);
- return 0;
- }
-
- s->socket_protocol = r;
-
- return 0;
-}
-
-int config_parse_socket_bind(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) {
-
- Socket *s;
- SocketAddressBindIPv6Only b;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- s = SOCKET(data);
-
- b = parse_socket_address_bind_ipv6_only_or_bool(rvalue);
- if (b < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
- return 0;
- }
-
- s->bind_ipv6_only = b;
-
- return 0;
-}
-
int config_parse_exec_nice(
const char *unit,
const char *filename,
@@ -528,13 +453,17 @@ int config_parse_exec_nice(
assert(rvalue);
assert(data);
+ if (isempty(rvalue)) {
+ c->nice_set = false;
+ return 0;
+ }
+
r = parse_nice(rvalue, &priority);
if (r < 0) {
if (r == -ERANGE)
log_syntax(unit, LOG_ERR, filename, line, r, "Nice priority out of range, ignoring: %s", rvalue);
else
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse nice priority, ignoring: %s", rvalue);
-
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse nice priority '%s', ignoring: %m", rvalue);
return 0;
}
@@ -544,16 +473,17 @@ int config_parse_exec_nice(
return 0;
}
-int config_parse_exec_oom_score_adjust(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_exec_oom_score_adjust(
+ 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) {
ExecContext *c = data;
int oa, r;
@@ -563,14 +493,17 @@ int config_parse_exec_oom_score_adjust(const char* unit,
assert(rvalue);
assert(data);
- r = safe_atoi(rvalue, &oa);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
+ if (isempty(rvalue)) {
+ c->oom_score_adjust_set = false;
return 0;
}
- if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "OOM score adjust value out of range, ignoring: %s", rvalue);
+ r = parse_oom_score_adjust(rvalue, &oa);
+ if (r < 0) {
+ if (r == -ERANGE)
+ log_syntax(unit, LOG_ERR, filename, line, r, "OOM score adjust value out of range, ignoring: %s", rvalue);
+ else
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value '%s', ignoring: %m", rvalue);
return 0;
}
@@ -662,7 +595,7 @@ int config_parse_exec(
r = unit_full_printf(u, f, &path);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to resolve unit specifiers on %s%s: %m",
+ "Failed to resolve unit specifiers in '%s'%s: %m",
f, ignore ? ", ignoring" : "");
return ignore ? 0 : -ENOEXEC;
}
@@ -670,29 +603,57 @@ int config_parse_exec(
if (isempty(path)) {
/* First word is either "-" or "@" with no command. */
log_syntax(unit, LOG_ERR, filename, line, 0,
- "Empty path in command line%s: \"%s\"",
+ "Empty path in command line%s: '%s'",
ignore ? ", ignoring" : "", rvalue);
return ignore ? 0 : -ENOEXEC;
}
if (!string_is_safe(path)) {
log_syntax(unit, LOG_ERR, filename, line, 0,
- "Executable path contains special characters%s: %s",
- ignore ? ", ignoring" : "", rvalue);
- return ignore ? 0 : -ENOEXEC;
- }
- if (!path_is_absolute(path)) {
- log_syntax(unit, LOG_ERR, filename, line, 0,
- "Executable path is not absolute%s: %s",
- ignore ? ", ignoring" : "", rvalue);
+ "Executable name contains special characters%s: %s",
+ ignore ? ", ignoring" : "", path);
return ignore ? 0 : -ENOEXEC;
}
if (endswith(path, "/")) {
log_syntax(unit, LOG_ERR, filename, line, 0,
"Executable path specifies a directory%s: %s",
- ignore ? ", ignoring" : "", rvalue);
+ ignore ? ", ignoring" : "", path);
return ignore ? 0 : -ENOEXEC;
}
+ if (!path_is_absolute(path)) {
+ const char *prefix;
+ bool found = false;
+
+ if (!filename_is_valid(path)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "Neither a valid executable name nor an absolute path%s: %s",
+ ignore ? ", ignoring" : "", path);
+ return ignore ? 0 : -ENOEXEC;
+ }
+
+ /* Resolve a single-component name to a full path */
+ NULSTR_FOREACH(prefix, DEFAULT_PATH_NULSTR) {
+ _cleanup_free_ char *fullpath = NULL;
+
+ fullpath = strjoin(prefix, "/", path);
+ if (!fullpath)
+ return log_oom();
+
+ if (access(fullpath, F_OK) >= 0) {
+ free_and_replace(path, fullpath);
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "Executable \"%s\" not found in path \"%s\"%s",
+ path, DEFAULT_PATH, ignore ? ", ignoring" : "");
+ return ignore ? 0 : -ENOEXEC;
+ }
+ }
+
if (!separate_argv0) {
char *w = NULL;
@@ -706,7 +667,7 @@ int config_parse_exec(
n[nlen] = NULL;
}
- path_kill_slashes(path);
+ path_simplify(path, false);
while (!isempty(p)) {
_cleanup_free_ char *word = NULL, *resolved = NULL;
@@ -748,16 +709,16 @@ int config_parse_exec(
r = unit_full_printf(u, word, &resolved);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to resolve unit specifiers on %s%s: %m",
+ "Failed to resolve unit specifiers in %s%s: %m",
word, ignore ? ", ignoring" : "");
return ignore ? 0 : -ENOEXEC;
}
if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
return log_oom();
- n[nlen++] = resolved;
+
+ n[nlen++] = TAKE_PTR(resolved);
n[nlen] = NULL;
- resolved = NULL;
}
if (!n || !n[0]) {
@@ -771,15 +732,13 @@ int config_parse_exec(
if (!nce)
return log_oom();
- nce->argv = n;
- nce->path = path;
+ nce->argv = TAKE_PTR(n);
+ nce->path = TAKE_PTR(path);
nce->flags = flags;
exec_command_append_list(e, nce);
/* Do not _cleanup_free_ these. */
- n = NULL;
- path = NULL;
nce = NULL;
rvalue = p;
@@ -788,9 +747,6 @@ int config_parse_exec(
return 0;
}
-DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
-DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
-
int config_parse_socket_bindtodevice(
const char* unit,
const char *filename,
@@ -804,27 +760,24 @@ int config_parse_socket_bindtodevice(
void *userdata) {
Socket *s = data;
- char *n;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
- if (rvalue[0] && !streq(rvalue, "*")) {
- if (!ifname_valid(rvalue)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is invalid, ignoring: %s", rvalue);
- return 0;
- }
+ if (isempty(rvalue) || streq(rvalue, "*")) {
+ s->bind_to_device = mfree(s->bind_to_device);
+ return 0;
+ }
- n = strdup(rvalue);
- if (!n)
- return log_oom();
- } else
- n = NULL;
+ if (!ifname_valid(rvalue)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid interface name, ignoring: %s", rvalue);
+ return 0;
+ }
- free(s->bind_to_device);
- s->bind_to_device = n;
+ if (free_and_strdup(&s->bind_to_device, rvalue) < 0)
+ return log_oom();
return 0;
}
@@ -858,13 +811,13 @@ int config_parse_exec_input(
r = unit_full_printf(u, n, &resolved);
if (r < 0)
- return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s: %m", n);
+ return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s': %m", n);
if (isempty(resolved))
resolved = mfree(resolved);
else if (!fdname_is_valid(resolved)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name: %s", resolved);
- return -EINVAL;
+ return -ENOEXEC;
}
free_and_replace(c->stdio_fdname[STDIN_FILENO], resolved);
@@ -876,17 +829,11 @@ int config_parse_exec_input(
r = unit_full_printf(u, n, &resolved);
if (r < 0)
- return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s: %m", n);
-
- if (!path_is_absolute(resolved)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "file: requires an absolute path name: %s", resolved);
- return -EINVAL;
- }
+ return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s': %m", n);
- if (!path_is_normalized(resolved)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "file: requires a normalized path name: %s", resolved);
- return -EINVAL;
- }
+ r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE | PATH_CHECK_FATAL, unit, filename, line, lvalue);
+ if (r < 0)
+ return -ENOEXEC;
free_and_replace(c->stdio_file[STDIN_FILENO], resolved);
@@ -937,11 +884,11 @@ int config_parse_exec_input_text(
r = cunescape(rvalue, 0, &unescaped);
if (r < 0)
- return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to decode C escaped text: %s", rvalue);
+ return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to decode C escaped text '%s': %m", rvalue);
r = unit_full_printf(u, unescaped, &resolved);
if (r < 0)
- return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers: %s", unescaped);
+ return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s': %m", unescaped);
sz = strlen(resolved);
if (c->stdin_data_size + sz + 1 < c->stdin_data_size || /* check for overflow */
@@ -1045,13 +992,13 @@ int config_parse_exec_output(
if (n) {
r = unit_full_printf(u, n, &resolved);
if (r < 0)
- return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s: %m", n);
+ return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", n);
if (isempty(resolved))
resolved = mfree(resolved);
else if (!fdname_is_valid(resolved)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name: %s", resolved);
- return -EINVAL;
+ return -ENOEXEC;
}
eo = EXEC_OUTPUT_NAMED_FD;
@@ -1060,17 +1007,11 @@ int config_parse_exec_output(
r = unit_full_printf(u, n, &resolved);
if (r < 0)
- return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s: %m", n);
-
- if (!path_is_absolute(resolved)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "file: requires an absolute path name: %s", resolved);
- return -EINVAL;
- }
+ return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", n);
- if (!path_is_normalized(resolved)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "file: requires a normalized path name, ignoring: %s", resolved);
- return -EINVAL;
- }
+ r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE | PATH_CHECK_FATAL, unit, filename, line, lvalue);
+ if (r < 0)
+ return -ENOEXEC;
eo = EXEC_OUTPUT_FILE;
@@ -1123,6 +1064,12 @@ int config_parse_exec_io_class(const char *unit,
assert(rvalue);
assert(data);
+ if (isempty(rvalue)) {
+ c->ioprio_set = false;
+ c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0);
+ return 0;
+ }
+
x = ioprio_class_from_string(rvalue);
if (x < 0) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue);
@@ -1154,6 +1101,12 @@ int config_parse_exec_io_priority(const char *unit,
assert(rvalue);
assert(data);
+ if (isempty(rvalue)) {
+ c->ioprio_set = false;
+ c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0);
+ return 0;
+ }
+
r = ioprio_parse_priority(rvalue, &i);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IO priority, ignoring: %s", rvalue);
@@ -1177,7 +1130,6 @@ int config_parse_exec_cpu_sched_policy(const char *unit,
void *data,
void *userdata) {
-
ExecContext *c = data;
int x;
@@ -1186,6 +1138,13 @@ int config_parse_exec_cpu_sched_policy(const char *unit,
assert(rvalue);
assert(data);
+ if (isempty(rvalue)) {
+ c->cpu_sched_set = false;
+ c->cpu_sched_policy = SCHED_OTHER;
+ c->cpu_sched_priority = 0;
+ return 0;
+ }
+
x = sched_policy_from_string(rvalue);
if (x < 0) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
@@ -1221,7 +1180,7 @@ int config_parse_exec_cpu_sched_prio(const char *unit,
r = safe_atoi(rvalue, &i);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU scheduling priority, ignoring: %s", rvalue);
return 0;
}
@@ -1272,8 +1231,7 @@ int config_parse_exec_cpu_affinity(const char *unit,
}
if (!c->cpuset) {
- c->cpuset = cpuset;
- cpuset = NULL;
+ c->cpuset = TAKE_PTR(cpuset);
c->cpuset_ncpus = (unsigned) ncpus;
return 0;
}
@@ -1281,8 +1239,7 @@ int config_parse_exec_cpu_affinity(const char *unit,
if (c->cpuset_ncpus < (unsigned) ncpus) {
CPU_OR_S(CPU_ALLOC_SIZE(c->cpuset_ncpus), cpuset, c->cpuset, cpuset);
CPU_FREE(c->cpuset);
- c->cpuset = cpuset;
- cpuset = NULL;
+ c->cpuset = TAKE_PTR(cpuset);
c->cpuset_ncpus = (unsigned) ncpus;
return 0;
}
@@ -1292,45 +1249,6 @@ int config_parse_exec_cpu_affinity(const char *unit,
return 0;
}
-int config_parse_exec_secure_bits(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) {
-
- ExecContext *c = data;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- /* An empty assignment resets the field */
- c->secure_bits = 0;
- return 0;
- }
-
- r = secure_bits_from_string(rvalue);
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0) {
- log_syntax(unit, LOG_WARNING, filename, line, r,
- "Invalid syntax, ignoring: %s", rvalue);
- return 0;
- }
-
- c->secure_bits = r;
-
- return 0;
-}
-
int config_parse_capability_set(
const char *unit,
const char *filename,
@@ -1363,10 +1281,8 @@ int config_parse_capability_set(
/* else "AmbientCapabilities" initialized to all bits off */
r = capability_set_from_string(rvalue, &sum);
- if (r == -ENOMEM)
- return log_oom();
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse word: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= specifier '%s', ignoring: %m", lvalue, rvalue);
return 0;
}
@@ -1384,109 +1300,6 @@ int config_parse_capability_set(
return 0;
}
-int config_parse_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) {
-
- struct rlimit **rl = data, d = {};
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- r = rlimit_parse(ltype, rvalue, &d);
- if (r == -EILSEQ) {
- log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
- return 0;
- }
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
- return 0;
- }
-
- if (rl[ltype])
- *rl[ltype] = d;
- else {
- rl[ltype] = newdup(struct rlimit, &d, 1);
- if (!rl[ltype])
- return log_oom();
- }
-
- return 0;
-}
-
-#if HAVE_SYSV_COMPAT
-int config_parse_sysv_priority(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 *priority = data;
- int i, r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- r = safe_atoi(rvalue, &i);
- if (r < 0 || i < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse SysV start priority, ignoring: %s", rvalue);
- return 0;
- }
-
- *priority = (int) i;
- return 0;
-}
-#endif
-
-DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode, "Failed to parse utmp mode");
-DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
-
-int config_parse_exec_mount_flags(
- 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) {
-
-
- ExecContext *c = data;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- r = mount_propagation_flags_from_string(rvalue, &c->mount_flags);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse mount flag %s, ignoring.", rvalue);
-
- return 0;
-}
-
int config_parse_exec_selinux_context(
const char *unit,
const char *filename,
@@ -1525,13 +1338,12 @@ int config_parse_exec_selinux_context(
r = unit_full_printf(u, rvalue, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to resolve specifiers%s: %m",
- ignore ? ", ignoring" : "");
+ "Failed to resolve unit specifiers in '%s'%s: %m",
+ rvalue, ignore ? ", ignoring" : "");
return ignore ? 0 : -ENOEXEC;
}
- free(c->selinux_context);
- c->selinux_context = k;
+ free_and_replace(c->selinux_context, k);
c->selinux_context_ignore = ignore;
return 0;
@@ -1575,13 +1387,12 @@ int config_parse_exec_apparmor_profile(
r = unit_full_printf(u, rvalue, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to resolve specifiers%s: %m",
- ignore ? ", ignoring" : "");
+ "Failed to resolve unit specifiers in '%s'%s: %m",
+ rvalue, ignore ? ", ignoring" : "");
return ignore ? 0 : -ENOEXEC;
}
- free(c->apparmor_profile);
- c->apparmor_profile = k;
+ free_and_replace(c->apparmor_profile, k);
c->apparmor_profile_ignore = ignore;
return 0;
@@ -1625,13 +1436,12 @@ int config_parse_exec_smack_process_label(
r = unit_full_printf(u, rvalue, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to resolve specifiers%s: %m",
- ignore ? ", ignoring" : "");
+ "Failed to resolve unit specifiers in '%s'%s: %m",
+ rvalue, ignore ? ", ignoring" : "");
return ignore ? 0 : -ENOEXEC;
}
- free(c->smack_process_label);
- c->smack_process_label = k;
+ free_and_replace(c->smack_process_label, k);
c->smack_process_label_ignore = ignore;
return 0;
@@ -1652,7 +1462,7 @@ int config_parse_timer(const char *unit,
usec_t usec = 0;
TimerValue *v;
TimerBase b;
- CalendarSpec *c = NULL;
+ _cleanup_(calendar_spec_freep) CalendarSpec *c = NULL;
Unit *u = userdata;
_cleanup_free_ char *k = NULL;
int r;
@@ -1676,7 +1486,7 @@ int config_parse_timer(const char *unit,
r = unit_full_printf(u, rvalue, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
return 0;
}
@@ -1685,22 +1495,19 @@ int config_parse_timer(const char *unit,
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse calendar specification, ignoring: %s", k);
return 0;
}
- } else {
+ } else
if (parse_sec(k, &usec) < 0) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer value, ignoring: %s", k);
return 0;
}
- }
v = new0(TimerValue, 1);
- if (!v) {
- calendar_spec_free(c);
+ if (!v)
return log_oom();
- }
v->base = b;
v->value = usec;
- v->calendar_spec = c;
+ v->calendar_spec = TAKE_PTR(c);
LIST_PREPEND(value, t->values, v);
@@ -1736,7 +1543,7 @@ int config_parse_trigger_unit(
r = unit_name_printf(u, rvalue, &p);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
return 0;
}
@@ -1795,22 +1602,20 @@ int config_parse_path_spec(const char *unit,
r = unit_full_printf(UNIT(p), rvalue, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
return 0;
}
- if (!path_is_absolute(k)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Path is not absolute, ignoring: %s", k);
+ r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
+ if (r < 0)
return 0;
- }
s = new0(PathSpec, 1);
if (!s)
return log_oom();
s->unit = UNIT(p);
- s->path = path_kill_slashes(k);
- k = NULL;
+ s->path = TAKE_PTR(k);
s->type = b;
s->inotify_fd = -1;
@@ -1844,7 +1649,7 @@ int config_parse_socket_service(
r = unit_name_printf(UNIT(s), rvalue, &p);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", rvalue);
return -ENOEXEC;
}
@@ -1892,7 +1697,7 @@ int config_parse_fdname(
r = unit_full_printf(UNIT(s), rvalue, &p);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
return 0;
}
@@ -1941,7 +1746,7 @@ int config_parse_service_sockets(
r = unit_name_printf(UNIT(s), word, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", word);
continue;
}
@@ -1985,12 +1790,12 @@ int config_parse_bus_name(
r = unit_full_printf(u, rvalue, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
return 0;
}
if (!service_name_is_valid(k)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid bus name %s, ignoring.", k);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid bus name, ignoring: %s", k);
return 0;
}
@@ -2018,26 +1823,21 @@ int config_parse_service_timeout(
assert(rvalue);
assert(s);
- /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
+ /* This is called for two cases: TimeoutSec= and TimeoutStartSec=. */
- r = parse_sec(rvalue, &usec);
+ /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
+ * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
+ * all other timeouts. */
+ r = parse_sec_fix_0(rvalue, &usec);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
return 0;
}
- /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
- * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
- * all other timeouts. */
- if (usec <= 0)
- usec = USEC_INFINITY;
+ s->start_timeout_defined = true;
+ s->timeout_start_usec = usec;
- if (!streq(lvalue, "TimeoutStopSec")) {
- s->start_timeout_defined = true;
- s->timeout_start_usec = usec;
- }
-
- if (!streq(lvalue, "TimeoutStartSec"))
+ if (streq(lvalue, "TimeoutSec"))
s->timeout_stop_usec = usec;
return 0;
@@ -2088,7 +1888,8 @@ int config_parse_user_group(
void *data,
void *userdata) {
- char **user = data, *n;
+ _cleanup_free_ char *k = NULL;
+ char **user = data;
Unit *u = userdata;
int r;
@@ -2097,30 +1898,23 @@ int config_parse_user_group(
assert(rvalue);
assert(u);
- if (isempty(rvalue))
- n = NULL;
- else {
- _cleanup_free_ char *k = NULL;
-
- r = unit_full_printf(u, rvalue, &k);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", rvalue);
- return -ENOEXEC;
- }
-
- if (!valid_user_group_name_or_id(k)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
- return -ENOEXEC;
- }
+ if (isempty(rvalue)) {
+ *user = mfree(*user);
+ return 0;
+ }
- n = k;
- k = NULL;
+ r = unit_full_printf(u, rvalue, &k);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", rvalue);
+ return -ENOEXEC;
}
- free(*user);
- *user = n;
+ if (!valid_user_group_name_or_id(k)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
+ return -ENOEXEC;
+ }
- return 0;
+ return free_and_replace(*user, k);
}
int config_parse_user_group_strv(
@@ -2137,7 +1931,7 @@ int config_parse_user_group_strv(
char ***users = data;
Unit *u = userdata;
- const char *p;
+ const char *p = rvalue;
int r;
assert(filename);
@@ -2150,7 +1944,6 @@ int config_parse_user_group_strv(
return 0;
}
- p = rvalue;
for (;;) {
_cleanup_free_ char *word = NULL, *k = NULL;
@@ -2208,6 +2001,12 @@ int config_parse_working_directory(
assert(c);
assert(u);
+ if (isempty(rvalue)) {
+ c->working_directory_home = false;
+ c->working_directory = mfree(c->working_directory);
+ return 0;
+ }
+
if (rvalue[0] == '-') {
missing_ok = true;
rvalue++;
@@ -2228,19 +2027,9 @@ int config_parse_working_directory(
return missing_ok ? 0 : -ENOEXEC;
}
- path_kill_slashes(k);
-
- if (!utf8_is_valid(k)) {
- log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
- return missing_ok ? 0 : -ENOEXEC;
- }
-
- if (!path_is_absolute(k)) {
- log_syntax(unit, LOG_ERR, filename, line, 0,
- "Working directory path '%s' is not absolute%s.",
- rvalue, missing_ok ? ", ignoring" : "");
+ r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE | (missing_ok ? 0 : PATH_CHECK_FATAL), unit, filename, line, lvalue);
+ if (r < 0)
return missing_ok ? 0 : -ENOEXEC;
- }
c->working_directory_home = false;
free_and_replace(c->working_directory, k);
@@ -2279,19 +2068,20 @@ int config_parse_unit_env_file(const char *unit,
r = unit_full_printf(u, rvalue, &n);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
return 0;
}
- if (!path_is_absolute(n[0] == '-' ? n + 1 : n)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Path '%s' is not absolute, ignoring.", n);
+ r = path_simplify_and_warn(n[0] == '-' ? n + 1 : n, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
+ if (r < 0)
return 0;
- }
- r = strv_extend(env, n);
+ r = strv_push(env, n);
if (r < 0)
return log_oom();
+ n = NULL;
+
return 0;
}
@@ -2341,13 +2131,11 @@ int config_parse_environ(
r = unit_full_printf(u, word, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to resolve specifiers, ignoring: %s", word);
+ "Failed to resolve unit specifiers in %s, ignoring: %m", word);
continue;
}
- } else {
- k = word;
- word = NULL;
- }
+ } else
+ k = TAKE_PTR(word);
if (!env_assignment_is_valid(k)) {
log_syntax(unit, LOG_ERR, filename, line, 0,
@@ -2375,10 +2163,10 @@ int config_parse_pass_environ(
void *data,
void *userdata) {
- const char *whole_rvalue = rvalue;
_cleanup_strv_free_ char **n = NULL;
size_t nlen = 0, nbufsize = 0;
char*** passenv = data;
+ const char *p = rvalue;
Unit *u = userdata;
int r;
@@ -2396,14 +2184,14 @@ int config_parse_pass_environ(
for (;;) {
_cleanup_free_ char *word = NULL, *k = NULL;
- r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES);
+ 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,
- "Trailing garbage in %s, ignoring: %s", lvalue, whole_rvalue);
+ "Trailing garbage in %s, ignoring: %s", lvalue, rvalue);
break;
}
@@ -2411,13 +2199,11 @@ int config_parse_pass_environ(
r = unit_full_printf(u, word, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to resolve specifiers, ignoring: %s", word);
+ "Failed to resolve specifiers in %s, ignoring: %m", word);
continue;
}
- } else {
- k = word;
- word = NULL;
- }
+ } else
+ k = TAKE_PTR(word);
if (!env_name_is_valid(k)) {
log_syntax(unit, LOG_ERR, filename, line, 0,
@@ -2428,9 +2214,8 @@ int config_parse_pass_environ(
if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
return log_oom();
- n[nlen++] = k;
+ n[nlen++] = TAKE_PTR(k);
n[nlen] = NULL;
- k = NULL;
}
if (n) {
@@ -2455,9 +2240,9 @@ int config_parse_unset_environ(
void *userdata) {
_cleanup_strv_free_ char **n = NULL;
- const char *whole_rvalue = rvalue;
size_t nlen = 0, nbufsize = 0;
char*** unsetenv = data;
+ const char *p = rvalue;
Unit *u = userdata;
int r;
@@ -2475,14 +2260,14 @@ int config_parse_unset_environ(
for (;;) {
_cleanup_free_ char *word = NULL, *k = NULL;
- r = extract_first_word(&rvalue, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_QUOTES);
+ r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_QUOTES);
if (r == 0)
break;
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "Trailing garbage in %s, ignoring: %s", lvalue, whole_rvalue);
+ "Trailing garbage in %s, ignoring: %s", lvalue, rvalue);
break;
}
@@ -2490,13 +2275,11 @@ int config_parse_unset_environ(
r = unit_full_printf(u, word, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to resolve specifiers, ignoring: %s", word);
+ "Failed to resolve unit specifiers in %s, ignoring: %m", word);
continue;
}
- } else {
- k = word;
- word = NULL;
- }
+ } else
+ k = TAKE_PTR(word);
if (!env_assignment_is_valid(k) && !env_name_is_valid(k)) {
log_syntax(unit, LOG_ERR, filename, line, 0,
@@ -2507,9 +2290,8 @@ int config_parse_unset_environ(
if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
return log_oom();
- n[nlen++] = k;
+ n[nlen++] = TAKE_PTR(k);
n[nlen] = NULL;
- k = NULL;
}
if (n) {
@@ -2535,7 +2317,7 @@ int config_parse_log_extra_fields(
ExecContext *c = data;
Unit *u = userdata;
- const char *p;
+ const char *p = rvalue;
int r;
assert(filename);
@@ -2548,14 +2330,14 @@ int config_parse_log_extra_fields(
return 0;
}
- for (p = rvalue;; ) {
+ for (;;) {
_cleanup_free_ char *word = NULL, *k = NULL;
struct iovec *t;
const char *eq;
r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_QUOTES);
if (r == 0)
- break;
+ return 0;
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
@@ -2565,18 +2347,18 @@ int config_parse_log_extra_fields(
r = unit_full_printf(u, word, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring field: %m", word);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", word);
continue;
}
eq = strchr(k, '=');
if (!eq) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Log field lacks '=' character, ignoring field: %s", k);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Log field lacks '=' character, ignoring: %s", k);
continue;
}
if (!journal_field_valid(k, eq-k, false)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Log field name is invalid, ignoring field: %s", k);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Log field name is invalid, ignoring: %s", k);
continue;
}
@@ -2589,36 +2371,6 @@ int config_parse_log_extra_fields(
k = NULL;
}
-
- return 0;
-}
-
-int config_parse_ip_tos(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 *ip_tos = data, x;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- x = ip_tos_from_string(rvalue);
- if (x < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue);
- return 0;
- }
-
- *ip_tos = x;
- return 0;
}
int config_parse_unit_condition_path(
@@ -2661,14 +2413,13 @@ int config_parse_unit_condition_path(
r = unit_full_printf(u, rvalue, &p);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
return 0;
}
- if (!path_is_absolute(p)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Path in condition not absolute, ignoring: %s", p);
+ r = path_simplify_and_warn(p, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
+ if (r < 0)
return 0;
- }
c = condition_new(t, p, trigger, negate);
if (!c)
@@ -2718,7 +2469,7 @@ int config_parse_unit_condition_string(
r = unit_full_printf(u, rvalue, &s);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
return 0;
}
@@ -2782,9 +2533,6 @@ int config_parse_unit_condition_null(
return 0;
}
-DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
-DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action, emergency_action, EmergencyAction, "Failed to parse failure action specifier");
-
int config_parse_unit_requires_mounts_for(
const char *unit,
const char *filename,
@@ -2797,8 +2545,8 @@ int config_parse_unit_requires_mounts_for(
void *data,
void *userdata) {
+ const char *p = rvalue;
Unit *u = userdata;
- const char *p;
int r;
assert(filename);
@@ -2806,7 +2554,7 @@ int config_parse_unit_requires_mounts_for(
assert(rvalue);
assert(data);
- for (p = rvalue;; ) {
+ for (;;) {
_cleanup_free_ char *word = NULL, *resolved = NULL;
r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
@@ -2820,20 +2568,19 @@ int config_parse_unit_requires_mounts_for(
return 0;
}
- if (!utf8_is_valid(word)) {
- log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
- continue;
- }
-
r = unit_full_printf(u, word, &resolved);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit name \"%s\", ignoring: %m", word);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", word);
continue;
}
+ r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
+ if (r < 0)
+ continue;
+
r = unit_require_mounts_for(u, resolved, UNIT_DEPENDENCY_FILE);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add required mount \"%s\", ignoring: %m", resolved);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add required mount '%s', ignoring: %m", resolved);
continue;
}
}
@@ -2947,12 +2694,12 @@ int config_parse_syscall_filter(
r = extract_first_word(&p, &word, NULL, 0);
if (r == 0)
- break;
+ return 0;
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
- break;
+ return 0;
}
r = parse_syscall_and_errno(word, &name, &num);
@@ -2967,8 +2714,6 @@ int config_parse_syscall_filter(
if (r < 0)
return r;
}
-
- return 0;
}
int config_parse_syscall_archs(
@@ -2983,8 +2728,8 @@ int config_parse_syscall_archs(
void *data,
void *userdata) {
+ const char *p = rvalue;
Set **archs = data;
- const char *p;
int r;
if (isempty(rvalue)) {
@@ -2996,7 +2741,7 @@ int config_parse_syscall_archs(
if (r < 0)
return log_oom();
- for (p = rvalue;;) {
+ for (;;) {
_cleanup_free_ char *word = NULL;
uint32_t a;
@@ -3116,9 +2861,9 @@ int config_parse_address_families(
}
af = af_from_name(word);
- if (af <= 0) {
+ if (af <= 0) {
log_syntax(unit, LOG_ERR, filename, line, 0,
- "Failed to parse address family \"%s\", ignoring: %m", word);
+ "Failed to parse address family, ignoring: %s", word);
continue;
}
@@ -3147,11 +2892,22 @@ int config_parse_restrict_namespaces(
void *userdata) {
ExecContext *c = data;
+ unsigned long flags;
bool invert = false;
int r;
if (isempty(rvalue)) {
/* Reset to the default. */
+ c->restrict_namespaces = NAMESPACE_FLAGS_INITIAL;
+ return 0;
+ }
+
+ /* Boolean parameter ignores the previous settings */
+ r = parse_boolean(rvalue);
+ if (r > 0) {
+ c->restrict_namespaces = 0;
+ return 0;
+ } else if (r == 0) {
c->restrict_namespaces = NAMESPACE_FLAGS_ALL;
return 0;
}
@@ -3161,23 +2917,19 @@ int config_parse_restrict_namespaces(
rvalue++;
}
- r = parse_boolean(rvalue);
- if (r > 0)
- c->restrict_namespaces = 0;
- else if (r == 0)
- c->restrict_namespaces = NAMESPACE_FLAGS_ALL;
- else {
- /* Not a boolean argument, in this case it's a list of namespace types. */
-
- r = namespace_flag_from_string_many(rvalue, &c->restrict_namespaces);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse namespace type string, ignoring: %s", rvalue);
- return 0;
- }
+ /* Not a boolean argument, in this case it's a list of namespace types. */
+ r = namespace_flags_from_string(rvalue, &flags);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse namespace type string, ignoring: %s", rvalue);
+ return 0;
}
- if (invert)
- c->restrict_namespaces = (~c->restrict_namespaces) & NAMESPACE_FLAGS_ALL;
+ if (c->restrict_namespaces == NAMESPACE_FLAGS_INITIAL)
+ /* Initial assignment. Just set the value. */
+ c->restrict_namespaces = invert ? (~flags) & NAMESPACE_FLAGS_ALL : flags;
+ else
+ /* Merge the value with the previous one. */
+ SET_FLAG(c->restrict_namespaces, flags, !invert);
return 0;
}
@@ -3195,6 +2947,7 @@ int config_parse_unit_slice(
void *data,
void *userdata) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *k = NULL;
Unit *u = userdata, *slice = NULL;
int r;
@@ -3206,77 +2959,19 @@ int config_parse_unit_slice(
r = unit_name_printf(u, rvalue, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
return 0;
}
- r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
+ r = manager_load_unit(u->manager, k, NULL, &error, &slice);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load slice unit %s. Ignoring.", k);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load slice unit %s, ignoring: %s", k, bus_error_message(&error, r));
return 0;
}
r = unit_set_slice(u, slice);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to assign slice %s to unit %s. Ignoring.", slice->id, u->id);
- return 0;
- }
-
- return 0;
-}
-
-DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
-
-int config_parse_cpu_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) {
-
- uint64_t *weight = data;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- r = cg_weight_parse(rvalue, weight);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "CPU weight '%s' invalid. Ignoring.", rvalue);
- return 0;
- }
-
- return 0;
-}
-
-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) {
-
- uint64_t *shares = data;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- r = cg_cpu_shares_parse(rvalue, shares);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "CPU shares '%s' invalid. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to assign slice %s to unit %s, ignoring: %m", slice->id, u->id);
return 0;
}
@@ -3309,7 +3004,7 @@ int config_parse_cpu_quota(
r = parse_percent_unbounded(rvalue);
if (r <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "CPU quota '%s' invalid. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Invalid CPU quota '%s', ignoring.", rvalue);
return 0;
}
@@ -3339,14 +3034,15 @@ int config_parse_memory_limit(
if (r < 0) {
r = parse_size(rvalue, 1024, &bytes);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Invalid memory limit '%s', ignoring: %m", rvalue);
return 0;
}
} else
bytes = physical_memory_scale(r, 100U);
- if (bytes <= 0 || bytes >= UINT64_MAX) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Memory limit '%s' out of range. Ignoring.", rvalue);
+ if (bytes >= UINT64_MAX ||
+ (bytes <= 0 && !streq(lvalue, "MemorySwapMax"))) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Memory limit '%s' out of range, ignoring.", rvalue);
return 0;
}
}
@@ -3397,14 +3093,14 @@ int config_parse_tasks_max(
if (r < 0) {
r = safe_atou64(rvalue, &v);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Invalid maximum tasks value '%s', ignoring: %m", rvalue);
return 0;
}
} else
v = system_tasks_max_scale(r, 100U);
if (v <= 0 || v >= UINT64_MAX) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Maximum tasks value '%s' out of range, ignoring.", rvalue);
return 0;
}
@@ -3425,13 +3121,23 @@ int config_parse_delegate(
void *userdata) {
CGroupContext *c = data;
+ UnitType t;
int r;
+ t = unit_name_to_type(unit);
+ assert(t != _UNIT_TYPE_INVALID);
+
+ if (!unit_vtable[t]->can_delegate) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Delegate= setting not supported for this unit type, ignoring.");
+ return 0;
+ }
+
/* 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. */
if (isempty(rvalue)) {
+ /* An empty string resets controllers and set Delegate=yes. */
c->delegate = true;
c->delegate_controllers = 0;
return 0;
@@ -3453,12 +3159,12 @@ int config_parse_delegate(
return log_oom();
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
- return r;
+ return 0;
}
cc = cgroup_controller_from_string(word);
if (cc < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Invalid controller name '%s', ignoring", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Invalid controller name '%s', ignoring", word);
continue;
}
@@ -3491,11 +3197,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)) {
@@ -3505,31 +3210,41 @@ 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 (!startswith(resolved, "block-") && !startswith(resolved, "char-")) {
+
+ r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
+ if (r < 0)
+ return 0;
+
+ if (!valid_device_node_path(resolved)) {
+ 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;
}
@@ -3537,44 +3252,15 @@ int config_parse_device_allow(
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');
+ 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;
}
-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) {
-
- uint64_t *weight = data;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- r = cg_weight_parse(rvalue, weight);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", rvalue);
- return 0;
- }
-
- return 0;
-}
-
int config_parse_io_device_weight(
const char *unit,
const char *filename,
@@ -3587,12 +3273,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);
@@ -3606,28 +3291,34 @@ 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.");
+ 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,
+ "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;
}
- path = strndup(rvalue, n);
- if (!path)
- 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);
+ 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;
}
- r = cg_weight_parse(weight, &u);
+ r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
+ if (r < 0)
+ return 0;
+
+ r = cg_weight_parse(p, &u);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", weight);
+ log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid, ignoring: %m", p);
return 0;
}
@@ -3637,9 +3328,7 @@ int config_parse_io_device_weight(
if (!w)
return log_oom();
- w->path = path;
- path = NULL;
-
+ w->path = TAKE_PTR(resolved);
w->weight = u;
LIST_PREPEND(device_weights, c->io_device_weights, w);
@@ -3658,13 +3347,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);
@@ -3680,37 +3368,43 @@ 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.");
+ 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,
+ "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;
}
- path = strndup(rvalue, n);
- if (!path)
- 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);
+ 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 (streq("infinity", limit)) {
+ r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
+ if (r < 0)
+ return 0;
+
+ if (streq("infinity", p))
num = CGROUP_LIMIT_MAX;
- } else {
- r = parse_size(limit, 1000, &num);
+ else {
+ 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;
}
@@ -3723,8 +3417,7 @@ int config_parse_io_limit(
if (!l)
return log_oom();
- l->path = path;
- path = NULL;
+ l->path = TAKE_PTR(resolved);
for (ttype = 0; ttype < _CGROUP_IO_LIMIT_TYPE_MAX; ttype++)
l->limits[ttype] = cgroup_io_limit_defaults[ttype];
@@ -3736,34 +3429,6 @@ int config_parse_io_limit(
return 0;
}
-int config_parse_blockio_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) {
-
- uint64_t *weight = data;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- r = cg_blkio_weight_parse(rvalue, weight);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", rvalue);
- return 0;
- }
-
- return 0;
-}
-
int config_parse_blockio_device_weight(
const char *unit,
const char *filename,
@@ -3776,12 +3441,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);
@@ -3795,28 +3459,34 @@ 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.");
+ 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,
+ "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;
}
- path = strndup(rvalue, n);
- if (!path)
- 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);
+ 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;
}
- r = cg_blkio_weight_parse(weight, &u);
+ r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
+ if (r < 0)
+ return 0;
+
+ r = cg_blkio_weight_parse(p, &u);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", weight);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Invalid block IO weight '%s', ignoring: %m", p);
return 0;
}
@@ -3826,9 +3496,7 @@ int config_parse_blockio_device_weight(
if (!w)
return log_oom();
- w->path = path;
- path = NULL;
-
+ w->path = TAKE_PTR(resolved);
w->weight = u;
LIST_PREPEND(device_weights, c->blockio_device_weights, w);
@@ -3847,13 +3515,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);
@@ -3870,33 +3537,39 @@ 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.");
+ 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,
+ "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;
}
- path = strndup(rvalue, n);
- if (!path)
- 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);
+ 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;
}
- r = parse_size(bandwidth, 1000, &bytes);
+ r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
+ if (r < 0)
+ 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;
}
@@ -3907,8 +3580,7 @@ int config_parse_blockio_bandwidth(
if (!b)
return log_oom();
- b->path = path;
- path = NULL;
+ b->path = TAKE_PTR(resolved);
b->rbps = CGROUP_LIMIT_MAX;
b->wbps = CGROUP_LIMIT_MAX;
@@ -3923,8 +3595,6 @@ int config_parse_blockio_bandwidth(
return 0;
}
-DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
-
int config_parse_job_mode_isolate(
const char *unit,
const char *filename,
@@ -3956,8 +3626,6 @@ int config_parse_job_mode_isolate(
return 0;
}
-DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode, exec_preserve_mode, ExecPreserveMode, "Failed to parse runtime directory preserve mode");
-
int config_parse_exec_directories(
const char *unit,
const char *filename,
@@ -4003,13 +3671,17 @@ int config_parse_exec_directories(
r = unit_full_printf(u, word, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to resolve specifiers in \"%s\", ignoring: %m", word);
+ "Failed to resolve unit specifiers in \"%s\", ignoring: %m", word);
continue;
}
- if (!path_is_normalized(k) || path_is_absolute(k)) {
+ r = path_simplify_and_warn(k, PATH_CHECK_RELATIVE, unit, filename, line, lvalue);
+ if (r < 0)
+ continue;
+
+ if (path_startswith(k, "private")) {
log_syntax(unit, LOG_ERR, filename, line, 0,
- "%s= path is not valid, ignoring assignment: %s", lvalue, rvalue);
+ "%s= path can't be 'private', ingoring assignment: %s", lvalue, word);
continue;
}
@@ -4059,7 +3731,7 @@ int config_parse_set_status(
r = safe_atoi(temp, &val);
if (r < 0) {
- val = signal_from_string_try_harder(temp);
+ val = signal_from_string(temp);
if (val <= 0) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse value, ignoring: %s", word);
@@ -4079,10 +3751,8 @@ int config_parse_set_status(
return log_oom();
r = set_put(*set, INT_TO_PTR(val));
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Unable to store: %s", word);
- return r;
- }
+ if (r < 0)
+ return log_oom();
}
if (!isempty(state))
log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
@@ -4104,7 +3774,7 @@ int config_parse_namespace_path_strv(
Unit *u = userdata;
char*** sv = data;
- const char *cur;
+ const char *p = rvalue;
int r;
assert(filename);
@@ -4118,13 +3788,12 @@ int config_parse_namespace_path_strv(
return 0;
}
- cur = rvalue;
for (;;) {
_cleanup_free_ char *word = NULL, *resolved = NULL, *joined = NULL;
const char *w;
bool ignore_enoent = false, shall_prefix = false;
- r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
if (r == 0)
break;
if (r == -ENOMEM)
@@ -4134,11 +3803,6 @@ int config_parse_namespace_path_strv(
return 0;
}
- if (!utf8_is_valid(word)) {
- log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
- continue;
- }
-
w = word;
if (startswith(w, "-")) {
ignore_enoent = true;
@@ -4151,16 +3815,13 @@ int config_parse_namespace_path_strv(
r = unit_full_printf(u, w, &resolved);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers in %s: %m", word);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", w);
continue;
}
- if (!path_is_absolute(resolved)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", resolved);
+ r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
+ if (r < 0)
continue;
- }
-
- path_kill_slashes(resolved);
joined = strjoin(ignore_enoent ? "-" : "",
shall_prefix ? "+" : "",
@@ -4190,7 +3851,7 @@ int config_parse_temporary_filesystems(
Unit *u = userdata;
ExecContext *c = data;
- const char *cur;
+ const char *p = rvalue;
int r;
assert(filename);
@@ -4206,14 +3867,13 @@ int config_parse_temporary_filesystems(
return 0;
}
- cur = rvalue;
for (;;) {
_cleanup_free_ char *word = NULL, *path = NULL, *resolved = NULL;
const char *w;
- r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
if (r == 0)
- break;
+ return 0;
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
@@ -4223,23 +3883,26 @@ int config_parse_temporary_filesystems(
w = word;
r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
- if (r < 0)
- return r;
- if (r == 0)
- return -EINVAL;
-
- r = unit_full_printf(u, path, &resolved);
+ if (r == -ENOMEM)
+ return log_oom();
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers in %s, ignoring: %m", word);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract first word, ignoring: %s", word);
+ continue;
+ }
+ if (r == 0) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring: %s", word);
continue;
}
- if (!path_is_absolute(resolved)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", resolved);
+ r = unit_full_printf(u, path, &resolved);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", path);
continue;
}
- path_kill_slashes(resolved);
+ r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
+ if (r < 0)
+ continue;
r = temporary_filesystem_add(&c->temporary_filesystems, &c->n_temporary_filesystems, path, w);
if (r == -ENOMEM)
@@ -4249,8 +3912,6 @@ int config_parse_temporary_filesystems(
continue;
}
}
-
- return 0;
}
int config_parse_bind_paths(
@@ -4296,15 +3957,15 @@ int config_parse_bind_paths(
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s: %s", lvalue, rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s, ignoring: %s", lvalue, rvalue);
return 0;
}
r = unit_full_printf(u, source, &sresolved);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to resolved specifiers in \"%s\", ignoring: %m", source);
- return 0;
+ "Failed to resolved unit specifiers in \"%s\", ignoring: %m", source);
+ continue;
}
s = sresolved;
@@ -4313,16 +3974,9 @@ int config_parse_bind_paths(
s++;
}
- if (!utf8_is_valid(s)) {
- log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, s);
- return 0;
- }
- if (!path_is_absolute(s)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute source path, ignoring: %s", s);
- return 0;
- }
-
- path_kill_slashes(s);
+ r = path_simplify_and_warn(s, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
+ if (r < 0)
+ continue;
/* Optionally, the destination is specified. */
if (p && p[-1] == ':') {
@@ -4330,31 +3984,26 @@ int config_parse_bind_paths(
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s: %s", lvalue, rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s, ignoring: %s", lvalue, rvalue);
return 0;
}
if (r == 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Missing argument after ':': %s", rvalue);
- return 0;
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Missing argument after ':', ignoring: %s", s);
+ continue;
}
r = unit_full_printf(u, destination, &dresolved);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to resolved specifiers in \"%s\", ignoring: %m", destination);
- return 0;
+ continue;
}
- if (!utf8_is_valid(dresolved)) {
- log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, dresolved);
- return 0;
- }
- if (!path_is_absolute(dresolved)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute destination path, ignoring: %s", dresolved);
- return 0;
- }
+ r = path_simplify_and_warn(dresolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
+ if (r < 0)
+ continue;
- d = path_kill_slashes(dresolved);
+ d = dresolved;
/* Optionally, there's also a short option string specified */
if (p && p[-1] == ':') {
@@ -4374,7 +4023,7 @@ int config_parse_bind_paths(
rbind = false;
else {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid option string, ignoring setting: %s", options);
- return 0;
+ continue;
}
}
} else
@@ -4395,107 +4044,6 @@ int config_parse_bind_paths(
return 0;
}
-int config_parse_no_new_privileges(
- 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) {
-
- ExecContext *c = data;
- int k;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- k = parse_boolean(rvalue);
- if (k < 0) {
- log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
- return 0;
- }
-
- c->no_new_privileges = k;
-
- return 0;
-}
-
-int config_parse_protect_home(
- 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) {
-
- ExecContext *c = data;
- ProtectHome h;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- /* Our enum shall be a superset of booleans, hence first try
- * to parse as boolean, and then as enum */
-
- h = parse_protect_home_or_bool(rvalue);
- if (h < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue);
- return 0;
- }
-
- c->protect_home = h;
-
- return 0;
-}
-
-int config_parse_protect_system(
- 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) {
-
- ExecContext *c = data;
- ProtectSystem s;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- /* Our enum shall be a superset of booleans, hence first try
- * to parse as boolean, and then as enum */
-
- s = parse_protect_system_or_bool(rvalue);
- if (s < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue);
- return 0;
- }
-
- c->protect_system = s;
-
- return 0;
-}
-
-DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_keyring_mode, exec_keyring_mode, ExecKeyringMode, "Failed to parse keyring mode");
-
int config_parse_job_timeout_sec(
const char* unit,
const char *filename,
@@ -4590,7 +4138,7 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
if (c++ >= FOLLOW_MAX)
return -ELOOP;
- path_kill_slashes(*filename);
+ path_simplify(*filename, false);
/* Add the file name we are currently looking at to
* the names of this unit, but only if it is a valid
@@ -4623,8 +4171,7 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
if (r < 0)
return r;
- free(*filename);
- *filename = target;
+ free_and_replace(*filename, target);
}
f = fdopen(fd, "re");
@@ -4798,9 +4345,7 @@ static int load_from_path(Unit *u, const char *path) {
return r;
}
- free(u->fragment_path);
- u->fragment_path = filename;
- filename = NULL;
+ free_and_replace(u->fragment_path, filename);
if (u->source_path) {
if (stat(u->source_path, &st) >= 0)
@@ -4907,9 +4452,7 @@ void unit_dump_config_items(FILE *f) {
const ConfigParserCallback callback;
const char *rvalue;
} table[] = {
-#if !HAVE_SYSV_COMPAT || !HAVE_SECCOMP || !HAVE_PAM || !HAVE_SELINUX || !ENABLE_SMACK || !HAVE_APPARMOR
{ config_parse_warn_compat, "NOTSUPPORTED" },
-#endif
{ config_parse_int, "INTEGER" },
{ config_parse_unsigned, "UNSIGNED" },
{ config_parse_iec_size, "SIZE" },
@@ -4935,14 +4478,11 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_log_level, "LEVEL" },
{ config_parse_exec_secure_bits, "SECUREBITS" },
{ config_parse_capability_set, "BOUNDINGSET" },
- { config_parse_limit, "LIMIT" },
+ { config_parse_rlimit, "LIMIT" },
{ config_parse_unit_deps, "UNIT [...]" },
{ config_parse_exec, "PATH [ARGUMENT [...]]" },
{ config_parse_service_type, "SERVICETYPE" },
{ config_parse_service_restart, "SERVICERESTART" },
-#if HAVE_SYSV_COMPAT
- { config_parse_sysv_priority, "SYSVPRIORITY" },
-#endif
{ config_parse_kill_mode, "KILLMODE" },
{ config_parse_signal, "SIGNAL" },
{ config_parse_socket_listen, "SOCKET [...]" },
@@ -4978,12 +4518,11 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_restrict_namespaces, "NAMESPACES" },
#endif
{ config_parse_cpu_shares, "SHARES" },
- { config_parse_cpu_weight, "WEIGHT" },
+ { config_parse_cg_weight, "WEIGHT" },
{ config_parse_memory_limit, "LIMIT" },
{ config_parse_device_allow, "DEVICE" },
{ config_parse_device_policy, "POLICY" },
{ config_parse_io_limit, "LIMIT" },
- { config_parse_io_weight, "WEIGHT" },
{ config_parse_io_device_weight, "DEVICEWEIGHT" },
{ config_parse_blockio_bandwidth, "BANDWIDTH" },
{ config_parse_blockio_weight, "WEIGHT" },
@@ -5005,13 +4544,24 @@ void unit_dump_config_items(FILE *f) {
NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
const char *rvalue = "OTHER", *lvalue;
- unsigned j;
+ const ConfigPerfItem *p;
size_t prefix_len;
const char *dot;
- const ConfigPerfItem *p;
+ unsigned j;
assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
+ /* Hide legacy settings */
+ if (p->parse == config_parse_warn_compat &&
+ p->ltype == DISABLED_LEGACY)
+ continue;
+
+ for (j = 0; j < ELEMENTSOF(table); j++)
+ if (p->parse == table[j].callback) {
+ rvalue = table[j].rvalue;
+ break;
+ }
+
dot = strchr(i, '.');
lvalue = dot ? dot + 1 : i;
prefix_len = dot-i;
@@ -5024,12 +4574,6 @@ void unit_dump_config_items(FILE *f) {
fprintf(f, "[%.*s]\n", (int) prefix_len, i);
}
- for (j = 0; j < ELEMENTSOF(table); j++)
- if (p->parse == table[j].callback) {
- rvalue = table[j].rvalue;
- break;
- }
-
fprintf(f, "%s=%s\n", lvalue, rvalue);
prev = i;
}
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 163b5ce485..dad281ef72 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -1,25 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
+#include "conf-parser.h"
#include "unit.h"
/* Read service data from .desktop file style configuration fragments */
@@ -28,110 +10,99 @@ int unit_load_fragment(Unit *u);
void unit_dump_config_items(FILE *f);
-int config_parse_warn_compat(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_unit_deps(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_obsolete_unit_deps(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_unit_string_printf(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_unit_strv_printf(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_unit_path_printf(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_unit_path_strv_printf(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_documentation(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_socket_listen(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_socket_protocol(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_socket_bind(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_exec_nice(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_exec_oom_score_adjust(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_exec(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_service_timeout(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_service_type(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_service_restart(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_socket_bindtodevice(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_exec_output(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_exec_input(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_exec_input_text(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_exec_input_data(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_exec_io_class(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_exec_io_priority(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_exec_cpu_sched_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_exec_cpu_sched_prio(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_exec_cpu_affinity(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_exec_secure_bits(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_capability_set(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_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_sysv_priority(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_kill_signal(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_exec_mount_flags(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_timer(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_trigger_unit(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_path_spec(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_socket_service(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_service_sockets(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_unit_env_file(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_ip_tos(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_unit_condition_path(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_unit_condition_string(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_unit_condition_null(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_kill_mode(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_notify_access(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_emergency_action(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_unit_requires_mounts_for(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_syscall_filter(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_syscall_archs(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_syscall_errno(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_environ(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_pass_environ(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_unset_environ(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_unit_slice(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_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_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_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_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_device_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_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_blockio_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_blockio_device_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_blockio_bandwidth(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_netclass(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_job_mode(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_job_mode_isolate(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_exec_selinux_context(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_exec_apparmor_profile(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_exec_smack_process_label(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_address_families(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_runtime_preserve_mode(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_exec_directories(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_set_status(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_namespace_path_strv(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_temporary_filesystems(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_no_new_privileges(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_quota(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_protect_home(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_protect_system(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_bus_name(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_exec_utmp_mode(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_working_directory(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_fdname(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_sec_fix_0(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_user_group(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_user_group_strv(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_restrict_namespaces(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_bind_paths(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_exec_keyring_mode(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_job_timeout_sec(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_job_running_timeout_sec(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_log_extra_fields(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_collect_mode(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);
+CONFIG_PARSER_PROTOTYPE(config_parse_unit_deps);
+CONFIG_PARSER_PROTOTYPE(config_parse_obsolete_unit_deps);
+CONFIG_PARSER_PROTOTYPE(config_parse_unit_string_printf);
+CONFIG_PARSER_PROTOTYPE(config_parse_unit_strv_printf);
+CONFIG_PARSER_PROTOTYPE(config_parse_unit_path_printf);
+CONFIG_PARSER_PROTOTYPE(config_parse_unit_path_strv_printf);
+CONFIG_PARSER_PROTOTYPE(config_parse_documentation);
+CONFIG_PARSER_PROTOTYPE(config_parse_socket_listen);
+CONFIG_PARSER_PROTOTYPE(config_parse_socket_protocol);
+CONFIG_PARSER_PROTOTYPE(config_parse_socket_bind);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_nice);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_oom_score_adjust);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec);
+CONFIG_PARSER_PROTOTYPE(config_parse_service_timeout);
+CONFIG_PARSER_PROTOTYPE(config_parse_service_type);
+CONFIG_PARSER_PROTOTYPE(config_parse_service_restart);
+CONFIG_PARSER_PROTOTYPE(config_parse_socket_bindtodevice);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_output);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_input);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_input_text);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_input_data);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_io_class);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_io_priority);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_sched_policy);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_sched_prio);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_affinity);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_secure_bits);
+CONFIG_PARSER_PROTOTYPE(config_parse_capability_set);
+CONFIG_PARSER_PROTOTYPE(config_parse_kill_signal);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_mount_flags);
+CONFIG_PARSER_PROTOTYPE(config_parse_timer);
+CONFIG_PARSER_PROTOTYPE(config_parse_trigger_unit);
+CONFIG_PARSER_PROTOTYPE(config_parse_path_spec);
+CONFIG_PARSER_PROTOTYPE(config_parse_socket_service);
+CONFIG_PARSER_PROTOTYPE(config_parse_service_sockets);
+CONFIG_PARSER_PROTOTYPE(config_parse_unit_env_file);
+CONFIG_PARSER_PROTOTYPE(config_parse_ip_tos);
+CONFIG_PARSER_PROTOTYPE(config_parse_unit_condition_path);
+CONFIG_PARSER_PROTOTYPE(config_parse_unit_condition_string);
+CONFIG_PARSER_PROTOTYPE(config_parse_unit_condition_null);
+CONFIG_PARSER_PROTOTYPE(config_parse_kill_mode);
+CONFIG_PARSER_PROTOTYPE(config_parse_notify_access);
+CONFIG_PARSER_PROTOTYPE(config_parse_emergency_action);
+CONFIG_PARSER_PROTOTYPE(config_parse_unit_requires_mounts_for);
+CONFIG_PARSER_PROTOTYPE(config_parse_syscall_filter);
+CONFIG_PARSER_PROTOTYPE(config_parse_syscall_archs);
+CONFIG_PARSER_PROTOTYPE(config_parse_syscall_errno);
+CONFIG_PARSER_PROTOTYPE(config_parse_environ);
+CONFIG_PARSER_PROTOTYPE(config_parse_pass_environ);
+CONFIG_PARSER_PROTOTYPE(config_parse_unset_environ);
+CONFIG_PARSER_PROTOTYPE(config_parse_unit_slice);
+CONFIG_PARSER_PROTOTYPE(config_parse_cg_weight);
+CONFIG_PARSER_PROTOTYPE(config_parse_cpu_shares);
+CONFIG_PARSER_PROTOTYPE(config_parse_memory_limit);
+CONFIG_PARSER_PROTOTYPE(config_parse_tasks_max);
+CONFIG_PARSER_PROTOTYPE(config_parse_delegate);
+CONFIG_PARSER_PROTOTYPE(config_parse_device_policy);
+CONFIG_PARSER_PROTOTYPE(config_parse_device_allow);
+CONFIG_PARSER_PROTOTYPE(config_parse_io_device_weight);
+CONFIG_PARSER_PROTOTYPE(config_parse_io_limit);
+CONFIG_PARSER_PROTOTYPE(config_parse_blockio_weight);
+CONFIG_PARSER_PROTOTYPE(config_parse_blockio_device_weight);
+CONFIG_PARSER_PROTOTYPE(config_parse_blockio_bandwidth);
+CONFIG_PARSER_PROTOTYPE(config_parse_netclass);
+CONFIG_PARSER_PROTOTYPE(config_parse_job_mode);
+CONFIG_PARSER_PROTOTYPE(config_parse_job_mode_isolate);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_selinux_context);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_apparmor_profile);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_smack_process_label);
+CONFIG_PARSER_PROTOTYPE(config_parse_address_families);
+CONFIG_PARSER_PROTOTYPE(config_parse_runtime_preserve_mode);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_directories);
+CONFIG_PARSER_PROTOTYPE(config_parse_set_status);
+CONFIG_PARSER_PROTOTYPE(config_parse_namespace_path_strv);
+CONFIG_PARSER_PROTOTYPE(config_parse_temporary_filesystems);
+CONFIG_PARSER_PROTOTYPE(config_parse_cpu_quota);
+CONFIG_PARSER_PROTOTYPE(config_parse_protect_home);
+CONFIG_PARSER_PROTOTYPE(config_parse_protect_system);
+CONFIG_PARSER_PROTOTYPE(config_parse_bus_name);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_utmp_mode);
+CONFIG_PARSER_PROTOTYPE(config_parse_working_directory);
+CONFIG_PARSER_PROTOTYPE(config_parse_fdname);
+CONFIG_PARSER_PROTOTYPE(config_parse_sec_fix_0);
+CONFIG_PARSER_PROTOTYPE(config_parse_user_group);
+CONFIG_PARSER_PROTOTYPE(config_parse_user_group_strv);
+CONFIG_PARSER_PROTOTYPE(config_parse_restrict_namespaces);
+CONFIG_PARSER_PROTOTYPE(config_parse_bind_paths);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_keyring_mode);
+CONFIG_PARSER_PROTOTYPE(config_parse_job_timeout_sec);
+CONFIG_PARSER_PROTOTYPE(config_parse_job_running_timeout_sec);
+CONFIG_PARSER_PROTOTYPE(config_parse_log_extra_fields);
+CONFIG_PARSER_PROTOTYPE(config_parse_collect_mode);
/* gperf prototypes */
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
extern const char load_fragment_gperf_nulstr[];
-
-typedef enum Disabled {
- DISABLED_CONFIGURATION,
- DISABLED_LEGACY,
- DISABLED_EXPERIMENTAL,
-} Disabled;
diff --git a/src/core/locale-setup.c b/src/core/locale-setup.c
index 0c43cf2418..c14523fee9 100644
--- a/src/core/locale-setup.c
+++ b/src/core/locale-setup.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
#include <stdlib.h>
@@ -37,7 +19,7 @@ int locale_setup(char ***environment) {
int r = 0, i;
if (detect_container() <= 0) {
- r = parse_env_file("/proc/cmdline", WHITESPACE,
+ r = parse_env_file(NULL, "/proc/cmdline", WHITESPACE,
"locale.LANG", &variables[VARIABLE_LANG],
"locale.LANGUAGE", &variables[VARIABLE_LANGUAGE],
"locale.LC_CTYPE", &variables[VARIABLE_LC_CTYPE],
@@ -61,7 +43,7 @@ int locale_setup(char ***environment) {
/* Hmm, nothing set on the kernel cmd line? Then let's
* try /etc/locale.conf */
if (r <= 0) {
- r = parse_env_file("/etc/locale.conf", NEWLINE,
+ r = parse_env_file(NULL, "/etc/locale.conf", NEWLINE,
"LANG", &variables[VARIABLE_LANG],
"LANGUAGE", &variables[VARIABLE_LANGUAGE],
"LC_CTYPE", &variables[VARIABLE_LC_CTYPE],
@@ -110,8 +92,7 @@ int locale_setup(char ***environment) {
goto finish;
}
- strv_free(*environment);
- *environment = e;
+ strv_free_and_replace(*environment, e);
}
r = 0;
diff --git a/src/core/locale-setup.h b/src/core/locale-setup.h
index c1bee3812b..01fadd06c7 100644
--- a/src/core/locale-setup.h
+++ b/src/core/locale-setup.h
@@ -1,23 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
int locale_setup(char ***environment);
diff --git a/src/core/loopback-setup.c b/src/core/loopback-setup.c
index 1528034e81..835553ec8f 100644
--- a/src/core/loopback-setup.c
+++ b/src/core/loopback-setup.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <net/if.h>
#include <stdlib.h>
diff --git a/src/core/loopback-setup.h b/src/core/loopback-setup.h
index 9fac0189e4..c0eea100ed 100644
--- a/src/core/loopback-setup.h
+++ b/src/core/loopback-setup.h
@@ -1,23 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
int loopback_setup(void);
diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c
index 1b7424800c..11528f83c4 100644
--- a/src/core/machine-id-setup.c
+++ b/src/core/machine-id-setup.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <fcntl.h>
#include <sched.h>
diff --git a/src/core/machine-id-setup.h b/src/core/machine-id-setup.h
index cbd83ba270..d6ac62a882 100644
--- a/src/core/machine-id-setup.h
+++ b/src/core/machine-id-setup.h
@@ -1,24 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
int machine_id_commit(const char *root);
int machine_id_setup(const char *root, sd_id128_t requested, sd_id128_t *ret);
diff --git a/src/core/macros.systemd.in b/src/core/macros.systemd.in
index 4e27e1b06a..f3b74f4273 100644
--- a/src/core/macros.systemd.in
+++ b/src/core/macros.systemd.in
@@ -4,19 +4,6 @@
# This file is part of systemd.
#
# Copyright 2012 Lennart Poettering
-#
-# systemd is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation; either version 2.1 of the License, or
-# (at your option) any later version.
-#
-# systemd is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with systemd; If not, see <http://www.gnu.org/licenses/>.
# RPM macros for packages installing systemd unit files
@@ -27,10 +14,13 @@
%_udevhwdbdir @udevhwdbdir@
%_udevrulesdir @udevrulesdir@
%_journalcatalogdir @catalogdir@
-%_tmpfilesdir @tmpfilesdir@
-%_sysusersdir @sysusersdir@
-%_sysctldir @sysctldir@
%_binfmtdir @binfmtdir@
+%_sysctldir @sysctldir@
+%_sysusersdir @sysusersdir@
+%_tmpfilesdir @tmpfilesdir@
+%_environmnentdir @environmentdir@
+%_modulesloaddir @modulesloaddir@
+%_modprobedir @modprobedir@
%_systemdgeneratordir @systemgeneratordir@
%_systemdusergeneratordir @usergeneratordir@
%_systemd_system_env_generator_dir @systemenvgeneratordir@
@@ -51,23 +41,23 @@ OrderWithRequires(postun): systemd \
%systemd_post() \
if [ $1 -eq 1 ] ; then \
# Initial installation \
- systemctl --no-reload preset %{?*} >/dev/null 2>&1 || : \
+ systemctl --no-reload preset %{?*} &>/dev/null || : \
fi \
%{nil}
-%systemd_user_post() %{expand:%systemd_post \\--user \\--global %%{?*}}
+%systemd_user_post() %{expand:%systemd_post \\--global %%{?*}}
%systemd_preun() \
if [ $1 -eq 0 ] ; then \
# Package removal, not upgrade \
- systemctl --no-reload disable --now %{?*} > /dev/null 2>&1 || : \
+ systemctl --no-reload disable --now %{?*} &>/dev/null || : \
fi \
%{nil}
%systemd_user_preun() \
if [ $1 -eq 0 ] ; then \
# Package removal, not upgrade \
- systemctl --no-reload --user --global disable %{?*} > /dev/null 2>&1 || : \
+ systemctl --global disable %{?*} &>/dev/null || : \
fi \
%{nil}
@@ -78,7 +68,7 @@ fi \
%systemd_postun_with_restart() \
if [ $1 -ge 1 ] ; then \
# Package upgrade, not uninstall \
- systemctl try-restart %{?*} >/dev/null 2>&1 || : \
+ systemctl try-restart %{?*} &>/dev/null || : \
fi \
%{nil}
@@ -92,16 +82,18 @@ fi \
# Deprecated. Use %tmpfiles_create_package instead
%tmpfiles_create() \
-systemd-tmpfiles --create %{?*} >/dev/null 2>&1 || : \
+systemd-tmpfiles --create %{?*} &>/dev/null || : \
%{nil}
# Deprecated. Use %sysusers_create_package instead
%sysusers_create() \
-systemd-sysusers %{?*} >/dev/null 2>&1 || : \
+systemd-sysusers %{?*} &>/dev/null || : \
%{nil}
%sysusers_create_inline() \
-echo %{?*} | systemd-sysusers - >/dev/null 2>&1 || : \
+systemd-sysusers - <<SYSTEMD_INLINE_EOF &>/dev/null || : \
+%{?*} \
+SYSTEMD_INLINE_EOF \
%{nil}
# This should be used by package installation scripts which require users or
@@ -118,7 +110,9 @@ echo %{?*} | systemd-sysusers - >/dev/null 2>&1 || : \
# %files
# %{_sysusersdir}/%{name}.conf
%sysusers_create_package() \
-echo "%(cat %2)" | systemd-sysusers --replace=%_sysusersdir/%1.conf - >/dev/null 2>&1 || : \
+systemd-sysusers --replace=%_sysusersdir/%1.conf - <<SYSTEMD_INLINE_EOF &>/dev/null || : \
+%(cat %2) \
+SYSTEMD_INLINE_EOF \
%{nil}
# This may be used by package installation scripts to create files according to
@@ -135,13 +129,15 @@ echo "%(cat %2)" | systemd-sysusers --replace=%_sysusersdir/%1.conf - >/dev/null
# %files
# %{_tmpfilesdir}/%{name}.conf
%tmpfiles_create_package() \
-echo "%(cat %2)" | systemd-tmpfiles --replace=%_tmpfilesdir/%1.conf --create - >/dev/null 2>&1 || : \
+systemd-tmpfiles --replace=%_tmpfilesdir/%1.conf --create - <<SYSTEMD_INLINE_EOF &>/dev/null || : \
+%(cat %2) \
+SYSTEMD_INLINE_EOF \
%{nil}
%sysctl_apply() \
-@rootlibexecdir@/systemd-sysctl %{?*} >/dev/null 2>&1 || : \
+@rootlibexecdir@/systemd-sysctl %{?*} &>/dev/null || : \
%{nil}
%binfmt_apply() \
-@rootlibexecdir@/systemd-binfmt %{?*} >/dev/null 2>&1 || : \
+@rootlibexecdir@/systemd-binfmt %{?*} &>/dev/null || : \
%{nil}
diff --git a/src/core/main.c b/src/core/main.c
index 076846a41c..44dd8348be 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
#include <fcntl.h>
@@ -49,10 +31,12 @@
#include "clock-util.h"
#include "conf-parser.h"
#include "cpu-set-util.h"
+#include "dbus.h"
#include "dbus-manager.h"
#include "def.h"
#include "emergency-action.h"
#include "env-util.h"
+#include "exit-status.h"
#include "fd-util.h"
#include "fdset.h"
#include "fileio.h"
@@ -69,6 +53,7 @@
#include "manager.h"
#include "missing.h"
#include "mount-setup.h"
+#include "os-util.h"
#include "pager.h"
#include "parse-util.h"
#include "path-util.h"
@@ -100,7 +85,8 @@ static enum {
ACTION_HELP,
ACTION_VERSION,
ACTION_TEST,
- ACTION_DUMP_CONFIGURATION_ITEMS
+ ACTION_DUMP_CONFIGURATION_ITEMS,
+ ACTION_DUMP_BUS_PROPERTIES,
} arg_action = ACTION_RUN;
static char *arg_default_unit = NULL;
static bool arg_system = false;
@@ -127,6 +113,7 @@ static char *arg_watchdog_device = NULL;
static char **arg_default_environment = NULL;
static struct rlimit *arg_default_rlimit[_RLIMIT_MAX] = {};
static uint64_t arg_capability_bounding_set = CAP_ALL;
+static bool arg_no_new_privs = false;
static nsec_t arg_timer_slack_nsec = NSEC_INFINITY;
static usec_t arg_default_timer_accuracy_usec = 1 * USEC_PER_MINUTE;
static Set* arg_syscall_archs = NULL;
@@ -141,7 +128,7 @@ static uint64_t arg_default_tasks_max = UINT64_MAX;
static sd_id128_t arg_machine_id = {};
static EmergencyAction arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE;
-noreturn static void freeze_or_reboot(void) {
+_noreturn_ static void freeze_or_reboot(void) {
if (arg_crash_reboot) {
log_notice("Rebooting in 10s...");
@@ -156,7 +143,7 @@ noreturn static void freeze_or_reboot(void) {
freeze();
}
-noreturn static void crash(int sig) {
+_noreturn_ static void crash(int sig) {
struct sigaction sa;
pid_t pid;
@@ -319,6 +306,7 @@ static int parse_confirm_spawn(const char *value, char **console) {
s = strjoin("/dev/", value);
if (!s)
return -ENOMEM;
+
*console = s;
return 0;
}
@@ -532,10 +520,10 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
return 0; \
}
-DEFINE_SETTER(config_parse_level2, log_set_max_level_from_string, "log level")
-DEFINE_SETTER(config_parse_target, log_set_target_from_string, "target")
-DEFINE_SETTER(config_parse_color, log_show_color_from_string, "color" )
-DEFINE_SETTER(config_parse_location, log_show_location_from_string, "location")
+DEFINE_SETTER(config_parse_level2, log_set_max_level_from_string, "log level");
+DEFINE_SETTER(config_parse_target, log_set_target_from_string, "target");
+DEFINE_SETTER(config_parse_color, log_show_color_from_string, "color" );
+DEFINE_SETTER(config_parse_location, log_show_location_from_string, "location");
static int config_parse_cpu_affinity2(
const char *unit,
@@ -671,6 +659,7 @@ static int parse_config_file(void) {
{ "Manager", "ShutdownWatchdogSec", config_parse_sec, 0, &arg_shutdown_watchdog },
{ "Manager", "WatchdogDevice", config_parse_path, 0, &arg_watchdog_device },
{ "Manager", "CapabilityBoundingSet", config_parse_capability_set, 0, &arg_capability_bounding_set },
+ { "Manager", "NoNewPrivileges", config_parse_bool, 0, &arg_no_new_privs },
#if HAVE_SECCOMP
{ "Manager", "SystemCallArchitectures", config_parse_syscall_archs, 0, &arg_syscall_archs },
#endif
@@ -685,22 +674,22 @@ static int parse_config_file(void) {
{ "Manager", "DefaultStartLimitIntervalSec",config_parse_sec, 0, &arg_default_start_limit_interval },
{ "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_default_start_limit_burst },
{ "Manager", "DefaultEnvironment", config_parse_environ, 0, &arg_default_environment },
- { "Manager", "DefaultLimitCPU", config_parse_limit, RLIMIT_CPU, arg_default_rlimit },
- { "Manager", "DefaultLimitFSIZE", config_parse_limit, RLIMIT_FSIZE, arg_default_rlimit },
- { "Manager", "DefaultLimitDATA", config_parse_limit, RLIMIT_DATA, arg_default_rlimit },
- { "Manager", "DefaultLimitSTACK", config_parse_limit, RLIMIT_STACK, arg_default_rlimit },
- { "Manager", "DefaultLimitCORE", config_parse_limit, RLIMIT_CORE, arg_default_rlimit },
- { "Manager", "DefaultLimitRSS", config_parse_limit, RLIMIT_RSS, arg_default_rlimit },
- { "Manager", "DefaultLimitNOFILE", config_parse_limit, RLIMIT_NOFILE, arg_default_rlimit },
- { "Manager", "DefaultLimitAS", config_parse_limit, RLIMIT_AS, arg_default_rlimit },
- { "Manager", "DefaultLimitNPROC", config_parse_limit, RLIMIT_NPROC, arg_default_rlimit },
- { "Manager", "DefaultLimitMEMLOCK", config_parse_limit, RLIMIT_MEMLOCK, arg_default_rlimit },
- { "Manager", "DefaultLimitLOCKS", config_parse_limit, RLIMIT_LOCKS, arg_default_rlimit },
- { "Manager", "DefaultLimitSIGPENDING", config_parse_limit, RLIMIT_SIGPENDING, arg_default_rlimit },
- { "Manager", "DefaultLimitMSGQUEUE", config_parse_limit, RLIMIT_MSGQUEUE, arg_default_rlimit },
- { "Manager", "DefaultLimitNICE", config_parse_limit, RLIMIT_NICE, arg_default_rlimit },
- { "Manager", "DefaultLimitRTPRIO", config_parse_limit, RLIMIT_RTPRIO, arg_default_rlimit },
- { "Manager", "DefaultLimitRTTIME", config_parse_limit, RLIMIT_RTTIME, arg_default_rlimit },
+ { "Manager", "DefaultLimitCPU", config_parse_rlimit, RLIMIT_CPU, arg_default_rlimit },
+ { "Manager", "DefaultLimitFSIZE", config_parse_rlimit, RLIMIT_FSIZE, arg_default_rlimit },
+ { "Manager", "DefaultLimitDATA", config_parse_rlimit, RLIMIT_DATA, arg_default_rlimit },
+ { "Manager", "DefaultLimitSTACK", config_parse_rlimit, RLIMIT_STACK, arg_default_rlimit },
+ { "Manager", "DefaultLimitCORE", config_parse_rlimit, RLIMIT_CORE, arg_default_rlimit },
+ { "Manager", "DefaultLimitRSS", config_parse_rlimit, RLIMIT_RSS, arg_default_rlimit },
+ { "Manager", "DefaultLimitNOFILE", config_parse_rlimit, RLIMIT_NOFILE, arg_default_rlimit },
+ { "Manager", "DefaultLimitAS", config_parse_rlimit, RLIMIT_AS, arg_default_rlimit },
+ { "Manager", "DefaultLimitNPROC", config_parse_rlimit, RLIMIT_NPROC, arg_default_rlimit },
+ { "Manager", "DefaultLimitMEMLOCK", config_parse_rlimit, RLIMIT_MEMLOCK, arg_default_rlimit },
+ { "Manager", "DefaultLimitLOCKS", config_parse_rlimit, RLIMIT_LOCKS, arg_default_rlimit },
+ { "Manager", "DefaultLimitSIGPENDING", config_parse_rlimit, RLIMIT_SIGPENDING, arg_default_rlimit },
+ { "Manager", "DefaultLimitMSGQUEUE", config_parse_rlimit, RLIMIT_MSGQUEUE, arg_default_rlimit },
+ { "Manager", "DefaultLimitNICE", config_parse_rlimit, RLIMIT_NICE, arg_default_rlimit },
+ { "Manager", "DefaultLimitRTPRIO", config_parse_rlimit, RLIMIT_RTPRIO, arg_default_rlimit },
+ { "Manager", "DefaultLimitRTTIME", config_parse_rlimit, RLIMIT_RTTIME, arg_default_rlimit },
{ "Manager", "DefaultCPUAccounting", config_parse_bool, 0, &arg_default_cpu_accounting },
{ "Manager", "DefaultIOAccounting", config_parse_bool, 0, &arg_default_io_accounting },
{ "Manager", "DefaultIPAccounting", config_parse_bool, 0, &arg_default_ip_accounting },
@@ -738,6 +727,10 @@ static void set_manager_defaults(Manager *m) {
assert(m);
+ /* Propagates the various default unit property settings into the manager object, i.e. properties that do not
+ * affect the manager itself, but are just what newly allocated units will have set if they haven't set
+ * anything else. (Also see set_manager_settings() for the settings that affect the manager's own behaviour) */
+
m->default_timer_accuracy_usec = arg_default_timer_accuracy_usec;
m->default_std_output = arg_default_std_output;
m->default_std_error = arg_default_std_error;
@@ -762,6 +755,9 @@ static void set_manager_settings(Manager *m) {
assert(m);
+ /* Propagates the various manager settings into the manager object, i.e. properties that effect the manager
+ * itself (as opposed to just being inherited into newly allocated units, see set_manager_defaults() above). */
+
m->confirm_spawn = arg_confirm_spawn;
m->service_watchdogs = arg_service_watchdogs;
m->runtime_watchdog = arg_runtime_watchdog;
@@ -772,7 +768,6 @@ static void set_manager_settings(Manager *m) {
}
static int parse_argv(int argc, char *argv[]) {
-
enum {
ARG_LOG_LEVEL = 0x100,
ARG_LOG_TARGET,
@@ -785,6 +780,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_NO_PAGER,
ARG_VERSION,
ARG_DUMP_CONFIGURATION_ITEMS,
+ ARG_DUMP_BUS_PROPERTIES,
ARG_DUMP_CORE,
ARG_CRASH_CHVT,
ARG_CRASH_SHELL,
@@ -812,6 +808,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "dump-configuration-items", no_argument, NULL, ARG_DUMP_CONFIGURATION_ITEMS },
+ { "dump-bus-properties", no_argument, NULL, ARG_DUMP_BUS_PROPERTIES },
{ "dump-core", optional_argument, NULL, ARG_DUMP_CORE },
{ "crash-chvt", required_argument, NULL, ARG_CRASH_CHVT },
{ "crash-shell", optional_argument, NULL, ARG_CRASH_SHELL },
@@ -931,6 +928,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_action = ACTION_DUMP_CONFIGURATION_ITEMS;
break;
+ case ARG_DUMP_BUS_PROPERTIES:
+ arg_action = ACTION_DUMP_BUS_PROPERTIES;
+ break;
+
case ARG_DUMP_CORE:
if (!optarg)
arg_dump_core = true;
@@ -1074,6 +1075,7 @@ static int help(void) {
" --test Determine startup sequence, dump it and exit\n"
" --no-pager Do not pipe output into a pager\n"
" --dump-configuration-items Dump understood unit configuration items\n"
+ " --dump-bus-properties Dump exposed bus properties\n"
" --unit=UNIT Set default unit\n"
" --system Run a system instance, even if PID != 1\n"
" --user Run a user instance\n"
@@ -1130,20 +1132,14 @@ static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching
if (r < 0)
return log_error_errno(r, "Failed to disable O_CLOEXEC for serialization fds: %m");
- *_f = f;
- *_fds = fds;
-
- f = NULL;
- fds = NULL;
+ *_f = TAKE_PTR(f);
+ *_fds = TAKE_PTR(fds);
return 0;
}
static int bump_rlimit_nofile(struct rlimit *saved_rlimit) {
- struct rlimit nl;
- int r;
- int min_max;
- _cleanup_free_ char *nr_open = NULL;
+ int r, nr;
assert(saved_rlimit);
@@ -1164,17 +1160,9 @@ static int bump_rlimit_nofile(struct rlimit *saved_rlimit) {
arg_default_rlimit[RLIMIT_NOFILE] = rl;
}
- /* Get current RLIMIT_NOFILE maximum compiled into the kernel. */
- r = read_one_line_file("/proc/sys/fs/nr_open", &nr_open);
- if (r >= 0)
- r = safe_atoi(nr_open, &min_max);
- /* If we fail, fallback to the hard-coded kernel limit of 1024 * 1024. */
- if (r < 0)
- min_max = 1024 * 1024;
-
- /* Bump up the resource limit for ourselves substantially */
- nl.rlim_cur = nl.rlim_max = min_max;
- r = setrlimit_closest(RLIMIT_NOFILE, &nl);
+ /* Bump up the resource limit for ourselves substantially, all the way to the maximum the kernel allows */
+ nr = read_nr_open();
+ r = setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(nr));
if (r < 0)
return log_warning_errno(r, "Setting RLIMIT_NOFILE failed, ignoring: %m");
@@ -1229,23 +1217,18 @@ static int enforce_syscall_archs(Set *archs) {
static int status_welcome(void) {
_cleanup_free_ char *pretty_name = NULL, *ansi_color = NULL;
- const char *fn;
int r;
if (arg_show_status <= 0)
return 0;
- FOREACH_STRING(fn, "/etc/os-release", "/usr/lib/os-release") {
- r = parse_env_file(fn, NEWLINE,
- "PRETTY_NAME", &pretty_name,
- "ANSI_COLOR", &ansi_color,
- NULL);
-
- if (r != -ENOENT)
- break;
- }
- if (r < 0 && r != -ENOENT)
- log_warning_errno(r, "Failed to read os-release file, ignoring: %m");
+ r = parse_os_release(NULL,
+ "PRETTY_NAME", &pretty_name,
+ "ANSI_COLOR", &ansi_color,
+ NULL);
+ if (r < 0)
+ log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to read os-release file, ignoring: %m");
if (log_get_show_color())
return status_printf(NULL, false, false,
@@ -1279,10 +1262,9 @@ static int bump_unix_max_dgram_qlen(void) {
unsigned long v;
int r;
- /* Let's bump the net.unix.max_dgram_qlen sysctl. The kernel
- * default of 16 is simply too low. We set the value really
- * really early during boot, so that it is actually applied to
- * all our sockets, including the $NOTIFY_SOCKET one. */
+ /* Let's bump the net.unix.max_dgram_qlen sysctl. The kernel default of 16 is simply too low. We set the value
+ * really really early during boot, so that it is actually applied to all our sockets, including the
+ * $NOTIFY_SOCKET one. */
r = read_one_line_file("/proc/sys/net/unix/max_dgram_qlen", &qlen);
if (r < 0)
@@ -1290,16 +1272,12 @@ static int bump_unix_max_dgram_qlen(void) {
r = safe_atolu(qlen, &v);
if (r < 0)
- return log_warning_errno(r, "Failed to parse AF_UNIX datagram queue length, ignoring: %m");
+ return log_warning_errno(r, "Failed to parse AF_UNIX datagram queue length '%s', ignoring: %m", qlen);
if (v >= DEFAULT_UNIX_MAX_DGRAM_QLEN)
return 0;
- qlen = mfree(qlen);
- if (asprintf(&qlen, "%lu\n", DEFAULT_UNIX_MAX_DGRAM_QLEN) < 0)
- return log_oom();
-
- r = write_string_file("/proc/sys/net/unix/max_dgram_qlen", qlen, 0);
+ r = write_string_filef("/proc/sys/net/unix/max_dgram_qlen", 0, "%lu", DEFAULT_UNIX_MAX_DGRAM_QLEN);
if (r < 0)
return log_full_errno(IN_SET(r, -EROFS, -EPERM, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to bump AF_UNIX datagram queue length, ignoring: %m");
@@ -1487,7 +1465,7 @@ static void initialize_clock(void) {
}
static void initialize_coredump(bool skip_setup) {
-
+#if ENABLE_COREDUMP
if (getpid_cached() != 1)
return;
@@ -1500,6 +1478,7 @@ static void initialize_coredump(bool skip_setup) {
* until the systemd-coredump tool is enabled via sysctl. */
if (!skip_setup)
disable_coredumps();
+#endif
}
static void do_reexecute(
@@ -1656,20 +1635,35 @@ static int invoke_main_loop(
switch (m->exit_code) {
- case MANAGER_RELOAD:
+ case MANAGER_RELOAD: {
+ LogTarget saved_log_target;
+ int saved_log_level;
+
log_info("Reloading.");
+ /* First, save any overridden log level/target, then parse the configuration file, which might
+ * change the log level to new settings. */
+
+ saved_log_level = m->log_level_overridden ? log_get_max_level() : -1;
+ saved_log_target = m->log_target_overridden ? log_get_target() : _LOG_TARGET_INVALID;
+
r = parse_config_file();
if (r < 0)
log_warning_errno(r, "Failed to parse config file, ignoring: %m");
set_manager_defaults(m);
+ if (saved_log_level >= 0)
+ manager_override_log_level(m, saved_log_level);
+ if (saved_log_target >= 0)
+ manager_override_log_target(m, saved_log_target);
+
r = manager_reload(m);
if (r < 0)
log_warning_errno(r, "Failed to reload, ignoring: %m");
break;
+ }
case MANAGER_REEXECUTE:
@@ -1865,6 +1859,13 @@ static int initialize_runtime(
}
}
+ if (arg_system && arg_no_new_privs) {
+ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
+ *ret_error_message = "Failed to disable new privileges";
+ return log_emergency_errno(errno, "Failed to disable new privileges: %m");
+ }
+ }
+
if (arg_syscall_archs) {
r = enforce_syscall_archs(arg_syscall_archs);
if (r < 0) {
@@ -1898,28 +1899,15 @@ static int do_queue_default_job(
log_debug("Activating default unit: %s", arg_default_unit);
- r = manager_load_unit(m, arg_default_unit, NULL, &error, &target);
- if (r < 0)
- log_error("Failed to load default target: %s", bus_error_message(&error, r));
- else if (IN_SET(target->load_state, UNIT_ERROR, UNIT_NOT_FOUND))
- log_error_errno(target->load_error, "Failed to load default target: %m");
- else if (target->load_state == UNIT_MASKED)
- log_error("Default target masked.");
-
- if (!target || target->load_state != UNIT_LOADED) {
- log_info("Trying to load rescue target...");
+ r = manager_load_startable_unit_or_warn(m, arg_default_unit, NULL, &target);
+ if (r < 0) {
+ log_info("Falling back to rescue target: " SPECIAL_RESCUE_TARGET);
- r = manager_load_unit(m, SPECIAL_RESCUE_TARGET, NULL, &error, &target);
+ r = manager_load_startable_unit_or_warn(m, SPECIAL_RESCUE_TARGET, NULL, &target);
if (r < 0) {
- *ret_error_message = "Failed to load rescue target";
- return log_emergency_errno(r, "Failed to load rescue target: %s", bus_error_message(&error, r));
- } else if (IN_SET(target->load_state, UNIT_ERROR, UNIT_NOT_FOUND)) {
- *ret_error_message = "Failed to load rescue target";
- return log_emergency_errno(target->load_error, "Failed to load rescue target: %m");
- } else if (target->load_state == UNIT_MASKED) {
- *ret_error_message = "Rescue target masked";
- log_emergency("Rescue target masked.");
- return -ERFKILL;
+ *ret_error_message = r == -ERFKILL ? "Rescue target masked"
+ : "Failed to load rescue target";
+ return r;
}
}
@@ -1948,12 +1936,9 @@ static int do_queue_default_job(
}
static void free_arguments(void) {
- size_t j;
/* Frees all arg_* variables, with the exception of arg_serialization */
-
- for (j = 0; j < ELEMENTSOF(arg_default_rlimit); j++)
- arg_default_rlimit[j] = mfree(arg_default_rlimit[j]);
+ rlimit_free_all(arg_default_rlimit);
arg_default_unit = mfree(arg_default_unit);
arg_confirm_spawn = mfree(arg_confirm_spawn);
@@ -2150,7 +2135,6 @@ static bool early_skip_setup_check(int argc, char *argv[]) {
* anyway, even if in that case we also do deserialization. */
for (i = 1; i < argc; i++) {
-
if (streq(argv[i], "--switched-root"))
return false; /* If we switched root, don't skip the setup. */
else if (streq(argv[i], "--deserialize"))
@@ -2199,11 +2183,14 @@ int main(int argc, char *argv[]) {
log_set_upgrade_syslog_to_journal(true);
if (getpid_cached() == 1) {
+ /* When we run as PID 1 force system mode */
+ arg_system = true;
+
/* Disable the umask logic */
umask(0);
- /* Make sure that at least initially we do not ever log to journald/syslogd, because it might not be activated
- * yet (even though the log socket for it exists). */
+ /* Make sure that at least initially we do not ever log to journald/syslogd, because it might not be
+ * activated yet (even though the log socket for it exists). */
log_set_prohibit_ipc(true);
/* Always reopen /dev/console when running as PID 1 or one of its pre-execve() children. This is
@@ -2211,62 +2198,68 @@ int main(int argc, char *argv[]) {
* child process right before execve()'ing the actual binary, at a point in time where socket
* activation stderr/stdout area already set up. */
log_set_always_reopen_console(true);
- }
- if (getpid_cached() == 1 && detect_container() <= 0) {
+ if (detect_container() <= 0) {
- /* Running outside of a container as PID 1 */
- arg_system = true;
- log_set_target(LOG_TARGET_KMSG);
- log_open();
+ /* Running outside of a container as PID 1 */
+ log_set_target(LOG_TARGET_KMSG);
+ log_open();
- if (in_initrd())
- initrd_timestamp = userspace_timestamp;
+ if (in_initrd())
+ initrd_timestamp = userspace_timestamp;
- if (!skip_setup) {
- r = mount_setup_early();
- if (r < 0) {
- error_message = "Failed to mount early API filesystems";
- goto finish;
+ if (!skip_setup) {
+ r = mount_setup_early();
+ if (r < 0) {
+ error_message = "Failed to mount early API filesystems";
+ goto finish;
+ }
+
+ r = initialize_security(
+ &loaded_policy,
+ &security_start_timestamp,
+ &security_finish_timestamp,
+ &error_message);
+ if (r < 0)
+ goto finish;
}
- r = initialize_security(
- &loaded_policy,
- &security_start_timestamp,
- &security_finish_timestamp,
- &error_message);
- if (r < 0)
+ if (mac_selinux_init() < 0) {
+ error_message = "Failed to initialize SELinux policy";
goto finish;
- }
+ }
- if (mac_selinux_init() < 0) {
- error_message = "Failed to initialize SELinux policy";
- goto finish;
+ if (!skip_setup)
+ initialize_clock();
+
+ /* Set the default for later on, but don't actually open the logs like this for now. Note that
+ * if we are transitioning from the initrd there might still be journal fd open, and we
+ * shouldn't attempt opening that before we parsed /proc/cmdline which might redirect output
+ * elsewhere. */
+ log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
+
+ } else {
+ /* Running inside a container, as PID 1 */
+ log_set_target(LOG_TARGET_CONSOLE);
+ log_open();
+
+ /* For later on, see above... */
+ log_set_target(LOG_TARGET_JOURNAL);
+
+ /* clear the kernel timestamp,
+ * because we are in a container */
+ kernel_timestamp = DUAL_TIMESTAMP_NULL;
}
- if (!skip_setup)
- initialize_clock();
-
- /* Set the default for later on, but don't actually
- * open the logs like this for now. Note that if we
- * are transitioning from the initrd there might still
- * be journal fd open, and we shouldn't attempt
- * opening that before we parsed /proc/cmdline which
- * might redirect output elsewhere. */
- log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
-
- } else if (getpid_cached() == 1) {
- /* Running inside a container, as PID 1 */
- arg_system = true;
- log_set_target(LOG_TARGET_CONSOLE);
- log_open();
+ initialize_coredump(skip_setup);
- /* For later on, see above... */
- log_set_target(LOG_TARGET_JOURNAL);
+ r = fixup_environment();
+ if (r < 0) {
+ log_emergency_errno(r, "Failed to fix up PID 1 environment: %m");
+ error_message = "Failed to fix up PID1 environment";
+ goto finish;
+ }
- /* clear the kernel timestamp,
- * because we are in a container */
- kernel_timestamp = DUAL_TIMESTAMP_NULL;
} else {
/* Running as user instance */
arg_system = false;
@@ -2278,24 +2271,14 @@ int main(int argc, char *argv[]) {
kernel_timestamp = DUAL_TIMESTAMP_NULL;
}
- initialize_coredump(skip_setup);
-
- r = fixup_environment();
- if (r < 0) {
- log_emergency_errno(r, "Failed to fix up PID 1 environment: %m");
- error_message = "Failed to fix up PID1 environment";
- goto finish;
- }
-
if (arg_system) {
-
- /* Try to figure out if we can use colors with the console. No
- * need to do that for user instances since they never log
- * into the console. */
+ /* Try to figure out if we can use colors with the console. No need to do that for user instances since
+ * they never log into the console. */
log_show_color(colors_enabled());
+
r = make_null_stdio();
if (r < 0)
- log_warning_errno(r, "Failed to redirect standard streams to /dev/null: %m");
+ log_warning_errno(r, "Failed to redirect standard streams to /dev/null, ignoring: %m");
}
/* Mount /proc, /sys and friends, so that /proc/cmdline and
@@ -2325,8 +2308,8 @@ int main(int argc, char *argv[]) {
if (r < 0)
goto finish;
- if (IN_SET(arg_action, ACTION_TEST, ACTION_HELP, ACTION_DUMP_CONFIGURATION_ITEMS))
- pager_open(arg_no_pager, false);
+ if (IN_SET(arg_action, ACTION_TEST, ACTION_HELP, ACTION_DUMP_CONFIGURATION_ITEMS, ACTION_DUMP_BUS_PROPERTIES))
+ (void) pager_open(arg_no_pager, false);
if (arg_action != ACTION_RUN)
skip_setup = true;
@@ -2341,6 +2324,10 @@ int main(int argc, char *argv[]) {
unit_dump_config_items(stdout);
retval = EXIT_SUCCESS;
goto finish;
+ } else if (arg_action == ACTION_DUMP_BUS_PROPERTIES) {
+ dump_bus_properties(stdout);
+ retval = EXIT_SUCCESS;
+ goto finish;
}
assert_se(IN_SET(arg_action, ACTION_RUN, ACTION_TEST));
@@ -2439,10 +2426,10 @@ int main(int argc, char *argv[]) {
finish:
pager_close();
- if (m)
+ if (m) {
arg_shutdown_watchdog = m->shutdown_watchdog;
-
- m = manager_free(m);
+ m = manager_free(m);
+ }
free_arguments();
mac_selinux_finish();
@@ -2469,13 +2456,12 @@ finish:
* in become_shutdown() so normally we cannot free them yet. */
watchdog_free_device();
arg_watchdog_device = mfree(arg_watchdog_device);
- return 0;
+ return retval;
}
#endif
if (shutdown_verb) {
r = become_shutdown(shutdown_verb, retval);
-
log_error_errno(r, "Failed to execute shutdown binary, %s: %m", getpid_cached() == 1 ? "freezing" : "quitting");
error_message = "Failed to execute shutdown binary";
}
diff --git a/src/core/manager.c b/src/core/manager.c
index 84adb9c666..930df4e23a 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
#include <fcntl.h>
@@ -41,6 +23,7 @@
#include "sd-path.h"
#include "alloc-util.h"
+#include "all-units.h"
#include "audit-fd.h"
#include "boot-timestamps.h"
#include "bus-common-errors.h"
@@ -76,14 +59,17 @@
#include "path-util.h"
#include "process-util.h"
#include "ratelimit.h"
+#include "rlimit-util.h"
#include "rm-rf.h"
#include "signal-util.h"
+#include "socket-util.h"
#include "special.h"
#include "stat-util.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
#include "strxcpyx.h"
+#include "syslog-util.h"
#include "terminal-util.h"
#include "time-util.h"
#include "transaction.h"
@@ -118,6 +104,7 @@ static int manager_dispatch_user_lookup_fd(sd_event_source *source, int fd, uint
static int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata);
static int manager_dispatch_run_queue(sd_event_source *source, void *userdata);
static int manager_dispatch_sigchld(sd_event_source *source, void *userdata);
+static int manager_dispatch_timezone_change(sd_event_source *source, const struct inotify_event *event, void *userdata);
static int manager_run_environment_generators(Manager *m);
static int manager_run_generators(Manager *m);
@@ -362,35 +349,27 @@ static void manager_close_idle_pipe(Manager *m) {
static int manager_setup_time_change(Manager *m) {
int r;
- /* We only care for the cancellation event, hence we set the
- * timeout to the latest possible value. */
- struct itimerspec its = {
- .it_value.tv_sec = TIME_T_MAX,
- };
-
assert(m);
- assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX));
if (m->test_run_flags)
return 0;
- /* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever
- * CLOCK_REALTIME makes a jump relative to CLOCK_MONOTONIC */
+ m->time_change_event_source = sd_event_source_unref(m->time_change_event_source);
+ m->time_change_fd = safe_close(m->time_change_fd);
- m->time_change_fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
+ m->time_change_fd = time_change_fd();
if (m->time_change_fd < 0)
- return log_error_errno(errno, "Failed to create timerfd: %m");
-
- if (timerfd_settime(m->time_change_fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) {
- log_debug_errno(errno, "Failed to set up TFD_TIMER_CANCEL_ON_SET, ignoring: %m");
- m->time_change_fd = safe_close(m->time_change_fd);
- return 0;
- }
+ return log_error_errno(m->time_change_fd, "Failed to create timer change timer fd: %m");
r = sd_event_add_io(m->event, &m->time_change_event_source, m->time_change_fd, EPOLLIN, manager_dispatch_time_change_fd, m);
if (r < 0)
return log_error_errno(r, "Failed to create time change event source: %m");
+ /* Schedule this slightly earlier than the .timer event sources */
+ r = sd_event_source_set_priority(m->time_change_event_source, SD_EVENT_PRIORITY_NORMAL-1);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set priority of time change event sources: %m");
+
(void) sd_event_source_set_description(m->time_change_event_source, "manager-time-change");
log_debug("Set up TFD_TIMER_CANCEL_ON_SET timerfd.");
@@ -398,6 +377,70 @@ static int manager_setup_time_change(Manager *m) {
return 0;
}
+static int manager_read_timezone_stat(Manager *m) {
+ struct stat st;
+ bool changed;
+
+ assert(m);
+
+ /* Read the current stat() data of /etc/localtime so that we detect changes */
+ if (lstat("/etc/localtime", &st) < 0) {
+ log_debug_errno(errno, "Failed to stat /etc/localtime, ignoring: %m");
+ changed = m->etc_localtime_accessible;
+ m->etc_localtime_accessible = false;
+ } else {
+ usec_t k;
+
+ k = timespec_load(&st.st_mtim);
+ changed = !m->etc_localtime_accessible || k != m->etc_localtime_mtime;
+
+ m->etc_localtime_mtime = k;
+ m->etc_localtime_accessible = true;
+ }
+
+ return changed;
+}
+
+static int manager_setup_timezone_change(Manager *m) {
+ _cleanup_(sd_event_source_unrefp) sd_event_source *new_event = NULL;
+ int r;
+
+ assert(m);
+
+ if (m->test_run_flags != 0)
+ return 0;
+
+ /* We watch /etc/localtime for three events: change of the link count (which might mean removal from /etc even
+ * though another link might be kept), renames, and file close operations after writing. Note we don't bother
+ * with IN_DELETE_SELF, as that would just report when the inode is removed entirely, i.e. after the link count
+ * went to zero and all fds to it are closed.
+ *
+ * Note that we never follow symlinks here. This is a simplification, but should cover almost all cases
+ * correctly.
+ *
+ * Note that we create the new event source first here, before releasing the old one. This should optimize
+ * behaviour as this way sd-event can reuse the old watch in case the inode didn't change. */
+
+ r = sd_event_add_inotify(m->event, &new_event, "/etc/localtime",
+ IN_ATTRIB|IN_MOVE_SELF|IN_CLOSE_WRITE|IN_DONT_FOLLOW, manager_dispatch_timezone_change, m);
+ if (r == -ENOENT) /* If the file doesn't exist yet, subscribe to /etc instead, and wait until it is created
+ * either by O_CREATE or by rename() */
+ r = sd_event_add_inotify(m->event, &new_event, "/etc",
+ IN_CREATE|IN_MOVED_TO|IN_ONLYDIR, manager_dispatch_timezone_change, m);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create timezone change event source: %m");
+
+ /* Schedule this slightly earlier than the .timer event sources */
+ r = sd_event_source_set_priority(new_event, SD_EVENT_PRIORITY_NORMAL-1);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set priority of timezone change event sources: %m");
+
+ sd_event_source_unref(m->timezone_change_event_source);
+ m->timezone_change_event_source = TAKE_PTR(new_event);
+
+ return 0;
+}
+
static int enable_special_signals(Manager *m) {
_cleanup_close_ int fd = -1;
@@ -426,6 +469,8 @@ static int enable_special_signals(Manager *m) {
return 0;
}
+#define RTSIG_IF_AVAILABLE(signum) (signum <= SIGRTMAX ? signum : -1)
+
static int manager_setup_signals(Manager *m) {
struct sigaction sa = {
.sa_handler = SIG_DFL,
@@ -479,22 +524,22 @@ static int manager_setup_signals(Manager *m) {
/* .. one free signal here ... */
-#if !defined(__hppa64__) && !defined(__hppa__)
- /* Apparently Linux on hppa has fewer RT
- * signals (SIGRTMAX is SIGRTMIN+25 there),
- * hence let's not try to make use of them
- * here. Since these commands are accessible
- * by different means and only really a safety
- * net, the missing functionality on hppa
- * shouldn't matter. */
-
- SIGRTMIN+26, /* systemd: set log target to journal-or-kmsg */
- SIGRTMIN+27, /* systemd: set log target to console */
- SIGRTMIN+28, /* systemd: set log target to kmsg */
- SIGRTMIN+29, /* systemd: set log target to syslog-or-kmsg (obsolete) */
+ /* Apparently Linux on hppa had fewer RT signals until v3.18,
+ * SIGRTMAX was SIGRTMIN+25, and then SIGRTMIN was lowered,
+ * see commit v3.17-7614-g1f25df2eff.
+ *
+ * We cannot unconditionally make use of those signals here,
+ * so let's use a runtime check. Since these commands are
+ * accessible by different means and only really a safety
+ * net, the missing functionality on hppa shouldn't matter.
+ */
+
+ RTSIG_IF_AVAILABLE(SIGRTMIN+26), /* systemd: set log target to journal-or-kmsg */
+ RTSIG_IF_AVAILABLE(SIGRTMIN+27), /* systemd: set log target to console */
+ RTSIG_IF_AVAILABLE(SIGRTMIN+28), /* systemd: set log target to kmsg */
+ RTSIG_IF_AVAILABLE(SIGRTMIN+29), /* systemd: set log target to syslog-or-kmsg (obsolete) */
/* ... one free signal here SIGRTMIN+30 ... */
-#endif
-1);
assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
@@ -667,7 +712,7 @@ static int manager_setup_sigchld_event_source(Manager *m) {
}
int manager_new(UnitFileScope scope, unsigned test_run_flags, Manager **_m) {
- Manager *m;
+ _cleanup_(manager_freep) Manager *m = NULL;
int r;
assert(_m);
@@ -686,6 +731,8 @@ int manager_new(UnitFileScope scope, unsigned test_run_flags, Manager **_m) {
m->default_timeout_start_usec = DEFAULT_TIMEOUT_USEC;
m->default_timeout_stop_usec = DEFAULT_TIMEOUT_USEC;
m->default_restart_usec = DEFAULT_RESTART_USEC;
+ m->original_log_level = -1;
+ m->original_log_target = _LOG_TARGET_INVALID;
#if ENABLE_EFI
if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0)
@@ -729,62 +776,74 @@ int manager_new(UnitFileScope scope, unsigned test_run_flags, Manager **_m) {
r = manager_default_environment(m);
if (r < 0)
- goto fail;
+ return r;
r = hashmap_ensure_allocated(&m->units, &string_hash_ops);
if (r < 0)
- goto fail;
+ return r;
r = hashmap_ensure_allocated(&m->jobs, NULL);
if (r < 0)
- goto fail;
+ return r;
r = hashmap_ensure_allocated(&m->cgroup_unit, &path_hash_ops);
if (r < 0)
- goto fail;
+ return r;
r = hashmap_ensure_allocated(&m->watch_bus, &string_hash_ops);
if (r < 0)
- goto fail;
+ return r;
+
+ r = manager_setup_prefix(m);
+ if (r < 0)
+ return r;
+
+ m->udev = udev_new();
+ if (!m->udev)
+ return -ENOMEM;
r = sd_event_default(&m->event);
if (r < 0)
- goto fail;
+ return r;
r = manager_setup_run_queue(m);
if (r < 0)
- goto fail;
+ return r;
- r = manager_setup_signals(m);
- if (r < 0)
- goto fail;
+ if (test_run_flags == MANAGER_TEST_RUN_MINIMAL) {
+ m->cgroup_root = strdup("");
+ if (!m->cgroup_root)
+ return -ENOMEM;
+ } else {
+ r = manager_setup_signals(m);
+ if (r < 0)
+ return r;
- r = manager_setup_cgroup(m);
- if (r < 0)
- goto fail;
+ r = manager_setup_cgroup(m);
+ if (r < 0)
+ return r;
- r = manager_setup_time_change(m);
- if (r < 0)
- goto fail;
+ r = manager_setup_time_change(m);
+ if (r < 0)
+ return r;
- r = manager_setup_sigchld_event_source(m);
- if (r < 0)
- goto fail;
+ r = manager_read_timezone_stat(m);
+ if (r < 0)
+ return r;
- m->udev = udev_new();
- if (!m->udev) {
- r = -ENOMEM;
- goto fail;
- }
+ r = manager_setup_timezone_change(m);
+ if (r < 0)
+ return r;
- r = manager_setup_prefix(m);
- if (r < 0)
- goto fail;
+ r = manager_setup_sigchld_event_source(m);
+ if (r < 0)
+ return r;
+ }
if (MANAGER_IS_SYSTEM(m) && test_run_flags == 0) {
r = mkdir_label("/run/systemd/units", 0755);
if (r < 0 && r != -EEXIST)
- goto fail;
+ return r;
}
m->taint_usr =
@@ -794,12 +853,9 @@ int manager_new(UnitFileScope scope, unsigned test_run_flags, Manager **_m) {
/* Note that we do not set up the notify fd here. We do that after deserialization,
* since they might have gotten serialized across the reexec. */
- *_m = m;
- return 0;
+ *_m = TAKE_PTR(m);
-fail:
- manager_free(m);
- return r;
+ return 0;
}
static int manager_setup_notify(Manager *m) {
@@ -841,8 +897,7 @@ static int manager_setup_notify(Manager *m) {
if (r < 0)
return log_error_errno(errno, "SO_PASSCRED failed: %m");
- m->notify_fd = fd;
- fd = -1;
+ m->notify_fd = TAKE_FD(fd);
log_debug("Using notification socket %s", m->notify_socket);
}
@@ -1183,7 +1238,6 @@ static void manager_clear_jobs_and_units(Manager *m) {
Manager* manager_free(Manager *m) {
UnitType c;
- int i;
ExecDirectoryType dt;
if (!m)
@@ -1222,6 +1276,7 @@ Manager* manager_free(Manager *m) {
sd_event_source_unref(m->notify_event_source);
sd_event_source_unref(m->cgroups_agent_event_source);
sd_event_source_unref(m->time_change_event_source);
+ sd_event_source_unref(m->timezone_change_event_source);
sd_event_source_unref(m->jobs_in_progress_event_source);
sd_event_source_unref(m->run_queue_event_source);
sd_event_source_unref(m->user_lookup_event_source);
@@ -1251,8 +1306,7 @@ Manager* manager_free(Manager *m) {
free(m->switch_root);
free(m->switch_root_init);
- for (i = 0; i < _RLIMIT_MAX; i++)
- m->rlimit[i] = mfree(m->rlimit[i]);
+ rlimit_free_all(m->rlimit);
assert(hashmap_isempty(m->units_requiring_mounts_for));
hashmap_free(m->units_requiring_mounts_for);
@@ -1266,23 +1320,37 @@ Manager* manager_free(Manager *m) {
return mfree(m);
}
-void manager_enumerate(Manager *m) {
+static void manager_enumerate_perpetual(Manager *m) {
UnitType c;
assert(m);
- /* Let's ask every type to load all units from disk/kernel
- * that it might know */
+ /* Let's ask every type to load all units from disk/kernel that it might know */
for (c = 0; c < _UNIT_TYPE_MAX; c++) {
if (!unit_type_supported(c)) {
log_debug("Unit type .%s is not supported on this system.", unit_type_to_string(c));
continue;
}
- if (!unit_vtable[c]->enumerate)
+ if (unit_vtable[c]->enumerate_perpetual)
+ unit_vtable[c]->enumerate_perpetual(m);
+ }
+}
+
+static void manager_enumerate(Manager *m) {
+ UnitType c;
+
+ assert(m);
+
+ /* Let's ask every type to load all units from disk/kernel that it might know */
+ for (c = 0; c < _UNIT_TYPE_MAX; c++) {
+ if (!unit_type_supported(c)) {
+ log_debug("Unit type .%s is not supported on this system.", unit_type_to_string(c));
continue;
+ }
- unit_vtable[c]->enumerate(m);
+ if (unit_vtable[c]->enumerate)
+ unit_vtable[c]->enumerate(m);
}
manager_dispatch_load_queue(m);
@@ -1296,7 +1364,9 @@ static void manager_coldplug(Manager *m) {
assert(m);
- /* Then, let's set up their initial state. */
+ log_debug("Invoking unit coldplug() handlers…");
+
+ /* Let's place the units back into their deserialized state */
HASHMAP_FOREACH_KEY(u, k, m->units, i) {
/* ignore aliases */
@@ -1309,6 +1379,26 @@ static void manager_coldplug(Manager *m) {
}
}
+static void manager_catchup(Manager *m) {
+ Iterator i;
+ Unit *u;
+ char *k;
+
+ assert(m);
+
+ log_debug("Invoking unit catchup() handlers…");
+
+ /* Let's catch up on any state changes that happened while we were reloading/reexecing */
+ HASHMAP_FOREACH_KEY(u, k, m->units, i) {
+
+ /* ignore aliases */
+ if (u->id != k)
+ continue;
+
+ unit_catchup(u);
+ }
+}
+
static void manager_build_unit_path_cache(Manager *m) {
char **i;
int r;
@@ -1409,6 +1499,48 @@ static bool manager_dbus_is_running(Manager *m, bool deserialized) {
return true;
}
+static void manager_setup_bus(Manager *m) {
+ assert(m);
+
+ /* Let's set up our private bus connection now, unconditionally */
+ (void) bus_init_private(m);
+
+ /* If we are in --user mode also connect to the system bus now */
+ if (MANAGER_IS_USER(m))
+ (void) bus_init_system(m);
+
+ /* Let's connect to the bus now, but only if the unit is supposed to be up */
+ if (manager_dbus_is_running(m, MANAGER_IS_RELOADING(m))) {
+ (void) bus_init_api(m);
+
+ if (MANAGER_IS_SYSTEM(m))
+ (void) bus_init_system(m);
+ }
+}
+
+static void manager_preset_all(Manager *m) {
+ int r;
+
+ assert(m);
+
+ if (m->first_boot <= 0)
+ return;
+
+ if (!MANAGER_IS_SYSTEM(m))
+ return;
+
+ if (m->test_run_flags != 0)
+ return;
+
+ /* If this is the first boot, and we are in the host system, then preset everything */
+ r = unit_file_preset_all(UNIT_FILE_SYSTEM, 0, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, NULL, 0);
+ if (r < 0)
+ log_full_errno(r == -EEXIST ? LOG_NOTICE : LOG_WARNING, r,
+ "Failed to populate /etc with preset unit settings, ignoring: %m");
+ else
+ log_info("Populated /etc with preset unit settings.");
+}
+
int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
int r;
@@ -1432,19 +1564,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
if (r < 0)
return r;
- /* If this is the first boot, and we are in the host system, then preset everything */
- if (m->first_boot > 0 &&
- MANAGER_IS_SYSTEM(m) &&
- !m->test_run_flags) {
-
- r = unit_file_preset_all(UNIT_FILE_SYSTEM, 0, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, NULL, 0);
- if (r < 0)
- log_full_errno(r == -EEXIST ? LOG_NOTICE : LOG_WARNING, r,
- "Failed to populate /etc with preset unit settings, ignoring: %m");
- else
- log_info("Populated /etc with preset unit settings.");
- }
-
+ manager_preset_all(m);
lookup_paths_reduce(&m->lookup_paths);
manager_build_unit_path_cache(m);
@@ -1456,6 +1576,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
/* First, enumerate what we can from all config files */
dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_UNITS_LOAD_START);
+ manager_enumerate_perpetual(m);
manager_enumerate(m);
dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_UNITS_LOAD_FINISH);
@@ -1489,20 +1610,8 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
/* This shouldn't fail, except if things are really broken. */
return r;
- /* Let's set up our private bus connection now, unconditionally */
- (void) bus_init_private(m);
-
- /* If we are in --user mode also connect to the system bus now */
- if (MANAGER_IS_USER(m))
- (void) bus_init_system(m);
-
- /* Let's connect to the bus now, but only if the unit is supposed to be up */
- if (manager_dbus_is_running(m, !!serialization)) {
- (void) bus_init_api(m);
-
- if (MANAGER_IS_SYSTEM(m))
- (void) bus_init_system(m);
- }
+ /* Connect to the bus if we are good for it */
+ manager_setup_bus(m);
/* Now that we are connected to all possible busses, let's deserialize who is tracking us. */
(void) bus_track_coldplug(m, &m->subscribed, false, m->deserialized_subscribed);
@@ -1530,6 +1639,9 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
m->send_reloading_done = true;
}
+ /* Let's finally catch up with any changes that took place while we were reloading/reexecing */
+ manager_catchup(m);
+
return 0;
}
@@ -1668,6 +1780,42 @@ Unit *manager_get_unit(Manager *m, const char *name) {
return hashmap_get(m->units, name);
}
+static int manager_dispatch_target_deps_queue(Manager *m) {
+ Unit *u;
+ unsigned k;
+ int r = 0;
+
+ static const UnitDependency deps[] = {
+ UNIT_REQUIRED_BY,
+ UNIT_REQUISITE_OF,
+ UNIT_WANTED_BY,
+ UNIT_BOUND_BY
+ };
+
+ assert(m);
+
+ while ((u = m->target_deps_queue)) {
+ assert(u->in_target_deps_queue);
+
+ LIST_REMOVE(target_deps_queue, u->manager->target_deps_queue, u);
+ u->in_target_deps_queue = false;
+
+ for (k = 0; k < ELEMENTSOF(deps); k++) {
+ Unit *target;
+ Iterator i;
+ void *v;
+
+ HASHMAP_FOREACH_KEY(v, target, u->dependencies[deps[k]], i) {
+ r = unit_add_default_target_dependency(u, target);
+ if (r < 0)
+ return r;
+ }
+ }
+ }
+
+ return r;
+}
+
unsigned manager_dispatch_load_queue(Manager *m) {
Unit *u;
unsigned n = 0;
@@ -1691,6 +1839,11 @@ unsigned manager_dispatch_load_queue(Manager *m) {
}
m->dispatching_load_queue = false;
+
+ /* Dispatch the units waiting for their target dependencies to be added now, as all targets that we know about
+ * should be loaded and have aliases resolved */
+ (void) manager_dispatch_target_deps_queue(m);
+
return n;
}
@@ -1701,6 +1854,7 @@ int manager_load_unit_prepare(
sd_bus_error *e,
Unit **_ret) {
+ _cleanup_(unit_freep) Unit *cleanup_ret = NULL;
Unit *ret;
UnitType t;
int r;
@@ -1733,29 +1887,26 @@ int manager_load_unit_prepare(
return 1;
}
- ret = unit_new(m, unit_vtable[t]->object_size);
+ ret = cleanup_ret = unit_new(m, unit_vtable[t]->object_size);
if (!ret)
return -ENOMEM;
if (path) {
ret->fragment_path = strdup(path);
- if (!ret->fragment_path) {
- unit_free(ret);
+ if (!ret->fragment_path)
return -ENOMEM;
- }
}
r = unit_add_name(ret, name);
- if (r < 0) {
- unit_free(ret);
+ if (r < 0)
return r;
- }
unit_add_to_load_queue(ret);
unit_add_to_dbus_queue(ret);
unit_add_to_gc_queue(ret);
*_ret = ret;
+ cleanup_ret = NULL;
return 0;
}
@@ -1782,7 +1933,32 @@ int manager_load_unit(
manager_dispatch_load_queue(m);
*_ret = unit_follow_merge(*_ret);
+ return 0;
+}
+
+int manager_load_startable_unit_or_warn(
+ Manager *m,
+ const char *name,
+ const char *path,
+ Unit **ret) {
+
+ /* Load a unit, make sure it loaded fully and is not masked. */
+
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ Unit *unit;
+ int r;
+ r = manager_load_unit(m, name, path, &error, &unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to load %s %s: %s",
+ name ? "unit" : "unit file", name ?: path,
+ bus_error_message(&error, r));
+
+ r = bus_unit_validate_load_state(unit, &error);
+ if (r < 0)
+ return log_error_errno(r, "%s", bus_error_message(&error, r));
+
+ *ret = unit;
return 0;
}
@@ -1853,8 +2029,7 @@ int manager_get_dump_string(Manager *m, char **ret) {
f = safe_fclose(f);
- *ret = dump;
- dump = NULL;
+ *ret = TAKE_PTR(dump);
return 0;
}
@@ -2049,7 +2224,7 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
_cleanup_free_ Unit **array_copy = NULL;
Unit *u1, *u2, **array;
int r, *fd_array = NULL;
- unsigned n_fds = 0;
+ size_t n_fds = 0;
bool found = false;
ssize_t n;
@@ -2283,7 +2458,7 @@ static void manager_handle_ctrl_alt_del(Manager *m) {
* 7 times within 2s, we reboot/shutdown immediately,
* unless it was disabled in system.conf */
- if (ratelimit_test(&m->ctrl_alt_del_ratelimit) || m->cad_burst_action == EMERGENCY_ACTION_NONE)
+ if (ratelimit_below(&m->ctrl_alt_del_ratelimit) || m->cad_burst_action == EMERGENCY_ACTION_NONE)
manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE_IRREVERSIBLY);
else
emergency_action(m, m->cad_burst_action, NULL,
@@ -2335,8 +2510,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
case SIGTERM:
if (MANAGER_IS_SYSTEM(m)) {
- /* This is for compatibility with the
- * original sysvinit */
+ /* This is for compatibility with the original sysvinit */
r = verify_run_space_and_log("Refusing to reexecute");
if (r >= 0)
m->exit_code = MANAGER_REEXECUTE;
@@ -2353,21 +2527,20 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
break;
case SIGWINCH:
+ /* This is a nop on non-init */
if (MANAGER_IS_SYSTEM(m))
manager_start_target(m, SPECIAL_KBREQUEST_TARGET, JOB_REPLACE);
- /* This is a nop on non-init */
break;
case SIGPWR:
+ /* This is a nop on non-init */
if (MANAGER_IS_SYSTEM(m))
manager_start_target(m, SPECIAL_SIGPWR_TARGET, JOB_REPLACE);
- /* This is a nop on non-init */
break;
case SIGUSR1:
-
if (manager_dbus_is_running(m, false)) {
log_info("Trying to reconnect to bus...");
@@ -2450,13 +2623,11 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
break;
case 22:
- log_set_max_level(LOG_DEBUG);
- log_info("Setting log level to debug.");
+ manager_override_log_level(m, LOG_DEBUG);
break;
case 23:
- log_set_max_level(LOG_INFO);
- log_info("Setting log level to info.");
+ manager_restore_original_log_level(m);
break;
case 24:
@@ -2470,18 +2641,15 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
case 26:
case 29: /* compatibility: used to be mapped to LOG_TARGET_SYSLOG_OR_KMSG */
- log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
- log_notice("Setting log target to journal-or-kmsg.");
+ manager_restore_original_log_target(m);
break;
case 27:
- log_set_target(LOG_TARGET_CONSOLE);
- log_notice("Setting log target to console.");
+ manager_override_log_target(m, LOG_TARGET_CONSOLE);
break;
case 28:
- log_set_target(LOG_TARGET_KMSG);
- log_notice("Setting log target to kmsg.");
+ manager_override_log_target(m, LOG_TARGET_KMSG);
break;
default:
@@ -2502,14 +2670,10 @@ static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint
log_struct(LOG_DEBUG,
"MESSAGE_ID=" SD_MESSAGE_TIME_CHANGE_STR,
- LOG_MESSAGE("Time has been changed"),
- NULL);
+ LOG_MESSAGE("Time has been changed"));
/* Restart the watch */
- m->time_change_event_source = sd_event_source_unref(m->time_change_event_source);
- m->time_change_fd = safe_close(m->time_change_fd);
-
- manager_setup_time_change(m);
+ (void) manager_setup_time_change(m);
HASHMAP_FOREACH(u, m->units, i)
if (UNIT_VTABLE(u)->time_change)
@@ -2518,6 +2682,41 @@ static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint
return 0;
}
+static int manager_dispatch_timezone_change(
+ sd_event_source *source,
+ const struct inotify_event *e,
+ void *userdata) {
+
+ Manager *m = userdata;
+ int changed;
+ Iterator i;
+ Unit *u;
+
+ assert(m);
+
+ log_debug("inotify event for /etc/localtime");
+
+ changed = manager_read_timezone_stat(m);
+ if (changed < 0)
+ return changed;
+ if (!changed)
+ return 0;
+
+ /* Something changed, restart the watch, to ensure we watch the new /etc/localtime if it changed */
+ (void) manager_setup_timezone_change(m);
+
+ /* Read the new timezone */
+ tzset();
+
+ log_debug("Timezone has been changed (now: %s).", tzname[daylight]);
+
+ HASHMAP_FOREACH(u, m->units, i)
+ if (UNIT_VTABLE(u)->timezone_change)
+ UNIT_VTABLE(u)->timezone_change(u);
+
+ return 0;
+}
+
static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
Manager *m = userdata;
@@ -2580,7 +2779,7 @@ int manager_loop(Manager *m) {
if (m->runtime_watchdog > 0 && m->runtime_watchdog != USEC_INFINITY && MANAGER_IS_SYSTEM(m))
watchdog_ping();
- if (!ratelimit_test(&rl)) {
+ if (!ratelimit_below(&rl)) {
/* Yay, something is going seriously wrong, pause a little */
log_warning("Looping too fast. Throttling execution a little.");
sleep(1);
@@ -2644,12 +2843,19 @@ int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e,
return 0;
}
- return sd_bus_error_setf(e, BUS_ERROR_NO_UNIT_FOR_INVOCATION_ID, "No unit with the specified invocation ID " SD_ID128_FORMAT_STR " known.", SD_ID128_FORMAT_VAL(invocation_id));
+ return sd_bus_error_setf(e, BUS_ERROR_NO_UNIT_FOR_INVOCATION_ID,
+ "No unit with the specified invocation ID " SD_ID128_FORMAT_STR " known.",
+ SD_ID128_FORMAT_VAL(invocation_id));
}
/* If this didn't work, we check if this is a unit name */
- if (!unit_name_is_valid(n, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
- return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is neither a valid invocation ID nor unit name.", n);
+ if (!unit_name_is_valid(n, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) {
+ _cleanup_free_ char *nn = NULL;
+
+ nn = cescape(n);
+ return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS,
+ "Unit name %s is neither a valid invocation ID nor unit name.", strnull(nn));
+ }
r = manager_load_unit(m, n, NULL, e, &u);
if (r < 0)
@@ -2813,6 +3019,11 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
fprintf(f, "taint-logged=%s\n", yes_no(m->taint_logged));
fprintf(f, "service-watchdogs=%s\n", yes_no(m->service_watchdogs));
+ if (m->log_level_overridden)
+ fprintf(f, "log-level-override=%i\n", log_get_max_level());
+ if (m->log_target_overridden)
+ fprintf(f, "log-target-override=%s\n", log_target_to_string(log_get_target()));
+
for (q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
/* The userspace and finish timestamps only apply to the host system, hence only serialize them there */
if (in_initrd() && IN_SET(q, MANAGER_TIMESTAMP_USERSPACE, MANAGER_TIMESTAMP_FINISH))
@@ -2897,8 +3108,9 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
assert(m->n_reloading > 0);
m->n_reloading--;
- if (ferror(f))
- return -EIO;
+ r = fflush_and_check(f);
+ if (r < 0)
+ return r;
r = bus_fdset_add_all(m, fds);
if (r < 0)
@@ -2996,6 +3208,24 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
else
m->service_watchdogs = b;
+ } else if ((val = startswith(l, "log-level-override="))) {
+ int level;
+
+ level = log_level_from_string(val);
+ if (level < 0)
+ log_notice("Failed to parse log-level-override value '%s', ignoring.", val);
+ else
+ manager_override_log_level(m, level);
+
+ } else if ((val = startswith(l, "log-target-override="))) {
+ LogTarget target;
+
+ target = log_target_from_string(val);
+ if (target < 0)
+ log_notice("Failed to parse log-target-override value '%s', ignoring.", val);
+ else
+ manager_override_log_target(m, target);
+
} else if (startswith(l, "env=")) {
r = deserialize_environment(&m->environment, l);
if (r == -ENOMEM)
@@ -3126,6 +3356,17 @@ finish:
return r;
}
+static void manager_flush_finished_jobs(Manager *m) {
+ Job *j;
+
+ while ((j = set_steal_first(m->pending_finished_jobs))) {
+ bus_job_send_removed_signal(j);
+ job_free(j);
+ }
+
+ m->pending_finished_jobs = set_free(m->pending_finished_jobs);
+}
+
int manager_reload(Manager *m) {
int r, q;
_cleanup_fclose_ FILE *f = NULL;
@@ -3194,8 +3435,7 @@ int manager_reload(Manager *m) {
r = q;
}
- fclose(f);
- f = NULL;
+ f = safe_fclose(f);
/* Re-register notify_fd as event source */
q = manager_setup_notify(m);
@@ -3222,17 +3462,23 @@ int manager_reload(Manager *m) {
exec_runtime_vacuum(m);
+ assert(m->n_reloading > 0);
+ m->n_reloading--;
+
/* It might be safe to log to the journal now and connect to dbus */
manager_recheck_journal(m);
manager_recheck_dbus(m);
+ /* Let's finally catch up with any changes that took place while we were reloading/reexecing */
+ manager_catchup(m);
+
/* Sync current state of bus names with our set of listening units */
q = manager_enqueue_sync_bus_names(m);
if (q < 0 && r >= 0)
r = q;
- assert(m->n_reloading > 0);
- m->n_reloading--;
+ if (!MANAGER_IS_RELOADING(m))
+ manager_flush_finished_jobs(m);
m->send_reloading_done = true;
@@ -3280,8 +3526,7 @@ static void log_taint_string(Manager *m) {
log_struct(LOG_NOTICE,
LOG_MESSAGE("System is tainted: %s", taint),
"TAINT=%s", taint,
- "MESSAGE_ID=" SD_MESSAGE_TAINTED_STR,
- NULL);
+ "MESSAGE_ID=" SD_MESSAGE_TAINTED_STR);
}
static void manager_notify_finished(Manager *m) {
@@ -3328,8 +3573,7 @@ static void manager_notify_finished(Manager *m) {
format_timespan(kernel, sizeof(kernel), kernel_usec, USEC_PER_MSEC),
format_timespan(initrd, sizeof(initrd), initrd_usec, USEC_PER_MSEC),
format_timespan(userspace, sizeof(userspace), userspace_usec, USEC_PER_MSEC),
- format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)),
- NULL);
+ format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)));
} else {
/* The initrd-less case on bare-metal*/
@@ -3344,8 +3588,7 @@ static void manager_notify_finished(Manager *m) {
buf,
format_timespan(kernel, sizeof(kernel), kernel_usec, USEC_PER_MSEC),
format_timespan(userspace, sizeof(userspace), userspace_usec, USEC_PER_MSEC),
- format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)),
- NULL);
+ format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)));
}
} else {
/* The container and --user case */
@@ -3356,8 +3599,7 @@ static void manager_notify_finished(Manager *m) {
"MESSAGE_ID=" SD_MESSAGE_USER_STARTUP_FINISHED_STR,
"USERSPACE_USEC="USEC_FMT, userspace_usec,
LOG_MESSAGE("Startup finished in %s.",
- format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)),
- NULL);
+ format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)));
}
bus_manager_send_finished(m, firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec);
@@ -3597,6 +3839,9 @@ void manager_recheck_dbus(Manager *m) {
* connection of the API bus). That's because the system bus after all runs as service of the system instance,
* while in the user instance we can assume it's already there. */
+ if (MANAGER_IS_RELOADING(m))
+ return; /* don't check while we are reloading… */
+
if (manager_dbus_is_running(m, false)) {
(void) bus_init_api(m);
@@ -3647,6 +3892,10 @@ void manager_recheck_journal(Manager *m) {
if (getpid_cached() != 1)
return;
+ /* Don't check this while we are reloading, things might still change */
+ if (MANAGER_IS_RELOADING(m))
+ return;
+
/* The journal is fully and entirely up? If so, let's permit logging to it, if that's configured. If the
* journal is down, don't ever log to it, otherwise we might end up deadlocking ourselves as we might trigger
* an activation ourselves we can't fulfill. */
@@ -3786,7 +4035,7 @@ Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) {
assert(path);
strcpy(p, path);
- path_kill_slashes(p);
+ path_simplify(p, false);
return hashmap_get(m->units_requiring_mounts_for, streq(p, "/") ? "" : p);
}
@@ -4215,6 +4464,59 @@ void manager_unref_console(Manager *m) {
m->no_console_output = false; /* unset no_console_output flag, since the console is definitely free now */
}
+void manager_override_log_level(Manager *m, int level) {
+ _cleanup_free_ char *s = NULL;
+ assert(m);
+
+ if (!m->log_level_overridden) {
+ m->original_log_level = log_get_max_level();
+ m->log_level_overridden = true;
+ }
+
+ (void) log_level_to_string_alloc(level, &s);
+ log_info("Setting log level to %s.", strna(s));
+
+ log_set_max_level(level);
+}
+
+void manager_restore_original_log_level(Manager *m) {
+ _cleanup_free_ char *s = NULL;
+ assert(m);
+
+ if (!m->log_level_overridden)
+ return;
+
+ (void) log_level_to_string_alloc(m->original_log_level, &s);
+ log_info("Restoring log level to original (%s).", strna(s));
+
+ log_set_max_level(m->original_log_level);
+ m->log_level_overridden = false;
+}
+
+void manager_override_log_target(Manager *m, LogTarget target) {
+ assert(m);
+
+ if (!m->log_target_overridden) {
+ m->original_log_target = log_get_target();
+ m->log_target_overridden = true;
+ }
+
+ log_info("Setting log target to %s.", log_target_to_string(target));
+ log_set_target(target);
+}
+
+void manager_restore_original_log_target(Manager *m) {
+ assert(m);
+
+ if (!m->log_target_overridden)
+ return;
+
+ log_info("Restoring log target to original %s.", log_target_to_string(m->original_log_target));
+
+ log_set_target(m->original_log_target);
+ m->log_target_overridden = false;
+}
+
static const char *const manager_state_table[_MANAGER_STATE_MAX] = {
[MANAGER_INITIALIZING] = "initializing",
[MANAGER_STARTING] = "starting",
diff --git a/src/core/manager.h b/src/core/manager.h
index d4eaaa1c4b..ea5d425030 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -1,26 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <libmount.h>
#include <stdbool.h>
#include <stdio.h>
@@ -34,6 +14,9 @@
#include "list.h"
#include "ratelimit.h"
+struct libmnt_monitor;
+typedef struct Unit Unit;
+
/* Enforce upper limit how many names we allow */
#define MANAGER_MAX_NAMES 131072 /* 128K */
@@ -96,10 +79,11 @@ typedef enum ManagerTimestamp {
enum {
/* 0 = run normally */
- MANAGER_TEST_RUN_MINIMAL = 1, /* run test w/o generators */
- MANAGER_TEST_RUN_ENV_GENERATORS = 2, /* also run env generators */
- MANAGER_TEST_RUN_GENERATORS = 4, /* also run unit generators */
- MANAGER_TEST_FULL = MANAGER_TEST_RUN_ENV_GENERATORS | MANAGER_TEST_RUN_GENERATORS,
+ MANAGER_TEST_RUN_MINIMAL = 1 << 1, /* create basic data structures */
+ MANAGER_TEST_RUN_BASIC = 1 << 2, /* interact with the environment */
+ MANAGER_TEST_RUN_ENV_GENERATORS = 1 << 3, /* also run env generators */
+ MANAGER_TEST_RUN_GENERATORS = 1 << 4, /* also run unit generators */
+ MANAGER_TEST_FULL = MANAGER_TEST_RUN_BASIC | MANAGER_TEST_RUN_ENV_GENERATORS | MANAGER_TEST_RUN_GENERATORS,
};
assert_cc((MANAGER_TEST_FULL & UINT8_MAX) == MANAGER_TEST_FULL);
@@ -143,6 +127,9 @@ struct Manager {
/* Units whose cgroup ran empty */
LIST_HEAD(Unit, cgroup_empty_queue);
+ /* Target units whose default target dependencies haven't been set yet */
+ LIST_HEAD(Unit, target_deps_queue);
+
sd_event *event;
/* This maps PIDs we care about to units that are interested in. We allow multiple units to he interested in
@@ -177,6 +164,8 @@ struct Manager {
int time_change_fd;
sd_event_source *time_change_event_source;
+ sd_event_source *timezone_change_event_source;
+
sd_event_source *jobs_in_progress_event_source;
int user_lookup_fds[2];
@@ -257,6 +246,10 @@ struct Manager {
unsigned gc_marker;
+ /* The stat() data the last time we saw /etc/localtime */
+ usec_t etc_localtime_mtime;
+ bool etc_localtime_accessible:1;
+
/* Flags */
ManagerExitCode exit_code:5;
@@ -303,10 +296,18 @@ struct Manager {
uint64_t default_tasks_max;
usec_t default_timer_accuracy_usec;
+ int original_log_level;
+ LogTarget original_log_target;
+ bool log_level_overridden:1;
+ bool log_target_overridden:1;
+
struct rlimit *rlimit[_RLIMIT_MAX];
/* non-zero if we are reloading or reexecuting, */
int n_reloading;
+ /* A set which contains all jobs that started before reload and finished
+ * during it */
+ Set *pending_finished_jobs;
unsigned n_installed_jobs;
unsigned n_failed_jobs;
@@ -379,8 +380,8 @@ struct Manager {
int manager_new(UnitFileScope scope, unsigned test_run_flags, Manager **m);
Manager* manager_free(Manager *m);
+DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
-void manager_enumerate(Manager *m);
int manager_startup(Manager *m, FILE *serialization, FDSet *fds);
Job *manager_get_job(Manager *m, uint32_t id);
@@ -390,6 +391,7 @@ int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j);
int manager_load_unit_prepare(Manager *m, const char *name, const char *path, sd_bus_error *e, Unit **_ret);
int manager_load_unit(Manager *m, const char *name, const char *path, sd_bus_error *e, Unit **_ret);
+int manager_load_startable_unit_or_warn(Manager *m, const char *name, const char *path, Unit **ret);
int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e, Unit **_u);
int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_error *e, Job **_ret);
@@ -462,6 +464,12 @@ char *manager_taint_string(Manager *m);
void manager_ref_console(Manager *m);
void manager_unref_console(Manager *m);
+void manager_override_log_level(Manager *m, int level);
+void manager_restore_original_log_level(Manager *m);
+
+void manager_override_log_target(Manager *m, LogTarget target);
+void manager_restore_original_log_target(Manager *m);
+
const char *manager_state_to_string(ManagerState m) _const_;
ManagerState manager_state_from_string(const char *s) _pure_;
diff --git a/src/core/meson.build b/src/core/meson.build
index 3fc43f6335..3852c5e9d8 100644
--- a/src/core/meson.build
+++ b/src/core/meson.build
@@ -1,19 +1,4 @@
# SPDX-License-Identifier: LGPL-2.1+
-#
-# Copyright 2017 Zbigniew Jędrzejewski-Szmek
-#
-# systemd is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation; either version 2.1 of the License, or
-# (at your option) any later version.
-#
-# systemd is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with systemd; If not, see <http://www.gnu.org/licenses/>.
libcore_la_sources = '''
audit-fd.c
@@ -140,7 +125,7 @@ load_fragment_gperf_gperf = custom_target(
'load-fragment-gperf.gperf',
input : 'load-fragment-gperf.gperf.m4',
output: 'load-fragment-gperf.gperf',
- command : [m4, '-P'] + m4_defines + ['@INPUT@'],
+ command : [meson_apply_m4, config_h, '@INPUT@'],
capture : true)
load_fragment_gperf_c = custom_target(
@@ -163,13 +148,14 @@ libcore = static_library(
load_fragment_gperf_c,
load_fragment_gperf_nulstr_c,
include_directories : includes,
- link_with : [libshared_static],
dependencies : [threads,
+ librt,
libseccomp,
libpam,
libaudit,
libkmod,
libapparmor,
+ libselinux,
libmount])
systemd_sources = files('main.c')
diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c
index 536c17b4d5..16880e6157 100644
--- a/src/core/mount-setup.c
+++ b/src/core/mount-setup.c
@@ -1,27 +1,10 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
#include <ftw.h>
#include <stdlib.h>
#include <sys/mount.h>
+#include <sys/statvfs.h>
#include <unistd.h>
#include "alloc-util.h"
@@ -47,10 +30,10 @@
#include "virt.h"
typedef enum MountMode {
- MNT_NONE = 0,
- MNT_FATAL = 1 << 0,
- MNT_IN_CONTAINER = 1 << 1,
- MNT_CHECK_WRITABLE = 1 << 2,
+ MNT_NONE = 0,
+ MNT_FATAL = 1 << 0,
+ MNT_IN_CONTAINER = 1 << 1,
+ MNT_CHECK_WRITABLE = 1 << 2,
} MountMode;
typedef struct MountPoint {
@@ -168,7 +151,7 @@ static int mount_one(const MountPoint *p, bool relabel) {
/* Relabel first, just in case */
if (relabel)
- (void) label_fix(p->where, true, true);
+ (void) label_fix(p->where, LABEL_IGNORE_ENOENT|LABEL_IGNORE_EROFS);
r = path_is_mount_point(p->where, NULL, AT_SYMLINK_FOLLOW);
if (r < 0 && r != -ENOENT) {
@@ -206,7 +189,7 @@ static int mount_one(const MountPoint *p, bool relabel) {
/* Relabel again, since we now mounted something fresh here */
if (relabel)
- (void) label_fix(p->where, false, false);
+ (void) label_fix(p->where, 0);
if (p->mode & MNT_CHECK_WRITABLE) {
if (access(p->where, W_OK) < 0) {
@@ -248,6 +231,7 @@ int mount_setup_early(void) {
int mount_cgroup_controllers(char ***join_controllers) {
_cleanup_set_free_free_ Set *controllers = NULL;
+ bool has_argument = !!join_controllers;
int r;
if (!cg_is_legacy_wanted())
@@ -255,7 +239,7 @@ int mount_cgroup_controllers(char ***join_controllers) {
/* Mount all available cgroup controllers that are built into the kernel. */
- if (!join_controllers)
+ if (!has_argument)
/* The defaults:
* mount "cpu" + "cpuacct" together, and "net_cls" + "net_prio".
*
@@ -290,7 +274,7 @@ int mount_cgroup_controllers(char ***join_controllers) {
if (strv_find(*k, controller))
break;
- if (k && *k) {
+ if (*k) {
char **i, **j;
for (i = *k, j = *k; *i; i++) {
@@ -300,7 +284,8 @@ int mount_cgroup_controllers(char ***join_controllers) {
t = set_remove(controllers, *i);
if (!t) {
- free(*i);
+ if (has_argument)
+ free(*i);
continue;
}
}
@@ -313,10 +298,8 @@ int mount_cgroup_controllers(char ***join_controllers) {
options = strv_join(*k, ",");
if (!options)
return log_oom();
- } else {
- options = controller;
- controller = NULL;
- }
+ } else
+ options = TAKE_PTR(controller);
where = strappend("/sys/fs/cgroup/", options);
if (!where)
@@ -329,7 +312,7 @@ int mount_cgroup_controllers(char ***join_controllers) {
if (r < 0)
return r;
- if (r > 0 && k && *k) {
+ if (r > 0 && *k) {
char **i;
for (i = *k; *i; i++) {
@@ -374,7 +357,7 @@ static int nftw_cb(
if (_unlikely_(ftwbuf->level == 0))
return FTW_CONTINUE;
- label_fix(fpath, false, false);
+ (void) label_fix(fpath, 0);
/* /run/initramfs is static data and big, no need to
* dynamically relabel its contents at boot... */
@@ -385,6 +368,34 @@ static int nftw_cb(
return FTW_CONTINUE;
};
+
+static int relabel_cgroup_filesystems(void) {
+ int r;
+ struct statfs st;
+
+ r = cg_all_unified();
+ if (r == 0) {
+ /* Temporarily remount the root cgroup filesystem to give it a proper label. Do this
+ only when the filesystem has been already populated by a previous instance of systemd
+ running from initrd. Otherwise don't remount anything and leave the filesystem read-write
+ for the cgroup filesystems to be mounted inside. */
+ if (statfs("/sys/fs/cgroup", &st) < 0)
+ return log_error_errno(errno, "Failed to determine mount flags for /sys/fs/cgroup: %m");
+
+ if (st.f_flags & ST_RDONLY)
+ (void) mount(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT, NULL);
+
+ (void) label_fix("/sys/fs/cgroup", 0);
+ (void) nftw("/sys/fs/cgroup", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
+
+ if (st.f_flags & ST_RDONLY)
+ (void) mount(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT|MS_RDONLY, NULL);
+
+ } else if (r < 0)
+ return log_error_errno(r, "Failed to determine whether we are in all unified mode: %m");
+
+ return 0;
+}
#endif
int mount_setup(bool loaded_policy) {
@@ -405,19 +416,13 @@ int mount_setup(bool loaded_policy) {
before_relabel = now(CLOCK_MONOTONIC);
- nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
- nftw("/dev/shm", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
- nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
+ (void) nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
+ (void) nftw("/dev/shm", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
+ (void) nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
- /* Temporarily remount the root cgroup filesystem to give it a proper label. */
- r = cg_all_unified();
- if (r == 0) {
- (void) mount(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT, NULL);
- label_fix("/sys/fs/cgroup", false, false);
- nftw("/sys/fs/cgroup", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
- (void) mount(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT|MS_RDONLY, NULL);
- } else if (r < 0)
- return log_error_errno(r, "Failed to determine whether we are in all unified mode: %m");
+ r = relabel_cgroup_filesystems();
+ if (r < 0)
+ return r;
after_relabel = now(CLOCK_MONOTONIC);
@@ -447,14 +452,20 @@ int mount_setup(bool loaded_policy) {
(void) mkdir_label("/run/systemd", 0755);
(void) mkdir_label("/run/systemd/system", 0755);
- /* Set up inaccessible items */
+ /* Set up inaccessible (and empty) file nodes of all types */
(void) mkdir_label("/run/systemd/inaccessible", 0000);
(void) mknod("/run/systemd/inaccessible/reg", S_IFREG | 0000, 0);
(void) mkdir_label("/run/systemd/inaccessible/dir", 0000);
- (void) mknod("/run/systemd/inaccessible/chr", S_IFCHR | 0000, makedev(0, 0));
- (void) mknod("/run/systemd/inaccessible/blk", S_IFBLK | 0000, makedev(0, 0));
(void) mkfifo("/run/systemd/inaccessible/fifo", 0000);
(void) mknod("/run/systemd/inaccessible/sock", S_IFSOCK | 0000, 0);
+ /* The following two are likely to fail if we lack the privs for it (for example in an userns environment, if
+ * CAP_SYS_MKNOD is missing, or if a device node policy prohibit major/minor of 0 device nodes to be
+ * created). But that's entirely fine. Consumers of these files should carry fallback to use a different node
+ * then, for example /run/systemd/inaccessible/sock, which is close enough in behaviour and semantics for most
+ * uses. */
+ (void) mknod("/run/systemd/inaccessible/chr", S_IFCHR | 0000, makedev(0, 0));
+ (void) mknod("/run/systemd/inaccessible/blk", S_IFBLK | 0000, makedev(0, 0));
+
return 0;
}
diff --git a/src/core/mount-setup.h b/src/core/mount-setup.h
index 2c96e64e52..43cd8908de 100644
--- a/src/core/mount-setup.h
+++ b/src/core/mount-setup.h
@@ -1,25 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include <stdbool.h>
int mount_setup_early(void);
diff --git a/src/core/mount.c b/src/core/mount.c
index cfe8ec9044..21437dad08 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -1,32 +1,17 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <sys/epoll.h>
+#include <libmount.h>
+
#include "sd-messages.h"
#include "alloc-util.h"
#include "dbus-mount.h"
+#include "device.h"
#include "escape.h"
#include "exit-status.h"
#include "format-util.h"
@@ -527,23 +512,23 @@ static int mount_verify(Mount *m) {
if (!unit_has_name(UNIT(m), e)) {
log_unit_error(UNIT(m), "Where= setting doesn't match unit name. Refusing.");
- return -EINVAL;
+ return -ENOEXEC;
}
if (mount_point_is_api(m->where) || mount_point_ignore(m->where)) {
log_unit_error(UNIT(m), "Cannot create mount unit for API file system %s. Refusing.", m->where);
- return -EINVAL;
+ return -ENOEXEC;
}
p = get_mount_parameters_fragment(m);
if (p && !p->what) {
log_unit_error(UNIT(m), "What= setting is missing. Refusing.");
- return -EBADMSG;
+ return -ENOEXEC;
}
if (m->exec_context.pam_name && m->kill_context.kill_mode != KILL_CONTROL_GROUP) {
log_unit_error(UNIT(m), "Unit has PAM enabled. Kill mode must be set to control-group'. Refusing.");
- return -EINVAL;
+ return -ENOEXEC;
}
return 0;
@@ -564,7 +549,7 @@ static int mount_add_extras(Mount *m) {
return r;
}
- path_kill_slashes(m->where);
+ path_simplify(m->where, false);
if (!u->description) {
r = unit_set_description(u, m->where);
@@ -667,7 +652,8 @@ static void mount_set_state(Mount *m, MountState state) {
if (state != old_state)
log_unit_debug(UNIT(m), "Changed %s -> %s", mount_state_to_string(old_state), mount_state_to_string(state));
- unit_notify(UNIT(m), state_translation_table[old_state], state_translation_table[state], m->reload_result == MOUNT_SUCCESS);
+ unit_notify(UNIT(m), state_translation_table[old_state], state_translation_table[state],
+ m->reload_result == MOUNT_SUCCESS ? 0 : UNIT_NOTIFY_RELOAD_FAILURE);
}
static int mount_coldplug(Unit *u) {
@@ -1608,11 +1594,8 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
assert(m);
t = mnt_new_table();
- if (!t)
- return log_oom();
-
i = mnt_new_iter(MNT_ITER_FORWARD);
- if (!i)
+ if (!t || !i)
return log_oom();
r = mnt_table_parse_mtab(t, NULL);
@@ -1621,9 +1604,9 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
r = 0;
for (;;) {
+ struct libmnt_fs *fs;
const char *device, *path, *options, *fstype;
_cleanup_free_ char *d = NULL, *p = NULL;
- struct libmnt_fs *fs;
int k;
k = mnt_table_next_fs(t, i, &fs);
@@ -1646,7 +1629,7 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
if (cunescape(path, UNESCAPE_RELAX, &p) < 0)
return log_oom();
- (void) device_found_node(m, d, true, DEVICE_FOUND_MOUNT, set_flags);
+ device_found_node(m, d, DEVICE_FOUND_MOUNT, DEVICE_FOUND_MOUNT);
k = mount_setup_unit(m, d, p, options, fstype, set_flags);
if (r == 0 && k < 0)
@@ -1683,7 +1666,7 @@ static int mount_get_timeout(Unit *u, usec_t *timeout) {
return 1;
}
-static int synthesize_root_mount(Manager *m) {
+static void mount_enumerate_perpetual(Manager *m) {
Unit *u;
int r;
@@ -1695,8 +1678,10 @@ static int synthesize_root_mount(Manager *m) {
u = manager_get_unit(m, SPECIAL_ROOT_MOUNT);
if (!u) {
r = unit_new_for_name(m, sizeof(Mount), SPECIAL_ROOT_MOUNT, &u);
- if (r < 0)
- return log_error_errno(r, "Failed to allocate the special " SPECIAL_ROOT_MOUNT " unit: %m");
+ if (r < 0) {
+ log_error_errno(r, "Failed to allocate the special " SPECIAL_ROOT_MOUNT " unit: %m");
+ return;
+ }
}
u->perpetual = true;
@@ -1704,8 +1689,6 @@ static int synthesize_root_mount(Manager *m) {
unit_add_to_load_queue(u);
unit_add_to_dbus_queue(u);
-
- return 0;
}
static bool mount_is_mounted(Mount *m) {
@@ -1719,10 +1702,6 @@ static void mount_enumerate(Manager *m) {
assert(m);
- r = synthesize_root_mount(m);
- if (r < 0)
- goto fail;
-
mnt_init_debug(0);
if (!m->mount_monitor) {
@@ -1908,7 +1887,7 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
continue;
/* Let the device units know that the device is no longer mounted */
- (void) device_found_node(m, what, false, DEVICE_FOUND_MOUNT, true);
+ device_found_node(m, what, 0, DEVICE_FOUND_MOUNT);
}
return 0;
@@ -2013,6 +1992,7 @@ const UnitVTable mount_vtable = {
.can_transient = true,
+ .enumerate_perpetual = mount_enumerate_perpetual,
.enumerate = mount_enumerate,
.shutdown = mount_shutdown,
diff --git a/src/core/mount.h b/src/core/mount.h
index 1a496def84..67ab8ecf93 100644
--- a/src/core/mount.h
+++ b/src/core/mount.h
@@ -1,29 +1,11 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
typedef struct Mount Mount;
#include "kill.h"
#include "dynamic-user.h"
+#include "unit.h"
typedef enum MountExecCommand {
MOUNT_EXEC_MOUNT,
@@ -110,3 +92,5 @@ MountExecCommand mount_exec_command_from_string(const char *s) _pure_;
const char* mount_result_to_string(MountResult i) _const_;
MountResult mount_result_from_string(const char *s) _pure_;
+
+DEFINE_CAST(MOUNT, Mount);
diff --git a/src/core/namespace.c b/src/core/namespace.c
index 0e9c7b8fb4..e4930db15c 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
#include <sched.h>
@@ -74,16 +56,18 @@ typedef struct MountEntry {
bool ignore:1; /* Ignore if path does not exist? */
bool has_prefix:1; /* Already is prefixed by the root dir? */
bool read_only:1; /* Shall this mount point be read-only? */
+ bool applied:1; /* Already applied */
char *path_malloc; /* Use this instead of 'path_const' if we had to allocate memory */
const char *source_const; /* The source path, for bind mounts */
char *source_malloc;
const char *options_const;/* Mount options for tmpfs */
char *options_malloc;
unsigned long flags; /* Mount flags used by EMPTY_DIR and TMPFS. Do not include MS_RDONLY here, but please use read_only. */
+ unsigned n_followed;
} MountEntry;
/* If MountAPIVFS= is used, let's mount /sys and /proc into the it, but only as a fallback if the user hasn't mounted
- * something there already. These mounts are hence overriden by any other explicitly configured mounts. */
+ * something there already. These mounts are hence overridden by any other explicitly configured mounts. */
static const MountEntry apivfs_table[] = {
{ "/proc", PROCFS, false },
{ "/dev", BIND_DEV, false },
@@ -92,23 +76,26 @@ static const MountEntry apivfs_table[] = {
/* ProtectKernelTunables= option and the related filesystem APIs */
static const MountEntry protect_kernel_tunables_table[] = {
- { "/proc/sys", READONLY, false },
- { "/proc/sysrq-trigger", READONLY, true },
- { "/proc/latency_stats", READONLY, true },
- { "/proc/mtrr", READONLY, true },
- { "/proc/apm", READONLY, true }, /* Obsolete API, there's no point in permitting access to this, ever */
{ "/proc/acpi", READONLY, true },
- { "/proc/timer_stats", READONLY, true },
+ { "/proc/apm", READONLY, true }, /* Obsolete API, there's no point in permitting access to this, ever */
{ "/proc/asound", READONLY, true },
{ "/proc/bus", READONLY, true },
{ "/proc/fs", READONLY, true },
{ "/proc/irq", READONLY, true },
+ { "/proc/kallsyms", INACCESSIBLE, true },
+ { "/proc/kcore", INACCESSIBLE, true },
+ { "/proc/latency_stats", READONLY, true },
+ { "/proc/mtrr", READONLY, true },
+ { "/proc/scsi", READONLY, true },
+ { "/proc/sys", READONLY, false },
+ { "/proc/sysrq-trigger", READONLY, true },
+ { "/proc/timer_stats", READONLY, true },
{ "/sys", READONLY, false },
- { "/sys/kernel/debug", READONLY, true },
- { "/sys/kernel/tracing", READONLY, true },
{ "/sys/fs/bpf", READONLY, true },
{ "/sys/fs/cgroup", READWRITE, false }, /* READONLY is set by ProtectControlGroups= option */
{ "/sys/fs/selinux", READWRITE, true },
+ { "/sys/kernel/debug", READONLY, true },
+ { "/sys/kernel/tracing", READONLY, true },
};
/* ProtectKernelModules= option */
@@ -286,8 +273,8 @@ static int append_empty_dir_mounts(MountEntry **p, char **strv) {
return 0;
}
-static int append_bind_mounts(MountEntry **p, const BindMount *binds, unsigned n) {
- unsigned i;
+static int append_bind_mounts(MountEntry **p, const BindMount *binds, size_t n) {
+ size_t i;
assert(p);
@@ -306,8 +293,8 @@ static int append_bind_mounts(MountEntry **p, const BindMount *binds, unsigned n
return 0;
}
-static int append_tmpfs_mounts(MountEntry **p, const TemporaryFileSystem *tmpfs, unsigned n) {
- unsigned i;
+static int append_tmpfs_mounts(MountEntry **p, const TemporaryFileSystem *tmpfs, size_t n) {
+ size_t i;
int r;
assert(p);
@@ -330,7 +317,7 @@ static int append_tmpfs_mounts(MountEntry **p, const TemporaryFileSystem *tmpfs,
if (r < 0)
return r;
- ro = !!(flags & MS_RDONLY);
+ ro = flags & MS_RDONLY;
if (ro)
flags ^= MS_RDONLY;
}
@@ -349,8 +336,8 @@ static int append_tmpfs_mounts(MountEntry **p, const TemporaryFileSystem *tmpfs,
return 0;
}
-static int append_static_mounts(MountEntry **p, const MountEntry *mounts, unsigned n, bool ignore_protect) {
- unsigned i;
+static int append_static_mounts(MountEntry **p, const MountEntry *mounts, size_t n, bool ignore_protect) {
+ size_t i;
assert(p);
assert(mounts);
@@ -423,15 +410,14 @@ static int mount_path_compare(const void *a, const void *b) {
/* If the paths are equal, check the mode */
if (p->mode < q->mode)
return -1;
-
if (p->mode > q->mode)
return 1;
return 0;
}
-static int prefix_where_needed(MountEntry *m, unsigned n, const char *root_directory) {
- unsigned i;
+static int prefix_where_needed(MountEntry *m, size_t n, const char *root_directory) {
+ size_t i;
/* Prefixes all paths in the bind mount table with the root directory if it is specified and the entry needs
* that. */
@@ -456,7 +442,7 @@ static int prefix_where_needed(MountEntry *m, unsigned n, const char *root_direc
return 0;
}
-static void drop_duplicates(MountEntry *m, unsigned *n) {
+static void drop_duplicates(MountEntry *m, size_t *n) {
MountEntry *f, *t, *previous;
assert(m);
@@ -467,8 +453,10 @@ static void drop_duplicates(MountEntry *m, unsigned *n) {
for (f = m, t = m, previous = NULL; f < m + *n; f++) {
/* The first one wins (which is the one with the more restrictive mode), see mount_path_compare()
- * above. */
- if (previous && path_equal(mount_entry_path(f), mount_entry_path(previous))) {
+ * above. Note that we only drop duplicates that haven't been mounted yet. */
+ if (previous &&
+ path_equal(mount_entry_path(f), mount_entry_path(previous)) &&
+ !f->applied && !previous->applied) {
log_debug("%s is duplicate.", mount_entry_path(f));
previous->read_only = previous->read_only || mount_entry_read_only(f); /* Propagate the read-only flag to the remaining entry */
mount_entry_done(f);
@@ -483,7 +471,7 @@ static void drop_duplicates(MountEntry *m, unsigned *n) {
*n = t - m;
}
-static void drop_inaccessible(MountEntry *m, unsigned *n) {
+static void drop_inaccessible(MountEntry *m, size_t *n) {
MountEntry *f, *t;
const char *clear = NULL;
@@ -512,7 +500,7 @@ static void drop_inaccessible(MountEntry *m, unsigned *n) {
*n = t - m;
}
-static void drop_nop(MountEntry *m, unsigned *n) {
+static void drop_nop(MountEntry *m, size_t *n) {
MountEntry *f, *t;
assert(m);
@@ -551,7 +539,7 @@ static void drop_nop(MountEntry *m, unsigned *n) {
*n = t - m;
}
-static void drop_outside_root(const char *root_directory, MountEntry *m, unsigned *n) {
+static void drop_outside_root(const char *root_directory, MountEntry *m, size_t *n) {
MountEntry *f, *t;
assert(m);
@@ -578,14 +566,14 @@ static void drop_outside_root(const char *root_directory, MountEntry *m, unsigne
*n = t - m;
}
-static int clone_device_node(const char *d, const char *temporary_mount) {
+static int clone_device_node(const char *d, const char *temporary_mount, bool *make_devnode) {
const char *dn;
struct stat st;
int r;
if (stat(d, &st) < 0) {
if (errno == ENOENT)
- return 0;
+ return -ENXIO;
return -errno;
}
@@ -594,17 +582,41 @@ static int clone_device_node(const char *d, const char *temporary_mount) {
return -EINVAL;
if (st.st_rdev == 0)
- return 0;
+ return -ENXIO;
dn = strjoina(temporary_mount, d);
- mac_selinux_create_file_prepare(d, st.st_mode);
- r = mknod(dn, st.st_mode, st.st_rdev);
+ if (*make_devnode) {
+ mac_selinux_create_file_prepare(d, st.st_mode);
+ r = mknod(dn, st.st_mode, st.st_rdev);
+ mac_selinux_create_file_clear();
+
+ if (r == 0)
+ return 0;
+ if (errno != EPERM)
+ return log_debug_errno(errno, "mknod failed for %s: %m", d);
+
+ *make_devnode = false;
+ }
+
+ /* We're about to fallback to bind-mounting the device
+ * node. So create a dummy bind-mount target. */
+ mac_selinux_create_file_prepare(d, 0);
+ r = mknod(dn, S_IFREG, 0);
mac_selinux_create_file_clear();
- if (r < 0)
- return log_debug_errno(errno, "mknod failed for %s: %m", d);
- return 1;
+ if (r < 0 && errno != EEXIST)
+ return log_debug_errno(errno, "mknod fallback failed for %s: %m", d);
+
+ /* Fallback to bind-mounting:
+ * The assumption here is that all used device nodes carry standard
+ * properties. Specifically, the devices nodes we bind-mount should
+ * either be owned by root:root or root:tty (e.g. /dev/tty, /dev/ptmx)
+ * and should not carry ACLs. */
+ if (mount(d, dn, NULL, MS_BIND, NULL) < 0)
+ return log_debug_errno(errno, "mount failed for %s: %m", d);
+
+ return 0;
}
static int mount_private_dev(MountEntry *m) {
@@ -618,6 +630,7 @@ static int mount_private_dev(MountEntry *m) {
char temporary_mount[] = "/tmp/namespace-dev-XXXXXX";
const char *d, *dev = NULL, *devpts = NULL, *devshm = NULL, *devhugepages = NULL, *devmqueue = NULL, *devlog = NULL, *devptmx = NULL;
+ bool can_mknod = true;
_cleanup_umask_ mode_t u;
int r;
@@ -658,13 +671,9 @@ static int mount_private_dev(MountEntry *m) {
goto fail;
}
} else {
- r = clone_device_node("/dev/ptmx", temporary_mount);
+ r = clone_device_node("/dev/ptmx", temporary_mount, &can_mknod);
if (r < 0)
goto fail;
- if (r == 0) {
- r = -ENXIO;
- goto fail;
- }
}
devshm = strjoina(temporary_mount, "/dev/shm");
@@ -687,8 +696,9 @@ static int mount_private_dev(MountEntry *m) {
(void) symlink("/run/systemd/journal/dev-log", devlog);
NULSTR_FOREACH(d, devnodes) {
- r = clone_device_node(d, temporary_mount);
- if (r < 0)
+ r = clone_device_node(d, temporary_mount, &can_mknod);
+ /* ENXIO means the the *source* is not a device file, skip creation in that case */
+ if (r < 0 && r != -ENXIO)
goto fail;
}
@@ -808,36 +818,37 @@ static int mount_tmpfs(const MountEntry *m) {
return 1;
}
-static int mount_entry_chase(
+static int follow_symlink(
const char *root_directory,
- const MountEntry *m,
- const char *path,
- bool chase_nonexistent,
- char **location) {
+ MountEntry *m) {
- char *chased;
+ _cleanup_free_ char *target = NULL;
int r;
- assert(m);
+ /* Let's chase symlinks, but only one step at a time. That's because depending where the symlink points we
+ * might need to change the order in which we mount stuff. Hence: let's normalize piecemeal, and do one step at
+ * a time by specifying CHASE_STEP. This function returns 0 if we resolved one step, and > 0 if we reached the
+ * end and already have a fully normalized name. */
- /* Since mount() will always follow symlinks and we need to take the different root directory into account we
- * chase the symlinks on our own first. This is called for the destination path, as well as the source path (if
- * that applies). The result is stored in "location". */
+ r = chase_symlinks(mount_entry_path(m), root_directory, CHASE_STEP|CHASE_NONEXISTENT, &target);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to chase symlinks '%s': %m", mount_entry_path(m));
+ if (r > 0) /* Reached the end, nothing more to resolve */
+ return 1;
- r = chase_symlinks(path, root_directory, chase_nonexistent ? CHASE_NONEXISTENT : 0, &chased);
- if (r == -ENOENT && m->ignore) {
- log_debug_errno(r, "Path %s does not exist, ignoring.", path);
- return 0;
+ if (m->n_followed >= CHASE_SYMLINKS_MAX) { /* put a boundary on things */
+ log_debug("Symlink loop on '%s'.", mount_entry_path(m));
+ return -ELOOP;
}
- if (r < 0)
- return log_debug_errno(r, "Failed to follow symlinks on %s: %m", path);
- log_debug("Followed symlinks %s → %s.", path, chased);
+ log_debug("Followed mount entry path symlink %s → %s.", mount_entry_path(m), target);
- free(*location);
- *location = chased;
+ free_and_replace(m->path_malloc, target);
+ m->has_prefix = true;
- return 1;
+ m->n_followed ++;
+
+ return 0;
}
static int apply_mount(
@@ -850,10 +861,6 @@ static int apply_mount(
assert(m);
- r = mount_entry_chase(root_directory, m, mount_entry_path(m), !IN_SET(m->mode, INACCESSIBLE, READONLY, READWRITE), &m->path_malloc);
- if (r <= 0)
- return r;
-
log_debug("Applying namespace mount on %s", mount_entry_path(m));
switch (m->mode) {
@@ -866,8 +873,12 @@ static int apply_mount(
* inaccessible path. */
(void) umount_recursive(mount_entry_path(m), 0);
- if (lstat(mount_entry_path(m), &target) < 0)
+ if (lstat(mount_entry_path(m), &target) < 0) {
+ if (errno == ENOENT && m->ignore)
+ return 0;
+
return log_debug_errno(errno, "Failed to lstat() %s to determine what to mount over it: %m", mount_entry_path(m));
+ }
what = mode_to_inaccessible_node(target.st_mode);
if (!what) {
@@ -880,6 +891,8 @@ static int apply_mount(
case READONLY:
case READWRITE:
r = path_is_mount_point(mount_entry_path(m), root_directory, 0);
+ if (r == -ENOENT && m->ignore)
+ return 0;
if (r < 0)
return log_debug_errno(r, "Failed to determine whether %s is already a mount point: %m", mount_entry_path(m));
if (r > 0) /* Nothing to do here, it is already a mount. We just later toggle the MS_RDONLY bit for the mount point if needed. */
@@ -892,16 +905,29 @@ static int apply_mount(
rbind = false;
_fallthrough_;
- case BIND_MOUNT_RECURSIVE:
- /* Also chase the source mount */
+ case BIND_MOUNT_RECURSIVE: {
+ _cleanup_free_ char *chased = NULL;
- r = mount_entry_chase(root_directory, m, mount_entry_source(m), false, &m->source_malloc);
- if (r <= 0)
- return r;
+ /* Since mount() will always follow symlinks we chase the symlinks on our own first. Note that bind
+ * mount source paths are always relative to the host root, hence we pass NULL as root directory to
+ * chase_symlinks() here. */
+
+ r = chase_symlinks(mount_entry_source(m), NULL, CHASE_TRAIL_SLASH, &chased);
+ if (r == -ENOENT && m->ignore) {
+ log_debug_errno(r, "Path %s does not exist, ignoring.", mount_entry_source(m));
+ return 0;
+ }
+ if (r < 0)
+ return log_debug_errno(r, "Failed to follow symlinks on %s: %m", mount_entry_source(m));
+
+ log_debug("Followed source symlinks %s → %s.", mount_entry_source(m), chased);
+
+ free_and_replace(m->source_malloc, chased);
what = mount_entry_source(m);
make = true;
break;
+ }
case EMPTY_DIR:
case TMPFS:
@@ -939,14 +965,22 @@ static int apply_mount(
/* Hmm, either the source or the destination are missing. Let's see if we can create the destination, then try again */
- if (stat(what, &st) >= 0) {
+ if (stat(what, &st) < 0)
+ log_debug_errno(errno, "Mount point source '%s' is not accessible: %m", what);
+ else {
+ int q;
(void) mkdir_parents(mount_entry_path(m), 0755);
if (S_ISDIR(st.st_mode))
- try_again = mkdir(mount_entry_path(m), 0755) >= 0;
+ q = mkdir(mount_entry_path(m), 0755) < 0 ? -errno : 0;
+ else
+ q = touch(mount_entry_path(m));
+
+ if (q < 0)
+ log_debug_errno(q, "Failed to create destination mount point node '%s': %m", mount_entry_path(m));
else
- try_again = touch(mount_entry_path(m)) >= 0;
+ try_again = true;
}
}
@@ -1011,22 +1045,22 @@ static bool namespace_info_mount_apivfs(const char *root_directory, const Namesp
ns_info->protect_kernel_tunables);
}
-static unsigned namespace_calculate_mounts(
+static size_t namespace_calculate_mounts(
const char* root_directory,
const NamespaceInfo *ns_info,
char** read_write_paths,
char** read_only_paths,
char** inaccessible_paths,
char** empty_directories,
- unsigned n_bind_mounts,
- unsigned n_temporary_filesystems,
+ size_t n_bind_mounts,
+ size_t n_temporary_filesystems,
const char* tmp_dir,
const char* var_tmp_dir,
ProtectHome protect_home,
ProtectSystem protect_system) {
- unsigned protect_home_cnt;
- unsigned protect_system_cnt =
+ size_t protect_home_cnt;
+ size_t protect_system_cnt =
(protect_system == PROTECT_SYSTEM_STRICT ?
ELEMENTSOF(protect_system_strict_table) :
((protect_system == PROTECT_SYSTEM_FULL) ?
@@ -1057,6 +1091,18 @@ static unsigned namespace_calculate_mounts(
(namespace_info_mount_apivfs(root_directory, ns_info) ? ELEMENTSOF(apivfs_table) : 0);
}
+static void normalize_mounts(const char *root_directory, MountEntry *mounts, size_t *n_mounts) {
+ assert(n_mounts);
+ assert(mounts || *n_mounts == 0);
+
+ qsort_safe(mounts, *n_mounts, sizeof(MountEntry), mount_path_compare);
+
+ drop_duplicates(mounts, n_mounts);
+ drop_outside_root(root_directory, mounts, n_mounts);
+ drop_inaccessible(mounts, n_mounts);
+ drop_nop(mounts, n_mounts);
+}
+
int setup_namespace(
const char* root_directory,
const char* root_image,
@@ -1066,9 +1112,9 @@ int setup_namespace(
char** inaccessible_paths,
char** empty_directories,
const BindMount *bind_mounts,
- unsigned n_bind_mounts,
+ size_t n_bind_mounts,
const TemporaryFileSystem *temporary_filesystems,
- unsigned n_temporary_filesystems,
+ size_t n_temporary_filesystems,
const char* tmp_dir,
const char* var_tmp_dir,
ProtectHome protect_home,
@@ -1082,9 +1128,9 @@ int setup_namespace(
_cleanup_free_ void *root_hash = NULL;
MountEntry *m, *mounts = NULL;
size_t root_hash_size = 0;
- bool make_slave = false;
const char *root;
- unsigned n_mounts;
+ size_t n_mounts;
+ bool make_slave;
bool require_prefix = false;
int r = 0;
@@ -1096,7 +1142,9 @@ int setup_namespace(
if (root_image) {
dissect_image_flags |= DISSECT_IMAGE_REQUIRE_ROOT;
- if (protect_system == PROTECT_SYSTEM_STRICT && strv_isempty(read_write_paths))
+ if (protect_system == PROTECT_SYSTEM_STRICT &&
+ protect_home != PROTECT_HOME_NO &&
+ strv_isempty(read_write_paths))
dissect_image_flags |= DISSECT_IMAGE_READ_ONLY;
r = loop_device_make_by_path(root_image,
@@ -1120,19 +1168,17 @@ int setup_namespace(
if (root_directory)
root = root_directory;
- else if (root_image || n_bind_mounts > 0 || n_temporary_filesystems > 0) {
-
- /* If we are booting from an image, create a mount point for the image, if it's still missing. We use
- * the same mount point for all images, which is safe, since they all live in their own namespaces
- * after all, and hence won't see each other. We also use such a root directory whenever there are bind
- * mounts configured, so that their source mounts are never obstructed by mounts we already applied
- * while we are applying them. */
+ else {
+ /* Always create the mount namespace in a temporary directory, instead of operating
+ * directly in the root. The temporary directory prevents any mounts from being
+ * potentially obscured my other mounts we already applied.
+ * We use the same mount point for all images, which is safe, since they all live
+ * in their own namespaces after all, and hence won't see each other. */
root = "/run/systemd/unit-root";
(void) mkdir_label(root, 0700);
require_prefix = true;
- } else
- root = NULL;
+ }
n_mounts = namespace_calculate_mounts(
root,
@@ -1147,8 +1193,7 @@ int setup_namespace(
protect_home, protect_system);
/* Set mount slave mode */
- if (root || n_mounts > 0)
- make_slave = true;
+ make_slave = root || n_mounts > 0 || ns_info->private_mounts;
if (n_mounts > 0) {
m = mounts = (MountEntry *) alloca0(n_mounts * sizeof(MountEntry));
@@ -1239,12 +1284,7 @@ int setup_namespace(
if (r < 0)
goto finish;
- qsort(mounts, n_mounts, sizeof(MountEntry), mount_path_compare);
-
- drop_duplicates(mounts, &n_mounts);
- drop_outside_root(root, mounts, &n_mounts);
- drop_inaccessible(mounts, &n_mounts);
- drop_nop(mounts, &n_mounts);
+ normalize_mounts(root_directory, mounts, &n_mounts);
}
if (unshare(CLONE_NEWNS) < 0) {
@@ -1304,7 +1344,7 @@ int setup_namespace(
if (n_mounts > 0) {
_cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
char **blacklist;
- unsigned j;
+ size_t j;
/* Open /proc/self/mountinfo now as it may become unavailable if we mount anything on top of /proc.
* For example, this is the case with the option: 'InaccessiblePaths=/proc' */
@@ -1314,11 +1354,38 @@ int setup_namespace(
goto finish;
}
- /* First round, add in all special mounts we need */
- for (m = mounts; m < mounts + n_mounts; ++m) {
- r = apply_mount(root, m);
- if (r < 0)
- goto finish;
+ /* First round, establish all mounts we need */
+ for (;;) {
+ bool again = false;
+
+ for (m = mounts; m < mounts + n_mounts; ++m) {
+
+ if (m->applied)
+ continue;
+
+ r = follow_symlink(root, m);
+ if (r < 0)
+ goto finish;
+ if (r == 0) {
+ /* We hit a symlinked mount point. The entry got rewritten and might point to a
+ * very different place now. Let's normalize the changed list, and start from
+ * the beginning. After all to mount the entry at the new location we might
+ * need some other mounts first */
+ again = true;
+ break;
+ }
+
+ r = apply_mount(root, m);
+ if (r < 0)
+ goto finish;
+
+ m->applied = true;
+ }
+
+ if (!again)
+ break;
+
+ normalize_mounts(root_directory, mounts, &n_mounts);
}
/* Create a blacklist we can pass to bind_mount_recursive() */
@@ -1359,8 +1426,8 @@ finish:
return r;
}
-void bind_mount_free_many(BindMount *b, unsigned n) {
- unsigned i;
+void bind_mount_free_many(BindMount *b, size_t n) {
+ size_t i;
assert(b || n == 0);
@@ -1372,7 +1439,7 @@ void bind_mount_free_many(BindMount *b, unsigned n) {
free(b);
}
-int bind_mount_add(BindMount **b, unsigned *n, const BindMount *item) {
+int bind_mount_add(BindMount **b, size_t *n, const BindMount *item) {
_cleanup_free_ char *s = NULL, *d = NULL;
BindMount *c;
@@ -1395,19 +1462,18 @@ int bind_mount_add(BindMount **b, unsigned *n, const BindMount *item) {
*b = c;
c[(*n) ++] = (BindMount) {
- .source = s,
- .destination = d,
+ .source = TAKE_PTR(s),
+ .destination = TAKE_PTR(d),
.read_only = item->read_only,
.recursive = item->recursive,
.ignore_enoent = item->ignore_enoent,
};
- s = d = NULL;
return 0;
}
-void temporary_filesystem_free_many(TemporaryFileSystem *t, unsigned n) {
- unsigned i;
+void temporary_filesystem_free_many(TemporaryFileSystem *t, size_t n) {
+ size_t i;
assert(t || n == 0);
@@ -1421,7 +1487,7 @@ void temporary_filesystem_free_many(TemporaryFileSystem *t, unsigned n) {
int temporary_filesystem_add(
TemporaryFileSystem **t,
- unsigned *n,
+ size_t *n,
const char *path,
const char *options) {
@@ -1449,11 +1515,10 @@ int temporary_filesystem_add(
*t = c;
c[(*n) ++] = (TemporaryFileSystem) {
- .path = p,
- .options = o,
+ .path = TAKE_PTR(p),
+ .options = TAKE_PTR(o),
};
- p = o = NULL;
return 0;
}
@@ -1491,8 +1556,7 @@ static int setup_one_tmp_dir(const char *id, const char *prefix, char **path) {
return -errno;
}
- *path = x;
- x = NULL;
+ *path = TAKE_PTR(x);
return 0;
}
@@ -1608,19 +1672,7 @@ static const char *const protect_home_table[_PROTECT_HOME_MAX] = {
[PROTECT_HOME_TMPFS] = "tmpfs",
};
-DEFINE_STRING_TABLE_LOOKUP(protect_home, ProtectHome);
-
-ProtectHome parse_protect_home_or_bool(const char *s) {
- int r;
-
- r = parse_boolean(s);
- if (r > 0)
- return PROTECT_HOME_YES;
- if (r == 0)
- return PROTECT_HOME_NO;
-
- return protect_home_from_string(s);
-}
+DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(protect_home, ProtectHome, PROTECT_HOME_YES);
static const char *const protect_system_table[_PROTECT_SYSTEM_MAX] = {
[PROTECT_SYSTEM_NO] = "no",
@@ -1629,19 +1681,7 @@ static const char *const protect_system_table[_PROTECT_SYSTEM_MAX] = {
[PROTECT_SYSTEM_STRICT] = "strict",
};
-DEFINE_STRING_TABLE_LOOKUP(protect_system, ProtectSystem);
-
-ProtectSystem parse_protect_system_or_bool(const char *s) {
- int r;
-
- r = parse_boolean(s);
- if (r > 0)
- return PROTECT_SYSTEM_YES;
- if (r == 0)
- return PROTECT_SYSTEM_NO;
-
- return protect_system_from_string(s);
-}
+DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(protect_system, ProtectSystem, PROTECT_SYSTEM_YES);
static const char* const namespace_type_table[] = {
[NAMESPACE_MOUNT] = "mnt",
diff --git a/src/core/namespace.h b/src/core/namespace.h
index 3d56a7302d..1188c6d595 100644
--- a/src/core/namespace.h
+++ b/src/core/namespace.h
@@ -2,23 +2,7 @@
#pragma once
/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
- Copyright 2016 Djalal Harouni
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ Copyright © 2016 Djalal Harouni
***/
typedef struct NamespaceInfo NamespaceInfo;
@@ -63,6 +47,7 @@ typedef enum ProtectSystem {
struct NamespaceInfo {
bool ignore_protect_paths:1;
bool private_dev:1;
+ bool private_mounts:1;
bool protect_control_groups:1;
bool protect_kernel_tunables:1;
bool protect_kernel_modules:1;
@@ -91,9 +76,9 @@ int setup_namespace(
char **inaccessible_paths,
char **empty_directories,
const BindMount *bind_mounts,
- unsigned n_bind_mounts,
+ size_t n_bind_mounts,
const TemporaryFileSystem *temporary_filesystems,
- unsigned n_temporary_filesystems,
+ size_t n_temporary_filesystems,
const char *tmp_dir,
const char *var_tmp_dir,
ProtectHome protect_home,
@@ -110,17 +95,15 @@ int setup_netns(int netns_storage_socket[2]);
const char* protect_home_to_string(ProtectHome p) _const_;
ProtectHome protect_home_from_string(const char *s) _pure_;
-ProtectHome parse_protect_home_or_bool(const char *s);
const char* protect_system_to_string(ProtectSystem p) _const_;
ProtectSystem protect_system_from_string(const char *s) _pure_;
-ProtectSystem parse_protect_system_or_bool(const char *s);
-void bind_mount_free_many(BindMount *b, unsigned n);
-int bind_mount_add(BindMount **b, unsigned *n, const BindMount *item);
+void bind_mount_free_many(BindMount *b, size_t n);
+int bind_mount_add(BindMount **b, size_t *n, const BindMount *item);
-void temporary_filesystem_free_many(TemporaryFileSystem *t, unsigned n);
-int temporary_filesystem_add(TemporaryFileSystem **t, unsigned *n,
+void temporary_filesystem_free_many(TemporaryFileSystem *t, size_t n);
+int temporary_filesystem_add(TemporaryFileSystem **t, size_t *n,
const char *path, const char *options);
const char* namespace_type_to_string(NamespaceType t) _const_;
diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf
index 645c8f1659..415b3f5d84 100644
--- a/src/core/org.freedesktop.systemd1.conf
+++ b/src/core/org.freedesktop.systemd1.conf
@@ -62,6 +62,10 @@
<allow send_destination="org.freedesktop.systemd1"
send_interface="org.freedesktop.systemd1.Manager"
+ send_member="GetUnitByControlGroup"/>
+
+ <allow send_destination="org.freedesktop.systemd1"
+ send_interface="org.freedesktop.systemd1.Manager"
send_member="LoadUnit"/>
<allow send_destination="org.freedesktop.systemd1"
@@ -114,6 +118,10 @@
<allow send_destination="org.freedesktop.systemd1"
send_interface="org.freedesktop.systemd1.Manager"
+ send_member="DumpByFileDescriptor"/>
+
+ <allow send_destination="org.freedesktop.systemd1"
+ send_interface="org.freedesktop.systemd1.Manager"
send_member="ListUnitFiles"/>
<allow send_destination="org.freedesktop.systemd1"
@@ -140,6 +148,10 @@
send_interface="org.freedesktop.systemd1.Manager"
send_member="LookupDynamicUserByUID"/>
+ <allow send_destination="org.freedesktop.systemd1"
+ send_interface="org.freedesktop.systemd1.Manager"
+ send_member="GetDynamicUsers"/>
+
<!-- Completely open to anyone: org.freedesktop.systemd1.Unit interface -->
<allow send_destination="org.freedesktop.systemd1"
diff --git a/src/core/org.freedesktop.systemd1.policy.in b/src/core/org.freedesktop.systemd1.policy.in
index 648221b85c..001408d34a 100644
--- a/src/core/org.freedesktop.systemd1.policy.in
+++ b/src/core/org.freedesktop.systemd1.policy.in
@@ -47,6 +47,7 @@
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin_keep</allow_active>
</defaults>
+ <annotate key="org.freedesktop.policykit.imply">org.freedesktop.systemd1.reload-daemon org.freedesktop.systemd1.manage-units</annotate>
</action>
<action id="org.freedesktop.systemd1.set-environment">
diff --git a/src/core/path.c b/src/core/path.c
index 1893d8de45..68b13b610a 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
#include <sys/epoll.h>
@@ -80,7 +62,7 @@ int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler) {
(void) sd_event_source_set_description(s->event_source, "path");
- /* This function assumes the path was passed through path_kill_slashes()! */
+ /* This function assumes the path was passed through path_simplify()! */
assert(!strstr(s->path, "//"));
for (slash = strchr(s->path, '/'); ; slash = strchr(slash+1, '/')) {
@@ -302,7 +284,7 @@ static int path_verify(Path *p) {
if (!p->specs) {
log_unit_error(UNIT(p), "Path unit lacks path setting. Refusing.");
- return -EINVAL;
+ return -ENOEXEC;
}
return 0;
@@ -438,7 +420,7 @@ static void path_set_state(Path *p, PathState state) {
if (state != old_state)
log_unit_debug(UNIT(p), "Changed %s -> %s", path_state_to_string(old_state), path_state_to_string(state));
- unit_notify(UNIT(p), state_translation_table[old_state], state_translation_table[state], true);
+ unit_notify(UNIT(p), state_translation_table[old_state], state_translation_table[state], 0);
}
static void path_enter_waiting(Path *p, bool initial, bool recheck);
diff --git a/src/core/path.h b/src/core/path.h
index 41e31986f2..4d4b6236c2 100644
--- a/src/core/path.h
+++ b/src/core/path.h
@@ -1,25 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
typedef struct Path Path;
typedef struct PathSpec PathSpec;
@@ -92,3 +73,5 @@ PathType path_type_from_string(const char *s) _pure_;
const char* path_result_to_string(PathResult i) _const_;
PathResult path_result_from_string(const char *s) _pure_;
+
+DEFINE_CAST(PATH, Path);
diff --git a/src/core/scope.c b/src/core/scope.c
index 5b9c2bb3c4..751556fecf 100644
--- a/src/core/scope.c
+++ b/src/core/scope.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
#include <unistd.h>
@@ -105,13 +87,15 @@ static void scope_set_state(Scope *s, ScopeState state) {
if (!IN_SET(state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
- if (IN_SET(state, SCOPE_DEAD, SCOPE_FAILED))
+ if (IN_SET(state, SCOPE_DEAD, SCOPE_FAILED)) {
unit_unwatch_all_pids(UNIT(s));
+ unit_dequeue_rewatch_pids(UNIT(s));
+ }
if (state != old_state)
log_debug("%s changed %s -> %s", UNIT(s)->id, scope_state_to_string(old_state), scope_state_to_string(state));
- unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
+ unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], 0);
}
static int scope_add_default_dependencies(Scope *s) {
@@ -144,7 +128,7 @@ static int scope_verify(Scope *s) {
!MANAGER_IS_RELOADING(UNIT(s)->manager) &&
!unit_has_name(UNIT(s), SPECIAL_INIT_SCOPE)) {
log_unit_error(UNIT(s), "Scope has no PIDs. Refusing.");
- return -EINVAL;
+ return -ENOENT;
}
return 0;
@@ -225,7 +209,7 @@ static int scope_coldplug(Unit *u) {
}
if (!IN_SET(s->deserialized_state, SCOPE_DEAD, SCOPE_FAILED))
- unit_watch_all_pids(UNIT(s));
+ (void) unit_enqueue_rewatch_pids(u);
bus_scope_track_controller(s);
@@ -270,7 +254,12 @@ static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
if (s->result == SCOPE_SUCCESS)
s->result = f;
- unit_watch_all_pids(UNIT(s));
+ /* Before sending any signal, make sure we track all members of this cgroup */
+ (void) unit_watch_all_pids(UNIT(s));
+
+ /* Also, enqueue a job that we recheck all our PIDs a bit later, given that it's likely some processes have
+ * died now */
+ (void) unit_enqueue_rewatch_pids(UNIT(s));
/* If we have a controller set let's ask the controller nicely to terminate the scope, instead of us going
* directly into SIGTERM berserk mode */
@@ -353,6 +342,9 @@ static int scope_start(Unit *u) {
s->result = SCOPE_SUCCESS;
scope_set_state(s, SCOPE_RUNNING);
+
+ /* Start watching the PIDs currently in the scope */
+ (void) unit_enqueue_rewatch_pids(UNIT(s));
return 1;
}
@@ -468,17 +460,13 @@ static void scope_notify_cgroup_empty_event(Unit *u) {
}
static void scope_sigchld_event(Unit *u, pid_t pid, int code, int status) {
-
assert(u);
/* If we get a SIGCHLD event for one of the processes we were interested in, then we look for others to
* watch, under the assumption that we'll sooner or later get a SIGCHLD for them, as the original
* process we watched was probably the parent of them, and they are hence now our children. */
- unit_tidy_watch_pids(u, 0, 0);
- unit_watch_all_pids(u);
- /* If the PID set is empty now, then let's finish this off. */
- unit_synthesize_cgroup_empty_event(u);
+ (void) unit_enqueue_rewatch_pids(u);
}
static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
@@ -528,13 +516,9 @@ int scope_abandon(Scope *s) {
scope_set_state(s, SCOPE_ABANDONED);
- /* The client is no longer watching the remaining processes,
- * so let's step in here, under the assumption that the
- * remaining processes will be sooner or later reassigned to
- * us as parent. */
-
- unit_tidy_watch_pids(UNIT(s), 0, 0);
- unit_watch_all_pids(UNIT(s));
+ /* The client is no longer watching the remaining processes, so let's step in here, under the assumption that
+ * the remaining processes will be sooner or later reassigned to us as parent. */
+ (void) unit_enqueue_rewatch_pids(UNIT(s));
return 0;
}
@@ -551,7 +535,7 @@ _pure_ static const char *scope_sub_state_to_string(Unit *u) {
return scope_state_to_string(SCOPE(u)->state);
}
-static void scope_enumerate(Manager *m) {
+static void scope_enumerate_perpetual(Manager *m) {
Unit *u;
int r;
@@ -600,6 +584,7 @@ const UnitVTable scope_vtable = {
.can_transient = true,
.can_delegate = true,
+ .once_only = true,
.init = scope_init,
.load = scope_load,
@@ -632,5 +617,5 @@ const UnitVTable scope_vtable = {
.bus_set_property = bus_scope_set_property,
.bus_commit_properties = bus_scope_commit_properties,
- .enumerate = scope_enumerate,
+ .enumerate_perpetual = scope_enumerate_perpetual,
};
diff --git a/src/core/scope.h b/src/core/scope.h
index ca7c6c868f..c38afb5e5d 100644
--- a/src/core/scope.h
+++ b/src/core/scope.h
@@ -1,25 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
typedef struct Scope Scope;
#include "cgroup.h"
@@ -59,3 +40,5 @@ int scope_abandon(Scope *s);
const char* scope_result_to_string(ScopeResult i) _const_;
ScopeResult scope_result_from_string(const char *s) _pure_;
+
+DEFINE_CAST(SCOPE, Scope);
diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c
index 475c3181c9..39e994afd7 100644
--- a/src/core/selinux-access.c
+++ b/src/core/selinux-access.c
@@ -1,21 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
/***
- This file is part of systemd.
-
- Copyright 2012 Dan Walsh
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ Copyright © 2012 Dan Walsh
***/
#include "selinux-access.h"
diff --git a/src/core/selinux-access.h b/src/core/selinux-access.h
index dd48d0654e..59f2e60c77 100644
--- a/src/core/selinux-access.h
+++ b/src/core/selinux-access.h
@@ -2,22 +2,7 @@
#pragma once
/***
- This file is part of systemd.
-
- Copyright 2012 Dan Walsh
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ Copyright © 2012 Dan Walsh
***/
#include "sd-bus.h"
diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c
index 7135542106..bac1aa3ff6 100644
--- a/src/core/selinux-setup.c
+++ b/src/core/selinux-setup.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
#include <stdio.h>
@@ -47,13 +29,15 @@ int mac_selinux_setup(bool *loaded_policy) {
usec_t before_load, after_load;
char *con;
int r;
- union selinux_callback cb;
+ static const union selinux_callback cb = {
+ .func_log = null_log,
+ };
+
bool initialized = false;
assert(loaded_policy);
/* Turn off all of SELinux' own logging, we want to do that */
- cb.func_log = null_log;
selinux_set_callback(SELINUX_CB_LOG, cb);
/* Don't load policy in the initrd if we don't appear to have
diff --git a/src/core/selinux-setup.h b/src/core/selinux-setup.h
index 410991c49f..ad0d4f65dc 100644
--- a/src/core/selinux-setup.h
+++ b/src/core/selinux-setup.h
@@ -1,25 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include <stdbool.h>
int mac_selinux_setup(bool *loaded_policy);
diff --git a/src/core/service.c b/src/core/service.c
index df36019f62..db1356c417 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
#include <signal.h>
@@ -396,6 +378,9 @@ static void service_done(Unit *u) {
s->bus_name_owner = mfree(s->bus_name_owner);
+ s->usb_function_descriptors = mfree(s->usb_function_descriptors);
+ s->usb_function_strings = mfree(s->usb_function_strings);
+
service_close_socket_fd(s);
s->peer = socket_peer_unref(s->peer);
@@ -553,37 +538,37 @@ static int service_verify(Service *s) {
if (!s->exec_command[SERVICE_EXEC_START] && !s->exec_command[SERVICE_EXEC_STOP]) {
log_unit_error(UNIT(s), "Service lacks both ExecStart= and ExecStop= setting. Refusing.");
- return -EINVAL;
+ return -ENOEXEC;
}
if (s->type != SERVICE_ONESHOT && !s->exec_command[SERVICE_EXEC_START]) {
log_unit_error(UNIT(s), "Service has no ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.");
- return -EINVAL;
+ return -ENOEXEC;
}
if (!s->remain_after_exit && !s->exec_command[SERVICE_EXEC_START]) {
log_unit_error(UNIT(s), "Service has no ExecStart= setting, which is only allowed for RemainAfterExit=yes services. Refusing.");
- return -EINVAL;
+ return -ENOEXEC;
}
if (s->type != SERVICE_ONESHOT && s->exec_command[SERVICE_EXEC_START]->command_next) {
log_unit_error(UNIT(s), "Service has more than one ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.");
- return -EINVAL;
+ return -ENOEXEC;
}
if (s->type == SERVICE_ONESHOT && s->restart != SERVICE_RESTART_NO) {
log_unit_error(UNIT(s), "Service has Restart= setting other than no, which isn't allowed for Type=oneshot services. Refusing.");
- return -EINVAL;
+ return -ENOEXEC;
}
if (s->type == SERVICE_ONESHOT && !exit_status_set_is_empty(&s->restart_force_status)) {
log_unit_error(UNIT(s), "Service has RestartForceStatus= set, which isn't allowed for Type=oneshot services. Refusing.");
- return -EINVAL;
+ return -ENOEXEC;
}
if (s->type == SERVICE_DBUS && !s->bus_name) {
log_unit_error(UNIT(s), "Service is of type D-Bus but no D-Bus service name has been specified. Refusing.");
- return -EINVAL;
+ return -ENOEXEC;
}
if (s->bus_name && s->type != SERVICE_DBUS)
@@ -591,7 +576,7 @@ static int service_verify(Service *s) {
if (s->exec_context.pam_name && !IN_SET(s->kill_context.kill_mode, KILL_CONTROL_GROUP, KILL_MIXED)) {
log_unit_error(UNIT(s), "Service has PAM enabled. Kill mode must be set to 'control-group' or 'mixed'. Refusing.");
- return -EINVAL;
+ return -ENOEXEC;
}
if (s->usb_function_descriptors && !s->usb_function_strings)
@@ -725,10 +710,9 @@ static int service_add_extras(Service *s) {
if (r < 0)
return r;
- if (s->type == SERVICE_NOTIFY && s->notify_access == NOTIFY_NONE)
- s->notify_access = NOTIFY_MAIN;
-
- if (s->watchdog_usec > 0 && s->notify_access == NOTIFY_NONE)
+ /* If the service needs the notify socket, let's enable it automatically. */
+ if (s->notify_access == NOTIFY_NONE &&
+ (s->type == SERVICE_NOTIFY || s->watchdog_usec > 0 || s->n_fd_store_max > 0))
s->notify_access = NOTIFY_MAIN;
r = service_add_default_dependencies(s);
@@ -876,7 +860,7 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
if (s->n_fd_store_max > 0)
fprintf(f,
"%sFile Descriptor Store Max: %u\n"
- "%sFile Descriptor Store Current: %u\n",
+ "%sFile Descriptor Store Current: %zu\n",
prefix, s->n_fd_store_max,
prefix, s->n_fd_store);
@@ -1069,8 +1053,10 @@ static void service_set_state(Service *s, ServiceState state) {
s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
}
- if (IN_SET(state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART))
+ if (IN_SET(state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART)) {
unit_unwatch_all_pids(UNIT(s));
+ unit_dequeue_rewatch_pids(UNIT(s));
+ }
if (!IN_SET(state,
SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
@@ -1091,7 +1077,9 @@ static void service_set_state(Service *s, ServiceState state) {
if (old_state != state)
log_unit_debug(UNIT(s), "Changed %s -> %s", service_state_to_string(old_state), service_state_to_string(state));
- unit_notify(UNIT(s), table[old_state], table[state], s->reload_result == SERVICE_SUCCESS);
+ unit_notify(UNIT(s), table[old_state], table[state],
+ (s->reload_result == SERVICE_SUCCESS ? 0 : UNIT_NOTIFY_RELOAD_FAILURE) |
+ (s->will_auto_restart ? UNIT_NOTIFY_WILL_AUTO_RESTART : 0));
}
static usec_t service_coldplug_timeout(Service *s) {
@@ -1163,17 +1151,15 @@ static int service_coldplug(Unit *u) {
return r;
}
- if (!IN_SET(s->deserialized_state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART))
- unit_watch_all_pids(UNIT(s));
-
- if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
- service_start_watchdog(s);
-
if (!IN_SET(s->deserialized_state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART)) {
+ (void) unit_enqueue_rewatch_pids(u);
(void) unit_setup_dynamic_creds(u);
(void) unit_setup_exec_runtime(u);
}
+ if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
+ service_start_watchdog(s);
+
if (UNIT_ISSET(s->accept_socket)) {
Socket* socket = SOCKET(UNIT_DEREF(s->accept_socket));
@@ -1247,10 +1233,8 @@ static int service_collect_fds(Service *s,
continue;
if (!rfds) {
- rfds = cfds;
+ rfds = TAKE_PTR(cfds);
rn_socket_fds = cn_fds;
-
- cfds = NULL;
} else {
int *t;
@@ -1302,14 +1286,11 @@ static int service_collect_fds(Service *s,
rfd_names[n_fds] = NULL;
}
- *fds = rfds;
- *fd_names = rfd_names;
+ *fds = TAKE_PTR(rfds);
+ *fd_names = TAKE_PTR(rfd_names);
*n_socket_fds = rn_socket_fds;
*n_storage_fds = rn_storage_fds;
- rfds = NULL;
- rfd_names = NULL;
-
return 0;
}
@@ -1606,6 +1587,7 @@ static bool service_will_restart(Unit *u) {
return false;
if (UNIT(s)->job->type == JOB_START)
return true;
+
return false;
}
@@ -1692,7 +1674,8 @@ static void service_enter_stop_post(Service *s, ServiceResult f) {
s->result = f;
service_unwatch_control_pid(s);
- unit_watch_all_pids(UNIT(s));
+
+ (void) unit_enqueue_rewatch_pids(UNIT(s));
s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST];
if (s->control_command) {
@@ -1744,7 +1727,12 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
if (s->result == SERVICE_SUCCESS)
s->result = f;
- unit_watch_all_pids(UNIT(s));
+ /* Before sending any signal, make sure we track all members of this cgroup */
+ (void) unit_watch_all_pids(UNIT(s));
+
+ /* Also, enqueue a job that we recheck all our PIDs a bit later, given that it's likely some processes have
+ * died now */
+ (void) unit_enqueue_rewatch_pids(UNIT(s));
r = unit_kill_context(
UNIT(s),
@@ -1785,7 +1773,7 @@ fail:
static void service_enter_stop_by_notify(Service *s) {
assert(s);
- unit_watch_all_pids(UNIT(s));
+ (void) unit_enqueue_rewatch_pids(UNIT(s));
service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_stop_usec));
@@ -1802,7 +1790,7 @@ static void service_enter_stop(Service *s, ServiceResult f) {
s->result = f;
service_unwatch_control_pid(s);
- unit_watch_all_pids(UNIT(s));
+ (void) unit_enqueue_rewatch_pids(UNIT(s));
s->control_command = s->exec_command[SERVICE_EXEC_STOP];
if (s->control_command) {
@@ -1855,10 +1843,11 @@ static void service_enter_running(Service *s, ServiceResult f) {
service_unwatch_control_pid(s);
- if (service_good(s)) {
+ if (s->result != SERVICE_SUCCESS)
+ service_enter_signal(s, SERVICE_STOP_SIGTERM, f);
+ else if (service_good(s)) {
- /* If there are any queued up sd_notify()
- * notifications, process them now */
+ /* If there are any queued up sd_notify() notifications, process them now */
if (s->notify_state == NOTIFY_RELOADING)
service_enter_reload_by_notify(s);
else if (s->notify_state == NOTIFY_STOPPING)
@@ -1868,9 +1857,7 @@ static void service_enter_running(Service *s, ServiceResult f) {
service_arm_timer(s, usec_add(UNIT(s)->active_enter_timestamp.monotonic, s->runtime_max_usec));
}
- } else if (f != SERVICE_SUCCESS)
- service_enter_signal(s, SERVICE_STOP_SIGTERM, f);
- else if (s->remain_after_exit)
+ } else if (s->remain_after_exit)
service_set_state(s, SERVICE_EXITED);
else
service_enter_stop(s, SERVICE_SUCCESS);
@@ -1955,7 +1942,7 @@ static void service_enter_start(Service *s) {
/* There's no command line configured for the main command? Hmm, that is strange. This can only
* happen if the configuration changes at runtime. In this case, let's enter a failure
* state. */
- log_unit_error(UNIT(s), "There's no 'start' task anymore we could start: %m");
+ log_unit_error(UNIT(s), "There's no 'start' task anymore we could start.");
r = -ENXIO;
goto fail;
}
@@ -2084,8 +2071,7 @@ static void service_enter_restart(Service *s) {
LOG_UNIT_ID(UNIT(s)),
LOG_UNIT_INVOCATION_ID(UNIT(s)),
LOG_UNIT_MESSAGE(UNIT(s), "Scheduled restart job, restart counter is at %u.", s->n_restarts),
- "N_RESTARTS=%u", s->n_restarts,
- NULL);
+ "N_RESTARTS=%u", s->n_restarts);
/* Notify clients about changed restart counter */
unit_add_to_dbus_queue(UNIT(s));
@@ -2551,8 +2537,7 @@ static int service_deserialize_exec_command(Unit *u, const char *key, const char
state = STATE_EXEC_COMMAND_PATH;
break;
case STATE_EXEC_COMMAND_PATH:
- path = arg;
- arg = NULL;
+ path = TAKE_PTR(arg);
state = STATE_EXEC_COMMAND_ARGS;
if (!path_is_absolute(path))
@@ -2904,7 +2889,7 @@ static int service_demand_pid_file(Service *s) {
return -ENOMEM;
}
- path_kill_slashes(ps->path);
+ path_simplify(ps->path, false);
/* PATH_CHANGED would not be enough. There are daemons (sendmail) that
* keep their PID file open all the time. */
@@ -3083,8 +3068,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
"EXIT_CODE=%s", sigchld_code_to_string(code),
"EXIT_STATUS=%i", status,
LOG_UNIT_ID(u),
- LOG_UNIT_INVOCATION_ID(u),
- NULL);
+ LOG_UNIT_INVOCATION_ID(u));
if (s->result == SERVICE_SUCCESS)
s->result = f;
@@ -3226,7 +3210,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
* The PID file might actually be created by a START_POST
* script. In that case don't worry if the loading fails. */
- has_start_post = !!s->exec_command[SERVICE_EXEC_START_POST];
+ has_start_post = s->exec_command[SERVICE_EXEC_START_POST];
r = service_load_pid_file(s, !has_start_post);
if (!has_start_post && r < 0) {
r = service_demand_pid_file(s);
@@ -3307,11 +3291,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
/* If we get a SIGCHLD event for one of the processes we were interested in, then we look for others to watch,
* under the assumption that we'll sooner or later get a SIGCHLD for them, as the original process we watched
* was probably the parent of them, and they are hence now our children. */
- unit_tidy_watch_pids(u, s->main_pid, s->control_pid);
- unit_watch_all_pids(u);
-
- /* If the PID set is empty now, then let's check if the cgroup is empty too and finish off the unit. */
- unit_synthesize_cgroup_empty_event(u);
+ (void) unit_enqueue_rewatch_pids(u);
}
static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
@@ -3397,10 +3377,15 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
break;
case SERVICE_AUTO_RESTART:
- log_unit_info(UNIT(s),
- s->restart_usec > 0 ?
- "Service hold-off time over, scheduling restart." :
- "Service has no hold-off time, scheduling restart.");
+ if (s->restart_usec > 0) {
+ char buf_restart[FORMAT_TIMESPAN_MAX];
+ log_unit_info(UNIT(s),
+ "Service RestartSec=%s expired, scheduling restart.",
+ format_timespan(buf_restart, sizeof buf_restart, s->restart_usec, USEC_PER_SEC));
+ } else
+ log_unit_info(UNIT(s),
+ "Service has no hold-off time (RestartSec=0), scheduling restart.");
+
service_enter_restart(s);
break;
diff --git a/src/core/service.h b/src/core/service.h
index 5c5b24e3ef..9c06e91883 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -1,25 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
typedef struct Service Service;
typedef struct ServiceFDStore ServiceFDStore;
@@ -27,6 +8,8 @@ typedef struct ServiceFDStore ServiceFDStore;
#include "kill.h"
#include "path.h"
#include "ratelimit.h"
+#include "socket.h"
+#include "unit.h"
typedef enum ServiceRestart {
SERVICE_RESTART_NO,
@@ -183,7 +166,7 @@ struct Service {
NotifyState notify_state;
ServiceFDStore *fd_store;
- unsigned n_fd_store;
+ size_t n_fd_store;
unsigned n_fd_store_max;
unsigned n_keep_fd_store;
@@ -217,3 +200,5 @@ NotifyState notify_state_from_string(const char *s) _pure_;
const char* service_result_to_string(ServiceResult i) _const_;
ServiceResult service_result_from_string(const char *s) _pure_;
+
+DEFINE_CAST(SERVICE, Service);
diff --git a/src/core/show-status.c b/src/core/show-status.c
index 40658a2e16..63262cc716 100644
--- a/src/core/show-status.c
+++ b/src/core/show-status.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2014 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include "alloc-util.h"
#include "fd-util.h"
diff --git a/src/core/show-status.h b/src/core/show-status.h
index a13d52484c..1a80de33d9 100644
--- a/src/core/show-status.h
+++ b/src/core/show-status.h
@@ -1,25 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2014 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include <stdbool.h>
#include "macro.h"
diff --git a/src/core/shutdown.c b/src/core/shutdown.c
index 58c9a9de79..038345b752 100644
--- a/src/core/shutdown.c
+++ b/src/core/shutdown.c
@@ -1,21 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
/***
- This file is part of systemd.
-
- Copyright 2010 ProFUSION embedded systems
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ Copyright © 2010 ProFUSION embedded systems
***/
#include <errno.h>
@@ -52,8 +37,6 @@
#include "virt.h"
#include "watchdog.h"
-#define FINALIZE_ATTEMPTS 50
-
#define SYNC_PROGRESS_ATTEMPTS 3
#define SYNC_TIMEOUT_USEC (10*USEC_PER_SEC)
@@ -269,11 +252,10 @@ static void sync_with_progress(void) {
int main(int argc, char *argv[]) {
bool need_umount, need_swapoff, need_loop_detach, need_dm_detach;
- bool in_container, use_watchdog = false;
+ bool in_container, use_watchdog = false, can_initrd;
_cleanup_free_ char *cgroup = NULL;
char *arguments[3];
- unsigned retries;
- int cmd, r;
+ int cmd, r, umount_log_level = LOG_INFO;
static const char* const dirs[] = {SYSTEM_SHUTDOWN_PATH, NULL};
char *watchdog_device;
@@ -318,7 +300,7 @@ int main(int argc, char *argv[]) {
(void) cg_get_root_path(&cgroup);
in_container = detect_container() > 0;
- use_watchdog = !!getenv("WATCHDOG_USEC");
+ use_watchdog = getenv("WATCHDOG_USEC");
watchdog_device = getenv("WATCHDOG_DEVICE");
if (watchdog_device) {
r = watchdog_set_device(watchdog_device);
@@ -349,9 +331,10 @@ int main(int argc, char *argv[]) {
need_swapoff = !in_container;
need_loop_detach = !in_container;
need_dm_detach = !in_container;
+ can_initrd = !in_container && !in_initrd() && access("/run/initramfs/shutdown", X_OK) == 0;
/* Unmount all mountpoints, swaps, and loopback devices */
- for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
+ for (;;) {
bool changed = false;
if (use_watchdog)
@@ -366,7 +349,7 @@ int main(int argc, char *argv[]) {
if (need_umount) {
log_info("Unmounting file systems.");
- r = umount_all(&changed);
+ r = umount_all(&changed, umount_log_level);
if (r == 0) {
need_umount = false;
log_info("All filesystems unmounted.");
@@ -390,7 +373,7 @@ int main(int argc, char *argv[]) {
if (need_loop_detach) {
log_info("Detaching loop devices.");
- r = loopback_detach_all(&changed);
+ r = loopback_detach_all(&changed, umount_log_level);
if (r == 0) {
need_loop_detach = false;
log_info("All loop devices detached.");
@@ -402,7 +385,7 @@ int main(int argc, char *argv[]) {
if (need_dm_detach) {
log_info("Detaching DM devices.");
- r = dm_detach_all(&changed);
+ r = dm_detach_all(&changed, umount_log_level);
if (r == 0) {
need_dm_detach = false;
log_info("All DM devices detached.");
@@ -413,10 +396,19 @@ int main(int argc, char *argv[]) {
}
if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) {
- if (retries > 0)
- log_info("All filesystems, swaps, loop devices, DM devices detached.");
+ log_info("All filesystems, swaps, loop devices and DM devices detached.");
/* Yay, done */
- goto initrd_jump;
+ break;
+ }
+
+ if (!changed && umount_log_level == LOG_INFO && !can_initrd) {
+ /* There are things we cannot get rid of. Loop one more time
+ * with LOG_ERR to inform the user. Note that we don't need
+ * to do this if there is a initrd to switch to, because that
+ * one is likely to get rid of the remounting mounts. If not,
+ * it will log about them. */
+ umount_log_level = LOG_ERR;
+ continue;
}
/* If in this iteration we didn't manage to
@@ -427,21 +419,16 @@ int main(int argc, char *argv[]) {
need_swapoff ? " swap devices," : "",
need_loop_detach ? " loop devices," : "",
need_dm_detach ? " DM devices," : "");
- goto initrd_jump;
+ break;
}
- log_debug("After %u retries, couldn't finalize remaining %s%s%s%s trying again.",
- retries + 1,
+ log_debug("Couldn't finalize remaining %s%s%s%s trying again.",
need_umount ? " file systems," : "",
need_swapoff ? " swap devices," : "",
need_loop_detach ? " loop devices," : "",
need_dm_detach ? " DM devices," : "");
}
- log_error("Too many iterations, giving up.");
-
- initrd_jump:
-
/* We're done with the watchdog. */
watchdog_free_device();
@@ -450,8 +437,7 @@ int main(int argc, char *argv[]) {
arguments[2] = NULL;
execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments);
- if (!in_container && !in_initrd() &&
- access("/run/initramfs/shutdown", X_OK) == 0) {
+ if (can_initrd) {
r = switch_root_initramfs();
if (r >= 0) {
argv[0] = (char*) "/shutdown";
diff --git a/src/core/slice.c b/src/core/slice.c
index 1c4574b8bb..58f18a4dad 100644
--- a/src/core/slice.c
+++ b/src/core/slice.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
@@ -55,7 +37,7 @@ static void slice_set_state(Slice *t, SliceState state) {
slice_state_to_string(old_state),
slice_state_to_string(state));
- unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
+ unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], 0);
}
static int slice_add_parent_slice(Slice *s) {
@@ -110,7 +92,7 @@ static int slice_verify(Slice *s) {
if (!slice_name_is_valid(UNIT(s)->id)) {
log_unit_error(UNIT(s), "Slice name %s is not valid. Refusing.", UNIT(s)->id);
- return -EINVAL;
+ return -ENOEXEC;
}
r = slice_build_parent_slice(UNIT(s)->id, &parent);
@@ -119,7 +101,7 @@ static int slice_verify(Slice *s) {
if (parent ? !unit_has_name(UNIT_DEREF(UNIT(s)->slice), parent) : UNIT_ISSET(UNIT(s)->slice)) {
log_unit_error(UNIT(s), "Located outside of parent slice. Refusing.");
- return -EINVAL;
+ return -ENOEXEC;
}
return 0;
@@ -339,7 +321,7 @@ static int slice_make_perpetual(Manager *m, const char *name, Unit **ret) {
return 0;
}
-static void slice_enumerate(Manager *m) {
+static void slice_enumerate_perpetual(Manager *m) {
Unit *u;
int r;
@@ -396,7 +378,7 @@ const UnitVTable slice_vtable = {
.bus_set_property = bus_slice_set_property,
.bus_commit_properties = bus_slice_commit_properties,
- .enumerate = slice_enumerate,
+ .enumerate_perpetual = slice_enumerate_perpetual,
.status_message_formats = {
.finished_start_job = {
diff --git a/src/core/slice.h b/src/core/slice.h
index 418327e933..4678c085c3 100644
--- a/src/core/slice.h
+++ b/src/core/slice.h
@@ -1,24 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
+#include "unit.h"
typedef struct Slice Slice;
@@ -31,3 +14,5 @@ struct Slice {
};
extern const UnitVTable slice_vtable;
+
+DEFINE_CAST(SLICE, Slice);
diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c
index b0d3612d69..50115c0454 100644
--- a/src/core/smack-setup.c
+++ b/src/core/smack-setup.c
@@ -1,23 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
/***
- This file is part of systemd.
-
- Copyright (C) 2013 Intel Corporation
+ Copyright © 2013 Intel Corporation
Authors:
Nathaniel Chen <nathaniel.chen@intel.com>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <dirent.h>
diff --git a/src/core/smack-setup.h b/src/core/smack-setup.h
index 8c2de5fdc5..b65daafcd8 100644
--- a/src/core/smack-setup.h
+++ b/src/core/smack-setup.h
@@ -2,24 +2,9 @@
#pragma once
/***
- This file is part of systemd.
-
- Copyright (C) 2013 Intel Corporation
+ Copyright © 2013 Intel Corporation
Authors:
Nathaniel Chen <nathaniel.chen@intel.com>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
int mac_smack_setup(bool *loaded_policy);
diff --git a/src/core/socket.c b/src/core/socket.c
index 41988788b8..56d32225c4 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <arpa/inet.h>
#include <errno.h>
@@ -454,32 +436,32 @@ static int socket_verify(Socket *s) {
if (!s->ports) {
log_unit_error(UNIT(s), "Unit has no Listen setting (ListenStream=, ListenDatagram=, ListenFIFO=, ...). Refusing.");
- return -EINVAL;
+ return -ENOEXEC;
}
if (s->accept && have_non_accept_socket(s)) {
log_unit_error(UNIT(s), "Unit configured for accepting sockets, but sockets are non-accepting. Refusing.");
- return -EINVAL;
+ return -ENOEXEC;
}
if (s->accept && s->max_connections <= 0) {
log_unit_error(UNIT(s), "MaxConnection= setting too small. Refusing.");
- return -EINVAL;
+ return -ENOEXEC;
}
if (s->accept && UNIT_DEREF(s->service)) {
log_unit_error(UNIT(s), "Explicit service configuration for accepting socket units not supported. Refusing.");
- return -EINVAL;
+ return -ENOEXEC;
}
if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) {
log_unit_error(UNIT(s), "Unit has PAM enabled. Kill mode must be set to 'control-group'. Refusing.");
- return -EINVAL;
+ return -ENOEXEC;
}
if (!strv_isempty(s->symlinks) && !socket_find_symlink_target(s)) {
log_unit_error(UNIT(s), "Unit has symlinks set but none or more than one node in the file system. Refusing.");
- return -EINVAL;
+ return -ENOEXEC;
}
return 0;
@@ -629,8 +611,7 @@ int socket_acquire_peer(Socket *s, int fd, SocketPeer **p) {
remote->socket = s;
- *p = remote;
- remote = NULL;
+ *p = TAKE_PTR(remote);
return 1;
}
@@ -800,27 +781,28 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
"%sKeepAliveTimeSec: %s\n",
prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, s->keep_alive_time, USEC_PER_SEC));
- if (s->keep_alive_interval)
+ if (s->keep_alive_interval > 0)
fprintf(f,
"%sKeepAliveIntervalSec: %s\n",
prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, s->keep_alive_interval, USEC_PER_SEC));
- if (s->keep_alive_cnt)
+ if (s->keep_alive_cnt > 0)
fprintf(f,
"%sKeepAliveProbes: %u\n",
prefix, s->keep_alive_cnt);
- if (s->defer_accept)
+ if (s->defer_accept > 0)
fprintf(f,
"%sDeferAcceptSec: %s\n",
prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, s->defer_accept, USEC_PER_SEC));
LIST_FOREACH(port, p, s->ports) {
- if (p->type == SOCKET_SOCKET) {
+ switch (p->type) {
+ case SOCKET_SOCKET: {
+ _cleanup_free_ char *k = NULL;
const char *t;
int r;
- char *k = NULL;
r = socket_address_print(&p->address, &k);
if (r < 0)
@@ -829,15 +811,20 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
t = k;
fprintf(f, "%s%s: %s\n", prefix, listen_lookup(socket_address_family(&p->address), p->address.type), t);
- free(k);
- } else if (p->type == SOCKET_SPECIAL)
+ break;
+ }
+ case SOCKET_SPECIAL:
fprintf(f, "%sListenSpecial: %s\n", prefix, p->path);
- else if (p->type == SOCKET_USB_FUNCTION)
+ break;
+ case SOCKET_USB_FUNCTION:
fprintf(f, "%sListenUSBFunction: %s\n", prefix, p->path);
- else if (p->type == SOCKET_MQUEUE)
+ break;
+ case SOCKET_MQUEUE:
fprintf(f, "%sListenMessageQueue: %s\n", prefix, p->path);
- else
+ break;
+ default:
fprintf(f, "%sListenFIFO: %s\n", prefix, p->path);
+ }
}
fprintf(f,
@@ -1047,43 +1034,43 @@ static void socket_apply_socket_options(Socket *s, int fd) {
assert(fd >= 0);
if (s->keep_alive) {
- int b = s->keep_alive;
- if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &b, sizeof(b)) < 0)
+ int one = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one)) < 0)
log_unit_warning_errno(UNIT(s), errno, "SO_KEEPALIVE failed: %m");
}
- if (s->keep_alive_time) {
+ if (s->keep_alive_time > 0) {
int value = s->keep_alive_time / USEC_PER_SEC;
if (setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &value, sizeof(value)) < 0)
log_unit_warning_errno(UNIT(s), errno, "TCP_KEEPIDLE failed: %m");
}
- if (s->keep_alive_interval) {
+ if (s->keep_alive_interval > 0) {
int value = s->keep_alive_interval / USEC_PER_SEC;
if (setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &value, sizeof(value)) < 0)
log_unit_warning_errno(UNIT(s), errno, "TCP_KEEPINTVL failed: %m");
}
- if (s->keep_alive_cnt) {
+ if (s->keep_alive_cnt > 0) {
int value = s->keep_alive_cnt;
if (setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &value, sizeof(value)) < 0)
log_unit_warning_errno(UNIT(s), errno, "TCP_KEEPCNT failed: %m");
}
- if (s->defer_accept) {
+ if (s->defer_accept > 0) {
int value = s->defer_accept / USEC_PER_SEC;
if (setsockopt(fd, SOL_TCP, TCP_DEFER_ACCEPT, &value, sizeof(value)) < 0)
log_unit_warning_errno(UNIT(s), errno, "TCP_DEFER_ACCEPT failed: %m");
}
if (s->no_delay) {
- int b = s->no_delay;
+ int one = 1;
if (s->socket_protocol == IPPROTO_SCTP) {
- if (setsockopt(fd, SOL_SCTP, SCTP_NODELAY, &b, sizeof(b)) < 0)
+ if (setsockopt(fd, SOL_SCTP, SCTP_NODELAY, &one, sizeof(one)) < 0)
log_unit_warning_errno(UNIT(s), errno, "SCTP_NODELAY failed: %m");
} else {
- if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &b, sizeof(b)) < 0)
+ if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one)) < 0)
log_unit_warning_errno(UNIT(s), errno, "TCP_NODELAY failed: %m");
}
}
@@ -1114,7 +1101,6 @@ static void socket_apply_socket_options(Socket *s, int fd) {
int value = (int) s->receive_buffer;
/* We first try with SO_RCVBUFFORCE, in case we have the perms for that */
-
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0)
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0)
log_unit_warning_errno(UNIT(s), errno, "SO_RCVBUF failed: %m");
@@ -1204,7 +1190,7 @@ static int fifo_address_create(
return r;
/* Enforce the right access mode for the fifo */
- old_mask = umask(~ socket_mode);
+ old_mask = umask(~socket_mode);
/* Include the original umask in our mask */
(void) umask(~socket_mode | old_mask);
@@ -1238,10 +1224,7 @@ static int fifo_address_create(
goto fail;
}
- r = fd;
- fd = -1;
-
- return r;
+ return TAKE_FD(fd);
fail:
mac_selinux_create_file_clear();
@@ -1251,7 +1234,6 @@ fail:
static int special_address_create(const char *path, bool writable) {
_cleanup_close_ int fd = -1;
struct stat st;
- int r;
assert(path);
@@ -1266,16 +1248,12 @@ static int special_address_create(const char *path, bool writable) {
if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode))
return -EEXIST;
- r = fd;
- fd = -1;
-
- return r;
+ return TAKE_FD(fd);
}
static int usbffs_address_create(const char *path) {
_cleanup_close_ int fd = -1;
struct stat st;
- int r;
assert(path);
@@ -1290,10 +1268,7 @@ static int usbffs_address_create(const char *path) {
if (!S_ISREG(st.st_mode))
return -EEXIST;
- r = fd;
- fd = -1;
-
- return r;
+ return TAKE_FD(fd);
}
static int mq_address_create(
@@ -1306,7 +1281,6 @@ static int mq_address_create(
struct stat st;
mode_t old_mask;
struct mq_attr _attr, *attr = NULL;
- int r;
assert(path);
@@ -1320,7 +1294,7 @@ static int mq_address_create(
}
/* Enforce the right access mode for the mq */
- old_mask = umask(~ mq_mode);
+ old_mask = umask(~mq_mode);
/* Include the original umask in our mask */
(void) umask(~mq_mode | old_mask);
@@ -1338,10 +1312,7 @@ static int mq_address_create(
st.st_gid != getgid())
return -EEXIST;
- r = fd;
- fd = -1;
-
- return r;
+ return TAKE_FD(fd);
}
static int socket_symlink(Socket *s) {
@@ -1395,13 +1366,14 @@ static int usbffs_select_ep(const struct dirent *d) {
static int usbffs_dispatch_eps(SocketPort *p) {
_cleanup_free_ struct dirent **ent = NULL;
- int r, i, n, k;
+ size_t n, k, i;
+ int r;
r = scandir(p->path, &ent, usbffs_select_ep, alphasort);
if (r < 0)
return -errno;
- n = r;
+ n = (size_t) r;
p->auxiliary_fds = new(int, n);
if (!p->auxiliary_fds)
return -ENOMEM;
@@ -1416,15 +1388,13 @@ static int usbffs_dispatch_eps(SocketPort *p) {
if (!ep)
return -ENOMEM;
- path_kill_slashes(ep);
+ path_simplify(ep, false);
r = usbffs_address_create(ep);
if (r < 0)
goto fail;
- p->auxiliary_fds[k] = r;
-
- ++k;
+ p->auxiliary_fds[k++] = r;
free(ent[i]);
}
@@ -1439,7 +1409,9 @@ fail:
}
static int socket_determine_selinux_label(Socket *s, char **ret) {
+ Service *service;
ExecCommand *c;
+ _cleanup_free_ char *path = NULL;
int r;
assert(s);
@@ -1461,11 +1433,16 @@ static int socket_determine_selinux_label(Socket *s, char **ret) {
if (!UNIT_ISSET(s->service))
goto no_label;
- c = SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START];
+ service = SERVICE(UNIT_DEREF(s->service));
+ c = service->exec_command[SERVICE_EXEC_START];
if (!c)
goto no_label;
- r = mac_selinux_get_create_label_from_exe(c->path, ret);
+ r = chase_symlinks(c->path, service->exec_context.root_directory, CHASE_PREFIX_ROOT, &path);
+ if (r < 0)
+ goto no_label;
+
+ r = mac_selinux_get_create_label_from_exe(path, ret);
if (IN_SET(r, -EPERM, -EOPNOTSUPP))
goto no_label;
}
@@ -1813,7 +1790,7 @@ static void socket_set_state(Socket *s, SocketState state) {
if (state != old_state)
log_unit_debug(UNIT(s), "Changed %s -> %s", socket_state_to_string(old_state), socket_state_to_string(state));
- unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
+ unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], 0);
}
static int socket_coldplug(Unit *u) {
@@ -2261,18 +2238,17 @@ static void socket_enter_running(Socket *s, int cfd) {
log_unit_debug(UNIT(s), "Suppressing connection request since unit stop is scheduled.");
if (cfd >= 0)
- cfd = safe_close(cfd);
+ goto refuse;
else
flush_ports(s);
return;
}
- if (!ratelimit_test(&s->trigger_limit)) {
- safe_close(cfd);
+ if (!ratelimit_below(&s->trigger_limit)) {
log_unit_warning(UNIT(s), "Trigger limit hit, refusing further activation.");
socket_enter_stop_pre(s, SOCKET_FAILURE_TRIGGER_LIMIT_HIT);
- return;
+ goto refuse;
}
if (cfd < 0) {
@@ -2310,15 +2286,13 @@ static void socket_enter_running(Socket *s, int cfd) {
if (s->n_connections >= s->max_connections) {
log_unit_warning(UNIT(s), "Too many incoming connections (%u), dropping connection.",
s->n_connections);
- safe_close(cfd);
- return;
+ goto refuse;
}
if (s->max_connections_per_source > 0) {
r = socket_acquire_peer(s, cfd, &p);
if (r < 0) {
- safe_close(cfd);
- return;
+ goto refuse;
} else if (r > 0 && p->n_ref > s->max_connections_per_source) {
_cleanup_free_ char *t = NULL;
@@ -2327,8 +2301,7 @@ static void socket_enter_running(Socket *s, int cfd) {
log_unit_warning(UNIT(s),
"Too many incoming connections (%u) from source %s, dropping connection.",
p->n_ref, strnull(t));
- safe_close(cfd);
- return;
+ goto refuse;
}
}
@@ -2344,8 +2317,7 @@ static void socket_enter_running(Socket *s, int cfd) {
/* ENOTCONN is legitimate if TCP RST was received.
* This connection is over, but the socket unit lives on. */
log_unit_debug(UNIT(s), "Got ENOTCONN on incoming socket, assuming aborted connection attempt, ignoring.");
- safe_close(cfd);
- return;
+ goto refuse;
}
r = unit_name_to_prefix(UNIT(s)->id, &prefix);
@@ -2373,8 +2345,7 @@ static void socket_enter_running(Socket *s, int cfd) {
cfd = -1; /* We passed ownership of the fd to the service now. Forget it here. */
s->n_connections++;
- service->peer = p; /* Pass ownership of the peer reference */
- p = NULL;
+ service->peer = TAKE_PTR(p); /* Pass ownership of the peer reference */
r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, &error, NULL);
if (r < 0) {
@@ -2390,6 +2361,11 @@ static void socket_enter_running(Socket *s, int cfd) {
return;
+refuse:
+ s->n_refused++;
+ safe_close(cfd);
+ return;
+
fail:
log_unit_warning(UNIT(s), "Failed to queue service startup job (Maybe the service file is missing or not a %s unit?): %s",
cfd >= 0 ? "template" : "non-template",
@@ -2533,6 +2509,7 @@ static int socket_serialize(Unit *u, FILE *f, FDSet *fds) {
unit_serialize_item(u, f, "state", socket_state_to_string(s->state));
unit_serialize_item(u, f, "result", socket_result_to_string(s->result));
unit_serialize_item_format(u, f, "n-accepted", "%u", s->n_accepted);
+ unit_serialize_item_format(u, f, "n-refused", "%u", s->n_refused);
if (s->control_pid > 0)
unit_serialize_item_format(u, f, "control-pid", PID_FMT, s->control_pid);
@@ -2613,6 +2590,13 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
log_unit_debug(u, "Failed to parse n-accepted value: %s", value);
else
s->n_accepted += k;
+ } else if (streq(key, "n-refused")) {
+ unsigned k;
+
+ if (safe_atou(value, &k) < 0)
+ log_unit_debug(u, "Failed to parse n-refused value: %s", value);
+ else
+ s->n_refused += k;
} else if (streq(key, "control-pid")) {
pid_t pid;
@@ -3120,8 +3104,9 @@ static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *use
}
int socket_collect_fds(Socket *s, int **fds) {
- int *rfds, k = 0, n = 0;
+ size_t k = 0, n = 0;
SocketPort *p;
+ int *rfds;
assert(s);
assert(fds);
@@ -3144,7 +3129,7 @@ int socket_collect_fds(Socket *s, int **fds) {
return -ENOMEM;
LIST_FOREACH(port, p, s->ports) {
- int i;
+ size_t i;
if (p->fd >= 0)
rfds[k++] = p->fd;
@@ -3155,7 +3140,7 @@ int socket_collect_fds(Socket *s, int **fds) {
assert(k == n);
*fds = rfds;
- return n;
+ return (int) n;
}
static void socket_reset_failed(Unit *u) {
diff --git a/src/core/socket.h b/src/core/socket.h
index 84ec9cff08..c4e25db1fc 100644
--- a/src/core/socket.h
+++ b/src/core/socket.h
@@ -1,31 +1,13 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
typedef struct Socket Socket;
typedef struct SocketPeer SocketPeer;
#include "mount.h"
#include "service.h"
#include "socket-util.h"
+#include "unit.h"
typedef enum SocketExecCommand {
SOCKET_EXEC_START_PRE,
@@ -67,7 +49,7 @@ typedef struct SocketPort {
SocketType type;
int fd;
int *auxiliary_fds;
- int n_auxiliary_fds;
+ size_t n_auxiliary_fds;
SocketAddress address;
char *path;
@@ -85,6 +67,7 @@ struct Socket {
unsigned n_accepted;
unsigned n_connections;
+ unsigned n_refused;
unsigned max_connections;
unsigned max_connections_per_source;
@@ -195,3 +178,5 @@ SocketResult socket_result_from_string(const char *s) _pure_;
const char* socket_port_type_to_string(SocketPort *p) _pure_;
SocketType socket_port_type_from_string(const char *p) _pure_;
+
+DEFINE_CAST(SOCKET, Socket);
diff --git a/src/core/swap.c b/src/core/swap.c
index ed397c4c9e..b78b1aa266 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
#include <sys/epoll.h>
@@ -27,6 +9,7 @@
#include "alloc-util.h"
#include "dbus-swap.h"
+#include "device.h"
#include "escape.h"
#include "exit-status.h"
#include "fd-util.h"
@@ -252,30 +235,34 @@ static int swap_verify(Swap *s) {
if (!unit_has_name(UNIT(s), e)) {
log_unit_error(UNIT(s), "Value of What= and unit name do not match, not loading.");
- return -EINVAL;
+ return -ENOEXEC;
}
if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) {
log_unit_error(UNIT(s), "Unit has PAM enabled. Kill mode must be set to 'control-group'. Refusing to load.");
- return -EINVAL;
+ return -ENOEXEC;
}
return 0;
}
static int swap_load_devnode(Swap *s) {
- _cleanup_udev_device_unref_ struct udev_device *d = NULL;
+ _cleanup_(udev_device_unrefp) struct udev_device *d = NULL;
struct stat st;
const char *p;
+ int r;
assert(s);
if (stat(s->what, &st) < 0 || !S_ISBLK(st.st_mode))
return 0;
- d = udev_device_new_from_devnum(UNIT(s)->manager->udev, 'b', st.st_rdev);
- if (!d)
+ r = udev_device_new_from_stat_rdev(UNIT(s)->manager->udev, &st, &d);
+ if (r < 0) {
+ log_unit_full(UNIT(s), r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to allocate udev device for swap %s: %m", s->what);
return 0;
+ }
p = udev_device_get_devnode(d);
if (!p)
@@ -319,7 +306,7 @@ static int swap_load(Unit *u) {
return -ENOMEM;
}
- path_kill_slashes(s->what);
+ path_simplify(s->what, false);
if (!UNIT(s)->description) {
r = unit_set_description(u, s->what);
@@ -438,7 +425,7 @@ fail:
}
static int swap_process_new(Manager *m, const char *device, int prio, bool set_flags) {
- _cleanup_udev_device_unref_ struct udev_device *d = NULL;
+ _cleanup_(udev_device_unrefp) struct udev_device *d = NULL;
struct udev_list_entry *item = NULL, *first = NULL;
const char *dn;
struct stat st;
@@ -455,9 +442,12 @@ static int swap_process_new(Manager *m, const char *device, int prio, bool set_f
if (stat(device, &st) < 0 || !S_ISBLK(st.st_mode))
return 0;
- d = udev_device_new_from_devnum(m->udev, 'b', st.st_rdev);
- if (!d)
+ r = udev_device_new_from_stat_rdev(m->udev, &st, &d);
+ if (r < 0) {
+ log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to allocate udev device for swap %s: %m", device);
return 0;
+ }
/* Add the main device node */
dn = udev_device_get_devnode(d);
@@ -508,7 +498,7 @@ static void swap_set_state(Swap *s, SwapState state) {
if (state != old_state)
log_unit_debug(UNIT(s), "Changed %s -> %s", swap_state_to_string(old_state), swap_state_to_string(state));
- unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
+ unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], 0);
/* If there other units for the same device node have a job
queued it might be worth checking again if it is runnable
@@ -1124,7 +1114,7 @@ static int swap_load_proc_swaps(Manager *m, bool set_flags) {
if (cunescape(dev, UNESCAPE_RELAX, &d) < 0)
return log_oom();
- device_found_node(m, d, true, DEVICE_FOUND_SWAP, set_flags);
+ device_found_node(m, d, DEVICE_FOUND_SWAP, DEVICE_FOUND_SWAP);
k = swap_process_new(m, d, prio, set_flags);
if (k < 0)
@@ -1179,7 +1169,7 @@ static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, v
}
if (swap->what)
- device_found_node(m, swap->what, false, DEVICE_FOUND_SWAP, true);
+ device_found_node(m, swap->what, 0, DEVICE_FOUND_SWAP);
} else if (swap->just_activated) {
@@ -1253,7 +1243,7 @@ static Unit *swap_following(Unit *u) {
static int swap_following_set(Unit *u, Set **_set) {
Swap *s = SWAP(u), *other;
- Set *set;
+ _cleanup_set_free_ Set *set = NULL;
int r;
assert(s);
@@ -1271,24 +1261,18 @@ static int swap_following_set(Unit *u, Set **_set) {
LIST_FOREACH_OTHERS(same_devnode, other, s) {
r = set_put(set, other);
if (r < 0)
- goto fail;
+ return r;
}
- *_set = set;
+ *_set = TAKE_PTR(set);
return 1;
-
-fail:
- set_free(set);
- return r;
}
static void swap_shutdown(Manager *m) {
assert(m);
m->swap_event_source = sd_event_source_unref(m->swap_event_source);
-
m->proc_swaps = safe_fclose(m->proc_swaps);
-
m->swaps_by_devnode = hashmap_free(m->swaps_by_devnode);
}
@@ -1301,9 +1285,9 @@ static void swap_enumerate(Manager *m) {
m->proc_swaps = fopen("/proc/swaps", "re");
if (!m->proc_swaps) {
if (errno == ENOENT)
- log_debug("Not swap enabled, skipping enumeration");
+ log_debug_errno(errno, "Not swap enabled, skipping enumeration.");
else
- log_error_errno(errno, "Failed to open /proc/swaps: %m");
+ log_warning_errno(errno, "Failed to open /proc/swaps, ignoring: %m");
return;
}
diff --git a/src/core/swap.h b/src/core/swap.h
index fa9d45ac0c..1c0c7fcadc 100644
--- a/src/core/swap.h
+++ b/src/core/swap.h
@@ -2,26 +2,11 @@
#pragma once
/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
- Copyright 2010 Maarten Lankhorst
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ Copyright © 2010 Maarten Lankhorst
***/
#include "libudev.h"
+#include "unit.h"
typedef struct Swap Swap;
@@ -108,3 +93,5 @@ SwapExecCommand swap_exec_command_from_string(const char *s) _pure_;
const char* swap_result_to_string(SwapResult i) _const_;
SwapResult swap_result_from_string(const char *s) _pure_;
+
+DEFINE_CAST(SWAP, Swap);
diff --git a/src/core/system.conf.in b/src/core/system.conf.in
index 08cbe529ba..f0a59a79a5 100644
--- a/src/core/system.conf.in
+++ b/src/core/system.conf.in
@@ -27,6 +27,7 @@
#RuntimeWatchdogSec=0
#ShutdownWatchdogSec=10min
#CapabilityBoundingSet=
+#NoNewPrivileges=no
#SystemCallArchitectures=
#TimerSlackNSec=
#DefaultTimerAccuracySec=1min
diff --git a/src/core/target.c b/src/core/target.c
index 756cbbfb6c..6446767504 100644
--- a/src/core/target.c
+++ b/src/core/target.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include "dbus-target.h"
#include "log.h"
@@ -44,7 +26,7 @@ static void target_set_state(Target *t, TargetState state) {
target_state_to_string(old_state),
target_state_to_string(state));
- unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
+ unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], 0);
}
static int target_add_default_dependencies(Target *t) {
diff --git a/src/core/target.h b/src/core/target.h
index 8d44a11545..28f78888dc 100644
--- a/src/core/target.h
+++ b/src/core/target.h
@@ -1,24 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
+#include "unit.h"
typedef struct Target Target;
@@ -29,3 +12,5 @@ struct Target {
};
extern const UnitVTable target_vtable;
+
+DEFINE_CAST(TARGET, Target);
diff --git a/src/core/timer.c b/src/core/timer.c
index ddb9c82b87..db202971d3 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
@@ -91,7 +73,7 @@ static int timer_verify(Timer *t) {
if (!t->values) {
log_unit_error(UNIT(t), "Timer unit lacks value setting. Refusing.");
- return -EINVAL;
+ return -ENOEXEC;
}
return 0;
@@ -277,7 +259,7 @@ static void timer_set_state(Timer *t, TimerState state) {
if (state != old_state)
log_unit_debug(UNIT(t), "Changed %s -> %s", timer_state_to_string(old_state), timer_state_to_string(state));
- unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
+ unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], 0);
}
static void timer_enter_waiting(Timer *t, bool initial);
@@ -832,6 +814,18 @@ static void timer_time_change(Unit *u) {
timer_enter_waiting(t, false);
}
+static void timer_timezone_change(Unit *u) {
+ Timer *t = TIMER(u);
+
+ assert(u);
+
+ if (t->state != TIMER_WAITING)
+ return;
+
+ log_unit_debug(u, "Timezone change, recalculating next elapse.");
+ timer_enter_waiting(t, false);
+}
+
static const char* const timer_base_table[_TIMER_BASE_MAX] = {
[TIMER_ACTIVE] = "OnActiveSec",
[TIMER_BOOT] = "OnBootSec",
@@ -881,6 +875,7 @@ const UnitVTable timer_vtable = {
.reset_failed = timer_reset_failed,
.time_change = timer_time_change,
+ .timezone_change = timer_timezone_change,
.bus_vtable = bus_timer_vtable,
.bus_set_property = bus_timer_set_property,
diff --git a/src/core/timer.h b/src/core/timer.h
index 096d48bd34..833aadb0b8 100644
--- a/src/core/timer.h
+++ b/src/core/timer.h
@@ -1,28 +1,10 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
typedef struct Timer Timer;
#include "calendarspec.h"
+#include "unit.h"
typedef enum TimerBase {
TIMER_ACTIVE,
@@ -90,3 +72,5 @@ TimerBase timer_base_from_string(const char *s) _pure_;
const char* timer_result_to_string(TimerResult i) _const_;
TimerResult timer_result_from_string(const char *s) _pure_;
+
+DEFINE_CAST(TIMER, Timer);
diff --git a/src/core/transaction.c b/src/core/transaction.c
index 32ad660026..1c7efb207a 100644
--- a/src/core/transaction.c
+++ b/src/core/transaction.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <fcntl.h>
#include <unistd.h>
@@ -413,7 +395,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
j->unit->id,
unit_id == array ? "ordering cycle" : "dependency",
*unit_id, *job_type,
- unit_ids, NULL);
+ unit_ids);
if (delete) {
const char *status;
@@ -422,7 +404,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
"MESSAGE=%s: Job %s/%s deleted to break ordering cycle starting with %s/%s",
j->unit->id, delete->unit->id, job_type_to_string(delete->type),
j->unit->id, job_type_to_string(j->type),
- unit_ids, NULL);
+ unit_ids);
if (log_get_show_color())
status = ANSI_HIGHLIGHT_RED " SKIP " ANSI_NORMAL;
@@ -438,7 +420,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
log_struct(LOG_ERR,
"MESSAGE=%s: Unable to break cycle starting with %s/%s",
j->unit->id, j->unit->id, job_type_to_string(j->type),
- unit_ids, NULL);
+ unit_ids);
return sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC,
"Transaction order is cyclic. See system logs for details.");
@@ -919,11 +901,13 @@ int transaction_add_job_and_dependencies(
/* by ? by->unit->id : "NA", */
/* by ? job_type_to_string(by->type) : "NA"); */
- if (!IN_SET(unit->load_state, UNIT_LOADED, UNIT_ERROR, UNIT_NOT_FOUND, UNIT_MASKED))
+ /* Safety check that the unit is a valid state, i.e. not in UNIT_STUB or UNIT_MERGED which should only be set
+ * temporarily. */
+ if (!IN_SET(unit->load_state, UNIT_LOADED, UNIT_ERROR, UNIT_NOT_FOUND, UNIT_BAD_SETTING, UNIT_MASKED))
return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id);
if (type != JOB_STOP) {
- r = bus_unit_check_load_state(unit, e);
+ r = bus_unit_validate_load_state(unit, e);
if (r < 0)
return r;
}
@@ -933,7 +917,6 @@ int transaction_add_job_and_dependencies(
"Job type %s is not applicable for unit %s.",
job_type_to_string(type), unit->id);
-
/* First add the job. */
ret = transaction_add_one_job(tr, type, unit, &is_new);
if (!ret)
diff --git a/src/core/transaction.h b/src/core/transaction.h
index 0d57b27f2e..70d74a4ccb 100644
--- a/src/core/transaction.h
+++ b/src/core/transaction.h
@@ -1,25 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
typedef struct Transaction Transaction;
#include "hashmap.h"
diff --git a/src/core/triggers.systemd.in b/src/core/triggers.systemd.in
index c582d40977..10b1889b57 100644
--- a/src/core/triggers.systemd.in
+++ b/src/core/triggers.systemd.in
@@ -2,22 +2,7 @@
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
-#
-# Copyright 2015 Zbigniew Jędrzejewski-Szmek
-# Copyright 2018 Neal Gompa
-#
-# systemd is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation; either version 2.1 of the License, or
-# (at your option) any later version.
-#
-# systemd is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with systemd; If not, see <http://www.gnu.org/licenses/>.
+# Copyright © 2018 Neal Gompa
# The contents of this are an example to be copied into systemd.spec.
#
@@ -84,7 +69,7 @@ if posix.access("/run/systemd/system") then
end
end
-%transfiletriggerin -P 100500 -- @tmpfilesdir@
+%transfiletriggerin -P 100500 -p <lua> -- @tmpfilesdir@
-- This script will process files installed in @tmpfilesdir@ to create
-- tmpfiles automatically. The priority is set such that it will run
-- after the sysusers file trigger, but before any other triggers.
@@ -97,7 +82,7 @@ if posix.access("/run/systemd/system") then
end
end
-%transfiletriggerin -- @udevhwdbdir@
+%transfiletriggerin -p <lua> -- @udevhwdbdir@
-- This script will automatically invoke hwdb update if files have been
-- installed or updated in @udevhwdbdir@.
if posix.access("/run/systemd/system") then
@@ -109,7 +94,7 @@ if posix.access("/run/systemd/system") then
end
end
-%transfiletriggerin -- @catalogdir@
+%transfiletriggerin -p <lua> -- @catalogdir@
-- This script will automatically invoke journal catalog update if files
-- have been installed or updated in @catalogdir@.
if posix.access("/run/systemd/system") then
@@ -121,7 +106,7 @@ if posix.access("/run/systemd/system") then
end
end
-%transfiletriggerin -- @udevrulesdir@
+%transfiletriggerin -p <lua> -- @udevrulesdir@
-- This script will automatically update udev with new rules if files
-- have been installed or updated in @udevrulesdir@.
if posix.access("/run/systemd/system") then
@@ -133,7 +118,7 @@ if posix.access("/run/systemd/system") then
end
end
-%transfiletriggerin -- @sysctldir@
+%transfiletriggerin -p <lua> -- @sysctldir@
-- This script will automatically apply sysctl rules if files have been
-- installed or updated in @sysctldir@.
if posix.access("/run/systemd/system") then
@@ -145,7 +130,7 @@ if posix.access("/run/systemd/system") then
end
end
-%transfiletriggerin -- @binfmtdir@
+%transfiletriggerin -p <lua> -- @binfmtdir@
-- This script will automatically apply binfmt rules if files have been
-- installed or updated in @binfmtdir@.
if posix.access("/run/systemd/system") then
diff --git a/src/core/umount.c b/src/core/umount.c
index ff3e63710c..241fe6fc62 100644
--- a/src/core/umount.c
+++ b/src/core/umount.c
@@ -1,21 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
/***
- This file is part of systemd.
-
- Copyright 2010 ProFUSION embedded systems
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ Copyright © 2010 ProFUSION embedded systems
***/
#include <errno.h>
@@ -25,6 +10,9 @@
#include <sys/mount.h>
#include <sys/swap.h>
+/* This needs to be after sys/mount.h :( */
+#include <libmount.h>
+
#include "libudev.h"
#include "alloc-util.h"
@@ -34,7 +22,6 @@
#include "fd-util.h"
#include "fstab-util.h"
#include "linux-3.13/dm-ioctl.h"
-#include "list.h"
#include "mount-setup.h"
#include "mount-util.h"
#include "path-util.h"
@@ -46,13 +33,8 @@
#include "util.h"
#include "virt.h"
-typedef struct MountPoint {
- char *path;
- char *options;
- char *type;
- dev_t devnum;
- LIST_FIELDS(struct MountPoint, mount_point);
-} MountPoint;
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_table*, mnt_free_table);
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_iter*, mnt_free_iter);
static void mount_point_free(MountPoint **head, MountPoint *m) {
assert(head);
@@ -61,58 +43,57 @@ static void mount_point_free(MountPoint **head, MountPoint *m) {
LIST_REMOVE(mount_point, *head, m);
free(m->path);
+ free(m->remount_options);
free(m);
}
-static void mount_points_list_free(MountPoint **head) {
+void mount_points_list_free(MountPoint **head) {
assert(head);
while (*head)
mount_point_free(head, *head);
}
-static int mount_points_list_get(MountPoint **head) {
- _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
- unsigned int i;
+int mount_points_list_get(const char *mountinfo, MountPoint **head) {
+ _cleanup_(mnt_free_tablep) struct libmnt_table *t = NULL;
+ _cleanup_(mnt_free_iterp) struct libmnt_iter *i = NULL;
int r;
assert(head);
- proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
- if (!proc_self_mountinfo)
- return -errno;
+ t = mnt_new_table();
+ i = mnt_new_iter(MNT_ITER_FORWARD);
+ if (!t || !i)
+ return log_oom();
- for (i = 1;; i++) {
- _cleanup_free_ char *path = NULL, *options = NULL, *type = NULL;
- char *p = NULL;
+ r = mnt_table_parse_mtab(t, mountinfo);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s: %m", mountinfo);
+
+ for (;;) {
+ struct libmnt_fs *fs;
+ const char *path, *options, *fstype;
+ _cleanup_free_ char *p = NULL;
+ unsigned long remount_flags = 0u;
+ _cleanup_free_ char *remount_options = NULL;
+ bool try_remount_ro;
MountPoint *m;
- int k;
-
- k = fscanf(proc_self_mountinfo,
- "%*s " /* (1) mount id */
- "%*s " /* (2) parent id */
- "%*s " /* (3) major:minor */
- "%*s " /* (4) root */
- "%ms " /* (5) mount point */
- "%*s" /* (6) mount flags */
- "%*[^-]" /* (7) optional fields */
- "- " /* (8) separator */
- "%ms " /* (9) file system type */
- "%*s" /* (10) mount source */
- "%ms" /* (11) mount options */
- "%*[^\n]", /* some rubbish at the end */
- &path, &type, &options);
- if (k != 3) {
- if (k == EOF)
- break;
-
- log_warning("Failed to parse /proc/self/mountinfo:%u.", i);
- continue;
- }
- r = cunescape(path, UNESCAPE_RELAX, &p);
+ r = mnt_table_next_fs(t, i, &fs);
+ if (r == 1)
+ break;
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to get next entry from %s: %m", mountinfo);
+
+ path = mnt_fs_get_target(fs);
+ if (!path)
+ continue;
+
+ if (cunescape(path, UNESCAPE_RELAX, &p) < 0)
+ return log_oom();
+
+ options = mnt_fs_get_options(fs);
+ fstype = mnt_fs_get_fstype(fs);
/* Ignore mount points we can't unmount because they
* are API or because we are keeping them open (like
@@ -125,22 +106,56 @@ static int mount_points_list_get(MountPoint **head) {
mount_point_ignore(p) ||
path_startswith(p, "/dev") ||
path_startswith(p, "/sys") ||
- path_startswith(p, "/proc")) {
- free(p);
+ path_startswith(p, "/proc"))
continue;
+
+ /* If we are in a container, don't attempt to
+ * read-only mount anything as that brings no real
+ * benefits, but might confuse the host, as we remount
+ * the superblock here, not the bind mount.
+ *
+ * If the filesystem is a network fs, also skip the
+ * remount. It brings no value (we cannot leave
+ * a "dirty fs") and could hang if the network is down.
+ * Note that umount2() is more careful and will not
+ * hang because of the network being down. */
+ try_remount_ro = detect_container() <= 0 &&
+ !fstype_is_network(fstype) &&
+ !fstype_is_api_vfs(fstype) &&
+ !fstype_is_ro(fstype) &&
+ !fstab_test_yes_no_option(options, "ro\0rw\0");
+
+ if (try_remount_ro) {
+ /* mount(2) states that mount flags and options need to be exactly the same
+ * as they were when the filesystem was mounted, except for the desired
+ * changes. So we reconstruct both here and adjust them for the later
+ * remount call too. */
+
+ r = mnt_fs_get_propagation(fs, &remount_flags);
+ if (r < 0) {
+ log_warning_errno(r, "mnt_fs_get_propagation() failed for %s, ignoring: %m", path);
+ continue;
+ }
+
+ r = mount_option_mangle(options, remount_flags, &remount_flags, &remount_options);
+ if (r < 0) {
+ log_warning_errno(r, "mount_option_mangle failed for %s, ignoring: %m", path);
+ continue;
+ }
+
+ /* MS_BIND is special. If it is provided it will only make the mount-point
+ * read-only. If left out, the super block itself is remounted, which we want. */
+ remount_flags = (remount_flags|MS_REMOUNT|MS_RDONLY) & ~MS_BIND;
}
m = new0(MountPoint, 1);
- if (!m) {
- free(p);
- return -ENOMEM;
- }
+ if (!m)
+ return log_oom();
- m->path = p;
- m->options = options;
- options = NULL;
- m->type = type;
- type = NULL;
+ free_and_replace(m->path, p);
+ free_and_replace(m->remount_options, remount_options);
+ m->remount_flags = remount_flags;
+ m->try_remount_ro = try_remount_ro;
LIST_PREPEND(mount_point, *head, m);
}
@@ -148,44 +163,40 @@ static int mount_points_list_get(MountPoint **head) {
return 0;
}
-static int swap_list_get(MountPoint **head) {
- _cleanup_fclose_ FILE *proc_swaps = NULL;
- unsigned int i;
+int swap_list_get(const char *swaps, MountPoint **head) {
+ _cleanup_(mnt_free_tablep) struct libmnt_table *t = NULL;
+ _cleanup_(mnt_free_iterp) struct libmnt_iter *i = NULL;
int r;
assert(head);
- proc_swaps = fopen("/proc/swaps", "re");
- if (!proc_swaps)
- return (errno == ENOENT) ? 0 : -errno;
+ t = mnt_new_table();
+ i = mnt_new_iter(MNT_ITER_FORWARD);
+ if (!t || !i)
+ return log_oom();
+
+ r = mnt_table_parse_swaps(t, swaps);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s: %m", swaps);
- (void) fscanf(proc_swaps, "%*s %*s %*s %*s %*s\n");
+ for (;;) {
+ struct libmnt_fs *fs;
- for (i = 2;; i++) {
MountPoint *swap;
- _cleanup_free_ char *dev = NULL, *d = NULL;
- int k;
-
- k = fscanf(proc_swaps,
- "%ms " /* device/file */
- "%*s " /* type of swap */
- "%*s " /* swap size */
- "%*s " /* used */
- "%*s\n", /* priority */
- &dev);
-
- if (k != 1) {
- if (k == EOF)
- break;
-
- log_warning("Failed to parse /proc/swaps:%u.", i);
- continue;
- }
+ const char *source;
+ _cleanup_free_ char *d = NULL;
- if (endswith(dev, " (deleted)"))
+ r = mnt_table_next_fs(t, i, &fs);
+ if (r == 1)
+ break;
+ if (r < 0)
+ return log_error_errno(r, "Failed to get next entry from %s: %m", swaps);
+
+ source = mnt_fs_get_source(fs);
+ if (!source)
continue;
- r = cunescape(dev, UNESCAPE_RELAX, &d);
+ r = cunescape(source, UNESCAPE_RELAX, &d);
if (r < 0)
return r;
@@ -201,9 +212,9 @@ static int swap_list_get(MountPoint **head) {
}
static int loopback_list_get(MountPoint **head) {
- _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
+ _cleanup_(udev_enumerate_unrefp) struct udev_enumerate *e = NULL;
struct udev_list_entry *item = NULL, *first = NULL;
- _cleanup_udev_unref_ struct udev *udev = NULL;
+ _cleanup_(udev_unrefp) struct udev *udev = NULL;
int r;
assert(head);
@@ -234,10 +245,9 @@ static int loopback_list_get(MountPoint **head) {
first = udev_enumerate_get_list_entry(e);
udev_list_entry_foreach(item, first) {
- MountPoint *lb;
- _cleanup_udev_device_unref_ struct udev_device *d;
- char *loop;
+ _cleanup_(udev_device_unrefp) struct udev_device *d;
const char *dn;
+ _cleanup_free_ MountPoint *lb = NULL;
d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
if (!d)
@@ -247,27 +257,25 @@ static int loopback_list_get(MountPoint **head) {
if (!dn)
continue;
- loop = strdup(dn);
- if (!loop)
- return -ENOMEM;
-
lb = new0(MountPoint, 1);
- if (!lb) {
- free(loop);
+ if (!lb)
return -ENOMEM;
- }
- lb->path = loop;
+ r = free_and_strdup(&lb->path, dn);
+ if (r < 0)
+ return r;
+
LIST_PREPEND(mount_point, *head, lb);
+ lb = NULL;
}
return 0;
}
static int dm_list_get(MountPoint **head) {
- _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
+ _cleanup_(udev_enumerate_unrefp) struct udev_enumerate *e = NULL;
struct udev_list_entry *item = NULL, *first = NULL;
- _cleanup_udev_unref_ struct udev *udev = NULL;
+ _cleanup_(udev_unrefp) struct udev *udev = NULL;
int r;
assert(head);
@@ -294,11 +302,10 @@ static int dm_list_get(MountPoint **head) {
first = udev_enumerate_get_list_entry(e);
udev_list_entry_foreach(item, first) {
- MountPoint *m;
- _cleanup_udev_device_unref_ struct udev_device *d;
+ _cleanup_(udev_device_unrefp) struct udev_device *d;
dev_t devnum;
- char *node;
const char *dn;
+ _cleanup_free_ MountPoint *m = NULL;
d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
if (!d)
@@ -309,19 +316,17 @@ static int dm_list_get(MountPoint **head) {
if (major(devnum) == 0 || !dn)
continue;
- node = strdup(dn);
- if (!node)
+ m = new0(MountPoint, 1);
+ if (!m)
return -ENOMEM;
- m = new(MountPoint, 1);
- if (!m) {
- free(node);
- return -ENOMEM;
- }
-
- m->path = node;
m->devnum = devnum;
+ r = free_and_strdup(&m->path, dn);
+ if (r < 0)
+ return r;
+
LIST_PREPEND(mount_point, *head, m);
+ m = NULL;
}
return 0;
@@ -331,6 +336,8 @@ static int delete_loopback(const char *device) {
_cleanup_close_ int fd = -1;
int r;
+ assert(device);
+
fd = open(device, O_RDONLY|O_CLOEXEC);
if (fd < 0)
return errno == ENOENT ? 0 : -errno;
@@ -380,12 +387,14 @@ static bool nonunmountable_path(const char *path) {
|| path_startswith(path, "/run/initramfs");
}
-static int remount_with_timeout(MountPoint *m, char *options, int *n_failed) {
+static int remount_with_timeout(MountPoint *m, int umount_log_level) {
pid_t pid;
int r;
BLOCK_SIGNALS(SIGCHLD);
+ assert(m);
+
/* Due to the possiblity of a remount operation hanging, we
* fork a child process and set a timeout. If the timeout
* lapses, the assumption is that that particular remount
@@ -394,12 +403,12 @@ static int remount_with_timeout(MountPoint *m, char *options, int *n_failed) {
if (r < 0)
return r;
if (r == 0) {
- log_info("Remounting '%s' read-only in with options '%s'.", m->path, options);
+ log_info("Remounting '%s' read-only in with options '%s'.", m->path, m->remount_options);
/* Start the mount operation here in the child */
- r = mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, options);
+ r = mount(NULL, m->path, NULL, m->remount_flags, m->remount_options);
if (r < 0)
- log_error_errno(errno, "Failed to remount '%s' read-only: %m", m->path);
+ log_full_errno(umount_log_level, errno, "Failed to remount '%s' read-only: %m", m->path);
_exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
}
@@ -409,19 +418,21 @@ static int remount_with_timeout(MountPoint *m, char *options, int *n_failed) {
log_error_errno(r, "Remounting '%s' timed out, issuing SIGKILL to PID " PID_FMT ".", m->path, pid);
(void) kill(pid, SIGKILL);
} else if (r == -EPROTO)
- log_error_errno(r, "Remounting '%s' failed abnormally, child process " PID_FMT " aborted or exited non-zero.", m->path, pid);
+ log_debug_errno(r, "Remounting '%s' failed abnormally, child process " PID_FMT " aborted or exited non-zero.", m->path, pid);
else if (r < 0)
log_error_errno(r, "Remounting '%s' failed unexpectedly, couldn't wait for child process " PID_FMT ": %m", m->path, pid);
return r;
}
-static int umount_with_timeout(MountPoint *m, bool *changed) {
+static int umount_with_timeout(MountPoint *m, int umount_log_level) {
pid_t pid;
int r;
BLOCK_SIGNALS(SIGCHLD);
+ assert(m);
+
/* Due to the possiblity of a umount operation hanging, we
* fork a child process and set a timeout. If the timeout
* lapses, the assumption is that that particular umount
@@ -441,7 +452,7 @@ static int umount_with_timeout(MountPoint *m, bool *changed) {
* then return EBUSY).*/
r = umount2(m->path, MNT_FORCE);
if (r < 0)
- log_error_errno(errno, "Failed to unmount %s: %m", m->path);
+ log_full_errno(umount_log_level, errno, "Failed to unmount %s: %m", m->path);
_exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
}
@@ -451,7 +462,7 @@ static int umount_with_timeout(MountPoint *m, bool *changed) {
log_error_errno(r, "Unmounting '%s' timed out, issuing SIGKILL to PID " PID_FMT ".", m->path, pid);
(void) kill(pid, SIGKILL);
} else if (r == -EPROTO)
- log_error_errno(r, "Unmounting '%s' failed abnormally, child process " PID_FMT " aborted or exited non-zero.", m->path, pid);
+ log_debug_errno(r, "Unmounting '%s' failed abnormally, child process " PID_FMT " aborted or exited non-zero.", m->path, pid);
else if (r < 0)
log_error_errno(r, "Unmounting '%s' failed unexpectedly, couldn't wait for child process " PID_FMT ": %m", m->path, pid);
@@ -460,38 +471,15 @@ static int umount_with_timeout(MountPoint *m, bool *changed) {
/* This includes remounting readonly, which changes the kernel mount options.
* Therefore the list passed to this function is invalidated, and should not be reused. */
-
-static int mount_points_list_umount(MountPoint **head, bool *changed) {
+static int mount_points_list_umount(MountPoint **head, bool *changed, int umount_log_level) {
MountPoint *m;
int n_failed = 0;
assert(head);
+ assert(changed);
LIST_FOREACH(mount_point, m, *head) {
- bool mount_is_readonly;
-
- mount_is_readonly = fstab_test_yes_no_option(m->options, "ro\0rw\0");
-
- /* If we are in a container, don't attempt to
- read-only mount anything as that brings no real
- benefits, but might confuse the host, as we remount
- the superblock here, not the bind mount.
- If the filesystem is a network fs, also skip the
- remount. It brings no value (we cannot leave
- a "dirty fs") and could hang if the network is down.
- Note that umount2() is more careful and will not
- hang because of the network being down. */
- if (detect_container() <= 0 &&
- !fstype_is_network(m->type) &&
- !mount_is_readonly) {
- _cleanup_free_ char *options = NULL;
- /* MS_REMOUNT requires that the data parameter
- * should be the same from the original mount
- * except for the desired changes. Since we want
- * to remount read-only, we should filter out
- * rw (and ro too, because it confuses the kernel) */
- (void) fstab_filter_options(m->options, "rw\0ro\0", NULL, NULL, &options);
-
+ if (m->try_remount_ro) {
/* We always try to remount directories
* read-only first, before we go on and umount
* them.
@@ -506,16 +494,19 @@ static int mount_points_list_umount(MountPoint **head, bool *changed) {
* somehwere else via a bind mount. If we
* explicitly remount the super block of that
* alias read-only we hence should be
- * relatively safe regarding keeping dirty an fs
+ * relatively safe regarding keeping a dirty fs
* we cannot otherwise see.
*
* Since the remount can hang in the instance of
* remote filesystems, we remount asynchronously
- * and skip the subsequent umount if it fails */
- if (remount_with_timeout(m, options, &n_failed) < 0) {
- if (nonunmountable_path(m->path))
+ * and skip the subsequent umount if it fails. */
+ if (remount_with_timeout(m, umount_log_level) < 0) {
+ /* Remount failed, but try unmounting anyway,
+ * unless this is a mount point we want to skip. */
+ if (nonunmountable_path(m->path)) {
n_failed++;
- continue;
+ continue;
+ }
}
}
@@ -526,12 +517,10 @@ static int mount_points_list_umount(MountPoint **head, bool *changed) {
continue;
/* Trying to umount */
- if (umount_with_timeout(m, changed) < 0)
+ if (umount_with_timeout(m, umount_log_level) < 0)
n_failed++;
- else {
- if (changed)
- *changed = true;
- }
+ else
+ *changed = true;
}
return n_failed;
@@ -542,13 +531,12 @@ static int swap_points_list_off(MountPoint **head, bool *changed) {
int n_failed = 0;
assert(head);
+ assert(changed);
LIST_FOREACH_SAFE(mount_point, m, n, *head) {
log_info("Deactivating swap %s.", m->path);
if (swapoff(m->path) == 0) {
- if (changed)
- *changed = true;
-
+ *changed = true;
mount_point_free(head, m);
} else {
log_warning_errno(errno, "Could not deactivate swap %s: %m", m->path);
@@ -559,12 +547,13 @@ static int swap_points_list_off(MountPoint **head, bool *changed) {
return n_failed;
}
-static int loopback_points_list_detach(MountPoint **head, bool *changed) {
+static int loopback_points_list_detach(MountPoint **head, bool *changed, int umount_log_level) {
MountPoint *m, *n;
int n_failed = 0, k;
struct stat root_st;
assert(head);
+ assert(changed);
k = lstat("/", &root_st);
@@ -583,12 +572,12 @@ static int loopback_points_list_detach(MountPoint **head, bool *changed) {
log_info("Detaching loopback %s.", m->path);
r = delete_loopback(m->path);
if (r >= 0) {
- if (r > 0 && changed)
+ if (r > 0)
*changed = true;
mount_point_free(head, m);
} else {
- log_warning_errno(errno, "Could not detach loopback %s: %m", m->path);
+ log_full_errno(umount_log_level, errno, "Could not detach loopback %s: %m", m->path);
n_failed++;
}
}
@@ -596,12 +585,13 @@ static int loopback_points_list_detach(MountPoint **head, bool *changed) {
return n_failed;
}
-static int dm_points_list_detach(MountPoint **head, bool *changed) {
+static int dm_points_list_detach(MountPoint **head, bool *changed, int umount_log_level) {
MountPoint *m, *n;
int n_failed = 0, r;
dev_t rootdev;
assert(head);
+ assert(changed);
r = get_block_device("/", &rootdev);
if (r <= 0)
@@ -609,21 +599,18 @@ static int dm_points_list_detach(MountPoint **head, bool *changed) {
LIST_FOREACH_SAFE(mount_point, m, n, *head) {
- if (major(rootdev) != 0)
- if (rootdev == m->devnum) {
- n_failed ++;
- continue;
- }
+ if (major(rootdev) != 0 && rootdev == m->devnum) {
+ n_failed ++;
+ continue;
+ }
log_info("Detaching DM %u:%u.", major(m->devnum), minor(m->devnum));
r = delete_dm(m->devnum);
if (r >= 0) {
- if (changed)
- *changed = true;
-
+ *changed = true;
mount_point_free(head, m);
} else {
- log_warning_errno(errno, "Could not detach DM %s: %m", m->path);
+ log_full_errno(umount_log_level, errno, "Could not detach DM %s: %m", m->path);
n_failed++;
}
}
@@ -631,34 +618,33 @@ static int dm_points_list_detach(MountPoint **head, bool *changed) {
return n_failed;
}
-static int umount_all_once(bool *changed) {
+static int umount_all_once(bool *changed, int umount_log_level) {
int r;
- LIST_HEAD(MountPoint, mp_list_head);
+ _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, mp_list_head);
+
+ assert(changed);
LIST_HEAD_INIT(mp_list_head);
- r = mount_points_list_get(&mp_list_head);
+ r = mount_points_list_get(NULL, &mp_list_head);
if (r < 0)
- goto end;
-
- r = mount_points_list_umount(&mp_list_head, changed);
-
- end:
- mount_points_list_free(&mp_list_head);
+ return r;
- return r;
+ return mount_points_list_umount(&mp_list_head, changed, umount_log_level);
}
-int umount_all(bool *changed) {
+int umount_all(bool *changed, int umount_log_level) {
bool umount_changed;
int r;
+ assert(changed);
+
/* Retry umount, until nothing can be umounted anymore. Mounts are
* processed in order, newest first. The retries are needed when
* an old mount has been moved, to a path inside a newer mount. */
do {
umount_changed = false;
- r = umount_all_once(&umount_changed);
+ r = umount_all_once(&umount_changed, umount_log_level);
if (umount_changed)
*changed = true;
} while (umount_changed);
@@ -667,55 +653,46 @@ int umount_all(bool *changed) {
}
int swapoff_all(bool *changed) {
+ _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, swap_list_head);
int r;
- LIST_HEAD(MountPoint, swap_list_head);
+
+ assert(changed);
LIST_HEAD_INIT(swap_list_head);
- r = swap_list_get(&swap_list_head);
+ r = swap_list_get(NULL, &swap_list_head);
if (r < 0)
- goto end;
-
- r = swap_points_list_off(&swap_list_head, changed);
-
- end:
- mount_points_list_free(&swap_list_head);
+ return r;
- return r;
+ return swap_points_list_off(&swap_list_head, changed);
}
-int loopback_detach_all(bool *changed) {
+int loopback_detach_all(bool *changed, int umount_log_level) {
+ _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, loopback_list_head);
int r;
- LIST_HEAD(MountPoint, loopback_list_head);
+
+ assert(changed);
LIST_HEAD_INIT(loopback_list_head);
r = loopback_list_get(&loopback_list_head);
if (r < 0)
- goto end;
-
- r = loopback_points_list_detach(&loopback_list_head, changed);
-
- end:
- mount_points_list_free(&loopback_list_head);
+ return r;
- return r;
+ return loopback_points_list_detach(&loopback_list_head, changed, umount_log_level);
}
-int dm_detach_all(bool *changed) {
+int dm_detach_all(bool *changed, int umount_log_level) {
+ _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, dm_list_head);
int r;
- LIST_HEAD(MountPoint, dm_list_head);
+
+ assert(changed);
LIST_HEAD_INIT(dm_list_head);
r = dm_list_get(&dm_list_head);
if (r < 0)
- goto end;
-
- r = dm_points_list_detach(&dm_list_head, changed);
-
- end:
- mount_points_list_free(&dm_list_head);
+ return r;
- return r;
+ return dm_points_list_detach(&dm_list_head, changed, umount_log_level);
}
diff --git a/src/core/umount.h b/src/core/umount.h
index 7c029c384c..6f2b24d195 100644
--- a/src/core/umount.h
+++ b/src/core/umount.h
@@ -2,28 +2,29 @@
#pragma once
/***
- This file is part of systemd.
-
- Copyright 2010 ProFUSION embedded systems
+ Copyright © 2010 ProFUSION embedded systems
+***/
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
+#include "list.h"
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
+int umount_all(bool *changed, int umount_log_level);
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
+int swapoff_all(bool *changed);
-int umount_all(bool *changed);
+int loopback_detach_all(bool *changed, int umount_log_level);
-int swapoff_all(bool *changed);
+int dm_detach_all(bool *changed, int umount_log_level);
-int loopback_detach_all(bool *changed);
+/* This is exported just for testing */
+typedef struct MountPoint {
+ char *path;
+ char *remount_options;
+ unsigned long remount_flags;
+ bool try_remount_ro;
+ dev_t devnum;
+ LIST_FIELDS(struct MountPoint, mount_point);
+} MountPoint;
-int dm_detach_all(bool *changed);
+int mount_points_list_get(const char *mountinfo, MountPoint **head);
+void mount_points_list_free(MountPoint **head);
+int swap_list_get(const char *swaps, MountPoint **head);
diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c
index e61e0d1475..046e937e92 100644
--- a/src/core/unit-printf.c
+++ b/src/core/unit-printf.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include "alloc-util.h"
#include "cgroup-util.h"
@@ -68,6 +50,37 @@ static int specifier_instance_unescaped(char specifier, void *data, void *userda
return unit_name_unescape(strempty(u->instance), ret);
}
+static int specifier_last_component(char specifier, void *data, void *userdata, char **ret) {
+ Unit *u = userdata;
+ _cleanup_free_ char *prefix = NULL;
+ char *dash;
+ int r;
+
+ assert(u);
+
+ r = unit_name_to_prefix(u->id, &prefix);
+ if (r < 0)
+ return r;
+
+ dash = strrchr(prefix, '-');
+ if (dash)
+ return specifier_string(specifier, dash + 1, userdata, ret);
+
+ *ret = TAKE_PTR(prefix);
+ return 0;
+}
+
+static int specifier_last_component_unescaped(char specifier, void *data, void *userdata, char **ret) {
+ _cleanup_free_ char *p = NULL;
+ int r;
+
+ r = specifier_last_component(specifier, data, userdata, &p);
+ if (r < 0)
+ return r;
+
+ return unit_name_unescape(p, ret);
+}
+
static int specifier_filename(char specifier, void *data, void *userdata, char **ret) {
Unit *u = userdata;
@@ -214,6 +227,9 @@ int unit_full_printf(Unit *u, const char *format, char **ret) {
* %S: the state directory root (e.g. /var/lib or $XDG_CONFIG_HOME)
* %C: the cache directory root (e.g. /var/cache or $XDG_CACHE_HOME)
* %L: the log directory root (e.g. /var/log or $XDG_CONFIG_HOME/log)
+ * %E: the configuration directory root (e.g. /etc or $XDG_CONFIG_HOME)
+ * %T: the temporary directory (e.g. /tmp, or $TMPDIR, $TEMP, $TMP)
+ * %V: the temporary directory for large, persistent stuff (e.g. /var/tmp, or $TMPDIR, $TEMP, $TMP)
*
* %h: the homedir of the running user
* %s: the shell of the running user
@@ -226,31 +242,37 @@ int unit_full_printf(Unit *u, const char *format, char **ret) {
*/
const Specifier table[] = {
- { 'n', specifier_string, u->id },
- { 'N', specifier_prefix_and_instance, NULL },
- { 'p', specifier_prefix, NULL },
- { 'P', specifier_prefix_unescaped, NULL },
- { 'i', specifier_string, u->instance },
- { 'I', specifier_instance_unescaped, NULL },
-
- { 'f', specifier_filename, NULL },
- { 'c', specifier_cgroup, NULL },
- { 'r', specifier_cgroup_slice, NULL },
- { 'R', specifier_cgroup_root, NULL },
- { 't', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_RUNTIME) },
- { 'S', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_STATE) },
- { 'C', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_CACHE) },
- { 'L', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_LOGS) },
-
- { 'U', specifier_user_id, NULL },
- { 'u', specifier_user_name, NULL },
- { 'h', specifier_user_home, NULL },
- { 's', specifier_user_shell, NULL },
-
- { 'm', specifier_machine_id, NULL },
- { 'H', specifier_host_name, NULL },
- { 'b', specifier_boot_id, NULL },
- { 'v', specifier_kernel_release, NULL },
+ { 'n', specifier_string, u->id },
+ { 'N', specifier_prefix_and_instance, NULL },
+ { 'p', specifier_prefix, NULL },
+ { 'P', specifier_prefix_unescaped, NULL },
+ { 'i', specifier_string, u->instance },
+ { 'I', specifier_instance_unescaped, NULL },
+ { 'j', specifier_last_component, NULL },
+ { 'J', specifier_last_component_unescaped, NULL },
+
+ { 'f', specifier_filename, NULL },
+ { 'c', specifier_cgroup, NULL },
+ { 'r', specifier_cgroup_slice, NULL },
+ { 'R', specifier_cgroup_root, NULL },
+
+ { 't', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_RUNTIME) },
+ { 'S', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_STATE) },
+ { 'C', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_CACHE) },
+ { 'L', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_LOGS) },
+ { 'E', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_CONFIGURATION) },
+ { 'T', specifier_tmp_dir, NULL },
+ { 'V', specifier_var_tmp_dir, NULL },
+
+ { 'U', specifier_user_id, NULL },
+ { 'u', specifier_user_name, NULL },
+ { 'h', specifier_user_home, NULL },
+ { 's', specifier_user_shell, NULL },
+
+ { 'm', specifier_machine_id, NULL },
+ { 'H', specifier_host_name, NULL },
+ { 'b', specifier_boot_id, NULL },
+ { 'v', specifier_kernel_release, NULL },
{}
};
diff --git a/src/core/unit-printf.h b/src/core/unit-printf.h
index f1b620e162..5bd1d77bb2 100644
--- a/src/core/unit-printf.h
+++ b/src/core/unit-printf.h
@@ -1,25 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include "unit.h"
int unit_name_printf(Unit *u, const char* text, char **ret);
diff --git a/src/core/unit.c b/src/core/unit.c
index c3056624ef..113205bf25 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -1,22 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
#include <stdlib.h>
@@ -29,6 +11,7 @@
#include "sd-messages.h"
#include "alloc-util.h"
+#include "all-units.h"
#include "bus-common-errors.h"
#include "bus-util.h"
#include "cgroup-util.h"
@@ -128,7 +111,7 @@ Unit *unit_new(Manager *m, size_t size) {
}
int unit_new_for_name(Manager *m, size_t size, const char *name, Unit **ret) {
- Unit *u;
+ _cleanup_(unit_freep) Unit *u = NULL;
int r;
u = unit_new(m, size);
@@ -136,12 +119,11 @@ int unit_new_for_name(Manager *m, size_t size, const char *name, Unit **ret) {
return -ENOMEM;
r = unit_add_name(u, name);
- if (r < 0) {
- unit_free(u);
+ if (r < 0)
return r;
- }
- *ret = u;
+ *ret = TAKE_PTR(u);
+
return r;
}
@@ -267,13 +249,11 @@ int unit_add_name(Unit *u, const char *text) {
if (u->type == _UNIT_TYPE_INVALID) {
u->type = t;
u->id = s;
- u->instance = i;
+ u->instance = TAKE_PTR(i);
LIST_PREPEND(units_by_type, u->manager->units_by_type[t], u);
unit_init(u);
-
- i = NULL;
}
s = NULL;
@@ -582,8 +562,9 @@ void unit_free(Unit *u) {
unit_done(u);
- sd_bus_slot_unref(u->match_bus_slot);
+ unit_dequeue_rewatch_pids(u);
+ sd_bus_slot_unref(u->match_bus_slot);
sd_bus_track_unref(u->bus_track);
u->deserialized_refs = strv_free(u->deserialized_refs);
@@ -650,6 +631,9 @@ void unit_free(Unit *u) {
if (u->in_cleanup_queue)
LIST_REMOVE(cleanup_queue, u->manager->cleanup_queue, u);
+ if (u->in_target_deps_queue)
+ LIST_REMOVE(target_deps_queue, u->manager->target_deps_queue, u);
+
safe_close(u->ip_accounting_ingress_map_fd);
safe_close(u->ip_accounting_egress_map_fd);
@@ -710,10 +694,8 @@ static int set_complete_move(Set **s, Set **other) {
if (*s)
return set_move(*s, *other);
- else {
- *s = *other;
- *other = NULL;
- }
+ else
+ *s = TAKE_PTR(*other);
return 0;
}
@@ -727,10 +709,8 @@ static int hashmap_complete_move(Hashmap **s, Hashmap **other) {
if (*s)
return hashmap_move(*s, *other);
- else {
- *s = *other;
- *other = NULL;
- }
+ else
+ *s = TAKE_PTR(*other);
return 0;
}
@@ -1069,7 +1049,7 @@ static void print_unit_dependency_mask(FILE *f, const char *kind, UnitDependency
if (mask == 0)
break;
- if ((mask & table[i].mask) == table[i].mask) {
+ if (FLAGS_SET(mask, table[i].mask)) {
if (*space)
fputc(' ', f);
else
@@ -1331,7 +1311,7 @@ int unit_load_fragment_and_dropin_optional(Unit *u) {
/* Same as unit_load_fragment_and_dropin(), but whether
* something can be loaded or not doesn't matter. */
- /* Load a .service file */
+ /* Load a .service/.socket/.slice/… file */
r = unit_load_fragment(u);
if (r < 0)
return r;
@@ -1343,6 +1323,18 @@ int unit_load_fragment_and_dropin_optional(Unit *u) {
return unit_load_dropin(unit_follow_merge(u));
}
+void unit_add_to_target_deps_queue(Unit *u) {
+ Manager *m = u->manager;
+
+ assert(u);
+
+ if (u->in_target_deps_queue)
+ return;
+
+ LIST_PREPEND(target_deps_queue, m->target_deps_queue, u);
+ u->in_target_deps_queue = true;
+}
+
int unit_add_default_target_dependency(Unit *u, Unit *target) {
assert(u);
assert(target);
@@ -1369,35 +1361,6 @@ int unit_add_default_target_dependency(Unit *u, Unit *target) {
return unit_add_dependency(target, UNIT_AFTER, u, true, UNIT_DEPENDENCY_DEFAULT);
}
-static int unit_add_target_dependencies(Unit *u) {
-
- static const UnitDependency deps[] = {
- UNIT_REQUIRED_BY,
- UNIT_REQUISITE_OF,
- UNIT_WANTED_BY,
- UNIT_BOUND_BY
- };
-
- unsigned k;
- int r = 0;
-
- assert(u);
-
- for (k = 0; k < ELEMENTSOF(deps); k++) {
- Unit *target;
- Iterator i;
- void *v;
-
- HASHMAP_FOREACH_KEY(v, target, u->dependencies[deps[k]], i) {
- r = unit_add_default_target_dependency(u, target);
- if (r < 0)
- return r;
- }
- }
-
- return r;
-}
-
static int unit_add_slice_dependencies(Unit *u) {
UnitDependencyMask mask;
assert(u);
@@ -1526,10 +1489,7 @@ int unit_load(Unit *u) {
}
if (u->load_state == UNIT_LOADED) {
-
- r = unit_add_target_dependencies(u);
- if (r < 0)
- goto fail;
+ unit_add_to_target_deps_queue(u);
r = unit_add_slice_dependencies(u);
if (r < 0)
@@ -1545,7 +1505,7 @@ int unit_load(Unit *u) {
if (u->on_failure_job_mode == JOB_ISOLATE && hashmap_size(u->dependencies[UNIT_ON_FAILURE]) > 1) {
log_unit_error(u, "More than one OnFailure= dependencies specified but OnFailureJobMode=isolate set. Refusing.");
- r = -EINVAL;
+ r = -ENOEXEC;
goto fail;
}
@@ -1563,14 +1523,18 @@ int unit_load(Unit *u) {
return 0;
fail:
- u->load_state = u->load_state == UNIT_STUB ? UNIT_NOT_FOUND : UNIT_ERROR;
+ /* We convert ENOEXEC errors to the UNIT_BAD_SETTING load state here. Configuration parsing code should hence
+ * return ENOEXEC to ensure units are placed in this state after loading */
+
+ u->load_state = u->load_state == UNIT_STUB ? UNIT_NOT_FOUND :
+ r == -ENOEXEC ? UNIT_BAD_SETTING :
+ UNIT_ERROR;
u->load_error = r;
+
unit_add_to_dbus_queue(u);
unit_add_to_gc_queue(u);
- log_unit_debug_errno(u, r, "Failed to load configuration: %m");
-
- return r;
+ return log_unit_debug_errno(u, r, "Failed to load configuration: %m");
}
static bool unit_condition_test_list(Unit *u, Condition *first, const char *(*to_string)(ConditionType t)) {
@@ -1716,8 +1680,7 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
LOG_MESSAGE("%s", buf),
LOG_UNIT_ID(u),
LOG_UNIT_INVOCATION_ID(u),
- mid,
- NULL);
+ mid);
}
void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t) {
@@ -1732,7 +1695,7 @@ void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t) {
int unit_start_limit_test(Unit *u) {
assert(u);
- if (ratelimit_test(&u->start_limit)) {
+ if (ratelimit_below(&u->start_limit)) {
u->start_limit_hit = false;
return 0;
}
@@ -1790,6 +1753,7 @@ static bool unit_verify_deps(Unit *u) {
* -EINVAL: Unit not loaded
* -EOPNOTSUPP: Unit type not supported
* -ENOLINK: The necessary dependencies are not fulfilled.
+ * -ESTALE: This unit has been started before and can't be started a second time
*/
int unit_start(Unit *u) {
UnitActiveState state;
@@ -1809,6 +1773,10 @@ int unit_start(Unit *u) {
if (u->load_state != UNIT_LOADED)
return -EINVAL;
+ /* Refuse starting scope units more than once */
+ if (UNIT_VTABLE(u)->once_only && dual_timestamp_is_set(&u->inactive_enter_timestamp))
+ return -ESTALE;
+
/* If the conditions failed, don't do anything at all. If we
* already are activating this call might still be useful to
* speed up activation in case there is some hold-off time,
@@ -1872,6 +1840,10 @@ bool unit_can_start(Unit *u) {
if (!unit_supported(u))
return false;
+ /* Scope units may be started only once */
+ if (UNIT_VTABLE(u)->once_only && dual_timestamp_is_set(&u->inactive_exit_timestamp))
+ return false;
+
return !!UNIT_VTABLE(u)->start;
}
@@ -1959,7 +1931,7 @@ int unit_reload(Unit *u) {
if (!UNIT_VTABLE(u)->reload) {
/* Unit doesn't have a reload function, but we need to propagate the reload anyway */
- unit_notify(u, unit_active_state(u), unit_active_state(u), true);
+ unit_notify(u, unit_active_state(u), unit_active_state(u), 0);
return 0;
}
@@ -2016,7 +1988,7 @@ static void unit_check_unneeded(Unit *u) {
/* If stopping a unit fails continuously we might enter a stop
* loop here, hence stop acting on the service being
* unnecessary after a while. */
- if (!ratelimit_test(&u->auto_stop_ratelimit)) {
+ if (!ratelimit_below(&u->auto_stop_ratelimit)) {
log_unit_warning(u, "Unit not needed anymore, but not stopping since we tried this too often recently.");
return;
}
@@ -2066,7 +2038,7 @@ static void unit_check_binds_to(Unit *u) {
/* If stopping a unit fails continuously we might enter a stop
* loop here, hence stop acting on the service being
* unnecessary after a while. */
- if (!ratelimit_test(&u->auto_stop_ratelimit)) {
+ if (!ratelimit_below(&u->auto_stop_ratelimit)) {
log_unit_warning(u, "Unit is bound to inactive unit %s, but not stopping since we tried this too often recently.", other->id);
return;
}
@@ -2153,6 +2125,7 @@ void unit_start_on_failure(Unit *u) {
Unit *other;
Iterator i;
void *v;
+ int r;
assert(u);
@@ -2162,11 +2135,11 @@ void unit_start_on_failure(Unit *u) {
log_unit_info(u, "Triggering OnFailure= dependencies.");
HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_ON_FAILURE], i) {
- int r;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- r = manager_add_job(u->manager, JOB_START, other, u->on_failure_job_mode, NULL, NULL);
+ r = manager_add_job(u->manager, JOB_START, other, u->on_failure_job_mode, &error, NULL);
if (r < 0)
- log_unit_error_errno(u, r, "Failed to enqueue OnFailure= job: %m");
+ log_unit_warning_errno(u, r, "Failed to enqueue OnFailure= job, ignoring: %s", bus_error_message(&error, r));
}
}
@@ -2324,10 +2297,9 @@ static void unit_update_on_console(Unit *u) {
manager_ref_console(u->manager);
else
manager_unref_console(u->manager);
-
}
-void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success) {
+void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlags flags) {
bool unexpected;
Manager *m;
@@ -2403,7 +2375,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
if (u->job->state == JOB_RUNNING) {
if (ns == UNIT_ACTIVE)
- job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED, true, false);
+ job_finish_and_invalidate(u->job, (flags & UNIT_NOTIFY_RELOAD_FAILURE) ? JOB_FAILED : JOB_DONE, true, false);
else if (!IN_SET(ns, UNIT_ACTIVATING, UNIT_RELOADING)) {
unexpected = true;
@@ -2456,7 +2428,9 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
if (ns != os && ns == UNIT_FAILED) {
log_unit_debug(u, "Unit entered failed state.");
- unit_start_on_failure(u);
+
+ if (!(flags & UNIT_NOTIFY_WILL_AUTO_RESTART))
+ unit_start_on_failure(u);
}
}
@@ -2504,6 +2478,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
manager_recheck_journal(m);
manager_recheck_dbus(m);
+
unit_trigger_notify(u);
if (!MANAGER_IS_RELOADING(u->manager)) {
@@ -2629,7 +2604,8 @@ void unit_unwatch_all_pids(Unit *u) {
u->pids = set_free(u->pids);
}
-void unit_tidy_watch_pids(Unit *u, pid_t except1, pid_t except2) {
+static void unit_tidy_watch_pids(Unit *u) {
+ pid_t except1, except2;
Iterator i;
void *e;
@@ -2637,6 +2613,9 @@ void unit_tidy_watch_pids(Unit *u, pid_t except1, pid_t except2) {
/* Cleans dead PIDs from our list */
+ except1 = unit_main_pid(u);
+ except2 = unit_control_pid(u);
+
SET_FOREACH(e, u->pids, i) {
pid_t pid = PTR_TO_PID(e);
@@ -2648,6 +2627,76 @@ void unit_tidy_watch_pids(Unit *u, pid_t except1, pid_t except2) {
}
}
+static int on_rewatch_pids_event(sd_event_source *s, void *userdata) {
+ Unit *u = userdata;
+
+ assert(s);
+ assert(u);
+
+ unit_tidy_watch_pids(u);
+ unit_watch_all_pids(u);
+
+ /* If the PID set is empty now, then let's finish this off. */
+ unit_synthesize_cgroup_empty_event(u);
+
+ return 0;
+}
+
+int unit_enqueue_rewatch_pids(Unit *u) {
+ int r;
+
+ assert(u);
+
+ if (!u->cgroup_path)
+ return -ENOENT;
+
+ r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER);
+ if (r < 0)
+ return r;
+ if (r > 0) /* On unified we can use proper notifications */
+ return 0;
+
+ /* Enqueues a low-priority job that will clean up dead PIDs from our list of PIDs to watch and subscribe to new
+ * PIDs that might have appeared. We do this in a delayed job because the work might be quite slow, as it
+ * involves issuing kill(pid, 0) on all processes we watch. */
+
+ if (!u->rewatch_pids_event_source) {
+ _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
+
+ r = sd_event_add_defer(u->manager->event, &s, on_rewatch_pids_event, u);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate event source for tidying watched PIDs: %m");
+
+ r = sd_event_source_set_priority(s, SD_EVENT_PRIORITY_IDLE);
+ if (r < 0)
+ return log_error_errno(r, "Failed to adjust priority of event source for tidying watched PIDs: m");
+
+ (void) sd_event_source_set_description(s, "tidy-watch-pids");
+
+ u->rewatch_pids_event_source = TAKE_PTR(s);
+ }
+
+ r = sd_event_source_set_enabled(u->rewatch_pids_event_source, SD_EVENT_ONESHOT);
+ if (r < 0)
+ return log_error_errno(r, "Failed to enable event source for tidying watched PIDs: %m");
+
+ return 0;
+}
+
+void unit_dequeue_rewatch_pids(Unit *u) {
+ int r;
+ assert(u);
+
+ if (!u->rewatch_pids_event_source)
+ return;
+
+ r = sd_event_source_set_enabled(u->rewatch_pids_event_source, SD_EVENT_OFF);
+ if (r < 0)
+ log_warning_errno(r, "Failed to disable event source for tidying watched PIDs, ignoring: %m");
+
+ u->rewatch_pids_event_source = sd_event_source_unref(u->rewatch_pids_event_source);
+}
+
bool unit_job_is_applicable(Unit *u, JobType j) {
assert(u);
assert(j >= 0 && j < _JOB_TYPE_MAX);
@@ -2721,8 +2770,8 @@ static int unit_add_dependency_hashmap(
if (info.data) {
/* Entry already exists. Add in our mask. */
- if ((info.origin_mask & origin_mask) == info.origin_mask &&
- (info.destination_mask & destination_mask) == info.destination_mask)
+ if (FLAGS_SET(origin_mask, info.origin_mask) &&
+ FLAGS_SET(destination_mask, info.destination_mask))
return 0; /* NOP */
info.origin_mask |= origin_mask;
@@ -3628,7 +3677,6 @@ void unit_deserialize_skip(FILE *f) {
}
}
-
int unit_add_node_dependency(Unit *u, const char *what, bool wants, UnitDependency dep, UnitDependencyMask mask) {
Unit *device;
_cleanup_free_ char *e = NULL;
@@ -3680,8 +3728,7 @@ int unit_coldplug(Unit *u) {
assert(u);
- /* Make sure we don't enter a loop, when coldplugging
- * recursively. */
+ /* Make sure we don't enter a loop, when coldplugging recursively. */
if (u->coldplugged)
return 0;
@@ -3709,6 +3756,13 @@ int unit_coldplug(Unit *u) {
return r;
}
+void unit_catchup(Unit *u) {
+ assert(u);
+
+ if (UNIT_VTABLE(u)->catchup)
+ UNIT_VTABLE(u)->catchup(u);
+}
+
static bool fragment_mtime_newer(const char *path, usec_t mtime, bool path_masked) {
struct stat st;
@@ -3843,7 +3897,7 @@ int unit_kill(Unit *u, KillWho w, int signo, sd_bus_error *error) {
}
static Set *unit_pid_set(pid_t main_pid, pid_t control_pid) {
- Set *pid_set;
+ _cleanup_set_free_ Set *pid_set = NULL;
int r;
pid_set = set_new(NULL);
@@ -3854,20 +3908,16 @@ static Set *unit_pid_set(pid_t main_pid, pid_t control_pid) {
if (main_pid > 0) {
r = set_put(pid_set, PID_TO_PTR(main_pid));
if (r < 0)
- goto fail;
+ return NULL;
}
if (control_pid > 0) {
r = set_put(pid_set, PID_TO_PTR(control_pid));
if (r < 0)
- goto fail;
+ return NULL;
}
- return pid_set;
-
-fail:
- set_free(pid_set);
- return NULL;
+ return TAKE_PTR(pid_set);
}
int unit_kill_common(
@@ -4017,8 +4067,7 @@ static int user_from_unit_name(Unit *u, char **ret) {
return r;
if (valid_user_group_name(n)) {
- *ret = n;
- n = NULL;
+ *ret = TAKE_PTR(n);
return 0;
}
@@ -4220,7 +4269,7 @@ char* unit_escape_setting(const char *s, UnitWriteFlags flags, char **buf) {
char* unit_concat_strv(char **l, UnitWriteFlags flags) {
_cleanup_free_ char *result = NULL;
size_t n = 0, allocated = 0;
- char **i, *ret;
+ char **i;
/* Takes a list of strings, escapes them, and concatenates them. This may be used to format command lines in a
* way suitable for ExecStart= stanzas */
@@ -4255,10 +4304,7 @@ char* unit_concat_strv(char **l, UnitWriteFlags flags) {
result[n] = 0;
- ret = result;
- result = NULL;
-
- return ret;
+ return TAKE_PTR(result);
}
int unit_write_setting(Unit *u, UnitWriteFlags flags, const char *name, const char *data) {
@@ -4562,7 +4608,8 @@ int unit_kill_context(
}
int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask) {
- char prefix[strlen(path) + 1], *p;
+ _cleanup_free_ char *p = NULL;
+ char *prefix;
UnitDependencyInfo di;
int r;
@@ -4585,34 +4632,30 @@ int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask)
if (!p)
return -ENOMEM;
- path_kill_slashes(p);
+ path = path_simplify(p, false);
- if (!path_is_normalized(p)) {
- free(p);
+ if (!path_is_normalized(path))
return -EPERM;
- }
- if (hashmap_contains(u->requires_mounts_for, p)) {
- free(p);
+ if (hashmap_contains(u->requires_mounts_for, path))
return 0;
- }
di = (UnitDependencyInfo) {
.origin_mask = mask
};
- r = hashmap_put(u->requires_mounts_for, p, di.data);
- if (r < 0) {
- free(p);
+ r = hashmap_put(u->requires_mounts_for, path, di.data);
+ if (r < 0)
return r;
- }
+ p = NULL;
- PATH_FOREACH_PREFIX_MORE(prefix, p) {
+ prefix = alloca(strlen(path) + 1);
+ PATH_FOREACH_PREFIX_MORE(prefix, path) {
Set *x;
x = hashmap_get(u->manager->units_requiring_mounts_for, prefix);
if (!x) {
- char *q;
+ _cleanup_free_ char *q = NULL;
r = hashmap_ensure_allocated(&u->manager->units_requiring_mounts_for, &path_hash_ops);
if (r < 0)
@@ -4623,17 +4666,15 @@ int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask)
return -ENOMEM;
x = set_new(NULL);
- if (!x) {
- free(q);
+ if (!x)
return -ENOMEM;
- }
r = hashmap_put(u->manager->units_requiring_mounts_for, q, x);
if (r < 0) {
- free(q);
set_free(x);
return r;
}
+ q = NULL;
}
r = set_put(x, u);
@@ -4721,8 +4762,7 @@ void unit_warn_if_dir_nonempty(Unit *u, const char* where) {
LOG_UNIT_ID(u),
LOG_UNIT_INVOCATION_ID(u),
LOG_UNIT_MESSAGE(u, "Directory %s to mount over is not empty, mounting anyway.", where),
- "WHERE=%s", where,
- NULL);
+ "WHERE=%s", where);
}
int unit_fail_if_noncanonical(Unit *u, const char* where) {
@@ -4748,8 +4788,7 @@ int unit_fail_if_noncanonical(Unit *u, const char* where) {
LOG_UNIT_ID(u),
LOG_UNIT_INVOCATION_ID(u),
LOG_UNIT_MESSAGE(u, "Mount path %s is not canonical (contains a symlink).", where),
- "WHERE=%s", where,
- NULL);
+ "WHERE=%s", where);
return -ELOOP;
}
@@ -4760,9 +4799,8 @@ bool unit_is_pristine(Unit *u) {
/* Check if the unit already exists or is already around,
* in a number of different ways. Note that to cater for unit
* types such as slice, we are generally fine with units that
- * are marked UNIT_LOADED even though nothing was
- * actually loaded, as those unit types don't require a file
- * on disk to validly load. */
+ * are marked UNIT_LOADED even though nothing was actually
+ * loaded, as those unit types don't require a file on disk. */
return !(!IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_LOADED) ||
u->fragment_path ||
@@ -5215,6 +5253,9 @@ void unit_export_state_files(Unit *u) {
if (!MANAGER_IS_SYSTEM(u->manager))
return;
+ if (u->manager->test_run_flags != 0)
+ return;
+
/* Exports a couple of unit properties to /run/systemd/units/, so that journald can quickly query this data
* from there. Ideally, journald would use IPC to query this, like everybody else, but that's hard, as long as
* the IPC system itself and PID 1 also log to the journal.
@@ -5378,7 +5419,7 @@ int unit_pid_attachable(Unit *u, pid_t pid, sd_bus_error *error) {
/* Some extra safety check */
if (pid == 1 || pid == getpid_cached())
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Process " PID_FMT " is a manager processs, refusing.", pid);
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Process " PID_FMT " is a manager process, refusing.", pid);
/* Don't even begin to bother with kernel threads */
r = is_kernel_thread(pid);
diff --git a/src/core/unit.h b/src/core/unit.h
index e903bf8ad7..b3131eba1b 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -1,34 +1,10 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
-typedef struct Unit Unit;
-typedef struct UnitVTable UnitVTable;
-typedef struct UnitRef UnitRef;
-typedef struct UnitStatusMessageFormats UnitStatusMessageFormats;
-
#include "bpf-program.h"
#include "condition.h"
#include "emergency-action.h"
@@ -37,6 +13,8 @@ typedef struct UnitStatusMessageFormats UnitStatusMessageFormats;
#include "unit-name.h"
#include "cgroup.h"
+typedef struct UnitRef UnitRef;
+
typedef enum KillOperation {
KILL_TERMINATE,
KILL_TERMINATE_AND_LOG,
@@ -102,7 +80,7 @@ typedef enum UnitDependencyMask {
/* A dependency created because of data read from /proc/swaps and no other configuration source */
UNIT_DEPENDENCY_PROC_SWAP = 1 << 7,
- _UNIT_DEPENDENCY_MASK_FULL = (1 << 8) - 1,
+ _UNIT_DEPENDENCY_MASK_FULL = (1 << 8) - 1,
} UnitDependencyMask;
/* The Unit's dependencies[] hashmaps use this structure as value. It has the same size as a void pointer, and thus can
@@ -133,7 +111,7 @@ typedef enum UnitCGroupBPFState {
UNIT_CGROUP_BPF_INVALIDATED = -1,
} UnitCGroupBPFState;
-struct Unit {
+typedef struct Unit {
Manager *manager;
UnitType type;
@@ -231,6 +209,9 @@ struct Unit {
/* cgroup empty queue */
LIST_FIELDS(Unit, cgroup_empty_queue);
+ /* Target dependencies queue */
+ LIST_FIELDS(Unit, target_deps_queue);
+
/* PIDs we keep an eye on. Note that a unit might have many
* more, but these are the ones we care enough about to
* process SIGCHLD for */
@@ -292,6 +273,10 @@ struct Unit {
uint64_t ip_accounting_extra[_CGROUP_IP_ACCOUNTING_METRIC_MAX];
+ /* Low-priority event source which is used to remove watched PIDs that have gone away, and subscribe to any new
+ * ones which might have appeared. */
+ sd_event_source *rewatch_pids_event_source;
+
/* How to start OnFailure units */
JobMode on_failure_job_mode;
@@ -336,6 +321,7 @@ struct Unit {
bool in_gc_queue:1;
bool in_cgroup_realize_queue:1;
bool in_cgroup_empty_queue:1;
+ bool in_target_deps_queue:1;
bool sent_dbus_new_signal:1;
@@ -367,13 +353,13 @@ struct Unit {
/* When writing transient unit files, stores which section we stored last. If < 0, we didn't write any yet. If
* == 0 we are in the [Unit] section, if > 0 we are in the unit type-specific section. */
int last_section_private:2;
-};
+} Unit;
-struct UnitStatusMessageFormats {
+typedef struct UnitStatusMessageFormats {
const char *starting_stopping[2];
const char *finished_start_job[_JOB_RESULT_MAX];
const char *finished_stop_job[_JOB_RESULT_MAX];
-};
+} UnitStatusMessageFormats;
/* Flags used when writing drop-in files or transient unit files */
typedef enum UnitWriteFlags {
@@ -396,17 +382,9 @@ typedef enum UnitWriteFlags {
/* Returns true if neither persistent, nor runtime storage is requested, i.e. this is a check invocation only */
#define UNIT_WRITE_FLAGS_NOOP(flags) (((flags) & (UNIT_RUNTIME|UNIT_PERSISTENT)) == 0)
-#include "automount.h"
-#include "device.h"
-#include "path.h"
-#include "scope.h"
-#include "slice.h"
-#include "socket.h"
-#include "swap.h"
-#include "target.h"
-#include "timer.h"
-
-struct UnitVTable {
+#include "kill.h"
+
+typedef struct UnitVTable {
/* How much memory does an object of this unit type need */
size_t object_size;
@@ -453,10 +431,14 @@ struct UnitVTable {
* UNIT_STUB if no configuration could be found. */
int (*load)(Unit *u);
- /* If a lot of units got created via enumerate(), this is
- * where to actually set the state and call unit_notify(). */
+ /* During deserialization we only record the intended state to return to. With coldplug() we actually put the
+ * deserialized state in effect. This is where unit_notify() should be called to start things up. */
int (*coldplug)(Unit *u);
+ /* This is called shortly after all units' coldplug() call was invoked. It's supposed to catch up state changes
+ * we missed so far (for example because they took place while we were reloading/reexecing) */
+ void (*catchup)(Unit *u);
+
void (*dump)(Unit *u, FILE *f, const char *prefix);
int (*start)(Unit *u);
@@ -532,6 +514,9 @@ struct UnitVTable {
/* Called whenever CLOCK_REALTIME made a jump */
void (*time_change)(Unit *u);
+ /* Called whenever /etc/localtime was modified */
+ void (*timezone_change)(Unit *u);
+
/* Returns the next timeout of a unit */
int (*get_timeout)(Unit *u, usec_t *timeout);
@@ -544,11 +529,15 @@ struct UnitVTable {
/* Returns true if the unit currently needs access to the console */
bool (*needs_console)(Unit *u);
- /* This is called for each unit type and should be used to
- * enumerate existing devices and load them. However,
- * everything that is loaded here should still stay in
- * inactive state. It is the job of the coldplug() call above
- * to put the units into the initial state. */
+ /* Like the enumerate() callback further down, but only enumerates the perpetual units, i.e. all units that
+ * unconditionally exist and are always active. The main reason to keep both enumeration functions separate is
+ * philosophical: the state of perpetual units should be put in place by coldplug(), while the state of those
+ * discovered through regular enumeration should be put in place by catchup(), see below. */
+ void (*enumerate_perpetual)(Manager *m);
+
+ /* This is called for each unit type and should be used to enumerate units already existing in the system
+ * internally and load them. However, everything that is loaded here should still stay in inactive state. It is
+ * the job of the catchup() call above to put the units into the discovered state. */
void (*enumerate)(Manager *m);
/* Type specific cleanups. */
@@ -570,9 +559,12 @@ struct UnitVTable {
/* True if cgroup delegation is permissible */
bool can_delegate:1;
+ /* True if units of this type shall be startable only once and then never again */
+ bool once_only:1;
+
/* True if queued jobs of this type should be GC'ed if no other job needs them anymore */
bool gc_jobs:1;
-};
+} UnitVTable;
extern const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX];
@@ -596,20 +588,9 @@ extern const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX];
#define UNIT_TRIGGER(u) ((Unit*) hashmap_first_key((u)->dependencies[UNIT_TRIGGERS]))
-DEFINE_CAST(SERVICE, Service);
-DEFINE_CAST(SOCKET, Socket);
-DEFINE_CAST(TARGET, Target);
-DEFINE_CAST(DEVICE, Device);
-DEFINE_CAST(MOUNT, Mount);
-DEFINE_CAST(AUTOMOUNT, Automount);
-DEFINE_CAST(SWAP, Swap);
-DEFINE_CAST(TIMER, Timer);
-DEFINE_CAST(PATH, Path);
-DEFINE_CAST(SLICE, Slice);
-DEFINE_CAST(SCOPE, Scope);
-
Unit *unit_new(Manager *m, size_t size);
void unit_free(Unit *u);
+DEFINE_TRIVIAL_CLEANUP_FUNC(Unit *, unit_free);
int unit_new_for_name(Manager *m, size_t size, const char *name, Unit **ret);
int unit_add_name(Unit *u, const char *name);
@@ -631,6 +612,7 @@ void unit_add_to_load_queue(Unit *u);
void unit_add_to_dbus_queue(Unit *u);
void unit_add_to_cleanup_queue(Unit *u);
void unit_add_to_gc_queue(Unit *u);
+void unit_add_to_target_deps_queue(Unit *u);
int unit_merge(Unit *u, Unit *other);
int unit_merge_by_name(Unit *u, const char *other);
@@ -666,13 +648,19 @@ int unit_reload(Unit *u);
int unit_kill(Unit *u, KillWho w, int signo, sd_bus_error *error);
int unit_kill_common(Unit *u, KillWho who, int signo, pid_t main_pid, pid_t control_pid, sd_bus_error *error);
-void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success);
+typedef enum UnitNotifyFlags {
+ UNIT_NOTIFY_RELOAD_FAILURE = 1 << 0,
+ UNIT_NOTIFY_WILL_AUTO_RESTART = 1 << 1,
+} UnitNotifyFlags;
+
+void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlags flags);
int unit_watch_pid(Unit *u, pid_t pid);
void unit_unwatch_pid(Unit *u, pid_t pid);
void unit_unwatch_all_pids(Unit *u);
-void unit_tidy_watch_pids(Unit *u, pid_t except1, pid_t except2);
+int unit_enqueue_rewatch_pids(Unit *u);
+void unit_dequeue_rewatch_pids(Unit *u);
int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name);
int unit_watch_bus_name(Unit *u, const char *name);
@@ -701,6 +689,7 @@ void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *v
int unit_add_node_dependency(Unit *u, const char *what, bool wants, UnitDependency d, UnitDependencyMask mask);
int unit_coldplug(Unit *u);
+void unit_catchup(Unit *u);
void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) _printf_(3, 0);
void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t);